August 26, 2026

Release Notes for Safari Technology Preview 251

Surfin’ Safari

Safari Technology Preview Release 251 is now available for download for macOS Golden Gate and macOS Tahoe. If you already have Safari Technology Preview installed, you can update it in System Settings under General → Software Update.

This release includes WebKit changes between: 317935@main…319386@main.

Accessibility

Resolved Issues

  • Fixed SVG anchors without an href being exposed as links. (318186@main) (181924326)

CSS

New Features

  • Added support for @supports at-rule(...), which tests if a CSS at-rule is supported. (318482@main) (87884897)
  • Added support for the object-view-box property. (318981@main) (132624217)
  • Added support for property-scoped and property-index-scoped caching keywords in random(). (318960@main) (176395332)
  • Added support for the random-item() function. (319180@main) (181816677)
  • Added support for a comma-separated list of conditions in @container queries. (318233@main) (182249814)
  • Added support for white-space-trim in the white-space shorthand. (318486@main) (182739052)
  • Added support for external and data: URL filter references on HTML elements. (317991@main) (183059589)
  • Added support for HighlightRegistry.highlightsFromPoint(). (318758@main) (184150480)
  • Added support for random() in custom properties. (319039@main) (184715508)
  • Added support for the ident() function. (319049@main) (184732904)
  • Added support for the inherit() function. (319062@main) (184738624)
  • Added support for the corner-shape property. (319205@main) (184950973)

Resolved Issues

  • Fixed text overflowing a max-width constrained box when the page is zoomed out, by scaling the minimum font size with the zoom factor. (318509@main) (66569768)
  • Fixed a background image not being repainted when only the URL fragment identifier changes. (318879@main) (105118256)
  • Fixed a subgrid with a large column-gap overflowing a parent constrained by max-width. (318009@main) (137422489)
  • Fixed nested @scope picking the wrong scoping roots when <scope-start> contains :has(:scope ...). (318711@main) (138495467)
  • Fixed outside list markers disappearing or being mispositioned around line breaks. (318561@main) (159277763)
  • Fixed the serialization of the size property in @page when both a page size and orientation are given. (318083@main) (162168233)
  • Fixed the computed value of outline-offset not being snapped as a line width. (319236@main) (180054053)
  • Fixed a flex item’s flex base size being clamped by its own min-width and max-width. (318264@main) (180064739)
  • Fixed :focus-visible being shown after calling focus() inside an already focused ancestor. (318775@main) (181570771)
  • Fixed multi-column height ignoring min-height when it exceeds max-height. (318676@main) (182381903)
  • Fixed scroll snap selecting among equally aligned snap targets in the wrong order. (317997@main) (182571341)
  • Fixed text-underline-offset being mispositioned for highlighted text in vertical writing modes. (318107@main) (182889143)
  • Fixed the serialization of an unrecognized media query to preserve the original text as closely as possible. (318627@main) (182958311)
  • Fixed the serialization of an unrecognized media query feature name to preserve the original casing. (318965@main) (183065105)
  • Fixed @container style queries evaluating root-relative lengths incorrectly. (318144@main) (183094796)
  • Fixed the originating element of ::part() in @container queries to be the element itself. (318620@main) (183154183)
  • Fixed an anti-aliased fringe on ::highlight() background fills in vertical writing modes. (318177@main) (183496114)
  • Fixed the first baseline of a wrap-reverse flex container coming from the wrong flex line. (318154@main) (183516222)
  • Fixed a flex line’s cross size mixing the baseline and last baseline alignment groups. (318165@main) (183536181)
  • Fixed the -webkit-border-image width flag being lost when a length edge precedes a non-length edge. (318214@main) (183584830)
  • Fixed rounding of central baselines for atomic inline elements. (318268@main) (183584888)
  • Fixed the block-ellipsis of a clamped block being styled from the wrong block formatting context. (318437@main) (183606151)
  • Fixed ::highlight() pseudo-elements not inheriting from the parent element’s highlight. (318779@main) (183702060)
  • Fixed clip on a child being ignored when determining whether an ancestor’s background is obscured. (318636@main) (183841775)
  • Fixed var() not behaving as an arbitrary substitution function. (318912@main) (183913427)
  • Fixed line-height units resolving incorrectly when the page is zoomed. (318558@main) (184032914)
  • Fixed the computed value of line-height to more closely match how it was specified. (318710@main) (184232888)
  • Fixed font-* properties resolving font-relative units against their own font instead of the parent element’s font metrics. (319052@main) (184336424)
  • Fixed the rangeStart and rangeEnd animation attributes accepting length values that are not computationally independent when set from script. (318815@main) (184363719)
  • Fixed -webkit-text-stroke not applying to highlighted text. (318976@main) (184375039)
  • Fixed the ViewTimelineOptions inset member accepting length values that are not computationally independent when set from script. (318883@main) (184504829)
  • Fixed ::highlight() not repainting after a CSS rule change. (319169@main) (184643272)
  • Fixed ::highlight() not repainting when a highlight’s range is changed with CSS.highlights.set(). (319154@main) (184672580)
  • Fixed a @function body not inheriting computed custom property values from the calling context. (319031@main) (184701762)
  • Fixed arguments that invoke a @function being treated as a cycle. (319034@main) (184711017)
  • Fixed the random() caching key not including the custom property name. (319096@main) (184722866)
  • Fixed an auto <random-key> not being element-scoped, so every element shared the same item. (319153@main) (184845561)

Deprecations

  • Removed the non-standard percentage value from -webkit-line-clamp. (318858@main) (159808285)
  • Removed margin-trim support from flex containers, following the CSSWG resolution limiting it to block and multi-column containers. (318654@main) (184151309)
  • Removed margin-trim support from grid containers, following the CSSWG resolution limiting it to block and multi-column containers. (318690@main) (184164505)

Canvas

Resolved Issues

  • Fixed ctx.font not re-resolving relative font sizes when set to the same string after the canvas element’s style changed. (318753@main) (184194378)
  • Fixed the canvas font keywords larger and smaller scaling by 1.02 instead of approximately 1.2. (318798@main) (184312611)

HTML

New Features

  • Added support for popover=hint. (318958@main) (184548373)

Resolved Issues

  • Fixed a color input with display: none not opening when its <label> is clicked. (318723@main) (100476630)
  • Fixed createContextualFragment() leaving nested <head> and <body> elements behind when stripping a stray <html> element. (317962@main) (183163523)
  • Fixed a <label> default action triggering when clicked interactive content removes itself. (318827@main) (184381262)
  • Fixed clicking an element nested inside a checkbox or radio input wrongly activating the ancestor input. (318853@main) (184441087)
  • Fixed focus not being restored to the correct element when a <dialog> is closed. (319173@main) (184751412)
  • Fixed confirming an IME composition removing its containing positioned element. (319167@main) (184918934)

JavaScript

New Features

  • Added support for Iterator.prototype.includes(). (318184@main) (173846280)
  • Added support for the RegExp Buffer Boundaries proposal. (318415@main) (178287060)
  • Added support for era and monthCode fields in Intl and Temporal calendars. (318428@main) (182753821)
  • Added support for the traceStack option on WebAssembly.Exception and for Exception.stack. (318397@main) (183342491)
  • Added support for WebAssembly Memory64. (318257@main) (183543404)
  • Added support for deferred module evaluation with import defer. (318481@main) (183892394)
  • Added support for Iterator.prototype.join(). (318502@main) (183892495)
  • Added support for iterator chunking, including Iterator.prototype.chunks() and Iterator.prototype.windows(). (318479@main) (183892687)
  • Added support for the joint iteration proposal, including Iterator.zip() and Iterator.zipKeyed(). (318477@main) (183892768)
  • Added support for importing text modules with an import attribute of type: text. (318950@main) (184443879)

Resolved Issues

  • Fixed a regular expression with ^ inside a group that can match empty failing to anchor the pattern. (317981@main) (183300022)
  • Fixed incorrect matching for sticky regular expressions wrapped in .*. (317983@main) (183300106)
  • Fixed a JSON.stringify() regression in how toJSON is checked. (318072@main) (183400665)
  • Fixed Iterator.zip to use null-prototype objects for its options object and synthetic underlying iterator. (318061@main) (183418070)
  • Fixed incorrect matching for regular expressions containing a negative lookahead. (318234@main) (183601444)
  • Fixed module resolution ignoring the import attribute type in a module request. (318292@main) (183700464)
  • Fixed the Array.from() fast path ignoring a Symbol.iterator override on set.keys() and set.values(). (318374@main) (183801651)
  • Fixed stale character widths produced by v mode class set operations in regular expressions. (318416@main) (183879621)
  • Fixed incorrect matching for regular expressions containing a lookbehind. (318418@main) (183881829)
  • Fixed Temporal.PlainDate construction with years outside the supported range. (318504@main) (183960408)
  • Fixed a TypeError regression when passing monthCode to Temporal calendar methods. (318566@main) (183980712)
  • Fixed the order in which Temporal constructors read newTarget.prototype. (318635@main) (184072358)
  • Fixed the String.prototype.localeCompare() collator cache going stale after a language change. (318616@main) (184096794)
  • Fixed Temporal skipping the epoch range check when resolving a time inside a daylight saving time gap. (318663@main) (184140083)
  • Fixed Temporal time zone identifier parsing to match the specification’s parse records. (318741@main) (184169471)
  • Fixed Array.prototype.sort() not being stable when called without a comparator. (318682@main) (184189734)
  • Fixed global object attribute getters and setters throwing when called as bare functions from global scope. (318748@main) (184273476)
  • Fixed Iterator.prototype.join() to match the latest specification. (318806@main) (184321382)
  • Fixed Iterator.prototype.chunks() and Iterator.prototype.windows() to match the latest specification. (318802@main) (184321801)
  • Fixed Intl.Locale collections not being sorted. (318808@main) (184322384)
  • Fixed formatToParts() omitting the era separator that format() inserts. (318847@main) (184382546)
  • Fixed the import defer implementation to match the updated proposal. (318875@main) (184423667)
  • Fixed \P{...} on the right side of a v mode && or -- operation being treated as a union. (318854@main) (184443379)
  • Fixed Temporal.Duration rounding decisions being made on doubles instead of exact integers. (318901@main) (184472920)
  • Fixed non-ISO calendar date field resolution at the edges of the supported range. (318940@main) (184478785)
  • Fixed Temporal returning plausible values instead of throwing when an underlying calendar operation fails. (318953@main) (184567556)
  • Fixed a regular expression string-list alternative containing a non-BMP character matching on only its leading code units. (318956@main) (184582034)
  • Fixed the WebAssembly.Global value setter not treating a missing argument as undefined. (318967@main) (184608074)
  • Fixed Unicode property escapes ignoring case-insensitive matching in u and v modes. (319064@main) (184762230)
  • Fixed the Before Hijra era year being computed from rendered text instead of the calendar. (319172@main) (184853584)

Media

New Features

  • Added support for HTMLMediaElement.removeTextTrack(). (318250@main) (183365541)

Resolved Issues

  • Fixed WebVTT cue overlap avoidance to move a cue the shortest possible distance. (318012@main) (183151333)
  • Fixed legacy EME generateKeyRequest() returning an incorrect destination URL. (317970@main) (183305929)
  • Fixed requestFullscreen() and requestPictureInPicture() not consuming user activation. (318673@main) (183621577)
  • Fixed selecting On in the media controls captions menu not turning on subtitles. (318468@main) (183776073)
  • Fixed MediaRecorder dropping pending video frames when recording is stopped. (318595@main) (183975207)
  • Fixed the auto position of a WebVTT cue with start or end text alignment to be 50%. (318610@main) (184039946)
  • Fixed MediaRecorder dropping a frame whenever the writer input reports that it is not ready. (318778@main) (184271782)

Navigation API

New Features

  • Added support for the to property on NavigationTransition. (319142@main) (184792753)
  • Added support for intercepting a navigation with a precommit handler. (319208@main) (184893603)

Resolved Issues

  • Fixed sourceElement reporting the deepest clicked element instead of the element responsible for the navigation. (319005@main) (184581613)
  • Fixed NavigationHistoryEntry returning null instead of the empty string for url, key, and id when the document is not fully active. (319007@main) (184590003)
  • Fixed navigateEvent.scroll() not scrolling to the beginning of the document when the fragment does not exist. (319068@main) (184595100)
  • Fixed navigation.activation.from not being null when navigating away from the initial about:blank. (319217@main) (184624752)
  • Fixed navigateerror not firing for a navigation started from a navigateerror handler. (319222@main) (184633618)

Networking

New Features

  • Added support for backpressure when uploading a stream request body with fetch(). (318236@main) (183400867)

Resolved Issues

  • Fixed a same-frame fragment navigation cancelling a download started by a download attribute click in the same task. (319105@main) (165498647)
  • Fixed a page reloading continually by tracking the latest navigation action when considering Enhanced Security state changes. (318304@main) (183480452)
  • Fixed XMLHttpRequest.getAllResponseHeaders() returning the previous response’s headers when the object is reused. (318217@main) (183561750)
  • Fixed XMLHttpRequest.responseURL still returning the aborted request’s URL after calling abort(). (318241@main) (183587043)
  • Fixed the CNAME-cloaking cookie expiry cap being applied to a top-level page’s own cookies instead of only subresources. (318332@main) (183664485)
  • Fixed XMLHttpRequest.send() setting a Content-Type request header on GET and HEAD requests when passed a URLSearchParams. (318424@main) (183801778)
  • Fixed imagesrcset not overriding href on <link rel="preload" as="image">. (318544@main) (183945535)
  • Fixed <link rel=preload as> keywords not being matched ASCII case-insensitively. (318584@main) (184013239)
  • Fixed PDF byte-range requests being blocked by the connect-src Content Security Policy directive instead of object-src. (318797@main) (184258237)
  • Fixed a Content Security Policy host-source of the form *:*/path not matching. (318612@main) (184902666)
  • Fixed a policy decision that outlives its navigation being applied to an unrelated load. (319378@main) (184974939)

Rendering

Resolved Issues

  • Fixed text selection highlighting extending incorrectly when a float precedes the text. (319128@main) (109610452)
  • Fixed text underlines rendering incorrectly for Urdu text. (319220@main) (161299983)
  • Fixed a regression where editing text in some inputs stopped responding to backspace. (318095@main) (183391399)
  • Fixed text-align: justify justifying the last line of a block. (318562@main) (183976364)
  • Fixed Arabic letters in adjacent inline boxes not being joined. (319209@main) (184071471)
  • Fixed a self-collapsing block nested in an inline box losing its margin when the root has a border. (318646@main) (184145672)
  • Fixed trailing whitespace not being collapsed before a block nested in an inline box. (318653@main) (184151239)
  • Fixed baseline alignment ignoring the offset of a block level box nested in an inline box. (318656@main) (184153324)
  • Fixed an empty orthogonal block nested in an inline box stretching the line. (318659@main) (184158817)
  • Fixed the margin after a block level box on a line being lost on relayout. (318660@main) (184159645)
  • Fixed an empty editable container with only an out-of-flow child losing its line. (318671@main) (184176269)
  • Fixed a float inside a block nested in an inline box intruding at the wrong position. (318678@main) (184184683)
  • Fixed the baseline of an inline-block whose last line box holds a block level box dropping that line’s offset. (318702@main) (184222186)
  • Fixed nested inline boxes around a block level box being stretched by their nesting depth. (318704@main) (184222677)
  • Fixed an inline box with cloned decorations generating an extra line between two block level boxes. (318718@main) (184241600)
  • Fixed a block whose content is a table being treated as self-collapsing. (318782@main) (184337051)
  • Fixed a block level box’s margin after being counted twice when only that box needs layout. (318792@main) (184344633)
  • Fixed an outside list marker making its list item’s children inline. (318891@main) (184380304)
  • Fixed an excluded list marker aligning with a block level box on a line instead of the first line of text. (318908@main) (184405037)
  • Fixed a block level box on a line reporting its scrollable overflow at its static position. (318885@main) (184505703)
  • Fixed a block level box on a line not starting a new paragraph for unicode-bidi: plaintext and text-indent: each-line. (318886@main) (184505835)
  • Fixed a highlight on the line after a block level box covering the box’s margin. (318887@main) (184506039)
  • Fixed a block level box on a line switching off text-wrap: balance for the whole container. (318893@main) (184508888)
  • Fixed inline boxes that are not relatively positioned offsetting their out-of-flow children by the position of the line. (318897@main) (184512485)
  • Fixed a block level box on a line not contributing its margin box to its container’s overflow. (318906@main) (184526625)
  • Fixed list-based hit testing reporting the container before a block level box on an earlier line. (318909@main) (184527135)
  • Fixed selection gaps not being filled around a block level box on a line. (318911@main) (184527621)
  • Fixed line-clamp not counting the lines of a block level box on a line. (318921@main) (184545926)
  • Fixed a forced page break after a block level box on a line not moving the following content to the next page. (319029@main) (184712866)
  • Fixed a float not being offered to the caret when its container has a block level box on a line. (319030@main) (184713698)
  • Fixed a <fieldset> on a line taking its legend’s overhang twice. (319033@main) (184714637)
  • Fixed a box that collapsed through with clearance on a line pushing the following content down by its margin. (319160@main) (184917509)
  • Fixed intrinsic width computation when a line holds a block level box. (319212@main) (184968113)

SVG

New Features

  • Added support for external and data: URL filter references on SVG elements. (317538@main) (114823248)
  • Added support for passing a DOMMatrix2DInit dictionary to SVGMatrix.multiply(). (318109@main) (180896205)
  • Added support for external SVG resource references, including clip-path, marker, and paint servers. (318543@main) (183941298)

Resolved Issues

  • Fixed auto sizing of <svg:image> to follow the CSS default sizing algorithm. (318548@main) (122586485)
  • Fixed SVGSVGElement.currentScale being a no-op on an outermost <svg> that is not the document root. (318762@main) (180889449)
  • Fixed SVGLength.value returning negative numbers for r, rx, ry, width, height, and textLength, which disagreed with getComputedStyle(). (317963@main) (181108927)
  • Fixed a clip-path basic shape being mispositioned on a <foreignObject> with a non-zero x or y. (318904@main) (182755161)
  • Fixed feDropShadow ignoring an update to the Y component of stdDeviation when X changes. (318281@main) (183678196)
  • Fixed <animateMotion> ignoring a numeric rotate value. (318565@main) (183832405)
  • Fixed SVG enumerated attributes not reverting to their initial value when removed or set to an invalid value. (319093@main) (184076505)
  • Fixed dynamic changes to x and y on <foreignObject> having no effect. (318669@main) (184172530)
  • Fixed a clip-path basic shape being mispositioned on a rotated or scaled SVG element. (318924@main) (184494108)
  • Fixed <animateMotion> ignoring a zero-length motion path. (318963@main) (184569273)

Deprecations

  • Removed the SVGPathSegList collection and the SVGPathSeg family of interfaces from SVGPathElement, matching SVG 2. (318760@main) (115039851)

Scrolling

Resolved Issues

  • Fixed re-snapping to prefer the block-axis box when the two scroll axes conflict. (318343@main) (183366125)
  • Fixed scroll snapping when a scroll overshoots past the end of the scroll container. (318081@main) (183375912)
  • Fixed element.scroll() and element.scrollTo() not scrolling inside a content-visibility: hidden subtree. (319219@main) (184935071)

Service Workers

New Features

  • Added support for service workers reading stream upload data from a fetch event request body. (317964@main) (183108477)
  • Added support for stream upload backpressure when a service worker reads the upload data. (318346@main) (183529369)

Resolved Issues

  • Fixed a missing Sec-Fetch-Dest header on service worker script requests. (318237@main) (181909962)
  • Fixed network fallback being allowed after a fetch event request body was already disturbed. (318042@main) (183125740)
  • Fixed cancellation of a fetch event request body not being propagated to the original ReadableStream. (318043@main) (183317580)

Web API

Resolved Issues

  • Fixed: Improved the InvalidStateError message thrown by selection methods to explain what is invalid. (318520@main) (134645414)
  • Fixed a missing resize event when an iframe transitions from display: none to visible. (318713@main) (174638256)
  • Fixed timeOrigin being skewed for Navigation Timing entries when the browsing context group changes. (318057@main) (179332119)
  • Fixed the Digital Credentials API to consume transient activation before serializing the request. (318122@main) (182412996)
  • Fixed the Cookie Store API not preserving the order of the cookie change subscription list. (318087@main) (183271849)
  • Fixed notifications after the first persistent one not being closed. (318007@main) (183362637)
  • Fixed getBoundingClientRect() returning a non-zero rect for SVG elements inside hidden containers. (318744@main) (183425103)
  • Fixed quota accounting over-charging positioned writes through a FileSystemWritableFileStream. (318130@main) (183489019)
  • Fixed an Apple Pay deferred payment request being dropped when the payment method changes. (318155@main) (183516996)
  • Fixed Cache Storage size accounting underflowing and persisting a corrupt size. (318204@main) (183578693)
  • Fixed FileReader.abort() being silently ignored on a reader reused after a completed read. (318288@main) (183695958)
  • Fixed MathML and SVG elements not resetting tabIndex when tabindex is changed to an invalid value. (318303@main) (183696552)
  • Fixed fullscreen state not being unwound when entering fullscreen fails. (319243@main) (184157871)
  • Fixed the SharedWorkerGlobalScope prototype not being an immutable prototype exotic object. (318684@main) (184190755)
  • Fixed the scrollend event not firing when wheel-scrolling a subframe. (318805@main) (184352772)

Web Audio

Resolved Issues

  • Fixed a loss of precision in exponentialRampToValueAtTime() caused by accumulating the ramp value. (317955@main) (124498013)
  • Fixed decodeAudioData() failing with an EncodingError for valid M4A files whose ftyp brand is not mp4. (318005@main) (183148186)
  • Fixed registerProcessor() error messages so they name the offending AudioParam instead of the processor. (317948@main) (183189781)
  • Fixed an OscillatorNode with a-rate automation starting out of phase by honoring sub-sample start times. (317953@main) (183194827)
  • Fixed the AudioBufferSourceNode output channel count to account for whether the node is actively processing. (317956@main) (183245229)
  • Fixed stale audio being played instead of silence when the audio destination ring buffer underruns. (317968@main) (183305574)
  • Fixed an AudioScheduledSourceNode not firing the ended event when it is not connected to the destination. (318515@main) (183986981)
  • Fixed a k-rate AudioParam input to AudioBufferSourceNode.detune diverging from the equivalent automation. (318516@main) (183987621)
  • Fixed AudioContext.close() not rejecting when called on an already-closed context. (318522@main) (183989479)
  • Fixed AudioWorkletGlobalScope.currentFrame reporting 0 for a worklet created while the context is suspended. (318601@main) (184081765)
  • Fixed an AudioWorkletProcessor being torn down too early after process() returns false. (318621@main) (184107806)
  • Fixed the AudioWorkletNode processorerror event missing filename, lineno, and colno. (318705@main) (184224032)
  • Fixed MediaStreamAudioSourceNode capturing the wrong track and continuing to play after the track ends. (318706@main) (184224142)
  • Fixed a zero-duration exponentialRampToValueAtTime() at a non-frame-aligned time rendering NaN. (318868@main) (184434164)
  • Fixed setting ConvolverNode.buffer to null not releasing the impulse response. (318870@main) (184434803)
  • Fixed reverse playback of buffers longer than 2^23 frames extrapolating outside the source samples. (318869@main) (184439324)

Web Extensions

New Features

  • Added support for wildcard domains and subdomains in externally_connectable.matches. (318361@main) (183642164)
  • Added support for setAccessLevel() on the local and sync storage areas. (318980@main) (183680404)
  • Added support for scripting.ExecutionWorld. (319009@main) (184284891)

Resolved Issues

  • Fixed several inconsistencies in the browser.alarms API. (318493@main) (183770530)
  • Fixed a significant delay loading web extensions when the browser is launched cold. (318756@main) (183827503)

Web Inspector

New Features

  • Added icons for recorded WebGL and WebGPU actions in the Canvas tab. (318517@main) (42777850)
  • Added support for recording WebGPU devices in the Canvas tab. (318407@main) (183538409)
  • Added support for instrumenting WebGPU devices in the Canvas tab. (318336@main) (183757645)
  • Added support for WebGPU content previews in the Canvas tab. (318363@main) (183785306)
  • Added support for instrumenting WebGPU pipelines in the Canvas tab. (318366@main) (183790749)
  • Added support for disabling WebGPU render pipelines in the Canvas tab. (318403@main) (183857257)
  • Added support for using the WebGPU label of devices and pipelines as their name in the Canvas tab. (318409@main) (183876768)
  • Added support for exposing client metadata for WebGPU devices. (318467@main) (183939079)
  • Added support for recording WebGL extension actions in the Canvas tab. (318474@main) (183945866)
  • Added support for mapping WebAssembly byte offsets to original sources with source maps. (318546@main) (184017160)
  • Added support for editing WebGPU shaders in the Canvas tab. (318633@main) (184128414)
  • Added support for highlighting WebGPU render pipelines in the Canvas tab. (318668@main) (184169419)
  • Improved the estimated memory use reported for WebGL and WebGPU canvases to include their graphics resources. (318915@main) (184535731)
  • Added support for recording object arguments and result objects in the Canvas tab. (319059@main) (184759172)
  • Added support for showing names for recorded WebGPU bitfields. (319174@main) (184928178)
  • Added support for snapshotting WebGPU element image copies. (319176@main) (184928370)
  • Added syntax highlighting to recording actions in the Canvas tab. (319189@main) (184936730)

Resolved Issues

  • Fixed canvas recordings retaining memory by pruning recordings that are no longer in use. (318613@main) (35893620)
  • Fixed searching resources returning duplicate results for the same resource. (319061@main) (42879586)
  • Fixed resource data for non-buffered resources persisting across navigations. (318035@main) (181210169)
  • Fixed WebAssembly module scripts not being associated with the resource that fetched them. (318207@main) (183583149)
  • Fixed stale frame navigation event timestamps being shown after initializing. (318213@main) (183584784)
  • Fixed a selected details sidebar panel not being restored when it becomes available again. (318353@main) (183778380)
  • Fixed detaching a child frame also detaching its parent frame. (318355@main) (183778531)
  • Fixed stale execution contexts being kept when their identifiers change. (318356@main) (183779166)
  • Fixed response end times being dropped for resources without request timing data. (318360@main) (183783292)
  • Fixed recorded WebGPU object arguments not being swizzled correctly. (318545@main) (184017109)
  • Fixed missing console.record() options being treated as if they were present. (318555@main) (184029716)
  • Fixed recorded object identifiers colliding by assigning them per type. (318567@main) (184040370)
  • Fixed configured WebGPU <canvas> elements not being distinguished from CSS canvas client nodes. (318794@main) (184346714)

WebCodecs

New Features

  • Added support for the WebCodecs ImageDecoder API. (319179@main) (184857272)

WebGPU

Resolved Issues

  • Fixed a WGSL miscompilation when swizzling a packed vec3 value. (318098@main) (183426431)
  • Fixed a large frame-rate drop when executeBundles() is called with bundles containing indirect draws. (318538@main) (183458069)
  • Fixed textureDimensions(t, level) clamping the mip level one past the last valid level. (318273@main) (183673818)
  • Fixed GPUQueue.copyExternalImageToTexture() uploading indexed PNG images incorrectly. (318952@main) (184529653)

WebRTC

New Features

  • Added WebRTC AV1 software fallback support. (317986@main) (182789617)

Resolved Issues

  • Fixed a valid current value being ignored when both min and max are given in a capture constraint range. (318046@main) (182968516)
  • Fixed setSinkId() reporting success without switching audio output for a single-track MediaStream. (318149@main) (183147942)
  • Fixed getUserMedia() interrupting the microphone system-wide when echoCancellation is disabled. (318164@main) (183517329)
  • Fixed ImageCapture.takePhoto() failing permanently after a single transient capture error. (318260@main) (183640839)

August 26, 2026 09:36 PM

August 24, 2026

Igalia WebKit Team: WebKit Igalia Periodical #74

Igalia WebKit

Update on what happened in WebKit in the week from August 17 to August 24.

Another periodical packed with updates on the graphics, multimedia, and tooling fronts. Which sure has to do with preparing for the upcoming 2.54.x release series, that now has release candidates published. Also, do not miss a new stable release being published with fixes for security issues, and make sure to update.

Cross-Port 🐱

Fixed flakiness in the Web Inspector heap snapshot tests.

Extended the webkit-sysprof analyze tool cover the remaining marks emitted along the rendering pipeline, from RenderTreeBuild and CompositingUpdate through FinalizeRenderingUpdate, RenderLayerTree and WaitForCompositionCompletion down to the individual tile marks, pulling the tile count and the dirty region out of the mark messages as statistics next to the durations. The statistics tables also gained mean and median columns, so a captured trace now shows where the time in a frame actually goes.

Fixed test fast/canvas/canvas-composite-text-alpha.html, and improved the state of several other tests which relied on setTimeout().

Implemented moving steps for <option> elements.

Add support for asynchronous scrolling with touch events.

Touch events are now dispatched to the EventDispatcher thread in the Web Process, enabling smooth scrolling even when the main thread is busy. Additionally, this change fixed a bug where precise scrolling delta wheel events, dispatched by touchpads, failed to trigger asynchronous scrolling.

Multimedia 🎥

GStreamer-based multimedia support for WebKit, including (but not limited to) playback, capture, WebAudio, WebCodecs, and WebRTC.

Ensure that multimedia on pages restored from the back-forward cache is correctly processed without errors or reloading.

The robustness level is now queried from the CDM (if supported) when using Encrypted Media Extensions (EME).

Added video rendering support for Qualcomm hardware-accelerated decoders when the Skia compositor is in use, complementing the earlier TextureMapper-only support that left such videos blank with the new compositor.

Video frame processing now relies on the driver's implicit YUV to RGB conversion, steered by the colour space and sample range hints taken from the frame colorimetry, with a hint-free import as fallback.

Graphics 🖼️

Fixed how <feImage> paints its referenced element in the Layer-Based SVG Engine (LBSE), which still used a helper written for the legacy SVG engine, where SVG content never had layers, so it used to paint renderers directly and skipped any child that owns a RenderLayer under LBSE, silently dropping its opacity, mask, filter or 3D transform. The referenced content is now painted through the layer tree, the way <mask>,<clipPath>, <pattern> and <marker> content already is.

Made SVG mask no longer force a RenderLayer in the Layer-Based SVG Engine (LBSE), mirroring the earlier change for clip-path. A mask is now applied during painting by SVGNonLayerClippingAndMaskingScope, which opens one transparency layer capturing the renderer's foreground and composites the mask over it afterwards, and which also absorbed the clips that cannot be expressed as a path. A container with a mask keeps its layer, since the mask covers its whole subtree, while a leaf stays layer-free. This further reduces the layer overhead that has been holding LBSE back against the legacy SVG engine.

Skipped scroll coordination for composited layers that have no scrolling role, where the per-layer update previously walked every branch to detach roles the layer had never registered for, only to hand back the parent node ID unchanged. Cutting that work out shortens every compositing update, which matters for composition-heavy workloads.

Fixed rendering of an outermost <svg> with an empty viewBox in the Layer-Based SVG Engine (LBSE), which per the SVG specification should disable painting when the width or height is zero, matching what the legacy engine already did.

Skipped scroll coordination work for layers that have no scrolling role during compositing updates, where updateScrollCoordinationForLayer previously walked every branch to detach roles the layer had never registered for, only to hand back the unchanged parent node ID.

Releases 📦️

WebKitGTK 2.52.6 and WPE WebKit 2.52.6 have been released, including a number of fixes for security issues covered in the accompanying security advisory WSA-2026-0005 (GTK, WPE). It is recommended for everybody to update to these stable releases.

Stabilization for the upcoming 2.54.x release series for both the GTK and WPE ports is ongoing, with the first stable release, 2.54.0, expected around mid-September 2026. In the meantime release candidates WebKitGTK 2.53.91 and WPE WebKit 2.53.91 have been released.

Those interested in previewing the work done by the team in the last half year, including the new Skia-based compositor that is expected to eventually replace the aging TextureMapper, may want to give them a try and report any issues found in Bugzilla.

That’s all for this week!

By Igalia WebKit Team at August 24, 2026 11:30 PM

August 17, 2026

Igalia WebKit Team: WebKit Igalia Periodical #73

Igalia WebKit

Update on what happened in WebKit in the week from August 10 to August 17.

Following an extra packed periodical, this week we get back to a more regular pace with two nice bugfixes, and a new tool to analyze WebKit performance on Linux!

Cross-Port 🐱

The webkit-sysprof toolkit landed in main thus introducing a set of tools for processing Sysprof .syscap capture files recorded from WebKit (GTK/WPE ports). It extracts marks (timeline events) and counters (time-series metrics) from a capture and lets one dump, summarize, analyze, or plot delta-time histograms for them.

Graphics 🖼️

Fixed filters specified on the outermost <svg> element in the Layer-Based SVG Engine (LBSE), where a filter: url(...) reference on an SVG root was silently dropped because the layer code skipped it, as the legacy engine used to apply it by itself. The filter region is now resolved against the SVG root's border box in its container's coordinate system, since the outermost <svg> is a replaced element in the CSS box tree, not part of the SVG user space its children live in.

Avoided serializing gradient and pattern transforms just to answer a presence check in the Layer-Based SVG Engine (LBSE). Asking hasAttribute() whether gradientTransform or patternTransform was specified forced the transform list to be serialized into the attribute map whenever the base value was changed through the SVG DOM, even though that string is never read back, so the check is now answered directly from the typed accessor.

That’s all for this week!

By Igalia WebKit Team at August 17, 2026 07:08 PM

August 13, 2026

Release Notes for Safari Technology Preview 250

Surfin’ Safari

Safari Technology Preview Release 250 is now available for download for macOS Golden Gate and macOS Tahoe. If you already have Safari Technology Preview installed, you can update it in System Settings under General → Software Update.

This release includes WebKit changes between: 317507@main…317934@main.

Accessibility

Resolved Issues

  • Fixed VoiceOver reading a stray newline and skipping lines when navigating a <textarea> whose value ends in a line break. (317784@main) (182912872)

CSS

New Features

  • Added support for the spaces value of the ruby-overhang property, which limits annotation overhang to adjacent spaces and punctuation, with none now an alias for spaces. (317569@main) (181808420)
  • Added support for the content property on the ::marker pseudo-element. (317570@main) (182750380)
  • Added support for the text-decoration-inset property. (317571@main) (182750933)
  • Added support for the white-space-trim property. (317573@main) (182751076)
  • Added support for the wrap-inside property. (317574@main) (182751559)

Resolved Issues

  • Fixed a list-style-position: inside marker glyph being painted one device pixel away from the equivalent inline text. (317789@main) (182447949)
  • Fixed text-decoration specified on ::selection never being painted. (317673@main) (182757292)
  • Fixed a text decoration on ::selection not being painted when the selected text had no decoration of its own. (317695@main) (182864748)
  • Fixed a max-content sized block collapsing to zero width when its child used an orthogonal writing mode. (317781@main) (183026896)

Deprecations

  • Removed support for the non-standard text color value; use canvastext instead. (317687@main) (100364547)

Editing

New Features

  • Added support for copying and pasting image/svg+xml data with the Clipboard API, sanitizing the markup on both read and write. (317528@main) (137553836)

JavaScript

New Features

  • Added support for the Explicit Resource Management proposal, including using and await using declarations, Symbol.dispose, DisposableStack, and AsyncDisposableStack. (317894@main) (103209363)
  • Added support for Iterator.zip() and Iterator.zipKeyed() from the Joint Iteration proposal. (317886@main) (180967133)
  • Added JavaScript and WebAssembly feature flags alongside other web feature settings. (317306@main (https://commits.webkit.org/317306@main)) (182210113)

Media

Resolved Issues

  • Fixed a spurious pause and ended event firing on a live HLS stream when playback reached the live edge. (317626@main) (100556746)
  • Fixed a media fragment with an out-of-range hours value being accepted as a valid seek instead of being rejected. (317869@main) (181820705)
  • Fixed a WebVTT cue incorrectly inheriting a preceding line as its identifier across a REGION or STYLE block. (317811@main) (181977285)

Networking

New Features

  • Added initial support for uploading a ReadableStream body with fetch(). (317724@main) (182510365)
  • Added support for the duplex option on Request, which is required when uploading a ReadableStream body. (317768@main) (182802330)

Scrolling

Resolved Issues

  • Fixed scrollIntoView() on an inline element sharing a line with a much taller element scrolling to the top of the line box instead of to the element. (317933@main) (178491868)
  • Fixed paged scrolling with Page Down or the spacebar skipping over intermediate scroll snap points. (317562@main) (182562852)
  • Fixed a crash that could occur while sending a scroll update during window tear-down. (317785@main) (182972245)
  • Fixed re-snapping after layout always preferring a focused element, instead of only when focus has changed. (317892@main) (183146768)

Storage

Resolved Issues

  • Fixed an IndexedDB put() that fails a unique index constraint deleting the record it would have overwritten, leaving the object store with neither the old nor the new record. (317632@main) (181513905)

Web API

Resolved Issues

  • Fixed Digital Credentials get() being rejected in an iframe inside a focused window. (317656@main) (109191868)

Web Inspector

New Features

  • Added support for showing WebAssembly modules in the Sources tab. (317891@main) (182605814)

Resolved Issues

  • Fixed disabling the resource cache overwriting a Cache-Control header already set by the page. (317814@main) (183072123)

WebAssembly

New Features

  • Added support for relaxed SIMD instructions. (317549@main) (180967232)
  • Added support for multiple memories in a single WebAssembly module. (317636@main) (182219080)

WebDriver

New Features

  • Added support for the “consume user activation” extension command, which consumes the current browsing context’s transient user activation and reports whether it was present. (317715@main) (102634281)

August 13, 2026 09:24 PM

August 10, 2026

Igalia WebKit Team: WebKit Igalia Periodical #72

Igalia WebKit

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:

That’s all for this week!

By Igalia WebKit Team at August 10, 2026 06:51 PM

July 29, 2026

Release Notes for Safari Technology Preview 249

Surfin’ Safari

Safari Technology Preview Release 249 is now available for download for macOS Golden Gate and macOS Tahoe. If you already have Safari Technology Preview installed, you can update it in System Settings under General → Software Update.

This release includes WebKit changes between: 316531@main…317820@main.

Accessibility

Resolved Issues

  • Fixed an issue where an aria-labelledby relation was not built when its target element was inserted via innerHTML. (316913@main) (179677418)
  • Fixed an issue where VoiceOver was silent during character navigation inside a local iframe. (317264@main) (182229891)
  • Fixed an issue where web content somtimes appeared empty to assistive technology after navigation. (317449@main) (182544199)

Animations

Resolved Issues

  • Fixed an issue where calling play() on a finite scroll-driven animation timeline did not reset its start time to the current time. (316745@main) (181712713)
  • Fixed an issue where animation-timeline did not use the last matching timeline when it matched multiple timelines. (317330@main) (182405676)
  • Fixed an issue where animation-timeline could match a timeline outside the nearest timeline-scope element with that name. (317376@main) (182417407)

CSS

New Features

  • Added support for the attr() function. (316672@main) (173992627)
  • Added support for outline-offset: inset. (316677@main) (180547604)
  • Added support for the @function custom functions rule. (316671@main) (181625123)
  • Added preview support for the wrap-inside property. (317182@main) (181751564)
  • Added support for the if() function. (316813@main) (181806268)
  • Added support for calc-mix(). (316847@main) (181839626)
  • Added support for justify-self on block-level boxes. (317212@main) (181926245)
  • Added preview support for text-decoration-inset. (317230@main) (182019037)
  • Added preview support for the content property on the ::marker pseudo-element. (317211@main) (182066124)

Resolved Issues

  • Fixed an issue where setting view-transition-name dynamically did not create a stacking context. (317310@main) (178316558)
  • Fixed an issue where CSS Grid items with a computed preferred size that behaves as auto did not correctly compute their minimum content contribution. (316697@main) (181146154)
  • Fixed an issue where visually overflowing content in a CSS Grid item was not painted. (316668@main) (181277780)
  • Fixed anchor-center in vertical writing modes not being scroll-adjusted along the block axis. (316537@main) (181413103)
  • Fixed an issue where an empty editable flex container did not reserve a line’s worth of block size in vertical writing modes. (317467@main) (181485387)
  • Fixed an issue where CSS Grid did not correctly increase track sizes to accommodate items spanning flexible tracks. (317426@main) (181635324)
  • Fixed an issue where stretch alignment did not trigger stretch sizing for CSS Grid items. (316949@main) (181750071)
  • Fixed an issue where CSS Grid items could retain stale block sizes after a subsequent layout. (317166@main) (182144347)
  • Fixed an issue where clip-path shapes could render with incorrect arcs. (317397@main) (182443333)
  • Fixed an issue where ::highlight() and ::target-text ignored text-underline-offset. (317440@main) (182466757)
  • Fixed an issue where ::highlight() decoration replaced the originating element’s decoration instead of layering over it. (317439@main) (182523249)

Editing

Resolved Issues

  • Fixed an issue that disallowed font names that were not a valid CSS identifiers. (316948@main) (51409819)
  • Fixed the Edit menu’s Copy item being incorrectly enabled when there was no selection in the web page. (316571@main) (176061974)

Forms

Resolved Issues

  • Fixed an issue where the datalist popup menu was presented in the wrong place on a screen to the left of the main screen. (316965@main) (181967418)

HTML

New Features

  • Added support for popover=hint. (317402@main) (129495028)

JavaScript

New Features

  • Added support for the Temporal object. (316742@main) (181723535)

MathML

Resolved Issues

  • Fixed an issue where U+2016 (DOUBLE VERTICAL LINE) was missing the symmetric property in the MathML operator dictionary. (316867@main) (179558196)

Media

Resolved Issues

  • Fixed an issue where finding text starting from a selection could resolve to the wrong caption cue instead of the one nearest the video’s playhead. (317168@main) (182001231)

Rendering

New Features

  • Added support for dark mode in the XML document viewer. (316832@main) (122234600)

Resolved Issues

  • Fixed an issue where box-shadow rendering broke when the page was zoomed. (317080@main) (169167365)

Scrolling

Resolved Issues

  • Fixed an issue where re-snapping did not select the snap area aligned in both axes when multiple targets were aligned. (317294@main) (182285397)
  • Fixed an issue where scroll-snap-align was not respected when scrolling to an anchor or calling scrollIntoView(). (317495@main) (182544180)

Spatial Web

Resolved Issues

  • Fixed an issue where navigating back to a page with a previously active web environment left the UI stuck showing the environment as active. (316891@main) (180966321)
  • Fixed an issue where the background color of HTMLModelElement did not match spec for non-opaque colors. (316788@main) (181641249)

Web API

New Features

  • Added support for subgroups in WebGPU. (317145@main) (154874391)
  • Added support for close watchers, including the closedby attribute for dialog elements. (316680@main) (180105698)

Resolved Issues

  • Fixed an issue where a user gesture authorization token was not properly verified for Digital Credentials requests. (317228@main) (174908839)
  • Fixed DOMMatrix and IntersectionObserver correctly enforcing absolute-length unit requirements when parsing values. (316532@main) (181453666)
  • Fixed an issue where Scroll To Text Fragment directives could run outside text/html and text/plain documents. (316976@main) (181763736)
  • Fixed an issue where replaceChildren() could not replace a document’s children. (316909@main) (181921026)

Web Audio

Resolved Issues

  • Fixed Web Audio PannerNode orientation-only changes not updating the directional cone gain. (316541@main) (181413407)

Web Inspector

New Features

  • Added support for the range mappings proposal in source maps. (316748@main) (178564308)
  • Added per-element Layout Invalidated events in Web Inspector to reflect the number of elements affected by a layout invalidation. (317302@main) (181243589)

Resolved Issues

  • Fixed an issue where every <input> element showed a Scroll badge in the Elements tab. (316773@main) (101661656)
  • Fixed an issue where search results did not select the corresponding source code line for fetched JSON. (317499@main) (118115749)
  • Fixed an issue where search in Web Inspector did not find results inside the shadow DOM. (317500@main) (126458322)
  • Fixed an issue where Web Inspector could crash when selecting a popover matching a nested @scope with a bare declaration. (316987@main) (181745000)
  • Fixed an issue where Web Inspector mapped the crimson named color to the wrong RGB value. (317047@main) (182090064)
  • Fixed an issue where the gradient editor in Web Inspector dropped explicit 0% color stops and misparsed leading radial color stops. (317192@main) (182172439)
  • Fixed an issue where autocompleting a vendor-prefixed value in Styles could duplicate the prefix, for example producing -apple--apple-system. (317167@main) (182178871)

WebAssembly

Resolved Issues

  • Fixed an issue where Error stack traces did not include names for modules instantiated with WebAssembly.instantiateStreaming. (316642@main) (181523735)

WebDriver

New Features

  • Added WebDriver support for the Digital Credentials API, including commands to simulate wallet payloads, indefinite waits, and user rejection. (316435@main) (168941907)

WebRTC

Resolved Issues

  • Fixed OverconstrainedError to inherit from DOMException and expose a code attribute per the Media Capture spec. (316578@main) (180728516)

July 29, 2026 09:46 PM

July 28, 2026

Igalia WebKit Team: WebKit Igalia Periodical #71

Igalia WebKit

Update on what happened in WebKit in the week from July 14 to July 27.

This two-week update includes plenty of changes to the Skia compositor, changes to multimedia support, three blog posts, and assorted improvements.

Cross-Port 🐱

The Web Inspector “Layout & Rendering” timeline now shows a Layout Invalidated event for every element that needs relayout, not just the layout root (with the old root-only event renamed to Layout Scheduled). This unveils why some layouts take much longer than others. No more guessing which of dozens of nodes is actually to blame!

The webkit://gpu page has gained a dark style, which will be used when the system settings indicate that dark mode is preferred by the user.

Multimedia 🎥

GStreamer-based multimedia support for WebKit, including (but not limited to) playback, capture, WebAudio, WebCodecs, and WebRTC.

The experimental GstWebRTC backend was removed and libwebrtc usage was enabled in the main branch. We hope to enable WebRTC support by default in the 2.56 series, scheduled around March 2027.

MP4 edit lists support was enabled in the MSE backend, improving timestamp accuracy, specially when handling of B-frames.

Graphics 🖼️

Split the compositing walk in the Skia compositor into a damage pass and a paint pass, so the frame damage is known before the first draw. The damage pass walks the layer tree with a SkNoDrawCanvas in place of the real canvas, so every draw is discarded and only the damage is collected. Both passes run from a single paint() that applies animations and computes the transforms once, so the two see the same tree. Knowing the damage up front is what lets the compositor eventually paint only the parts of a frame that actually changed.

Wired up damage-driven compositing on the Skia compositor, so a frame re-composites only the region that actually changed instead of the whole surface, when the UseDamagingInformationForCompositing feature is enabled (not yet on by default). Each frame's damage is combined with what each swap-chain target still needs to redraw since it was last drawn into, and the clear and every draw are clipped to that region, which is a milestone towards no longer repainting untouched pixels every frame.

Made the root layer collect the frame damage itself in the Skia compositor, instead of having each layer report its own changes. Reporting leaves a gap whenever a layer is in no position to report, e.g. a destroyed one took its painted rectangle with it, so what it had drawn stayed on screen. The root now holds one rectangle per layer and compares it against what each frame's walk finds, so a layer that moved is repainted in both places, and a layer the walk never reaches is repainted where it used to be and dropped. Nothing has to notice anything for the pixels it left behind to be repainted, which is what makes it safe to restrict composition to the damaged region by default in future commits.

Limited every content draw to the target's repaint region in the Skia compositor, so a composited frame can redraw only the pixels that actually changed. Each content type restricts itself to the region's rectangles rather than clipping the canvas, since a multi-rectangle clip cannot be a hardware scissor and would make Skia build a mask and break batching. This is the groundwork for damage-driven compositing, which stays off by default behind the damage-tracking feature flag, as the compositor still passes no region and nothing is restricted yet.

Made each swap-chain target track its own damage since it was last current. Repainting only what changed is correct only when drawing into the target that holds the previous frame, but the swap chain hands back whichever target is free, and that one is a frame or more behind. Each frame's damage is now added to every target as it is recorded and cleared from a target when that target is presented, instead of being built as a side effect of reading it.

Taught the tile and image draws in the Skia compositor to split themselves by damage rectangle, so a frame only repaints the parts of a layer that actually changed. A new SkiaDamageRegion holds the frame's damage in device space and is built once per frame, and each draw is restricted to it: skipped when it touches no damage, split into one sub-draw per damage rectangle it overlaps, or drawn under a device-space clip when a rotated or skewed transform rules out working with rectangles. Nothing feeds a damage region in yet, so every draw still paints in full—this prepares for future patches enabling using damage information in the composition

Fixed missing repaints when compositor-applied layer state changes dynamically in the Coordinated Graphics backend. A layer recorded damage when its backing store re-rendered or a new contents buffer arrived, but the compositor also handles filters, masks, clip path changes, the contents rectangle, the contents tiling, the blend mode and contents visibility, and changing any of those alters the pixels it produces without dirtying a tile. Those setters now damage the whole layer, so a compositor that repaints only the damaged rectangles no longer leaves the previous frame's pixels on screen.

Community & Events 🤝

Nikolas Zimmermann has written a two-part blog series about the current the new Layer-Based SVG Engine (LBSE), with the first post covering the effort to reduce layer overhead using layers conditionally, and the second about how compositing is being implemented and the complications introduced due to paint ordering rules.

Loïc Le Page has published a blog post explaining how to use the new WPEPlatform API to implement a custom WPE integration. While presented example uses GLFW and EGL to show Web content on an X11 window, the concepts are useful for anyone looking into embedding WPE.

That’s all for this week!

By Igalia WebKit Team at July 28, 2026 01:04 AM

July 27, 2026

WebKit Features for Safari 26.6

Surfin’ Safari

Safari 26.6 is here. This release adds a small refinement to WebAssembly’s streaming compilation paths, and delivers eight bug fixes across CSS, service workers, networking, extensions, and WebRTC.

This release continues the ongoing focus of this entire year — polishing how features fit together, and resolving issues you might have run into as a web developer.

WebAssembly

WebKit for Safari 26.6 adds a compileOptions parameter to WebAssembly.compileStreaming() and WebAssembly.instantiateStreaming().

Safari 26.2 shipped support for Wasm JS String Builtins — a way for WebAssembly modules to import a set of standardized JavaScript string operations as builtins, which the engine can then optimize much more aggressively than a normal JS import. To turn them on, you pass an options object to WebAssembly.compile() or WebAssembly.instantiate().

The two streaming variants (compileStreaming() and instantiateStreaming()) didn’t yet accept that same options object. Now they do.

const module = await WebAssembly.compileStreaming(
  fetch("example.wasm"),
  { builtins: ["js-string"] }
);

Now you don’t have to fall back from streaming compilation to use JS String Builtins.

Bug fixes and more

In addition to the WebAssembly update, WebKit for Safari 26.6 includes eight bug fixes:

CSS

  • Fixed an issue where the ic length unit scaled incorrectly with page zoom, causing it to no longer equal 1em as expected by the CSS specification. (174857144)
  • Fixed an issue where fixed-positioned elements using position-area did not fall back properly when the body was scrollable. (175544079)
  • Fixed an issue where CSS zoom interacted incorrectly with font-size, font-weight, font-variant, and font-style on iPad when requesting the desktop website. (176647969)

Networking

  • Fixed an issue where partitioned cookies could not be deleted using WKHTTPCookieStore. (176097960)

Service Workers

  • Fixed an issue where service worker registrations with missing main scripts were not automatically unregistered, preventing pages from re-registering new service workers. (175522651)
  • Fixed an issue where service worker registrations with missing imported scripts were not automatically unregistered. (175522816)

Web Extensions

  • Fixed an issue where web extension service worker registration database files accumulated on each Safari launch, causing performance degradation. (175810627)

WebRTC

  • Fixed an issue where RTCPeerConnection configured with iceTransportPolicy: "relay" failed to gather any ICE candidates on macOS Sequoia. (175009190)

Updating to Safari 26.6

Safari 26.6 is available on iOS 26.6, iPadOS 26.6, visionOS 26.6, macOS Tahoe 26.6, macOS Sequoia, and macOS Sonoma. On iOS, iPadOS, and visionOS, you can update to Safari 26.6 as part of the OS update in Settings > General > Software Update. On macOS, Safari updates are delivered through System Settings > General > Software Update.

Feedback

We love hearing from you. To share your thoughts, find us online: Jen Simmons on Bluesky / Mastodon, Saron Yitbarek on BlueSky / Mastodon, and Jon Davis on Bluesky / Mastodon. You can follow WebKit on LinkedIn.

If you run into any issues, we welcome your bug report. Filing issues really does make a difference.

You can also find this information in the Safari release notes.

July 27, 2026 06:00 PM

July 22, 2026

Release Notes for Safari Technology Preview 248

Surfin’ Safari

Safari Technology Preview Release 248 is now available for download for macOS Golden Gate and macOS Tahoe. If you already have Safari Technology Preview installed, you can update it in System Settings under General → Software Update.

This release includes WebKit changes between: 315567@main…316817@main.

Accessibility

Resolved Issues

  • Fixed VoiceOver on Safari unable to navigate to content revealed by disclosure widgets using hidden="until-found". (315964@main) (173228707)
  • Fixed stale aria-labelledby when the referenced element dynamically changes its aria-label. (316316@main) (180319221)

CSS

New Features

  • Added support for forwarding missing color components when interpolating between analogous color spaces. (315569@main) (180239320)
  • Added support for the no-clamp option on the CSS progress() function. (315977@main) (180473472)

Resolved Issues

  • Fixed serialization of various CSS at-rules not escaping identifiers. (315795@main) (178750383)
  • Fixed :last-child and related selectors incorrectly gating on parser state outside of style resolution. (316495@main) (178879939)
  • Fixed changing the color-scheme of an <iframe> not invalidating the appearance of the embedded document. (316467@main) (179177141)
  • Fixed CSS scroll snap re-snap to prefer the fragment-targeted (:target) snap area over other aligned snap targets. (315880@main) (180108825)
  • Fixed the CSS preload scanner failing to preload @import rules that follow an @layer statement rule. (315576@main) (180170656)
  • Fixed serialization of CSSViewTransitionRule. (315614@main) (180170814)
  • Fixed MediaList.deleteMedium() to parse its argument as a media query and remove all matching queries. (315579@main) (180270019)
  • Fixed MediaList.appendMedium() to parse its argument as a single media query and suppress duplicates. (315594@main) (180291283)
  • Fixed grid items with stretch or fit-content preferred sizes computing incorrect minimum-content contributions when sizing tracks. (316296@main) (180748205)
  • Fixed inserting a CSS rule while a view transition is active causing the group animation to snap to its final state. (316436@main) (181100818)
  • Fixed CSS var() to only resolve its fallback when the first argument resolves to the guaranteed-invalid value. (316280@main) (181114298)
  • Fixed navigating away from a render-blocked document before its first rendering opportunity incorrectly firing pagereveal and starting an outbound cross-document view transition. (316446@main) (181191512)

Editing

Resolved Issues

  • Fixed drag images of DOM elements with CSS transforms not rendering correctly. (316077@main) (99614217)
  • Fixed opaque DOM mutations coming from dictation on iOS. (316049@main) (163454428)
  • Fixed deletion in an editable table leaving an empty trailing table row behind. (315990@main) (180877315)
  • Fixed vertical caret movement in editable content ignoring the requested editable-type parameter. (316241@main) (181000174)

Forms

Resolved Issues

  • Fixed the concentric inner-button corner radius on horizontal text form controls incorrectly ignoring the bottom inset. (316022@main) (180869927)

Images

Resolved Issues

  • Fixed a regression where RGB gain map images were decoded to 8 bits per channel, causing a color shift and incorrect brightness. (316069@main) (179152566)
  • Fixed handling of the gain-map target pixel format when decoding HDR images to fall back safely when the format cannot be parsed. (316405@main) (181180757)

JavaScript

New Features

  • Added support for the TC39 BigInt Math proposal, exposing Math-equivalent methods on BigInt such as BigInt.pow and BigInt.sqrt. (315974@main) (152472996)

Media

Resolved Issues

  • Fixed <audio> and <video> controls rendering incorrectly when rotated via CSS transform. (315718@main) (37516619)
  • Fixed subtitles and closed captions not appearing in fullscreen video on iPhone. (315789@main) (175298523)
  • Fixed ArrayBuffer-backed YUV VideoFrame with a visibleRect rendering with offset chroma channels. (315742@main) (180202939)
  • Fixed video playback of streams from certain sources such as security cameras not working. (315774@main) (180411019)
  • Fixed transient device rotation resulting in captured video frames having the wrong orientation. (315821@main) (180429147)
  • Fixed Media Source Extensions playback and seek by loosening the gap tolerance between buffered ranges. (316146@main) (180439090)

Navigation

Resolved Issues

  • Fixed a <meta http-equiv="refresh"> to a URL differing only in fragment identifier being incorrectly treated as a page reload. (316001@main) (176933795)

Networking

Resolved Issues

  • Fixed URL path separators being encoded as %2F following a percent-encoded Armenian path segment. (315627@main) (180067095)

Rendering

Resolved Issues

  • Fixed the background of a composited <html> element not being repainted when the <body> background changed. (316415@main) (177975964)
  • Fixed a regression where block-axis padding on a flex column container with overflow: auto was excluded from scrollHeight. (315813@main) (179376053)
  • Fixed an issue where an <img> embedding an SVG with a near-integral intrinsic width rendered one device pixel narrower than expected. (315807@main) (180490343)
  • Fixed elements with filter: drop-shadow() not being fully repainted when a child is resized. (316450@main) (181284741)

SVG

Resolved Issues

  • Fixed SVG SMIL length animations to reject invalid to, from, and by values such as those with leading whitespace. (315949@main) (118537155)
  • Fixed Unicode text with complex scripts not rendering correctly along a curved <textPath>. (316144@main) (120284006)
  • Fixed SVGLength.convertToSpecifiedUnits() failing when converting from px to %, em, or ex. (315953@main) (172056830)
  • Fixed SVG geometry presentation attributes like cx, cy, r, rx, ry, x, y, width, and height being incorrectly applied to elements such as <g> on which they are not permitted. (315946@main) (175672111)
  • Fixed an issue where the per-character rotate attribute was discarded on a <textPath>, so it now composes with the path tangent angle. (315786@main) (178044478)
  • Fixed several SVG styling spec-compliance failures. (316174@main) (181052042)
  • Fixed dynamic changes to orient and markerUnits on <marker> not repainting elements that reference it. (316350@main) (181106538)
  • Fixed SVG SMIL number, integer-optional-integer, number-optional-number, and path animations to not apply when their from, to, or by values fail to parse. (316468@main) (181308150)

Scrolling

Resolved Issues

  • Fixed CSS scroll snap points inside zero-sized elements not working correctly. (315948@main) (172863699)
  • Fixed CSS scroll snap re-snap to prefer a snap area that contains the focused or fragment-targeted element. (315927@main) (180707984)

Security

Resolved Issues

  • Fixed a regression where some websites failed to display and logged Content Security Policy errors in the console. (316290@main) (179684592)
  • Fixed same-page navigations being incorrectly checked against Content Security Policy. (315759@main) (180342503)
  • Fixed Content Security Policy frame-ancestors violations in report-only policies being ignored instead of reported. (315753@main) (180447621)
  • Fixed Content Security Policy parsing to reject trailing characters after the closing quote on nonce-source and hash-source values. (316008@main) (180903857)
  • Fixed Content Security Policy trusted-types expressions to reject trailing characters after keywords and the wildcard. (316089@main) (180973793)

Storage

Resolved Issues

  • Fixed an issue where IndexedDB transactions could be blocked for an extended period before starting when another page’s transaction was suspended in the background. (315609@main) (178769599)

Web API

Resolved Issues

  • Fixed the Async Clipboard API to request paste access asynchronously. (315997@main) (75969974)
  • Fixed Digital Credentials to surface OperationError for platform-cancellation and unknown errors instead of AbortError or UnknownError. (315973@main) (174308268)
  • Fixed Digital Credentials rejecting with the wrong error code and synchronously; rejections are now queued as a task with the correct error. (315895@main) (174895437)
  • Fixed KeyboardEvent.getModifierState("AltGraph") and MouseEvent.getModifierState("AltGraph") always returning false. (315804@main) (180597374)
  • Fixed Credential.type returning "digital-credential" instead of "digital" for digital credentials. (315891@main) (180618646)
  • Fixed aborting navigator.credentials.get() leaving the digital-credentials document picker stuck on screen. (316494@main) (180812397)
  • Fixed FileReader.readAsText() ignoring the charset parameter of the Blob‘s MIME type. (315996@main) (180890703)

Web Inspector

Resolved Issues

  • Fixed showing ES2022 class private fields, methods, and accessors when inspecting object instances in the Console. (316171@main) (88527162)
  • Fixed symbolic breakpoints in the debugger so they work with intrinsic functions. (315713@main) (99037335)
  • Fixed a JavaScript breakpoint on a line containing only a semicolon not being triggered. (316519@main) (126707973)
  • Fixed the Console REPL to allow redefinition of variables declared with let and const. (316523@main) (143140659)
  • Fixed the Timeline exporting and importing the wrong timestamp for performance.mark() records. (316073@main) (145226764)
  • Fixed local response overrides mapped to a file being interpreted as Latin-1 (ISO-8859-1) instead of their actual encoding. (316074@main) (149847746)
  • Fixed the Media Logging setting not persisting across page loads. (315758@main) (154766890)
  • Fixed symbolic breakpoints to work with native constructors such as Array, Date, EventTarget, and Worker. (316262@main) (157178256)
  • Fixed missing stack traces for MIME type errors when importing modules. (316529@main) (169396940)
  • Fixed the Accessibility sidebar being empty for nodes inside cross-origin iframes. (316399@main) (178562336)
  • Fixed inline style invalidation to batch DOM.getAttributes commands per tick in cross-origin iframes instead of issuing one command per node. (316487@main) (178830496)
  • Fixed DOM Storage read and write commands to resolve against the frame’s own origin in cross-origin iframes. (316501@main) (179249711)
  • Fixed a moved breakpoint reverting to its original location after closing and reopening Web Inspector. (315585@main) (180083858)
  • Fixed showing the formatted parameters string for prototype objects such as Map.prototype. (315599@main) (180298712)
  • Fixed missing formatted parameter strings for object shorthand methods and arrow functions. (315723@main) (180466459)
  • Fixed an unnecessary colon appearing in front of non-class function properties. (315731@main) (180476445)
  • Fixed a self-canceling ternary that produced an incorrect cross-axis direction in the flex overlay. (316429@main) (181198803)
  • Fixed the color picker force-converting picked colors to Display P3. (316419@main) (181201503)
  • Fixed Page.searchInResources silently omitting cache-backed resources from search results. (316421@main) (181202027)
  • Fixed duplicate invalid CSS declarations both incorrectly displaying as Active in the Styles sidebar. (316418@main) (181203080)
  • Fixed adopted constructable stylesheets being misclassified as User Agent stylesheets in cross-origin iframes. (316433@main) (181204768)
  • Fixed an unsigned underflow that caused the DOM agent to spuriously report power-efficient playback. (316443@main) (181205602)
  • Fixed Network.setExtraHTTPHeaders to replace previously set headers instead of accumulating them. (316444@main) (181282814)

WebDriver

New Features

  • Added WebDriver support for the Digital Credentials API, including commands to simulate wallet payloads, indefinite waits, and user rejection. (316435@main) (168941907)

WebRTC

Resolved Issues

  • Fixed the WebProcess AudioSession to remain active while microphone capture is live. (316394@main) (180505014)
  • Fixed the configurationchange event being dropped when a source-side change occurred while a MediaStreamTrack was muted; the event is now deferred until unmute. (316301@main) (180728609)

July 22, 2026 06:58 PM

Nikolas Zimmermann: Implementing compositing in LBSE

Igalia WebKit

Keeping paint order correct with paint order segments

July 22, 2026 12:00 AM

July 14, 2026

Nikolas Zimmermann: Reducing layer overhead in LBSE

Igalia WebKit

Conditional layer creation in the layer based SVG engine

July 14, 2026 12:00 AM

July 13, 2026

Igalia WebKit Team: WebKit Igalia Periodical #70

Igalia WebKit

Update on what happened in WebKit in the week from June 30 to July 13.

The summer continues with many updates to the new SVG engine (LBSE), improvements to the new Skia-based compositor, some small API additions, and ever-important stable releases with security fixes.

Cross-Port 🐱

Enabled the CloseWatcher API and dialog's closedby attribute in stable.

New API has been added which allows specifying per-navigation User-Agent string values using webkit_policy_decision_use_with_policies(). Applications now have more granularity to decide which User-Agent websites are presented with, complementing the existing global WebKitSettings:user-agent setting.

Graphics 🖼️

Roughly halved the cost of the Skia based compositor on WPE running on Vivante GPUs with the Etnaviv driver, by turning off Skia's mipmap sharpening option. That option is enabled by default and makes the Skia shader generator append a small negative level-of-detail (LOD) bias to every mipmap-capable texture sample. WPE does not use mipmapping at all, so the bias sharpened nothing, but it still turned each texture fetch into a LOD lookup, which is a slow path on the tiled GPUs found in the i.MX series. Disabling it restores usage of faster, plain fetch operations.

Fixed broken rendering with the Skia compositor on WPE when super-tiled textures are enabled on Vivante GPUs. Those tile buffers are allocated padded up to a multiple of 64 pixels, so the physical texture is larger than the logical tile, but the Skia backing failed to take this difference into account, leading to distorted tile images being rendered.

Stopped the Skia compositor from blending opaque layers on WPE. Every layer was drawn with the default source-over blend mode, which leaves GPU blending switched on even for fully opaque layers that do not need it, so the cost was paid on every composited frame.

Layers that are opaque, drawn at full opacity and using the default blend mode are now composited with a plain source blend mode instead, which lets Skia turn blending off and lowers GPU bandwidth usage, benefiting tiled GPUs the most.

Cached the concatenated SVG transform attribute matrix on graphics elements in the Layer-Based SVG Engine (LBSE).

Reading the transform attribute walked the whole transform list and multiplied every item together again, and that happened around three times per animation frame for each element, even though the result only changes when the transform list itself is mutated.

The concatenated matrix is now stored on the element and invalidated whenever a transform-related attribute changes, so the multiplication runs once per mutation instead of once per read. This cuts repeated matrix work out of the per-frame path for animated SVG content.

Moved the clip out of the SVG child-paint loop in the Layer-Based SVG Engine (LBSE).

Painting a container used to set up a clip rectangle for every child shape in turn, so each shape did its own graphics-context save, clip and restore even though the clip rectangle was identical for all of them. When there is a single region to clip to and no child paints into its own layer, that clip is now established once and shared by every child, transformed or not.

This removes a per-shape save and clip from the hot painting path of SVG documents with many children.

Cached the SVG transform origin on SVG renderers in the Layer-Based SVG Engine (LBSE).

Every transform flush recomputed the origin for each non-layered SVG shape, even though it only depends on the transform-origin style and the transform reference box, and sampling MotionMark's Suits test at fixed complexity showed that computation taking around 1% of the WebProcess main thread.

The origin is now cached and keyed on the reference box, with a style change to transform-origin or transform-box dropping the cache, and the fast path is limited to plain SVG transforms so viewport containers and CSS-transformed renderers keep computing it directly. This removes a repeated per-shape cost from animated SVG content, and the caching scope can be widened later.

Cached the SVG viewport size used to resolve the transform reference box in the Layer-Based SVG Engine (LBSE).

The default transform-box for SVG is view-box, so every transformed shape resolved the viewport from the SVG root's content box again on each query, both when updating its local transform and again during paint. The viewport is constant after layout, so it is now cached on the <svg> element and only recomputed when layout actually changes it, on resize, zoom or a viewBox update. This removes another repeated per-frame computation from the transform path for animated SVG content.

Coalesced the SVG transform flush into one minimal repaint per container in the Layer-Based SVG Engine (LBSE).

Once per rendering update WebKit processes every SVG renderer whose transform changed, whether from script or an animation, and that repaint pass was the dominant per-frame cost on MotionMark's Suits subtest. Instead of walking each moved renderer up to its repaint container, the flush now computes each child's rectangle in its parent's coordinate space, unions the children per parent, maps that single union up the chain once, and issues one repaintUsingContainer() call per repaint container rather than one per shape.

This also stops requesting outline bounds, which for SVG merely duplicated the visual overflow rectangle, and refreshes the bounding-box and visual-overflow caches that a layout would normally update, so getBBox() and paint or hit-test culling never read a stale rectangle. This collapses many backing-store invalidations into one while keeping the repainted region minimal, closing the performance gap to the legacy SVG engine.

Avoided re-resolving the SVG transform from style on every paint in the Layer-Based SVG Engine (LBSE).

Non-layer SVG renderers already cache their transform in m_localTransform, but the painting code path used to recompute it from scratch each time, concatenating the transform list, applying transform-origin and multiplying matrices, only because the cached value uses a different transform origin. The paint transform is now derived directly from the cached one by translating around the nominal origin, which removes that per-paint recomputation and cuts the cost of painting transformed SVG content.

Fixed a repaint bug in the Layer-Based SVG Engine (LBSE) where dynamically changing a marker's markerUnits or orient attribute left stale pixels behind. Such a change resizes every shape that references the marker, but a referencing shape without a layer gets no post-layout position update, so only its new bounds were repainted—a shrinking marker left its former area on screen.

The visual overflow rectangle, markers included, is now cached at the end of shape layout while the geometry is still current, so a marker change can repaint the old bounds before recomputing the new ones. The extra repaint is limited to markers, since gradients and patterns do not affect a client's bounds, and the resulting repaint rects are more accurate than the legacy SVG engine's.

WPE WebKit 📟

Added a new feature flag, BackForwardCacheWithMedia, which may be used to disable storing pages with media content in the back-forward cache. This should solve the problem with hardware decoders kept occupied on low-end devices in case of caching pages with media after navigation.

Releases 📦️

WebKitGTK 2.52.5 and WPE WebKit 2.52.5 have been released, including a number of fixes for security issues, and therefore it is recommended to update. An accompanying security advisory will be published in the coming days. Additionally, these releases include small improvements and Web compatibility improvements.

That’s all for this week!

By Igalia WebKit Team at July 13, 2026 10:59 PM

July 01, 2026

Introducing the Safari MCP server for web developers

Surfin’ Safari

Update: In Safari 27 beta and Safari Technology Preview 247, we’re introducing the Safari MCP server — a Model Context Protocol server for web developers that makes your web development and debugging workflow faster and more powerful. We know agents are increasingly integral to the coding process and the Safari MCP server gives your agent the ability to know how your code actually renders in the browser by connecting it to a Safari browser window.

Any MCP-compatible client can connect to the Safari MCP server. By connecting your agent to a Safari browser window, your agent can emulate what your users experience, giving it the information it needs to debug more autonomously, like access to the DOM, network requests, screenshots, and console output.

It speeds up your debugging process and lets you stay in the comfort of your terminal, which means fewer rounds of hopping windows and typing prompts to debug your code.

The use cases

If you build for the web, then you know about the debugging dance. It usually goes something like this:

You see something wrong with your site in the browser. You open the console to hunt it down. You click into the styles tab. You see what’s broken. You go back to your code to fix it. Or maybe you take a screenshot, detail the problem to your agent, and let it do the fixing for you. Hopefully it gets it right, the bug is fixed, and you can move on.

But when it isn’t fixed, you go through the workflow again — Browser. Prompt. Agent.

And again and again, until you finally squash the bug.

Regardless of the browser or tools you use, the debugging workflow is a lot of clicks, tools, and window hopping to make a single fix, but it doesn’t have to be that way. If you’re already using agents in your development workflow, the Safari MCP server makes your debugging faster and more efficient.

The Safari MCP server enables your agent to do more debugging and troubleshooting on its own. Here are just a few examples of what it can help with:

Web development in Safari. The next time you develop in Safari, you’ll benefit from an upgraded workflow. Your agent already helps you with your code, now it can do even more by checking out how your code actually renders in Safari.

Improve compatibility with Safari. Testing in just one browser means missing potential bugs in another, giving those users a subpar experience. With the Safari MCP server, your agent can open your site in Safari, inspect computed styles, check layout, and compare it against what you expect without switching windows.

Analyze performance. See what parts of your site are slowing things down. The Safari MCP server lets your agent evaluate JavaScript on the page to surface performance metrics, like navigation timing and resource load times, so it can pinpoint what’s slowing your site down and work on the right fix.

Check for accessibility. The Safari MCP server lets your agent check for common accessibility issues like missing labels, improper ARIA attributes, and poor contrast, so you can catch problems that impact your users.

Verify any user state. Know that the page is working and looking as it should. Your agent can check the state of the form, query an element using a selector, confirm specific interactions, show different states of a checkout flow, and more. Spend less time on these manual checks and empower the agent to do it for you.

These are just a few of the use cases. However you decide to implement it, the Safari MCP server helps your agent do more for you and reduce all the back and forth that web development often requires. An easier workflow means more bugs squashed, happier users, and a better product.

The tools

Here are the available tools and what they do:

Tool Description
browser_console_messages Return buffered console logs for the current or specified tab
browser_dialogs List and respond to browser dialogs (accept, dismiss, or input text for JS prompts)
close_tab Close a browser tab by its handle
create_tab Create a new browser tab, optionally loading a URL
evaluate_javascript Execute JavaScript code within the page and return the result
get_network_request Get full detail for a single recorded network request (headers, body, timing)
get_page_content Extract text content of a page in various formats (markdown, HTML, JSON, etc.)
list_network_requests List network request summaries (URL, method, status, timing) for the current tab
list_tabs List all open browser tabs with their handles and URLs
navigate_to_url Navigate to a URL and return the loaded page’s content
page_info Get info about the current page: URL, title, and loading state
page_interactions Perform DOM interactions in sequence: click, type, scroll, hover, keyPress, etc.
screenshot Capture a screenshot of the current page as a PNG
set_emulated_media Emulate a CSS media type (e.g. “print”) for responsive-design testing
set_viewport_size Set the browser viewport size in CSS pixels
switch_tab Switch to a different browser tab by its handle
wait_for_navigation Wait for the current page to finish loading; returns final URL and title

With the Safari MCP server, you no longer have to write the perfect prompt, carefully describing to your agent what you’re experiencing in the browser. You can give your agent the ability to find out for itself.

How to get started

Safari 27 beta

First, you’ll need to install Safari 27 beta. Once installed, make sure to enable web developer features and remote automation. To enable features for web developers choose Safari > Settings > Advanced > check the Show features for web developers checkbox. Then go to Safari > Settings > Developer > check “Allow remote automation and external agents.”

If you’re using Claude, you can use the following command in your terminal:

claude mcp add safari-mcp -- "/usr/bin/safaridriver" --mcp

If you’re using Codex, you can use the following command in your terminal:

codex mcp add safari-mcp -- "/usr/bin/safaridriver" --mcp

For other agents, you can put the following in your mcp.json or config.json file.

{
  "mcpServers": {
    "safari-mcp": {
      "command": "/usr/bin/safaridriver",
      "args": ["--mcp"]
    }
  }
}

Safari Technology Preview

First, you’ll need to install Safari Technology Preview. Once installed, make sure you enable Safari Settings > Advanced > Show features for web developers. Then go to Safari Settings > Developer > Enable remote automation and external agents.

If you’re using Claude, you can use the following command in your terminal:

claude mcp add safari-mcp-stp -- "/Applications/Safari Technology Preview.app/Contents/MacOS/safaridriver" --mcp

If you’re using Codex, you can use the following command in your terminal:

codex mcp add safari-mcp-stp -- "/Applications/Safari Technology Preview.app/Contents/MacOS/safaridriver" --mcp

For other agents, you can put the following in your mcp.json or config.json :

"safari-mcp-stp": {
  "command": "/Applications/Safari Technology Preview.app/Contents/MacOS/safaridriver",
  "args": ["--mcp"] 
}

Note that while the above code names the server safari-mcp-stp, you can name it whatever you like, even just safari. Once you have the Safari MCP server installed, try one of the following prompts:

Find bugs on my site in Safari
How accessible is my site in Safari?
See how my website performs in Safari

While each agent works a little differently, it shouldn’t need to be told to use the Safari MCP server explicitly — it’ll figure it out on its own. Simple prompts like the ones above are enough to kickstart the MCP.

Here’s how a conversation with an agent using the Safari MCP server might go:

You: Got a bug report — something’s broken in Safari on the flight page. Can you figure out what’s going on?
Agent: Sure, let me take a look.
Agent: I found two distinct bugs on the flight page in Safari. Want me to fix them both?
You: Yes. Anything else here that might be causing problems for Safari users?
Agent: Yes, two more things worth flagging. The results reveal animation is silently broken and the API server startup log is wrong. Should I tackle both as well?

 

All you need is an initial request to get started, and with the help of the Safari MCP server, your agent can take it from there.

The Safari MCP server runs entirely on your local machine and makes no network calls of its own. It also does not have access to your personal information in Safari (e.g. AutoFill or other browser activity). When it captures page content, screenshots, or console logs, that data goes directly to the agent you’re running — not to Apple. What happens to that data from there depends on the agent and model you’re using. As with any agent you give access to your browser, only use ones you trust.

Why we built this

There are many ways to build for the web, both with and without AI. If AI is a part of your workflow, we think this tool will help make it even more productive. And if it isn’t, that’s OK too.

By creating this resource, we hope to make it easier than ever to test and debug in Safari by helping your agent understand how things look and work in the browser.

If you end up giving it a try or if this is your first time using an MCP server, let us know what you think.

Find us online: Saron Yitbarek on BlueSky, Jen Simmons on Bluesky / Mastodon, and Jon Davis on Bluesky / Mastodon. If you run into any issues, file a WebKit bug report. Filing issues really does make a difference.

July 01, 2026 09:28 PM

Release Notes for Safari Technology Preview 247

Surfin’ Safari

Safari Technology Preview Release 247 is now available for download for macOS Golden Gate and macOS Tahoe. If you already have Safari Technology Preview installed, you can update it in System Settings under General → Software Update.

This release includes WebKit changes between: 314716@main…315846@main.

Accessibility

Resolved Issues

  • Fixed VoiceOver jumping to the top of the page when navigating to an element that immediately becomes accessibility-ignored via JavaScript. (315078@main) (179065364)
  • Fixed VoiceOver reporting the Recent Events table on parks.wa.gov as empty. (314901@main) (179156593)
  • Fixed VoiceOver not exposing aria-actions custom actions when the action target is accessibility-ignored. (315097@main) (179286650)
  • Fixed an <a> element with a click handler but no href not being exposed as a link. (315102@main) (179398579)

CSS

New Features

  • Added support for calc-mix(). (314719@main) (176199063)

Resolved Issues

  • Fixed scroll overcompensation of fixed, nested anchor-positioned elements, so they no longer lose their position when scrolling. (314757@main) (174010503)
  • Fixed an issue where font-synthesis incorrectly applied synthetic oblique to variable fonts declared with @font-face. (314814@main) (178698772)
  • Fixed synthetic bold not being applied for a variable font whose @font-face font-weight descriptor explicitly restricts it to normal. (314537@main) (179001275)
  • Fixed an issue where CSS math functions produced an incorrect signed zero for subtraction, min(), max(), clamp(), and mod(). (315188@main) (179534440)
  • Fixed an issue where input[type=hidden] was not set to display: none !important in the user-agent stylesheet. (315559@main) (180137214)

Fonts

Resolved Issues

  • Fixed an issue where synthetic bold incorrectly added advance width to zero-advance glyphs. (315157@main) (179418570)

Forms

Resolved Issues

  • Fixed an issue where a positive margin-top on a <legend> element inside a <fieldset> did not shift the fieldset down. (315391@main) (141267953)

HTML

Resolved Issues

  • Fixed an issue where <link rel=preload as=json> incorrectly triggered a preload. (315422@main) (179843455)
  • Fixed an issue where the deprecated align="center" attribute was not treated as identical to align="middle" per spec. (315531@main) (180128710)

JavaScript

Resolved Issues

  • Fixed an issue where Temporal.Instant operations were not aligned with the spec’s abstract operations. (315377@main) (179844859)

MathML

New Features

  • Added support for embellished operator detection through mrow for underover layout. (314924@main) (173192995)

Resolved Issues

  • Fixed MathML operators routed through MathOperator being invisible when their glyph only exists in a fallback font. (314928@main) (178096170)
  • Fixed MathML to use MathML Core fallback values for script layout constants. (315004@main) (179177178)

Media

New Features

  • Added support for overriding color space for hardware video decoders in WebCodecs. (314887@main) (178717498)
  • Added support for mapping nextslide and previousslide MediaSession actions to nexttrack and previoustrack platform commands, so pressing next/previous track invokes a registered slide handler when no direct track handler is registered. (314839@main) (178744268)

Resolved Issues

  • Fixed media controls not appearing when tapping videos in the LinkedIn feed on iPad. (315049@main) (171231918)
  • Fixed an issue where the MediaSource text-track removal loop always processed only the last track. (315310@main) (179508398)
  • Fixed an issue where isValidVideoFrameBufferInit() tested displayWidth and displayHeight presence against themselves instead of the correct properties. (315401@main) (179514279)
  • Fixed an issue where MediaMetadata artwork sizes parsing read the wrong substring for the height value. (315402@main) (179523057)
  • Fixed an issue where the pictureInPictureElement getter inverted the shadow-host connectivity check. (315403@main) (179675087)

Model Element

Resolved Issues

  • Fixed setting the entityTransform on a <model> element while the model is unloaded or hidden. (314951@main) (179114750)
  • Fixed <model> elements losing gesture interactivity after the model player is reloaded (for example, when the model scrolls out of and back into the viewport). (315026@main) (179249565)

Networking

Resolved Issues

  • Fixed an issue where WebKit refused to load valid ASCII domains starting with xn-- that did not pass strict IDNA 2008 validation, aligning behavior with the WHATWG URL Standard. xn-- is the prefix of a punycode-encoded non-ASCII domain. (314820@main) (177686282)
  • Fixed an issue where arbitrary Content-* headers from 304 responses were not used to update cached entries. (315449@main) (179864251)
  • Fixed an issue where the Cache-Control request directives max-age, min-fresh, and no-store were not honored. (315447@main) (179865576)
  • Fixed an issue where Cache-Control: public was not honored on responses with unknown status codes. (315445@main) (179870099)
  • Fixed an issue where the HTTP cache did not store responses with explicit freshness for all status codes. (315450@main) (179871690)

Rendering

Resolved Issues

  • Fixed text-wrap: balance not being applied to content with -webkit-line-clamp. (314783@main) (172715503)
  • Fixed an issue where text changes that did not modify the text element’s size in a flex layout on a new compositing layer did not trigger re-rendering. (315173@main) (179292409)
  • Fixed an issue where an underline was drawn twice on <sup> elements. (315220@main) (179537119)
  • Fixed an issue where an underline under a <sup> element was offset by one device pixel from the rest of the line on subpixel displays. (315316@main) (179586525)
  • Fixed an issue where the ex unit in text-box-edge misplaced the propagated underline, causing it to be painted twice. (315331@main) (179769451)
  • Fixed an issue where min-width was not honored over max-width when sizing a shrink-to-fit container around a replaced element. (315396@main) (179935558)

SVG

Resolved Issues

  • Fixed SVG applying text-decoration to elements with display: contents. (314830@main) (85691104)
  • Fixed SVG <text> with textLength scaling each glyph separately when x or y is a list. (315146@main) (94161279)
  • Fixed an issue where box-shadow was not drawn on fixed-positioned SVG elements. (315468@main) (97098951)
  • Fixed an issue where an SVG filter applied via CSS to an element positioned below the viewport rendered a spurious black square at the viewport origin. (315329@main) (177482001)
  • Fixed IntersectionObserver not computing intersections for SVG element roots. (314837@main) (177807041)
  • Fixed SVG vertical <text> to honor the CSS text-orientation property instead of only the deprecated glyph-orientation-vertical presentation attribute. (315080@main) (178044217)
  • Fixed an issue where getRotationOfChar() returned approximately 360° instead of 0° for full-turn rotations after normalisation into the [0°, 360°) range. (315293@main) (178044934)
  • Fixed an issue where a non-BMP character before a <tspan> boundary shifted the x and y value lists by one position. (315418@main) (178360036)
  • Fixed interpolation of arc flags in the d property to treat them as non-zero booleans. (314745@main) (178950624)
  • Fixed pathFromEllipseElement to honor auto values for rx and ry, so APIs such as getTotalLength() return the correct length for ellipses. (314846@main) (178959205)
  • Fixed animated GIFs freezing when presentation attributes are changed on an SVG image referenced by a <use> element. (315094@main) (179414226)
  • Fixed an issue where getBoundingClientRect() on an SVG <tspan> element returned the bounds of the entire <text> element instead of the <tspan>‘s own area. (315234@main) (179626476)
  • Fixed an issue where a nested clip-path on a <clipPath> element ignored css zoom. (315562@main) (180162723)

Scrolling

Resolved Issues

  • Fixed an issue where scrollIntoView with nearest alignment incorrectly aligned to the far edge for an oversized target positioned before the scrollport. (315225@main) (106356373)
  • Fixed a regression on macOS 26 where horizontal rubber-banding interfered with vertical scrolling. (315424@main) (165449829)
  • Fixed an issue where scroll snapping selected a snap point that overshot the destination instead of the closest one in the scroll direction. (315522@main) (179549119)
  • Fixed an issue where interrupting a smooth scroll with a new scrollTo() call to a different target fired the scrollend event at the wrong position. (315471@main) (179551854)
  • Fixed an issue where re-snapping after a layout change moved away from a valid scroll position when the snap area was larger than the snapport. (315291@main) (179553122)

Security

Resolved Issues

  • Fixed an issue where Content Security Policy 'self' did not match script sources in opaque-origin HTTP(S) documents. (314912@main) (178638597)
  • Fixed an issue where Content Security Policy incorrectly applied script-src to JSON module imports instead of connect-src. (315497@main) (180006320)

Spatial Web

Known Issues

  • WebXR might not render when you use Simulator. (178666073)

    Workaround: Use an Apple Vision Pro device instead of Simulator.

Resolved Issues

  • Fixed an issue where transforming the camera instead of the model in a <model> element led to undesirable lighting effects. (312407@main) (179522538)

Deprecations

  • Removed the Spatial Backdrop developer preview in favor of the Immersive API. (315100@main) (160271766)

Text

Resolved Issues

  • Fixed a line break appearing after a U+201D Right Double Quotation Mark. (314829@main) (177952069)

Web API

Resolved Issues

  • Fixed an issue where the URL Pattern tokenizer emitted a spurious zero-length Regexp token for empty regexp groups. (315289@main) (179452346)

WebDriver

New Features

  • Allow your agent to connect to a Safari browser for development and debugging via the Safari MCP server. (176038457)

Resolved Issues

  • Fixed an issue where the WebDriver full page screenshot was clipped to the viewport dimensions instead of the full page. (315337@main) (179840186)

WebGL

Resolved Issues

  • Fixed a regression where a WebGL canvas was filled with opaque content that hid stacked canvases beneath it. (315018@main) (175352260)

July 01, 2026 09:28 PM

June 29, 2026

Igalia WebKit Team: WebKit Igalia Periodical #69

Igalia WebKit

Update on what happened in WebKit in the week from June 22 to June 29.

After a small break after the Web Engines Hackgest, we're back with another round of updates, this time with a couple of exciting improvements to the SVG engine, a WebRTC fix, and support for WebP images with the toDataURL() API.

Cross-Port 🐱

Made RenderLayer creation conditional for SVG renderers in the new Layer-Based SVG Engine (LBSE), so a layer is now only created when one is actually needed for intrinsic reasons (3D transforms, opacity, etc.) instead of unconditionally for every renderer. Plain 2D transforms no longer force a layer and are applied directly during painting. This is the groundwork for follow-up patches that remove the intrinsic need for layers when applying clipping, masking and filters to SVG subtrees. It is an important milestone towards reducing the overhead that has been holding back LBSE performance compared to the legacy SVG engine.

Fixed the paint order of non-composited children around composited SVG siblings in the Layer-Based SVG Engine (LBSE). A layered container paints its children from a single flat list in DOM (and SVG paint) order, but some children are composited into their own GraphicsLayer for reasons like will-change, a 3D transform or certain opacity cases. The flat child list is now split into contiguous paint-order segments at those boundaries, with each run of plain children painted by its own overlay layer placed at the correct depth in the compositor's child list. This keeps every child in its DOM order without giving trailing siblings a RenderLayer or backing store of their own, and a container with no composited children produces no segments at all, so the common case costs nothing. This allows us to support composition within LBSE subtrees in a performant way, after dropping the requirement that every renderer creates a layer.

Multimedia 🎥

GStreamer-based multimedia support for WebKit, including (but not limited to) playback, capture, WebAudio, WebCodecs, and WebRTC.

Fixed initial decoding issues on LibWebRTC on platforms that do video decoding on the final playback stage (for efficiency and performance), instead of on the LibWebRTC decoder component.

Graphics 🖼️

Added support for producing WebP images with canvas' .toDataURL(). Using 1.0 as the quality setting will produce lossless images, which matches the behaviour of Chromium and Firefox.

That’s all for this week!

By Igalia WebKit Team at June 29, 2026 09:00 PM

June 17, 2026

Release Notes for Safari Technology Preview 246

Surfin’ Safari

Safari Technology Preview Release 246 is now available for download for macOS Golden Gate and macOS Tahoe. If you already have Safari Technology Preview installed, you can update it in System Settings under General → Software Update.

This release includes WebKit changes between: 313555@main…315033@main.

Accessibility

Resolved Issues

  • Fixed an issue preventing VoiceOver from following focus() calls for newly added elements. (313425@main) (177167634)
  • Fixed role computation for elements with prefixes. (314273@main) (178399441)

CSS

New Features

  • Added support for <image> values in light-dark(<image>, <image>). (314244@main) (172290840)
  • Added support for using the CSS attr() substitution function on pseudo-elements with non-trivial originating elements. (313684@main) (177595332)
  • Added support for image(<color>) in the <image> value type. (314204@main) (178189616)
  • Enabled the font-variant-emoji property in preview. (314117@main) (178193814)
  • Enabled word-break: auto-phrase in preview. (314118@main) (178193962)
  • Added support for color-mix() with more than two colors. (314272@main) (178349405)
  • Added support for the alpha() relative color function. (314397@main) (178551773)

Resolved Issues

  • Fixed aspect-ratio intrinsic-size handling in flex layout to align with the specification. (313536@main) (83240099)
  • Fixed text-decoration-thickness propagation to inner spans with non-inline style. (314502@main) (111015539)
  • Fixed unnecessary text truncation that could occur with always-on scrollbars. (313584@main) (148428628)
  • Fixed CSS Container Style Queries to work when the container has display: contents. (313677@main) (164414720)
  • Fixed CSS Style Container Query to recognize the default value of a custom property in multiline cases. (313957@main) (165627262)
  • Fixed CSS Anchor Positioning so that absolutely positioned elements no longer anchor to viewport-fixed-position elements unexpectedly. (314706@main) (170323196)
  • Fixed -webkit-box-pack to account for box-direction and to handle overflow repositioning correctly. (313862@main) (174588996)
  • Fixed an emoji reaction overlapping the comment code box on GitHub. (311084@main) (174652842)
  • Fixed :hover state to repaint correctly on the customizable <select> element. (310623@main) (175273152)
  • Fixed text in nested CSS Subgrid with overflow: hidden clipping content on subsequent items. (313503@main) (175877530)
  • Fixed an interaction between an img with max-width and surrounding elements that caused the parent’s layout to compute incorrectly. (313105@main) (176889859)
  • Fixed incorrect margin offsets for inline <div> positioning to fix the broken layout of paragraph spacing on some sites. (313502@main) (177139092)
  • Fixed shrink-to-fit boxes to update their width when they gain or lose a scrollbar. (313390@main) (177172896)
  • Fixed CSS zoom to be animatable by the computed value. (313735@main) (177411607)
  • Fixed preferred width to trim trailing whitespace before a preserved newline. (313480@main) (177426037)
  • Fixed inline layout to apply margins of preceding block content at the line start eagerly when block-in-inline content is involved. (313489@main) (177438841)
  • Fixed CSS attr() to align with disallowing the <url> type. (313593@main) (177540489)
  • Fixed CSS attribute selector case-insensitivity handling for HTML attributes. (313654@main) (177547701)
  • Fixed ::first-letter to use the correct definition of punctuation. (313652@main) (177599506)
  • Fixed offset-path to respect <coord-box> when blending shape() and basic-shape paths. (313737@main) (177685457)
  • Fixed stretch-fit width with aspect-ratio providing a definite cross size to flex items when it should not. (313723@main) (177705930)
  • Fixed an aspect-ratio flex container resolving descendant percentage heights against a stale logical height. (313727@main) (177711905)
  • Fixed inline-block baseline to fall back to the bottom margin edge when the content has no in-flow line boxes. (313769@main) (177753094)
  • Fixed programmatic focus after keyboard interaction to match :focus-visible. (314012@main) (177850766)
  • Fixed @font-face font-style to serialize ‘oblique 0deg’ as ‘normal’. (314128@main) (178185291)
  • Fixed serialization of explicit font-variant longhands set after a system font. (314292@main) (178251443)
  • Fixed CSSFontFeatureValuesRule.fontFamily to be settable rather than readonly. (314602@main) (178323504)
  • Fixed font-style: oblique to be clamped against the font’s slant range rather than the @font-face weight range. (314280@main) (178324521)
  • Fixed font-style: oblique angle being applied to the variable font ‘slnt’ axis with the wrong sign. (314399@main) (178326843)
  • Fixed background and mask coordinated property list resolved values to match the specification. (314242@main) (178378309)
  • Fixed longer hue interpolation when one input is none. (314327@main) (178476769)
  • Fixed line-through to render with the correct thickness over a descendant inline box. (314391@main) (178547557)
  • Fixed font-synthesis to avoid synthesizing styles outside of a font’s variable axis range. (314537@main) (178550149)
  • Fixed font-style: italic to slant a variable font whose @font-face uses an oblique angle. (314681@main) (178566326)
  • Fixed SVG intrinsic sizing so that height: max-content uses the used width rather than the default width. (314556@main) (178712792)
  • Fixed color-mix() to allow percentages that sum to zero. (314577@main) (178758710)
  • Fixed color-mix() resolution for the new 0% rules. (314714@main) (178921722)
  • Fixed a flex item with min-width: min-content being clamped to a smaller max-width. (314599@main) (178777567)

Canvas

New Features

  • Made the radii argument of CanvasPath.roundRect() optional. (313882@main) (177944903)

Resolved Issues

  • Fixed canvas 2D context to set the origin-clean flag when reset. (313824@main) (177858398)
  • Fixed canvas fillText with textAlign=center misplacing complex-shaped text. (314522@main) (178682402)

Editing

Resolved Issues

  • Fixed typing Hindi (InScript) input on Google Docs. (297270@main) (177643899)

Forms

Resolved Issues

  • Fixed identically sized buttons to render with consistent corner radius. (313535@main) (173786057)
  • Fixed a box with percentage offset (e.g. top: 100%) being mispositioned when its containing block is out-of-flow with percentage height. (313364@main) (177181803)

HTML

New Features

  • Added support for popover close watcher integration. (313838@main) (129116634)
  • Added support for SVG <a> as an argument to Origin.from(). (314287@main) (178426374)

Resolved Issues

  • Fixed popover light dismiss to account for input buttons. (313840@main) (171352032)
  • Fixed popover light dismiss to account for disabled command buttons. (314400@main) (171358576)
  • Fixed a regression that broke pushState with custom application URL schemes. (312738@main) (177547157)
  • Fixed outerHTML setter to align with the HTML standard. (313795@main) (177788638)
  • Fixed fragment parsing of xmlns="" inheritance and annotation-xml encoding. (313803@main) (177808494)
  • Fixed createHTMLDocument() to no longer leave the body in a parsing state. (314295@main) (178440940)
  • Fixed text fragment matching so that a prefix is no longer matched outside of a word boundary near the start of the document. (314323@main) (178467104)

Images

Resolved Issues

  • Fixed images appearing then quickly disappearing on OpenTable search results. (313572@main) (176275269)
  • Fixed <picture> <source> candidates being speculatively preloaded even when the inner <img> has loading=lazy. (313833@main) (177833110)
  • Fixed HTMLImageElement.decode() to no longer resolve spuriously after adoption, src change, or cached-image reuse. (314536@main) (178118012)

JavaScript

Resolved Issues

  • Fixed multiple TypedArray constructor edge cases involving buffer sequences to align with the specification. (313401@main) (176724918)
  • Fixed WebAssembly.Memory and WebAssembly.Module to align their cloning and transferring behavior with SharedArrayBuffer. (313482@main) (176792374)
  • Fixed Array.prototype.join to include prototype elements added during element toString invocation. (314210@main) (178055452)

Media

Resolved Issues

  • Fixed WebVTT to not display cues that are larger than the viewport. (314333@main) (136809012)
  • Fixed <audio controls> to not show the “Subtitles” option when no subtitle track is present. (311465@main) (175357130)
  • Fixed MSE SourceBuffer.remove() to no longer remove an extra sample, and fixed buffered ranges to cover the correct ranges. (313383@main) (177065364)
  • Fixed an HTMLMediaElement that doesn’t display in an infinite scrolling webpage to use a viewport listener that notifies the media player about the visibility of the element. (311380@main) (177081214)
  • Fixed EME to use a 10 second key wait timeout. (313873@main) (177936893)
  • Fixed EME OCDM to prevent a spurious keystatuses event when all keys have expired. (313876@main) (177939767)
  • Fixed getSupportedCapabilitiesForAudioVideoType (EME) to no longer include unsupported capabilities. (314032@main) (178142768)
  • Fixed MediaSession.setActionHandler to not throw an exception when called. (314546@main) (178167294)
  • Fixed AudioData.copyTo to throw RangeError when frameOffset equals numberOfFrames. (314451@main) (178609688)
  • Fixed MIDI and AVI MIME signature matching due to a typo in MIME sniffing. (314499@main) (178661530)
  • Fixed PannerNode to no longer produce non-finite samples for edge-case distance parameters. (314608@main) (178784571)

Networking

Resolved Issues

  • Fixed URL parsing for sendBeacon() and the Media Session API. (313403@main) (177330315)

Rendering

Resolved Issues

  • Fixed Google search-suggestion font sizes increasing on rotation from portrait to landscape. (313547@main) (113801810)
  • Fixed misrendering of Pahawh Hmong text on Wikipedia. (313458@main) (167446860)
  • Fixed a black region appearing on the right side of swift.org when the sidebar is open. (313513@main) (173191807)
  • Fixed <legend> to mask the <fieldset>‘s border correctly when it has a negative left margin. (313863@main) (174185071)
  • Fixed a regression that caused incorrect layout in some content using stretch. (309433@main) (176398251)
  • Fixed justification expansion to apply around CJK Unified Ideographs Extensions E, F, G, and H. (313586@main) (176759766)
  • Fixed RTL position-fixed elements losing their contents when the document is scrolled on iOS. (313573@main) (177454608)

SVG

New Features

  • Made SVG <use> work without specifying a fragment identifier. (313550@main) (148973201)

Resolved Issues

  • Fixed the resolved value for the width and height properties on SVG <rect>, <image>, <svg>, and other elements. (313859@main) (96320059)
  • Fixed an animated GIF freezing when referenced by SVG <use> and the opacity was adjusted. (313531@main) (96837306)
  • Fixed vector-effect to apply a transform to path geometry rather than to stroke geometry. (314302@main) (103573160)
  • Fixed <animateMotion> non-path animations to apply the rotate attribute. (314508@main) (110915794)
  • Fixed SVG elements with display: contents being visually hidden. (314079@main) (141825746)
  • Fixed SVGPathElement.getTotalLength() and . SVGPathElement.getTotalLength.getPointAtLength() to respect the CSS d property. (314654@main) (167195297)
  • Fixed a rounding issue for SVG rect height with em and percentage values. (313935@main) (171587382)
  • Fixed SVG intrinsic sizing so that max-content and min-content use the viewBox aspect ratio when intrinsic sizes are missing. (313864@main) (174568894)
  • Fixed glyph-orientation-vertical: auto to decode surrogate pairs for UTR#50 lookup. (314070@main) (175570881)
  • Fixed handling of pathLength="0" and negative pathLength for stroke dashing. (314001@main) (175928827)
  • Fixed hit-testing of clip-path with nested objectBoundingBox <clipPath> to use the correct reference box. (313855@main) (177605894)
  • Fixed SVG overflowing edges when offset by a fractional value. (313886@main) (177630386)
  • Fixed feGaussianBlur not applying when stdDeviation contains a 0 in the second component. (313874@main) (177906905)

Deprecations

  • Removed support for the non-standard glyph-orientation-horizontal property. (314069@main) (176134352)

Scrolling

Resolved Issues

  • Fixed scrolling of the “Add Contacts” drop-down on outlook.live.com by narrowing the scope of a quirk. (314111@main) (48008837)
  • Fixed a passive: false wheel event listener combined with overscroll-behavior: contain preventing scrolling. (314170@main) (137757208)
  • Fixed the scroll anchoring behavior so that the comments panel on Quip is no longer blank when expanded. (314371@main) (178255628)

Storage

New Features

  • Added support for storing FileSystemHandle objects in IndexedDB. (314229@main) (176102643)

Resolved Issues

  • Fixed IndexedDB connections in workers to recover after a network process crash. (313509@main) (177219395)

Web API

New Features

  • Added support for the Origin-Agent-Cluster HTTP response header. (314346@main) (69452369)

Resolved Issues

  • Fixed IntersectionObserver to no longer notify targets in detached documents. (313834@main) (162699098)
  • Fixed IntersectionObserverEntry.boundingClientRect to honor CSS zoom aware getBoundingClientRect. (313512@main) (177250323)
  • Fixed IntersectionObserver to report correct bounds for SVG element targets. (313596@main) (177260411)
  • Fixed Web Locks API to remove the AbortSignal abort algorithm after a lock request settles. (314433@main) (178589067)

Web Extensions

Resolved Issues

  • Fixed cross-origin XMLHttpRequest from a Safari Web Extension to no longer trigger an additional permissions request. (313506@main) (154866064)

Web Inspector

New Features

  • Added a separate column to show the node associated with layout and rendering events. (314460@main) (177618501)

Resolved Issues

  • Fixed hovering over a node in a preview for a collection to highlight the node in the inspected page. (314589@main) (20341722)
  • Fixed style sheets created via CSSOM (such as adoptedStyleSheets) being incorrectly marked as User Agent Style Sheets. (313738@main) (134101594)
  • Fixed clearing the Console tab search field to dismiss the Clear Filters button. (313599@main) (176388155)
  • Fixed properties added to an element’s Style Attribute sometimes disappearing momentarily. (314467@main) (178053421)

WebGPU

Resolved Issues

  • Fixed WGSL parser handling of identifiers per the latest specification. (313405@main) (177008615)
  • Fixed WGSL validation of binary expressions involving short-circuit and/or operators. (313467@main) (177012957)

WebRTC

Resolved Issues

  • Fixed WebRTC media capabilities to report power-efficient AV1 decoding when supported. (313468@main) (174686183)
  • Fixed audio issues when joining Cisco Meeting Server meetings using Safari. (313415@main) (175260977)

June 17, 2026 11:08 PM

June 16, 2026

Igalia WebKit Team: WebKit Igalia Periodical #68

Igalia WebKit

Update on what happened in WebKit in the week from June 9 to June 16.

The major highlight this week is the Web Engines Hackfest! Despite it, there are a variety of updates as well, such as various improvements to input handling in WPE WebKit and WebKitGTK, WPE menu rendering changes, and a plethora of other smaller improvements.

Cross-Port 🐱

Input methods may now know whether a field is intended to be used as search input, in which case the WebKitInputMethodContext:input-purpose property will have the value WEBKIT_INPUT_PURPOSE_SEARCH.

Due to GTK not providing an equivalent value for GtkInputPurpose, the default behaviour is to continue mapping search fields to GTK_INPUT_PURPOSE_FREE_FORM as before; but custom input methods may use the new value to detect search inputs. When using WPEPlatform, the value is mapped to WPE_INPUT_PURPOSE_SEARCH, which has been added as well.

Handle selections as part of moveBefore.

Corrected user activation propagation for close watchers.

Invalidate :lang() and :dir() selectors after moveBefore.

Enable Close Watchers in preview.

WPE WebKit 📟

WPE now renders its own popup menus for elements such as select. It supports all styling options the web provides such as colors and fonts. The internal menu can be overriden with the existing WebView::show-option-menu signal. Cog for example still renders its own (with a recent commit).

A colorful context menu

A context menu with a simpler style

A context menu inside an iFrame

A context menu inside a rotated container

Community & Events 🤝

The Web Engines Hackfest started! We had a fantastic first day of talks, and now are heading to breakout sessions. Make sure to check the schedule for sessions that may interest you!

That’s all for this week!

By Igalia WebKit Team at June 16, 2026 10:14 AM

June 15, 2026

The golden rule of Customizable Select

Surfin’ Safari

Customizable select is coming to Safari 27. With this technology, developers can fully control the appearance of <select> elements — custom arrows, option layouts, color swatches, icons, full visual styling — without the need for JavaScript libraries or an endless parade of <div> elements. And because it’s a built-in control, you don’t have to compromise on keyboard navigation or accessibility semantics.

But, to ensure this built-in control works well for everyone, it’s important to follow this single but essential rule: always provide text content or accessible text attributes for your option elements.

Every time that rule is broken, every time an option is styled to show a visual without any text and without any accessible fallbacks, three different problems get introduced all at once. The menu is harder to use for everyone, impossible to use with accessibility tools, and it becomes a completely broken experience in browsers that don’t support it yet.

When you remember to follow the rule, you’ll improve the user experience, support accessibility, and provide progressive enhancement so it works for people regardless of what browser they choose.

We’ll show you why following this mission critical rule gets you:

Better UX

Take this category filter from a photographer’s gallery site. The version below uses icons alone — a building, a flower, a hummingbird — to represent each category:

customizable select of categories for photo gallery with no labels

It looks clean. But a user who doesn’t immediately recognize what the hummingbird icon represents has no fallback. The closed select shows only an icon in the button, with no other hint of what’s currently selected. Add a text label to each option and the experience becomes immediately scannable. The selected state is readable at a glance, and every option is unambiguous:

customizable select of categories for photo gallery with labels

The icons are still there. The labels make it readily decipherable for everyone.

Better accessibility

When a screen reader encounters an option with no text, the user may not hear a descriptive label for each option. Braille rendering and other assistive technology output may also be confusing. Text, even when hidden visually with a .visually-hidden class, stays in the accessibility tree and gives screen readers, braille displays, and speech recognition software something real to work with. If you use an icon as an <img>, add an alt or aria-label — or mark it decorative using alt="" and let the visible or visually-hidden label carry the meaning.

<option>
   <img src="bird.svg" alt="">
   <span>Wildlife</span>
</option>

The problem you solve isn’t just a compliance checkbox: it’s the difference between a visitor completing your form and someone abandoning it.

Better progressive enhancement

Customizable select is a new feature. Browsers that don’t yet support it fall back to the platform-native <select> — which is exactly the right behavior, as long as your options still make sense in that fallback state.

If you’ve removed text in favor of icons or swatches, a user on an older browser sees a dropdown full of empty options. The same is true when CSS fails to load at all: a slow connection, a corporate proxy stripping stylesheets, a user with custom styles enabled. Wrap your enhancements in @supports (appearance: base-select) and keep plain text as your baseline. Adding a swatch is an enhancement. Removing the color name to make room for it is a regression.

The rule for maximizing the power and utility of customizable select is simple: keep the text. You can hide it visually. You can make it tiny. You can position it off-screen. But it needs to be there. Icons, swatches, and illustrations are additions to an option — never substitutes for it. Follow that rule and the rest of customizable select is yours to play with.

Feedback

We love hearing from you. To share your thoughts, find our web evangelists online: Saron Yitbarek on BlueSky, Jen Simmons on Bluesky / Mastodon, and Jon Davis on Bluesky / Mastodon. You can follow WebKit on LinkedIn. If you run into any issues, we welcome your feedback on Safari UI (learn more about filing Feedback), or your WebKit bug report about web technologies or Web Inspector. If you run into a website that isn’t working as expected, please file a report at webcompat.com. Filing issues really does make a difference.

June 15, 2026 09:20 PM

June 10, 2026

Introducing the Field Guide to Grid Lanes

Surfin’ Safari

This week, we launched the Field Guide to Grid Lanes at gridlanes.webkit.org.

Field Guide to Grid Lanes website header

If you ever bookmarked the CSS Tricks Complete Guide to Flexbox, HTML5 Rocks, or CSS Zen Garden, a guide like this might feel familiar. It’s designed to be an easy introduction, a reference guide — and just plain fun.

The interactive playground

At the top is a live, editable Grid Lanes layout. Switch between Waterfall and Brick. Try preset layouts. Drag the slider labeled “Flow tolerance” and click “Play tab order” to understand the impact of flow-tolerance.

Interactive drawing of website with items laid out with Grid Lanes. Multiple buttons, sliders, and a code editor make it possible to try out many combinations quickly & see the results.

Resize the demo browser window to test responsive behavior without resizing your whole window. Edit the CSS directly. Copy the code you create.

The cheat sheet

Next is the Field Guide itself — a single-page reference for every property, value, and option.

Screenshot of first part of the reference guide, showing lots of definitions, little diagrams, and tiny code snippets

It has four sections:

  • Grid Lanes Basicsdisplay: grid-lanes, plus the difference between waterfall and brick layouts
  • Options for Lane Definitions — Grid track-sizing with fr units, fixed lengths, percentages, auto, min-content & max-content, fit-content(), minmax(), repeat(), and auto-fill vs auto-fit
  • Options for Placement & Spacingflow-tolerance, gap, spanning tracks, and explicit placement
  • Good to Know — info about source order, progressive enhancement, and switching layouts at different breakpoints

The demos

To showcase the possibilities of Grid Lanes, we created six demos, each available in several variations:

The six demos listed on the homepage — with a screenshot of each.
  • Photos — just images, in a variety of aspect ratios
  • Recipes — components containing both flexible images and varying lengths of text
  • Newspaper — longer passages of text, with a few images (and a lot of CSS puns)
  • Mega Menu — lists of very short text
  • Timeline — text in brick layout
  • Pinboard — mixed media

Each demo opens with a floating control panel.

Screenshot of one of the demos, happens to be of photo layout. The controls are showing, as described in the article.

“Layout” offers a dropdown of variations — showing off what Grid Lanes can do, and comparing it to Flexbox, Multicolumn, and Grid. “Numbers” shows item order. “Flow tolerance” lets you experiment with its effects. The code panel displays the key layout CSS.

“Hide controls” puts the focus on the demo itself. To get the controls back, click the gear that appears in the lower-right corner.

Working with Safari’s developer tools

Web Inspector knows about Grid Lanes, too. Toggle “Order Numbers” to reveal overlays marking the DOM order of items. These numbers are extremely useful when experimenting to find the best flow-tolerance value for your content.

Screenshot of photo demo, with Web Inspector open. The Grid Inspector is showing, with Item numbers are turned on. This creates lines all over the webpage, revealing the Grid Lanes layout, and marking each Item with a number.

Learn more by reading New Safari developer tools provide insight into CSS Grid Lanes.

What about other browsers?

Grid Lanes works today in Safari 26.4+. For the latest information about other browsers, check Can I Use. For progressive enhancement guidance, read When will CSS Grid Lanes arrive? How long until we can use it?

Made by the people who shipped it

The Field Guide was built by the same team behind Grid Lanes. We hope this is a fun experience that makes Grid Lanes easy to learn. Bookmark it, share it with colleagues, and let us know what you make.

Visit the Field Guide →

Feedback

We’d love to hear from you. Find us online: Jen Simmons on Bluesky / Mastodon, Saron Yitbarek on Bluesky / Mastodon, and Jon Davis on Bluesky / Mastodon. You can follow WebKit on LinkedIn.

June 10, 2026 07:30 AM

June 08, 2026

Igalia WebKit Team: WebKit Igalia Periodical #67

Igalia WebKit

Update on what happened in WebKit in the week from June 1 to June 8.

Another great week, this time we have a performance improvement implemented in the Skia-based compositor, an excellent writeup about how to investigate and isolate memory leaks in WPE WebKit, a couple of multimedia fixes, and a variety of improvements and fixes across WebKit ports.

Cross-Port 🐱

Implement dialog integration with close watcher.

Implement node iterator and live range pre-remove steps for in-progress moveBefore() implementation.

Fix an early return in CloseWatcher close to align with the spec.

The Web Inspector now shows DOM nodes associated with layout and rendering events in a separate column of layout timeline next to initiator, sizing, and timing information. Hovering over rows in the details table highlights the associated node, and clicking it reveals the node in the "Elements" tab. This makes it easier to match events with specific nodes and helps debugging changes to a web page.

Fix popover light dismiss to account for disabled command buttons.

Multimedia 🎥

GStreamer-based multimedia support for WebKit, including (but not limited to) playback, capture, WebAudio, WebCodecs, and WebRTC.

Fix mediaTime provided with requestVideoFrameCallback in case of captureCanvas as source.

Graphics 🖼️

Batched painting support was implemented in the Skia-based compositor, improving the performance in several cases.

Community & Events 🤝

Pawel Lampe published a blog post where he's presenting and discussing a guide on structured approach to narrowing down and debugging memory leaks within WPE WebKit.

That’s all for this week!

By Igalia WebKit Team at June 08, 2026 08:57 PM

June 02, 2026

Igalia WebKit Team: WebKit Igalia Periodical #66

Igalia WebKit

Update on what happened in WebKit in the week from May 19 to June 1.

The main feature of this week are new releases: stable ones with many security fixes, and development ones with the new Skia-based compositor enabled. Additionally, there was work on Web-facing features, optimizations, spell checking support for the WPE port, and more.

Cross-Port 🐱

WebKit now supports mirroring MathML stretchy operators using the OpenType rtlm feature.

Replaced the CloseWatcherManager's escapeKeyHandler, which will allow other types of close signals to be supported.

Implemented queuing mutation observer records in the work-in-progress moveBefore() implementation.

Implemented popover integration with close watcher.

Fixed popover light dismiss to account for popovertarget on input buttons.

Content filters now create temporary files in the compiled filters directory, which ensures that a file rename can always be used to place them at their final location. This avoids falling back to a regular file copy, which can be slower, when the temporary directory returned by g_get_tmp_dir() (typically /tmp) is in a different volume than the filters' storage path configured for WebKitUserContentFilterStore.

WPE WebKit 📟

Enabled spell checking support in WPE. The existing implementation for the WebKitGTK port, which uses the Enchant library as a backend, was generalized to provide spell checking support in WPE as well. The feature may be toggled at build time using the ENABLE_SPELLCHECK CMake option.

Releases 📦️

WebKitGTK 2.52.4 and WPE WebKit 2.52.4 have been released; they include a number of fixes for security issues, and it is a highly recommended update. The corresponding security advisory, WSA-2026-0003 (GTK, WPE is available as well. The release also includes a number of small improvements and Web compatibility fixes.

Additionally, development releases WebKitGTK 2.53.3 and WPE WebKit 2.53.3 are available since last week. These include a change to use a new Skia-based compositor by default, which is intended to replace TextureMapper once ready. Therefore, bug reports related to website rendering are particularly welcome when using this and subsequent development releases.

Infrastructure 🏗️

The deprecated and un-maintained Flatpak-based SDK was removed. Developers working on the WPE and GTK WebKit ports are encouraged to migrate to the new SDK.

That’s all for this week!

By Igalia WebKit Team at June 02, 2026 12:12 AM

Pawel Lampe: WPE memory leak investigation playbook

Igalia WebKit

Depending on the web application, the WPE WebKit memory usage trend can vary. When simple web applications are being processed, the memory consumption tends to be virtually stable (the same) no matter the period. However, when more complicated web applications are being executed, the memory usage usually grows over time while going back to normal from time to time e.g., when GC / memory pressure mechanism releases all kinds of caches and not-needed memory. Therefore, memory growth itself is not unusual. Nevertheless, as the memory leaks happen in WPE at times, the memory growth is worth investigating — especially if very rapid or unbounded.

This article presents a structured playbook for investigating such a memory growth and memory leaks in WPE. Rather than diving straight into debugging tools, it starts from first principles: confirming the problem is real, choosing the right environment to work in, and narrowing down the leaking area before any heavy tooling is involved. The goal is to reach actual debugging as fast as possible, regardless of whether the environment is an embedded device or a desktop machine, and regardless of how quickly the problem reproduces.

Playbook #

The high-level list of recommended steps to follow is presented below. In a nutshell, the steps 1, 2, and 3 are meant to choose and follow the fastest possible investigation path so that actual debugging of the problem (step 4) can be started as soon as possible.

  1. Confirming the problem
  2. Identifying the best setup for reproducing the problem
  3. Narrowing down
  4. Debugging

1. Confirming the problem #

The ultimate first step when working with alleged memory leak is to check whether the observed memory growth is actually abnormal. In the case of web browsers in general, the memory growth alone may not necessarily mean something is leaking. There may be many regular reasons why the browser’s memory usage is growing, but the usual suspects are:

  • JavaScript-level memory allocations — due to the very nature of JavaScript, the memory it allocates causes the overall web content process memory growth up until the garbage collector (GC) kicks in. Then (from the RSS perspective) some memory is usually freed. However, as it’s not easy to predict when the GC will be invoked (e.g., when the browser processes an application that performs heavy rendering), it’s possible that memory will grow but remain garbage-collectible.
  • JavaScript Just-in-Time (JIT) compilation — when not explicitly disabled or limited, the processing of any web application that has JavaScript code associated with it will cause the browser to continuously compile the JavaScript code in the background so that it executes such code faster in runtime at the expense of memory that is required for storing compiled artifacts.
  • Caches — as the WPE operates, it caches things such as web resources, style resolution artifacts, textures, glyph atlases, layer tiles, display lists, rasterization artifacts, and many others. Naturally, the cache sizes are limited, however, if many caches are growing at the same time, they may create an impression of a leak. The difference in that case is, the caches stop growing at some point.

Due to the above, to confirm the memory growth is abnormal, one should usually try the following first:

  1. Triggering memory pressure to force the browser to trigger GC and evict as many cache entries as possible,
  2. Rerunning the browser with JIT disabled to rule out the JIT-related memory growth — unless the application code is very small.

If the memory growth doesn’t stop with JIT disabled or its level does not go back to normal after triggering memory pressure, the growth can be assumed to be abnormal, and one can proceed to the next step.

2. Identifying the best setup for reproducing the problem #

When the memory growth is atypical, it needs to be narrowed down in a way that the final debugging is possible. For both narrowing down and the debugging, one should aim at the most flexible development environment along with the smallest possible web application that reproduces the problem quickly. What it means in practice is — desktop environment along with small demo web application that reproduces the problem. Whilst it’s not always possible to have such an environment, the 3 general rules are as follows:

  1. Desktop environment is usually better than embedded one in terms of working with memory leaks as it offers minimal overhead (e.g., in terms of compilation times) and huge flexibility in choosing the industry standard tools for profiling/debugging.
  2. Small web application is always better than a big one as long as it still reproduces the same problem in the same amount of time. In such case, a small application minimizes the amount of noise that usually stands in the way of profiling/debugging.
  3. A web application that reproduces the problem quickly is always better than the one that needs much more time for it. The worst thing that can happen in the case of narrowing down memory leaks, is when the memory growth is noticeable or starts after a very long time such as hours/days+.

Given the above, at this point one should go through the below steps:

  1. Check if the setup is trivial enough already — if the web application reproduces the problem quickly in a desktop environment and is simple enough, one should immediately jump to the Debugging section.
  2. Check if the problem can be reproduced on desktop assuming it originally reproduces on embedded.
  3. Check if the problem can be reproduced faster if it’s not reproducing fast enough.
  4. Check if the web application could be simplified.

Once the setup is simplified as much as possible, one should proceed to one of narrowing down sections depending on the setup. Also, if the setup is still not ideal, one should actively seek opportunities for simplifying the setup even during narrowing down as it’s likely that some new information will eventually open new possibilities in terms of simplifying setup.

3. Narrowing down #

When the problem has been confirmed but there are not enough clues to tell exactly which parts leak, the debugging cannot be started right away. In such case, it’s necessary to narrow down the problem to the browser/application area that can be easily debugged.

While in some cases narrowing down is not even necessary, quite often it takes orders of magnitude more time than actual debugging, and hence one should pay special attention to this step.

3a. Narrowing down on embedded when the problem takes a long time to reproduce #

This is the toughest situation one can find themselves in. When a problem takes a long time to reproduce (hours/days+), every iteration/test comes automatically with a significant cost. Moreover, when the environment is an embedded one, rebuilding WPE is usually more time-consuming and the amount of tooling is usually limited — or requires some work to bring it to the image at least.

Due to the above, narrowing down the problem in this setup requires a structured approach with extra care. In such case, the things to check should be approached in steps defined as follows:

  1. Things to check without rerunning the WebKit
    • in case of embedded devices, extra care is needed when attaching a memory profiler. On low-end devices, memory profilers tend to slow down the application hard enough to trigger otherwise non-existent problems.
  2. Things to check without rebuilding the WebKit
    • in case of embedded devices, one should prefer limiting JIT over disabling it as without it, the JS execution may be slow enough to trigger unexpected scenarios.
  3. Things to check if rebuilding WebKit

Ideally, while checking various things along the above steps, one should batch as many checks as possible within individual tests.

3b. Narrowing down on embedded when the problem reproduces quickly #

When the problem reproduces quickly, the limitations of embedded environment are not that relevant. In this scenario, one should prioritize getting debug symbols (RelWithDebInfo build) into the image and utilizing them by running the browser with whatever profilers are available. For the specific things to check, one should seek inspiration in the following groups:

  1. Things to check without rebuilding the WebKit.
  2. Things to check if rebuilding WebKit.

3c. Narrowing down on desktop when the problem takes a long time to reproduce #

This situation is similar to 3a and hence one should follow the things to check from the following groups:

  1. Things to check without rerunning the WebKit.
  2. Things to check without rebuilding the WebKit.
  3. Things to check if rebuilding WebKit.

However, this time, there are some extra opportunities around tooling:

  1. There should be many more tools available already in the system or available to be installed.
  2. Tools such as memory profilers that could slow down the application making it unusable on embedded, may turn out to be working well when the desktop-class processing power is available.

With the above in mind, it’s worth trying all the tools available with priority because if at least one tool works well, one can save hours of narrowing down.

3d. Narrowing down on desktop when the problem reproduces quickly #

This is technically the simplest possible scenario, so basically, all the possibilities are available. The most time-consuming activity in this case is very likely rebuilding WebKit itself — although it should still be relatively fast. In such case, just after a few quick checks with the Web Inspector, it’s recommended to get debug symbols (RelWithDebInfo build) and start with tools such as memory profilers.

Other than the above, one should go through the following groups on things to check:

  1. Things to check without rebuilding the WebKit.
  2. Things to check if rebuilding WebKit.

4. Debugging #

The WPE debugging is twofold and depends on whether the problem is within the engine (usually C/C++ code) or the web application (JavaScript code).

When problem lies in the engine #

Debugging WPE WebKit is the same as debugging any other C/C++ application on Linux (or Mac if the issue is cross-port and one prefers an Apple port to work with), and hence is outside the scope of this article. Some WebKit-specific information can be found in the WebKit Documentation article on building and debugging page and therefore is recommended as a first step.

When problem lies in web application #

When the problem lies in JavaScript code, the situation is usually fairly straightforward. The majority of bugs in this area should be reproducible across various browser engines and hence a full variety of tooling should be available. If the WebKit is preferred or if the problem reproduces only there, the tooling available is still very useful and helps debugging problems quickly. The ultimate tool in such case is the Web Inspector. On official WebKit’s web page there’s entire index of articles on Web Inspector. Among those, the most interesting read is about Timelines Tab where the most useful debugging can be done. Once the features of Timelines Tab are understood, the next important article is the memory debugging guide. It dives into the most important Timelines Tab subsections and showcases the work with heap snapshots which is a key. To supplement it, it’s very important to know the heap snapshot delta feature which is basically about button:

Web Inspector heap delta.

that allows one to inspect the delta-snapshot between 2 snapshots. It’s critical as it answers the question on what JS objects were added between the base snapshot and the later one. If some objects are piling up, it immediately shows which ones.

One important note on snapshots is that in some cases when using Web Inspector is not possible, one can generate the snapshots manually from the web engine’s C++ code by just calling GarbageCollectionController::singleton().dumpHeap(); at some appropriate moment. In this case, the dump will be written to standard output. It can be then turned into a file and imported from any Web Inspector using Import button.

As the Timelines Tab with its subsections should be able to answer on what happens, to understand why it actually happens, the last missing piece is the JS debugger within Web Inspector. It’s not very different to debuggers in other engines, but it’s worth checking a dedicated article on it just to understand the capabilities.

Appendix #

Things to check without rerunning the webkit #

Even if the WPE is running with default settings in release mode, there are plenty of useful things that can be checked while the browser is still running:

  1. Identifying which WebKit process allocates abnormally,
    • there are multiple ways to do this, but usually it’s as easy as using ps utility.
  2. Identifying how fast the process in question allocates the memory,
    • this is useful to know at least for comparison purposes, but it may hint some problems already if the numbers correlate with what web application does.
  3. Checking logs from stdout, stderr, and journal (using journalctl).
  4. Checking detailed process memory statistics.
  5. Triggering and checking the impact of memory pressure on given processes RSS,
    • in short, memory pressure triggers the cleanup of the majority of caches along with GC. Therefore, if this is able to bring memory back to normal level, then the problem is about caches, JS Heap / GC, or fragmentation.
  6. Attaching memory profilers if available,
    • even if the debug symbols are not present, this may be useful to see what data is being captured and how the web application behaves when slowed down by profiler.
  7. Attaching other tools if available,
    • even if the debug symbols are not present, various tools offer different perspectives on what the browser is doing. In some cases, such information may reveal some anomalies that may be related to the main issue.
  8. Cross-checking with other browsers,
    • if other browsers show a similar pattern of memory usage, it’s very likely the problem lies in web application itself. Otherwise, it strongly suggests a bug in the WPE.
  9. Cross-checking with other ports,
    • if any other WebKit port shows a similar pattern of memory usage, it allows one to narrow down the area in the code a bit based on what port it is:
      • if the same behavior is visible in any of Apple ports, the problem is most likely related to cross-platform code,
      • if the same behavior is visible only in GTK port, then the problem is most likely related to GLib-related part, coordinated graphics part, GStreamer-related part, or others that are shared.

Things to check without rebuilding the webkit #

  1. Tweaking and checking the logs from WPE,
    • while generic logs may hint some unusual behavior, more specific ones such as GC logs (JSC_logGC=1) may be used to check how the individual JS heap sizes evolve over time and how GC behaves. If it’s JavaScript leaking the memory, this log will quickly provide the evidence.
  2. Enabling Remote Web Inspector and checking:
    • both breakdown and trend of memory usage in the memory timeline after doing a bit of recording,
    • the effects of takeHeapSnapshot() invoked from JS console:
      • as this function usually triggers GC internally, it may be used to check how much RSS memory is reclaimed by GC in isolation (followed up by scavenger),
      • as this function takes a JS heap snapshot, it then can be used to explore manually if its contents point towards something interesting.
  3. Disabling JIT and checking the memory usage,
    • if the memory usage is stable with JIT disabled, one should proceed to the step below.
  4. Limiting JIT and checking the memory usage,
    • there are at least a few places (levels) where JIT compilation engine allocates memory. If limiting doesn’t resolve the issue completely, it’s likely the engine itself leaks some memory around temporary helper-heaps such as AssemblerData etc.
  5. Experimenting with environment variables and runtime preferences,
    • some environment variables and runtime preferences change the behavior of the web engine significantly. If changing one of them makes the problem go away, it usually helps to narrow down the problematic area quickly.
  6. Running WPE with system malloc (environment variable Malloc=1) and checking the memory usage,
    • when one suspects bmalloc/libpas issues with fragmentation or scavenger, it’s worth running a browser with system malloc to compare the memory evolution over time against the bmalloc/libpas.
  7. Limiting device memory and checking the memory usage,
    • if triggering memory pressure is not possible, an alternative solution is to limit the device memory so that the browser is under constant memory pressure.
  8. Running WPE with sysprof and checking:
    • stack traces — to see what parts of engine are particularly active as it may hint some problematic area,
    • WebKit marks — to see what the engine is doing as well as quantitative data in marks such as EventLoopRun etc. as in those cases the numeric value trends may reveal resource pile up.

Things to check if rebuilding webkit #

  1. Building WPE in release mode with debug symbols and re-trying memory profilers or other tools if the debug symbols were not present before,
    • if some desired tools such as heaptrack, valgrind, perf, or strace were not available before, it’s the right moment to get/build them as well,
    • once the debug symbols are in, one should try:
  2. Building and running with Google perftools,
    • as WPE allows switching to system malloc as an allocator, it’s possible to use custom malloc implementation with instrumentation such as gperftools. For that, the recommended read is this article from fellow Igalian, Pablo Saavedra.
  3. Building and running with sanitizers,
    • if the problem is about low-level leak, address/leak sanitizer should be able to help pointing out the problematic area.
  4. Building and running with memory sampler,
    • the data produced by memory sampler is roughly the same as inspector’s memory timeline, however, it’s much more convenient as it doesn’t need web inspector at all.
  5. Building and running with node statistics,
    • when memory growth seems to be related to DOM mutations, it’s worth enabling and reporting node statistics periodically — in some cases, it may directly suggest what the problem is about.
  6. Building and running with malloc heap breakdown,
    • when all other means fail, a very good last-resort approach for investigating memory usage statistics via a debug-only WebKit feature called Malloc Heap Breakdown. The details can be found in the dedicated article about it.
  7. Building and running with libpas statistics,
    • On very rare occasions such as memory fragmentation or allocation issues, it may be worth checking the libpas (low-level memory allocation and management library) statistics as WPE uses it by default on the vast majority of platforms.

Individual instructions #

Checking detailed process memory statistics #

As WPE WebKit uses multi-process architecture, there are multiple processes that can be checked, although the most interesting one is usually the Web Content Process. Once the PID of the given process is determined (e.g., using ps utility) the usual steps to check detailed memory statistics are:

  • cat /proc/<PID>/status or cat /proc/<PID>/statm for very basic statistics,
  • pmap -X <PID> - for detailed statistics (if available),
  • cat /proc/<PID>/smaps_rollup and cat /proc/<PID>/smaps for detailed statistics (requires CONFIG_PROC_PAGE_MONITOR kernel configuration option).

Triggering memory pressure from OS #

WPE uses a so-called Memory Pressure Monitor to observe the memory usage in the system and to react if there’s not much memory left. The default thresholds are specified in MemoryPressureMonitor.cpp and usually are 90% for non-critical and 95% for critical response. Depending on the response, WPE schedules GC and clears internal caches immediately.

As the above is usually on by default, one can leverage it to trigger GC (along with cache cleanups) by filling up the available memory in the OS to 95+%. There are many ways to allocate memory, yet the simplest is using stress:

  • e.g. stress --vm 1 --vm-bytes 1024M --vm-keep to allocate 1024 MB.

Attaching memory profilers #

When attaching any memory profiler, unless one wants to profile only native allocations (Skia, GStreamer, ICU, etc.), the key is to use Malloc=1 environment variable on WPE startup so that bmalloc uses system malloc instead of libpas. Also, if WebKit is using a sanboxed mode in given configuration, it’s usually necessary to use WEBKIT_DISABLE_SANDBOX_THIS_IS_DANGEROUS=1 as well. Then the commands are as follows:

  • to attach heaptrack:
    • heaptrack -p <PID> so e.g. heaptrack -p $(pgrep WPEWebProcess) (see this article for details),
  • to run with valgrind’s massif (as attaching to running process is not possible):
    • valgrind --tool=massif --trace-children=yes <WPE-BROWSER-COMMAND> (see this article for details).

Attaching other tools #

If memory profilers are unusable or unavailable, it’s worth checking if other tools are present and experimenting a bit with them if so. In some cases, tools other than memory profilers may give some hints on further investigation or reveal a suspicious pattern within application execution. Some ideas for experiments with various tools are listed below:

  • strace:
    • strace -c -p $(pgrep WPEWebProcess)strace called with -c gives a nice summary of system calls executed by the traced application. It can be useful to check the overall syscall usage pattern to see if there are any anomalies.
    • strace -p $(pgrep WPEWebProcess) -e trace=mmap,munmap,mremap,madvise -ttstrace focused on mmap()-related system calls may be useful to debug libpas.
  • perf:
    • perf record -F 999 -ag -p $(pgrep WPEWebProcess) -- sleep 60 — regular recording with perf can be very useful, especially if symbols are available. With that, one can generate flamegraphs and investigate what’s going on in the browser. While it’s not about profiling memory, it may be helpful to narrow down at least a bit.
    • perf record -F 999 -e syscalls:sys_enter_mmap,syscalls:sys_enter_munmap,syscalls:sys_enter_mremap:sys_enter_madvise -ag -p $(pgrep WPEWebProcess) -- sleep 60perf focused on mmap()-related system calls is much more superior than e.g. strace as it also records stack traces. Therefore, if debug symbols are present, and if the memory growth is very rapid, it’s very likely the libpas mmap() stacktraces will lead to the growth origin statistically.
    • perf trace -e mmap,munmap,mremap,madvise -p $(pgrep WPEWebProcess) — this is very much similar to strace focused on mmap()-related system calls as it shows a live preview of what’s happening.
  • sysprof:
    • sysprof-cli -f — while running system-wide sysprof won’t make WPE push marks into it, the profiling trace may still be useful to some degree, especially if debug symbols are available.

Disabling JIT #

This can be done using an environment variable:

  • JSC_useJIT=false.

Limiting JIT #

Limiting JIT can be achieved via environment variables:

  • JSC_jitMemoryReservationSize=<BYTES> to limit JIT memory usage (the limit is semi-strict as some JIT compilation engine buffers are limited by this value indirectly),
  • JSC_useFTLJIT=false to disable FTL tier,
  • JSC_useDFGJIT=false to disable DFG and FTL tiers,
  • JSC_useBaselineJIT=false to disable Baseline, DFG, and FTL tiers.

Tweaking WPE logs #

WPE is a fairly complex piece of software and hence it offers various logging capabilities related to WebKit itself, as well as to related libraries. The vast majority of logging can be controlled via environment variables:

  • WEBKIT_DEBUG=all to enable all logging channels,
  • WEBKIT_DEBUG=Layout,Media=debug,Events=debug to enable selected logging channels,
  • JSC_logGC=2 to enable JS garbage collector logs,
  • GST_DEBUG=4 to enable gstreamer (multimedia-related) logs (see the documentation),
  • G_MESSAGES_DEBUG=all to enable GLib-level logs.

If MiniBrowser (or similar browser) is used, one can also set a runtime preference to enable JS console.log(...) logging to the standard output:

  • --features=+LogsPageMessagesToSystemConsole.

Enabling remote web inspector #

Enabling WPE’s remote web inspector is a twofold process:

  1. The first step is to run WPE with the proper environment variable so that it starts listening on IP:PORT using tcp socket:
  • WEBKIT_INSPECTOR_SERVER=IP:PORT is the most reasonable option as it uses inspector:// protocol that can be utilized by WebKit-native browsers such as GNOME Web (Epiphany) or Safari,
  • WEBKIT_INSPECTOR_HTTP_SERVER=IP:PORT is a less preferable alternative that uses HTTP protocol and technically works from any browser. However, no seamless integration is guaranteed in this case.
  1. The second step is to connect from a regular web browser to the WPE:
  • using inspector://IP:PORT/ if native inspector server was started,
  • using http://IP:PORT/ if HTTP inspector server was started,
  • forwarding the ports using socat tcp-l:PORT,fork,reuseaddr tcp:IP:PORT if the WPE is running in unreachable network.

Experimenting with environment variables and runtime preferences #

The most outstanding environment variables changing the behavior of WPE are the following:

  • WPE_DISPLAY — assuming the new WPE platform API is used, this environment variable allows one to switch the pre-defined platform implementation thus changing a platform-facing part of graphics pipeline. The valid options are:
    • WPE_DISPLAY=wpe-display-headless — for headless implementation,
    • WPE_DISPLAY=wpe-display-drm — for direct rendering manager integration,
    • WPE_DISPLAY=wpe-display-wayland — for wayland integration,
  • WEBKIT_SKIA_ENABLE_CPU_RENDERING — when set to 1, rendering the DOM contents to the layers is done using Skia CPU backend instead of GPU one.

The most outstanding runtime preferences changing the behavior of WPE are the following:

  • CanvasUsesAcceleratedDrawing — when disabled, 2D canvas will use Skia CPU backend instead of GPU one,
  • LayerBasedSVGEngine — when enabled, WPE uses a different SVG engine internally,
  • AcceleratedCompositing — when disabled, WPE uses experimental, non-composited mode that bypasses all of the compositor work.

Limiting device memory #

On the majority of embedded devices, the device memory can be limited by:

  1. Interrupting the boot sequence (usually holding some key such as z upon booting),
  2. Invoking the command to change the limit and booting, e.g.:
    > global linux.bootargs.console="console=ttymxc0,115200n8 mem=2G"
    > boot
    

Running WPE with sysprof #

Regardless of whether it’s done on desktop (using wkdev-sdk) or on embedded device, the command is always as simple as:

  • sysprof-cli -f -- <WPE-INVOCATION>.

See the documentation entry for more details.

Building WPE in release mode with debug symbols #

On desktop, the simplest way to get release with debug symbols is to utilize CMake’s build type by using -DCMAKE_BUILD_TYPE=RelWithDebInfo within WPE build command, so:

  • ./Tools/Scripts/build-webkit --wpe --release --cmakeargs="-DCMAKE_BUILD_TYPE=RelWithDebInfo".

On embedded, when Yocto is used, one should tweak settings such as:

IMAGE_GEN_DEBUGFS = "1"                                                         
IMAGE_FSTYPES_DEBUGFS = "tar.bz2"
DEBUG_BUILD = "1"
EXTRA_IMAGE_FEATURES_append = " dbg-pkgs"

and potentially INHIBIT_PACKAGE_STRIP to control whether debug symbols should be kept with the binary or not. This may be necessary occasionally as some tools have problems reading .gnu_debuglink and therefore work only with symbols included in the binaries.

Building and running with sanitizers #

WebKit works pretty well with all kinds of sanitizers. To build with any of them a CMake-level helper called ENABLE_SANITIZERS can be used by specifying -DENABLE_SANITIZERS=address, -DENABLE_SANITIZERS=leak etc. With that, the command for building e.g. on desktop could look like:

  • ./Tools/Scripts/build-webkit --wpe --debug --cmakeargs=-DENABLE_SANITIZERS=address.

For more details, one can refer to this article from fellow Igalian, Fujii.

Building and running with memory sampler #

When WPE is built with -DENABLE_MEMORY_SAMPLER=ON, the simple memory sampler can be started along with the browser using environment variable:

  • WEBKIT_SAMPLE_MEMORY=1 (accompanied by WEBKIT_DISABLE_SANDBOX_THIS_IS_DANGEROUS=1 if needed).

With that, the memory of various WPE processes is sampled every second, and saved to the files under /tmp directory continuously.

Building and running with node statistics #

Node statistics are a debug-only feature that can be enabled by:

  • changing 0 of #define DUMP_NODE_STATISTICS 0 to 1 in Source/WebCore/dom/Element.h,
  • adding dumpStatistics() call, to e.g. Node constructor in Source/WebCore/dom/Node.cpp.

Building and running with libpas statistics #

Libpas statistics are a debug-only feature that can be enabled by changing 0 of #define PAS_ENABLE_STATS 0 to 1 in Source/bmalloc/libpas/src/libpas/pas_config.h and then running WPE with environment variable PAS_STATS_ENABLE=1.

June 02, 2026 12:00 AM

May 18, 2026

Igalia WebKit Team: WebKit Igalia Periodical #65

Igalia WebKit

Update on what happened in WebKit in the week from May 11 to May 18.

For this week we have quite a collection of news! Ranging a variety of improvements to dialog.requestClose(), rendering fixes, the new Skia-based compositor enabled by default, and proper versioning and improvements to the WebKit Container SDK, there's news for everyone.

Cross-Port 🐱

Update the closeWatcher.requestClose() function to no longer require user activation, aligning with the spec.

Implement actually moving the node in the DOM when moveBefore() is called.

Fix handling of nested calls to dialog.requestClose().

Add missing preliminary checks to dialog.requestClose().

Graphics 🖼️

Fixed an issue where background images were unexpectedly stretched, primarily affecting the reCAPTCHA checkmark image.

The new compositor using Skia API instead of TextureMapper is now enabled by default.

Infrastructure 🏗️

Added opt-in auto-enter for the WebKit Container SDK - the GTK/WPE wrapper scripts (build-webkit, run-webkit-tests, run-api-tests, etc.) now relaunch themselves inside a pinned wkdev-build podman container when WEBKIT_CONTAINER_SDK_ENABLE_AUTOENTER=1 is set. A new .wkdev-sdk-version file at the repo root pins the SDK image, so the image can be bumped in a PR and validated through EWS. Without the flag, wrappers run on the host exactly as before.

Introduced a proper version scheme for the wkdev-sdk image provided by the WebKit Container SDK so consumers can pin to a known revision. The :latest tag, the WKDEV_SDK_TAG/--tag override and the tag/* branch mechanism are replaced by a single machine-checkable format <major>.<minor>-v<count>-<gitsha> (e.g. 2.53-v1-916f9ef), where <major>.<minor> tracks the WebKitGTK/WPE release cycle, v<count> is the per-cycle SDK build counter, and <gitsha> traces the image back to its source commit. wkdev-create gains a --version switch (full or bare <major>.<minor>). wkdev-update supports updating from latest tag to the new versioning scheme, just run it on your host to update to the latest SDK.

Switched the wkdev-build container from a persistent container to ephemeral podman run --rm --init per invocation. This removes the manual podman rm step necessary whenever container creation arguments changed (which the tooling was not handling by itself), the first-run recursive-chown cost, and the podman start step after host reboots.

That’s all for this week!

By Igalia WebKit Team at May 18, 2026 07:39 PM

May 11, 2026

Igalia WebKit Team: WebKit Igalia Periodical #64

Igalia WebKit

Update on what happened in WebKit in the week from May 4 to May 11.

This week we have a bag of exciting updates, such as fixes to crashes, better YouTube playback, a handful of advancements to WebXR, and the development releases of WebKitGTK and WPE WebKit 2.53.2.

Cross-Port 🐱

If the filesystem runs out of space while the NetworkProcess is writing into its network cache, the process will crash with SIGBUS. This would surface to users as the "Internal error fired from WebLoaderStrategy.cpp(559) : internallyFailedLoadTimerFired" error, and would be handled by re-spawning another NetworkProcess that would similarly fail.

This was addressed by using fallocate, if available, to reserve the required size. If fallocate fails to reserve, the NetworkProcess will skip caching, avoiding the crash. If fallocate is not available, the existing behaviour is preserved.

Networking 📶

Networking support, including the libsoup HTTP library.

libsoup now supports the zstd compression encoding.

Multimedia 🎥

GStreamer-based multimedia support for WebKit, including (but not limited to) playback, capture, WebAudio, WebCodecs, and WebRTC.

getUserMedia() and getDisplayMedia() support should work better thanks to a couple PipeWire related fixes.

Playback of some YouTube videos (usually at low framerate) has been fixed. Eventually a better solution will involve supporting edit lists in the GStreamer MSE backend.

Graphics 🖼️

A crash when accessing the diagnostics webkit://gpu page was fixed, making sure we handle the case where libGL.so.1 or libOpenGL.so.0 are missing.

Fixed missing glyph before ZWJ/ZWNJ if no font is found for the cluster.

The WebXR implementation based on OpenXR has gained support for quad, equirect and cylinder layers.

Releases 📦️

The second unstable releases for the current development cycle have been published: WebKitGTK 2.53.2 and WPE WebKit 2.53.2. Development releases are intended is to gather early feedback on upcoming changes, and as such issue reports are welcome in Bugzilla.

That’s all for this week!

By Igalia WebKit Team at May 11, 2026 08:04 PM