February 06, 2023

ElementInternals and Form-Associated Custom Elements

Surfin’ Safari

In Safari Technology Preview 162 we enabled the support for ElementInternals and the form-associated custom elements by default. Custom elements is a feature which lets web developers create reusable components by defining their own HTML elements without relying on a JavaScript framework. ElementInternals is a new addition to custom elements API, which allows developers to manage a custom element’s internal states such as default ARIA role or ARIA label as well as having custom elements participate in form submissions and validations.

Default ARIA for Custom Elements

To use ElementInternals with a custom element, call this.attachInternals() in a custom element constructor just the same way we’d call attachShadow() as follows:

class SomeButtonElement extends HTMLElement {
        this.#internals = this.attachInternals();
        this.#internals.ariaRole = 'button';
        this.#shadowRoot = this.attachShadow({mode: 'closed'});
        this.#shadowRoot.innerHTML = '<slot></slot>';
customElements.define('some-button', SomeButtonElement);

Here, #internals and #shadowRoot are private member fields. The above code will define a simple custom element whose ARIA role is button by default. Achieving the same effect without using ElementInternals required sprouting ARIA content attribute on the custom element itself like this:

class SomeButtonElement extends HTMLElement {
        this.#shadowRoot = this.attachShadow({mode: 'closed'});
        this.#shadowRoot.innerHTML = '<slot></slot>';
        this.setAttribute('role', 'button');
customElements.define('some-button', SomeButtonElement);

This code is problematic for a few reasons. For one, it’s surprising for an element to automatically add content attributes on itself since no built-in element does this. But more importantly, the above code prevents users of this custom element to override ARIA role like this because the constructor will override the role content attribute upon upgrades:

<some-button role="switch"></some-button>

Using ElementInternals’s ariaRole property as done above, this example works seamlessly. ElementInternals similarly allows specifying the default values of other ARIA features such as ARIA label.

Participating in Form Submission

ElementInternals also adds the capability for custom elements to participate in a form submission. To use this feature of custom elements, we must declare that a custom element is associated with forms as follows:

class SomeButtonElement extends HTMLElement {
    static formAssociated = true;
    static observedAttributes = ['value'];
        this.#internals = this.attachInternals();
        this.#internals.ariaRole = 'button';
    attributeChangedCallback(name, oldValue, newValue)
customElements.define('some-button', SomeButtonElement);

With the above definition of a some-button element, some-button will submit the value of the value attribute specified on the element for the name attribute specified on the same element. E.g., if we had a markup like <some-element name="some-key" value="some-value"></some-element>, we would submit some-key=``some-value.

Participating in Form Validation

Likewise, ElementInternals adds the capability for custom elements to participate in form validation. In the following example, some-text-field is designed to require a minimum of two characters in the input element inside its shadow tree. When there are less than two characters, it reports a validation error to the user using the browser’s native UI using setValidity() and reportValidity():

class SomeTextFieldElement extends HTMLElement {
    static formAssociated = true;
        this.#internals = this.attachInternals();
        this.#shadowRoot = this.attachShadow({mode: 'closed', delegatesFocus: true});
        this.#shadowRoot.innerHTML = '<input autofocus>';
        const input = this.#shadowRoot.firstChild;
        input.addEventListener('change', () => {
        if (newValue.length >= 2) {
            this.#internals.setValidity({ });
        this.#internals.setValidity({tooShort: true}, 
            'value is too short', this.#shadowRoot.firstChild);
customElements.define('some-text-field', SomeTextFieldElement);

With this setup, :invalid pseudo class will automatically apply to the element when the number of characters user typed is less than 2.

Form-Associated Custom Element Callbacks

In addition, form-associated custom elements provide the following set of new custom element reaction callbacks:

  • formAssociatedCallback(form) – Called when the associated form element changes to form. ElementInternals.form returns the associated from element.
  • formResetCallback() – Called when the form is being reset. (e.g. user pressed input[type=reset] button). Custom element should clear whatever value set by the user.
  • formDisabledCallback(isDisabled) – Called when the disabled state of the element changes.
  • formStateRestoreCallback(state, reason) – Called when the browser is trying to restore element’s state to state in which case reason is “restore”, or when the browser is trying to fulfill autofill on behalf of user in which case reason is “autocomplete”. In the case of “restore”, state is a string, File, or FormData object previously set as the second argument to setFormValue.

Let’s take a look at formStateRestoreCallback as an example. In the following example, we store input.value as state whenever the value of input element inside the shadow tree changes (second argument to setFormValue). When the user navigates away to some other page and comes back to this page, browser can restore this state via formStateRestoreCallback. Note that WebKit currently has a limitation that only string can be used for the state, and “autocomplete” is not supported yet.

class SomeTextFieldElement extends HTMLElement {
    static formAssociated = true;
        this.#internals = this.attachInternals();
        this.#shadowRoot = this.attachShadow({mode: 'closed', delegatesFocus: true});
        this.#shadowRoot.innerHTML = '<input autofocus>';
        const input = this.#shadowRoot.querySelector('input');
        input.addEventListener('change', () => {
            this.#internals.setFormValue(input.value, input.value);
    formStateRestoreCallback(state, reason)
        this.#shadowRoot.querySelector('input').value = state;
customElements.define('some-text-field', SomeTextFieldElement);

In summary, ElementInternals and form-associated custom elements provide an exciting new way of writing reusable component that participates in form submission and validation. ElementInternals also provides the ability to specify the default value of ARIA role and other ARIA properties for a custom element. We’re excited to bring these features together to web developers.

February 06, 2023 08:51 PM

February 01, 2023

Pushing Interop Forward in 2023

Surfin’ Safari

A year ago, Apple, Bocoup, Google, Igalia, Microsoft, and Mozilla came together to improve the interoperability of the web and to continue our commitments to web standards — actions that ensure the web will work in any browser, on any operating system, with any computer.

Throughout last year, Interop 2022 focused on fifteen key areas of most importance to web developers, selecting automated tests to evaluate how closely each browser engine matches the web standards for those areas. Browsers made remarkable progress between January and December 2022, improving the number of tests that pass in all three browsers from 49% to 83%.

screenshot of the 2022 graph, also available at http://wpt.fyi/interop-2022Interop 2022 was a great success. The “Interop” line, in dark green, shows the percent of tests that passed in all three browsers

The WebKit team channeled efforts across all focus areas, and is proud to have reached a 98.2% pass-rate by the end of 2022.

The final scores for Interop 2022, ending in December. Chrome 88. Firefox 92. Safari 98. The final browser scores for Interop 2022.

Announcing this year’s Interop 2023

Now we are pleased to announce this year’s Interop 2023 project! Once again, we are joining with Bocoup, Google, Igalia, Microsoft, and Mozilla to move the interoperability of the web forward.

The scores have reset. We retired half of the tests used for scoring Interop 2022 last year, and added many new tests — all of which are focused on the technology web developers most expressed they want improved next.

Screenshot of the new Interop 2023 dashboardThe new Interop 2023 dashboard provides more insight than ever. Click the name of each technology to see the tests used to evaluate conformance to web standards.

Each “Focus Area” collects together a set of automated tests for a particular technology, used to evaluate browser implementations. The “Investigations” are team projects run by the people behind Interop 2023 to investigate a particularly-complex issue as a group, and find ways to make progress.

Last fall, the collaborative team planning Interop 2023 received 87 proposals for what to include. Of those, 35 were accepted and combined into 18 new Focus Areas, plus 2 new Investigations. They join 5 Focus Areas carried over from 2022 and 3 Focus Areas carried over from 2021, for a total of 26 “Active Focus Areas” for 2023.

Active focus areas tableThe new “Interop” column reflects the percentage of tests that pass in all three browser engines, which is the goal, to increase interoperability.

We achieved pretty great interoperability in 7 Focus Areas from 2022, and so we’re moving these to “Previous Focus Areas”, a new section on the Interop dashboard, where they no longer count towards the overall top-level score.

Previous Focus Areas tableA new “Previous Focus Areas” section lists that areas of focus from past years, where we can keep an eye on them.

The 2023 Focus Areas

Let’s take a look at all the web technology included in each of the 26 Focus Areas for 2023. They now include features in JavaScript and Web APIs, as well as CSS.

Border Image

Gray square with a gradient border from purple at the top to yellow at the bottom

The ability to use an image to provide the visual styling for a box’s border has been supported in browsers for many years. It opens up a world of possibilities for how a border can look. But behavioral differences between browsers have discouraged web developers from using border-image. Things have greatly improved over time, but there are still inconsistencies. By including Border Image in Interop 2023, the hope is that a renewed attention to detail will make all the difference.

Color Spaces and Functions

Expression of color is vital for designers. Having complete tools to cover the gamut of color spaces can help our most creative authors make the web a more beautiful place to visit. Color Spaces and Functions is a Focus Area carried over from Interop 2022. To ensure the work is completed, this year’s area still includes the tests for three expanded color spaces (lab, lch, P3), and writing color in CSS through functional notation with color-mix().

For 2023, this area now includes styling gradients so that interpolation — the method of determining intermediate color values — can happen across different color spaces. This illustration shows the differences between the default sRGB interpolation compared to interpolation in lab and lch color spaces:

Three stripes of red to purple gradients showing interpolation differences for sRGB, LAB, and LCH color spaces

Learn more about color spaces and functions in Improving Color on the Web, Wide Gamut Color in CSS with Display-P3, and Wide Gamut 2D Graphics using HTML Canvas.

Container Queries

Container Queries started arriving in 2022, allowing developers to apply styles to a particular item based on qualities of the container they live inside. Size queries let developers create components that adapt depending on the size of their container, and Container Query Units provide a measurement of the container, in cq* units.

Screenshot of Container Queries CSS example code with a browser window showing a demo store of apparel product card components with a large hero layout, three-column tile layout, and sidebar layout

A single card component can appear in different places in the layout at different sizes — a large hero graphic, a medium size displayed in rows, and a small version for the sidebar.

By including Size Queries and Container Query Units in Interop 2023, we can ensure the web has interoperable implementations across browsers.


Containment in CSS improves performance by limiting calculations of layout, style, paint, size (or any combination) to an isolated segment of the DOM instead of the entire page. The Focus Area includes the contain, contain-intrinsic-size, and content-visibility CSS properties. They are used to help the browser make optimization decisions. For example, content-visibility: auto is a convenient way to defer element rendering until the content becomes relevant to the user by scrolling to it, find-in-page, tab order navigation, etc.

CSS Pseudo-classes

This Focus Area covers a collection of CSS pseudo-classes: :dir(), :nth-child(), :nth-last-child(), :nth-of-type(), :nth-last-of-type(), :modal, :user-valid and :user-invalid.

The :nth-child(n of <selector>) and :nth-last-child(n of <selector>) pseudo-classes are particularly interesting. For example, :nth-child(2 of .foo), matches the 2nd element that has the class .foo among all the children. Here’s an example you can try in Safari, where this feature has been supported since 2015.

If you want to count from the bottom, use :nth-last-child(n of <selector>)!

It’s a particularly exciting time to add new and improve existing CSS pseudo-classes, because they can be used inside :has() — exponentially increasing their usefulness.

Custom Properties

The @property at-rule extends the capabilities of CSS variables much further by allowing developers to specify the syntax of the variable, the inheritance behavior, and the variable initial value. It allows developers to do things in CSS that were impossible before, like animating gradients or specific parts of transforms.

@property --size {
  syntax: "<length>";
  inherits: false;
  initial-value: 0px;

With @property support, developers can declare custom properties in a fashion that’s similar to how browser engines define CSS properties.


This flexible one-dimensional layout solution for arranging items in rows or columns has been around for over fifteen years. Over that time, the Flexbox specification has matured with both slight behavior changes and updated clarifications of precise details. This year’s Flexbox Focus Area expands on previous years, adding the latest WPT tests. Staying ahead of new unevenness in implementations maintains developer confidence in this widely-used layout technology.

Font Feature Detection and Palettes

Font feature detection extends Feature Queries by adding two functions for testing which font formats and technologies are supported by a browser. Developers can write statements like @supports font-format(woff) { ... } or @supports font-tech(color-COLRv0) { ... } to conditionally apply CSS only when WOFF fonts or COLRv0 are supported.
Color fonts provide a way to add richness to designs without sacrificing the benefits of using regular text. Regardless of how decorative a color font is, the underlying text is always searchable, copy/paste-able, scalable, translatable, and compatible with screen readers.

Font palettes provide a mechanism for web developers to alter the color palette used by a color font. The font-palette property provides a way for web developers to select one of several different predefined color palettes contained inside a color font — for example, to declare that a font’s dark color palette be used for the site’s dark mode design. The @font-palette-values rule provides a way for web developers to define their own custom color palette for recoloring color fonts. Learn more by reading Customizing Color Fonts on the Web.


Setting written text vertically can be commonplace in languages like Japanese and Chinese. Support for vertical text has been available in browsers for several years, but support for vertical text in form fields has been missing. Interop 2023 is a commitment by the industry to change that with vertical writing mode support in input, textarea, and select menus.

The 2023 Forms Focus Area also carries over the tests from Interop 2022. This includes tests for the appearance property, form, events on disabled form controls, input elements, form submission, and form validation.


CSS Grid is another layout tool even more powerful than Flexbox. The ability to divide the page into regions and define the relationship of content to areas of the grid offers unparalleled control within a structured layout. Similar to Flexbox, the Grid Focus Area expands on work from Interop 2021 to ensure reliable layout and adoption of this powerful technology.


The :has() pseudo-class wasn’t considered for inclusion in Interop 2022, because it still wasn’t clear that it’s possible to implement a “parent-selector” in a performant way in browsers. Then in March 2022, Safari 15.4 proved that it can be done.

This simple tool gives developers the long-awaited ability to apply styles to an ancestor based on the state of its descendant or sibling elements. It’s a powerful way to reduce the need for JavaScript, and something that will be most useful once it’s implemented interoperably in all browsers. That makes it important to include in Interop 2023. Learn about how powerful :has() can be by reading Using :has() as a CSS Parent Selector and much more.


Inert subtrees were first used by the modal dialog element to prevent user interaction with content appearing behind opened dialogs. The inert Focus Area covers the new inert attribute, which expands this capability to all HTML elements. When an element is marked as inert, it is no longer editable, focusable or clickable and hidden from assistive technologies. Read Non-interactive elements with the inert attribute to learn more.


CSS Masking provides several mechanisms to mask out part of an image or clip off part of a box. They have been supported in browsers for a long time, but like many things implemented long ago there are painful differences between browsers. It’s exactly the kind of developer pain point that Interop 2023 can address. The Masking Focus Area includes improving CSS clipping and masking behaviors, including their use in animations and with SVG content.

Math Functions

CSS Math Functions help developers create complex calculations to style complex layouts or control animations without the need for JavaScript. Interop 2023 includes:

  • Exponential functions: pow(), sqrt(), hypot(), log(), exp()
  • Sign-related functions: abs(), sign()
  • Stepped value functions: round(), mod(), rem()
  • Trigonometric functions: sin(), cos(), tan(), asin(), acos(), atan(), atan2()

Support for all of these CSS math functions first appeared on the web in Safari 15.4.

Media Queries 4

As most front-end web developers know, CSS Media Queries provides the mechanism for applying CSS depending on the size of the viewport or other qualities of the device. The most recent level of the specification, Media Queries level 4) adds new syntax for combining and modifying queries, plus a simplified range syntax that makes it easier for developers to write complicated queries. This new syntax matches the options available in Container Queries.

The and, not, and or conditionals make complex queries more readable. The new range syntax offers a more straightforward pattern for declaring a viewport range. For example, @media (500px <= width < 900px) { ... } applies when the viewport width is equal to 500px or between 500px and 900px, but not equal to 900px.


The Modules Focus Area includes support for Modules in Web Workers, Import Maps and Import Assertions. JavaScript Modules allow web developers to import and export variables, functions, and more. Import Maps give web developers the ability to control the behavior of JavaScript imports. Import Assertions adds syntax for module import statements to indicate the expected module type to help protect sites from unintentionally running malicious JavaScript.

Motion Path

CSS Motion Path (also known as Offset Path) is used to describe a path for an element to follow. It’s powerful when combined with CSS transformations and especially helpful with CSS animations — making it possible to code complex movements in CSS and avoid JavaScript performance costs. This Focus Area covers offset, offset-anchor, offset-distance, offset-path, offset-position, and offset-rotate.

Offscreen Canvas

When using Canvas, rendering, animation, and user interaction usually happen on the main execution thread of a web application. Offscreen Canvas provides a canvas that can be rendered off screen, decoupling the DOM and the Canvas API so that the <canvas> element is no longer entirely dependent on the DOM. Rendering can also be run inside a worker context, allowing developers to run tasks in a separate thread and avoid heavy work on the main thread.

The combination of DOM-independent operations and rendering off the main thread can provide a significantly better experience for users, especially on low-power devices.

This Focus Area also includes requestAnimationFrame()in web workers which can be used along with OffscreenCanvas to perform different rendering and animation related tasks off the main thread.

Pointer & Mouse Events

Pointer events are DOM events that are fired for a pointing device. They are designed to create a single DOM event model to handle pointing input devices such as a mouse, pen/stylus or touch (one or more fingers).

Last year, the Interop 2022 team took on an Investigation into the state of pointer and mouse events. Incomplete web standards have led to many differences between browsers, operating systems, and devices. The 2022 Investigation project took on a mission to assess what can be done to increase interoperability and chose a set of specific tests to reflect what browsers can improve.

The 2023 Focus Area now includes 16 tests that cover pointer and mouse interaction with pages, including how they behave with hit testing and scrolling areas. Touch and stylus are not included since additional WPT test infrastructure is needed before the appropriate devices can be tested.


The Scrolling Focus Area is a carryover from Interop 2022. There’s more work to do to increase interoperability, so everyone agreed to include it again. The effort includes Scroll Snap, scroll-behavior, and overscroll-behavior.

Scroll Snap provides the tools for designers and developers to control how interfaces scroll and how content appears. The scroll-behavior property in CSS sets the behavior for a scrolling box when scrolling is triggered by the navigation or CSSOM scrolling APIs. The overscroll-behavior CSS property determines what a browser does when reaching the boundary of a scrolling area.


Subgrid is another Focus Area from Interop 2022 which the team agreed to continue to include. Getting an interoperable implementation of Subgrid across all browsers will take layout on the web to the next level, fully realizing the vision of what CSS Grid can do.

a screenshot of the Grid Inspector in Web Inspector showing the subgrid

Subgrid provides an easy way to put grandchildren of a grid container on that grid. It makes it possible to line up items across complex layouts, without any regard for the DOM structure.


a 3D cylinder of numbered squares

CSS Transforms is a Focus Area being carried over from Interop 2021. Often used in animations, CSS Transforms provide a mechanism for transforming boxes in two- or three-dimensional space. Historically, 3D transforms have been tied to how the rendering engine handles layers. Over the last two years, engineers at Firefox, Chrome and Safari have been closely collaborating to especially improve the interoperability of 3D. By continuing to keep attention on this area, Interop 2023 aims to raise the number of tests that pass in all three browser engines up from its current 92.8%.


URLs are a fundamental part of the web. Without them, the web would not exist. But like many things invented very early in the history of the web, they are something that haven’t been fully interoperable. To improve this, the WHATWG wrote a specification full of details on precisely how URLs should work. To further promote interoperability, URL is now a Focus Area for Interop 2023.

WebCodecs (video)

The WebCodecs API gives web developers complete control over how media is processed by providing low-level access to the individual frames of a video stream and chunks of audio. This is especially useful for applications that do video or audio editing, video conferencing, or other real-time processing of video or audio. For Interop 2023, this Focus Area includes only video processing, and not audio.

Web Compat 2023

Similar to Interop 2022, this year’s project includes a Focus Area named Web Compat. It’s a grab bag of various bugs known to cause website compatibility issues, and features that, if missing, are most likely to create compat issues.

Last year’s effort was incredibly successful. The 2022 tests now have 96.9% interoperability across all three browser engines, with a score of 100% in two of the three browsers. Because of that success, the tests from Web Compat 2022 are now retired as a “Previous Focus Area”.

For 2023, a whole new set of tests have been selected. They include tests for Regex Lookbehind, inline editing, event dispatching on disabled controls, CSS image-set, white-space, and text-emphasis.

Web Components

Web Components is a suite of technologies for creating reusable custom elements, with encapsulated functionality. This Interop 2023 Focus Area includes Constructable stylesheets, adoptedStyleSheets, ElementInternals, Form-associated Custom Elements, and the basic behavior of Shadow DOM & Custom Elements.

2023 Investigation Projects

There are two Investigation efforts planned for 2023. Both are projects to improve the testing infrastructure of WPT, so that Interop 2024 can potentially include more types of technology.

One effort will take a look at how to test the interoperability of browser engines on mobile operating systems. The other will take a look at how to test the interoperability of accessibility-specific web technology.

Our Ongoing Commitment to Interoperability

We continue to believe that interoperability is one of the fundamental pillars that makes the web a uniquely successful platform. Our efforts in Interop 2022 demonstrate how deeply we care about the web. We’re excited to work with our colleagues on the opportunities Interop 2023 brings to help websites and web apps work better for everyone.

February 01, 2023 05:00 PM

January 31, 2023

Allowing Web Share on Third-Party Sites

Surfin’ Safari

As of Safari Technology Preview 160, it is no longer possible to use the W3C’s Web Share API with third-party sites within an iframe without including an allow attribute. All browser vendors agreed to this change as part of the W3C’s standardization process, and it is being rolled out in all major browser engines (including Chrome, Edge, Firefox, on mobile and desktop browsers).

The Web Share API allows web developers to enable the native sharing functionality of a device, such as sharing a link via email or social media. Prior to this change, the API could be used on any website within an iframe without restriction. However, due to concerns about privacy and security, browser vendors at the W3C have decided to limit the use of the API to only those sites that have explicitly been given permission to use it.

Web developers must now include an allow attribute in the iframe HTML element to use the Web Share API within an iframe on a third-party site. The attribute accepts a value of web-share and optionally the origin of the site that is allowed to use the API.

<iframe allow="web-share" src="https://example.com">


<iframe allow="web-share https://example.com" src="https://example.com">

Without the allow attribute, the API will throw an exception and will not function within the iframe. The syntax of the allow attribute is defined by the W3C’s Permissions Policy specification. You can learn more about the syntax on MDN.

This change is a necessary step in protecting user privacy and security. It helps ensure that the Web Share API is only used by sites that the developer signals is trustworthy. However, that means web developers will need to make some code changes to continue using the API within third-party iframes.

January 31, 2023 05:27 PM

January 25, 2023

Release Notes for Safari Technology Preview 162

Surfin’ Safari

Safari Technology Preview Release 162 is now available for download for macOS Monterey 12.3 or later and macOS Ventura. If you already have Safari Technology Preview installed, you can update in the Software Update pane of System Preferences on macOS Monterey, or System Settings under General → Software Update on macOS Ventura.

This release includes WebKit changes between: 258383@main…258608@main

Note: Enabled Shared Tab Groups and syncing for Tab Groups, Website Settings, and Web Extensions in this release. These features require Safari Technology Preview 162 or later running on macOS Ventura 13.2 or later, or macOS Monterey with Safari 16.2.

Web Inspector

  • Added editing capabilities for font variation axes in Fonts sidebar panel (258503@main)
  • Added showing parent style rules for nested style rules in Styles sidebar (258555@main)



  • Fixed page up and page down scrolling feeling slow (258598@main)

Gamepad API


  • Limited DOMAudioSession to third-party iframes that have microphone access (258423@main)


  • Enabled declarative Shadow DOM by default (258566@main, 258568@main)
  • Enabled form-associated custom elements with ElementInternals by default (258574@main, 258561@main)
  • Implemented non-autofill credential type for the autocomplete attribute (258582@main)
  • Changed <button> and <select> elements with a readonly attribute to not be barred from constraint validation (258485@main)
  • Fixed painting an in-process VideoFrame in a remotely-backed canvas does not work (258479@main)
  • Lowered per-process WebSocket connection limits (258488@main)
  • Made all FileSystemSyncAccessHandle methods sync (258473@main)
  • Moved oncopy, oncut, and onpaste to GlobalEventHandlers (258390@main)
  • Removed HTMLFrameElement.width and HTMLFrameElement.height (258573@main)
  • Removed HTMLHeadElement.profile (258397@main)
  • Removed HTMLPreElement.wrap IDL attribute (258445@main)


  • Enabled default ARIA for custom elements (258743@main)
  • Fixed aria-activedescendant to work with a standard “listbox” pattern (258478@main)
  • Fixed nested role="presentation" elements break role="tree" behavior (258435@main)

Browser Changes

  • Improved Safari’s form heuristics support for elements in the shadow DOM

January 25, 2023 09:31 PM

January 23, 2023

WebKit Features in Safari 16.3

Surfin’ Safari

Today we are pleased to announce Safari 16.3, our first release of many coming this year. With it, WebKit provides multiple bug fixes and feature polish.


  • Fixed MediaQueryList.matches to update the parent document layout for viewport-dependent media queries.
  • Fixed transfers of min and max sizes for CSS aspect-ratio to be constrained by defined sizes.
  • Fixed gap to be accounted for by using the unclamped subgrid track sizes to compute track positions.
  • Fixed calculating block size to use the correct box-sizing.
  • Fixed the transferred min and max sizes to be constrained by defined sizes.
  • Fixed: Use intrinsic ratio of replaced elements when computing flex sizes.
  • Fixed negative content sizes when using box-sizing: border-box with border and padding.
  • Fixed setting scrollTop on a fixed element with overflow breaking scrolling on a page with overscroll-behavior: none.


  • Fixed replaced elements with aspect ratio and size in one dimension to respect the min and max constraints in the opposite dimension.


  • Fixed decompressing content downloaded via fetch() with Content-Encoding: gzip set.
  • Fixed downloads served from a service worker that uses preload.
  • Fixed: Added an error event when link preload fails synchronously.
  • Fixed Cross-Origin-Embedder-Policy incorrectly blocking scripts.
  • Fixed Authorization header used for subsequent 301 redirects when the request header changes.
  • Fixed showing a dialog element when the target is a shadow host with a focus delegates.

Content Security Policy

  • Added support for the prefetch-src directive.
  • Fixed: Check for strict-dynamic in script-src and default-src directives.
  • Fixed: Added an error event when Content Security Policy blocks inline stylesheets.


  • Fixed web audio becoming garbled with switching from speakers to headphones.
  • Fixed video track’s size settings in the second MediaStream created when the aspectRatio constraint is applied.
  • Fixed showing Media Session API artwork.
  • Fixed “A MediaStreamTrack ended due to a capture failure” error when selecting bluetooth headphones as an audio input device.
  • Fixed WebVTT styles to apply with in-band tracks.
  • Fixed alternate VPx codec names to support vp8.0 and vp9.0.


  • Fixed MouseClick offsetX and offsetY on a foreign object in an SVG to be relative to the element rather than relative to the SVG container.


We love hearing from you. Send a tweet to @webkit to share your thoughts on Safari 16.3. Find us on Mastodon at @jensimmons@front-end.social and @jondavis@mastodon.social. If you run into any issues, we welcome your feedback on Safari UI, or your WebKit bug report about web technology or Web Inspector. Filing issues really does make a difference.

Download the latest Safari Technology Preview to stay at the forefront of the web platform and to use the latest Web Inspector features. You can also read the Safari 16.3 release notes.

Updating to Safari 16.3

Safari 16.3 is available for macOS Ventura, macOS Big Sur, macOS Catalina, iPadOS 16, and iOS 16. You can update to Safari 16.3 on macOS Monterey or macOS Big Sur by going to System Preferences → Software Update → More info, and choosing to update Safari. To update macOS Ventura, iOS or iPadOS, go to Settings → General → Software Update.

January 23, 2023 06:45 PM

January 19, 2023

WPE WebKit Blog: Status of the new SVG engine in WebKit

Igalia WebKit

figure { margin: 0; } figure > figure { border: 1px #cccccc solid; padding: 4px; } figcaption { background-color: #cccccc; color: black; padding: 1px; text-align: center; margin-bottom: 4px; }

In the previous posts of this series, various aspects of the WPE port architecture were covered. Besides maintaining and advancing the WPE port according to our customers’ needs, Igalia also participates in the development of the WebCore engine itself, which is shared by all WebKit ports. WebCore is the part of the browser engine that does the heavy lifting: it contains all functionality necessary to load, parse, lay out, and paint Web content.

Since late 2019, Igalia has been working on a new SVG engine, dubbed Layer-Based SVG Engine (LBSE), that will unify the HTML/SVG rendering pipelines in WebCore. This will resolve long-standing design issues of the “legacy” SVG engine and unlock a bunch of new exciting possibilities for Web developers to get creative with SVG. Hardware-accelerated compositing, driven by CSS transform animations, 3D perspective transformations for arbitrary SVG elements, CSS z-index support for all SVG graphics elements, and proper coverage rectangle computations and repaints are just a few highlights of the capabilities the future SVG engine will offer.

In this article, an overview is given about the problems that LBSE aims to solve, and the importance of a performant, well-integrated SVG engine especially for the embedded market. Finally, the current upstreaming status is summarized including an outlook for the year 2023.

LBSE in a nutshell

Before diving into the technical topics, let’s take a few minutes to recap the motivations behind the LBSE work, and explain the importance of a well-integrated, performant SVG engine in WebKit, especially for the embedded market.


Many of our customers build products that utilize a Linux-powered embedded device, typically using non-x86 CPUs, custom displays with built-in input capabilities (e.g., capacitive touchscreens) often without large amounts of memory or even permanent storage. The software stack for these devices usually consists of a device-specific Linux distribution, containing the proprietary network, GPU, and drivers for the embedded device - the vendor-approved “reference distribution”.

No matter what type of product is built nowadays, many of them need an active Internet connection, to e.g. update their software stack and access additional information. Besides the UI needed to control the product, a lot of additional dialogs, wizards and menus have to be provided to be able to alter the devices’ “system settings”, such as date/time information, time zones, display brightness, WiFi credentials, Bluetooth settings, and so on.

A variety of toolkits exist that assist in writing GUI applications for embedded devices, with a few open-source projects on the market, as well as commercial products providing closed-source, proprietary solutions, that specifically target the embedded market and are often optimized for specific target device families, e.g. certain ARM processors / certain GPUs.

If the need arises, not only to communicate with the Internet but also to display arbitrary Web content, WPE comes into play. As presented in the first post in this series, the flexible and modular WPE architecture makes it an ideal choice for any product in the embedded market that needs Web browsing abilities. The GLib/C-based WPE public APIs allow for customization of the browsing engine and its settings (react on page load/input events, inject custom JS objects, modify style sheets, etc.) and allow the embedder to control/monitor all relevant Web browsing-related activities.

With a full-fledged Web engine at hand, one might ponder if it is feasible to replace the whole native GUI stack with a set of Web pages/applications, and only use WPE to paint the UI in full-screen mode, thus migrating away from native GUI applications — following the trend in the desktop market. The number of organizations migrating native GUI applications into Web applications is rapidly increasing, since there are compelling reasons for Web apps: “write once, use everywhere”, avoiding vendor lock-in, easy/reliable deployment and update mechanisms, and efficient test/development cycles (local in-browser testing!).

Due to the sheer capabilities of the Web platform, it has grown to an environment in which any kind of application can be developed – ranging from video editing applications, big data processing pipelines to 3D games, all using JS/WebAssembly in a browser, presented using HTML5/CSS. And as an important bonus: in 2023, it’s much easier to find and attract talented Web developers and designers that are fluent in HTML/CSS/JS, than those that are comfortable designing UI applications in proprietary, closed-source C/C++ frameworks.

A long-term customer, successfully using WPE in their products, had very similar thoughts and carried out a study, contracting external Web designers to build a complete UI prototype using Web technology. The mock-up made extensive use of SVG2, embedded inline into HTML5 documents or via other mechanisms (CSS background-image, etc.). The UI fulfilled all expectations and worked great in Blink and WebKit-based browsers, delivering smooth animations. On the target device, however, the performance was too slow, far away from usable. A thorough analysis revealed that large parts of the Web page were constantly repainted, and layout operations were repeated for every frame when animations were active. The accumulated time to display a new frame during animations was in the order of a few milliseconds on desktop machines, but took 20-25 milliseconds on the target device, making smooth 60 FPS animations impossible.

The poor performance is not the result of shortcomings in the WPE port of WebKit: when replacing the aforementioned animated SVG document fragments with HTML/CSS “equivalents” (e.g. simulating SVG circles with CSS border-radius tricks) the performance issue vanisheed. Why? SVG lacks support for a key feature called accelerated compositing, which has been available for HTML/CSS since its introduction more than a decade ago. This compositing heavily relies on the Layer Tree, which is unaware of SVG. Extending the Layer Tree implementation to account for SVG is the main motivation for LBSE.

If you are unfamiliar with the concepts of Render Tree and Layer Tree, you might want to read the “Key concepts” section of an earlier LBSE design document, which provides an overview of the topic.


The LBSE effort began in October 2019 as a research project, to find out an ideal design for the SVG Render Tree, that allows SVG to re-use the existing Layer Tree implementation with minimal changes. The aim for LBSE is to share as much code as possible with the HTML/CSS implementation, removing the need for things like SVG specific clipping/masking/filter code and disjoint HTML counterparts for the same operations.

After an extensive phase of experimentation, two abandoned approaches, and a long time spent on regression fixing, the LBSE prototype was finally finished after almost two years of work. It passed all 60k+ WebKit layout tests and offered initial support for compositing, 3D transformations, z-index, and more. The intent was to prove that we can reach feature parity with the legacy SVG engine and retrieve the very same visual results, pixel-by-pixel (except for progressions of LBSE). Shortly after the finalization, the prototype was presented during the WebKit contributors meeting in 2021.

As the name “prototype” indicates, LBSE was not ready for integration into WebKit at this point. It replaced the old SVG engine with a new one, resulting in a monolithic patch exceeding 650 kb of code changes. WebKit demands small patches, with ChangeLogs, tests, etc. – no WebKit reviewer would sign off a patch replacing a core component of WebCore in one shot. Splitting up into small pieces is also not going to work, since SVG needs to be kept intact upstream all the time. Duplicating the whole SVG engine? Not practicable either. With that problem in mind, a fruitful discussion took place with Apple during and after the WebKit contributors meeting: a realistic upstreaming strategy was defined - thanks Simon Fraser for suggesting a pragmatic approach!

The idea is simple: bootstrap LBSE in parallel to the legacy SVG engine. Upstream LBSE behind a compile-time flag and additionally a runtime setting. This way the LBSE code is compiled by the EWS bots during upstreaming (rules out bit-rot) and we gain the ability to turn LBSE on, selectively, from our layout tests – very useful during early bootstrapping. For WebKit, that strategy is the best – for LBSE another major effort is necessary: moving from a drop-in replacement approach to a dual-stack SVG engine: LBSE + legacy built into the same WebKit binaries. At least the timing was good since a split-up into small pieces was needed anyhow for upstreaming. Time to dissect the huge branch into logical, atomic pieces with proper change logs.

Before we jump to the upstreaming status, one question should be answered, that came up during the WebKit contributors meeting and also during various discussions: why don’t you just fix the existing SVG engine and instead propose a new one - isn’t that too risky for Web compatibility?

Why don’t you fix the existing SVG engine?

LBSE logo

There was no initial intention to come up with a new SVG engine. During LBSE development it became apparent how much SVG-specific code can be erased when unifying certain aspects with HTML/CSS. After carrying out the integration work, layout/painting and hit-testing work fundamentally different than before. Since that time, LBSE is labeled as a “new SVG engine”, even though the SVG DOM tree part remained almost identical. Web compatibility will improve with LBSE: a few long-standing, critical interop issues with other browser vendors are solved in LBSE. Therefore, there are no concerns regarding Web compatibility risks from our side.

To answer the initial question, whether it is possible to fix the existing SVG engine to add layer support without adding a “new” SVG engine in parallel? Short answer: no.

In the following section, it is shown that adding support for layers implies changing the class hierarchy of the SVG render tree. All SVG renderers need to inherit from RenderLayerModelObject – a change like this cannot be split up easily into small, atomic pieces. Improving the design is difficult if there’s a requirement to keep the SVG engine working all the time upstream: all patches in that direction end up being large as many renderers have to be changed at the same time. Having distinct, LBSE-only implementations of SVG renderers, independent of the legacy engine, leaves a lot of freedom to strive for an optimal design, free of legacy constraints, and avoids huge patches that are impossible to review.

Let’s close the introduction and review the upstreaming status, and discuss where we stand today.

Upstreaming progress


To unify the HTML/CSS and SVG rendering pipelines there are two possible paths to choose from: teach the Layer Tree about the SVG Render Tree and its rendering model, or vice-versa. For the latter path, the HTML/CSS-specific RenderLayer needs to split into HTML/SVG subclasses and a base class, that is constructible from non-RenderLayerModelObject-derived renderers. The layer management code currently in RenderLayerModelObject would need to move into another place, and so forth. This invasive approach can potentially break lots of things. Besides that danger, many places in the layer/compositing system would need subtle changes to account for the specific needs of SVG (e.g. different coordinate system origin/convention).

Therefore the former route was chosen, which requires transforming the SVG render tree class hierarchy, such that all renderers that need to manage layers derive from RenderLayerModelObject. Using this approach support, for SVG can be added to the layer/compositing system in a non-invasive manner, with only a minimum of SVG-specific changes. The following class hierarchy diagrams illustrate the planned changes.

Legacy design (click to enlarge) Visualization of the legacy SVG render tree class hierarchy in WebCore LBSE design (click to enlarge) Visualization of the LBSE SVG render tree class hierarchy in WebCore

The first graph shows the class hierarchy of the render tree in the legacy SVG engine: RenderObject is the base class for all nodes in the render tree. RenderBoxModelObject is the common base class for all HTML/CSS renderers. It inherits from RenderLayerModelObject, potentially allowing HTML renderers to create layers. For the SVG part of the render tree, there is no common base class shared by all the SVG renderers, for historical reasons.

The second graph shows only the SVG renderers of the LBSE class hierarchy. In that design, all relevant SVG renderers may create/destroy/manage layers, via RenderLayerModelObject. More information regarding the challenges can be found in the earlier LBSE design document.


The upstreaming work started in December 2021, with the introduction of a new layer-aware root renderer for the SVG render subtree: RenderSVGRoot. The existing RenderSVGRoot class was renamed to LegacyRenderSVGRoot (as well as any files, comments, etc.) and all call sites and build systems were adapted. Afterward, a stub implementation of a layer-aware RenderSVGRoot class was added and assured that the new renderer is created for the corresponding SVG DOM element if LBSE is activated.

That process needs to be repeated for all SVG renderers that have substantially changed in LBSE and thus deserve an LBSE-specific upstream implementation. For all other cases, in-file #if ENABLE(LAYER_BASED_SVG_ENGINE) ... #endif blocks will be used to encapsulate LBSE-specific behavior. For example, RenderSVGText / RenderSVGInlineText are almost identical in LBSE downstream, compared to their legacy variants; thus, they are going to share the renderer implementation between the legacy SVG engine and LBSE.

The multi-step procedure was repeated for RenderSVGModelObject (the base class for SVG graphics primitives), RenderSVGShape, RenderSVGRect, and RenderSVGContainer. Core functionality such as laying out children of a container, previously hidden in SVGRenderSupport::layoutChildren() in the legacy SVG engine, now lives in a dedicated class: SVGContainerLayout. Computing the various SVG bounding boxes - object/stroke/decorated bounding box - is precisely specified in SVG2 and got a dedicated implementation as the SVGBoundingBoxComputation class, instead of fragmenting the algorithms all over the SVG render tree as in the legacy SVG engine.

By February 2022, enough functionality was in place to construct the LBSE render tree for basic SVG documents, utilizing nested containers and rectangles as leaves. While this doesn’t sound exciting at all, it provided an ideal environment to implement support for SVG in the RenderLayer-related code - before converting all SVG renderers to LBSE, and before implementing painting in the SVG renderers.

Both RenderLayer and RenderLayerBacking query CSS geometry information such as border box, padding box, or content box from their associated renderer, which is expected to be a RenderBox in many places. This is incorrect for SVG: RenderSVGModelObject inherits from RenderLayerModelObject, but not from RenderBox since it doesn’t adhere to the CSS box model. Various call sites cast the associated renderer to RenderBox to call e.g. borderBoxRect() to retrieve the border box rectangle. There are similar accessors in SVG to query the geometry, but there is no equivalent of a border box or other CSS concetps in SVG. Therefore, we extended RenderSVGModelObject to provide a CSS box model view of an SVG renderer, by offering methods such as borderBoxRectEquivalent() or visualOverflowRectEquivalent() that return geometry information in the same coordinate system using the same conventions as their HTML/CSS counterparts.

We also refactored RenderLayer to use a proxy method - rendererBorderBoxRect() - that provides access to the borderBoxRect() for HTML and the borderBoxRectEquivalent() for SVG renderers, and the same fix to RenderLayerBacking. With these fixes in place, support to position and size SVG layers and to compute overflow information could be added – both pre-conditions to enable painting.

By March 2022, LBSE was able to paint basic SVG documents - a major milestone for the bootstrapping process, demonstrating that the layer painting code was functional for SVG. It was time to move on to transformations: implementing RenderSVGTransformableContainer (e.g. <g> elements with a non-identity transform attribute or CSS transform property) and CSS/SVG transform support for all other graphics primitives, utilizing the RenderLayer-based CSS Transform implementation. As preparation, the existing code was reviewed and cleaned up: transform-origin computation was decoupled from CTM computation (CTM = current transformation matrix, see CSS Transforms Module Level 1) and transform-box computations were unified in a single place.

In April 2022, 2D transforms were enabled and became fully functional a few weeks later. Besides missing compositing support upstream, downstream work showed that enabling 3D transforms for SVG required fixing a decade-old bug that made the computed perspective transformation dependent on the choice of transform-origin. That became apparent when testing the layer code with SVG, which uses different default values for certain transform-related CSS properties than HTML does: transform-box: view-box and transform-origin: 0 0 are the relevant defaults for SVG, referring to the top-left corner of nearest SVG viewport vs. the center of the element in HTML.

By May 2022, the legacy SVG text rendering code was altered to be usable for LBSE as well. At this point, it made sense to run layout tests using LBSE. Previously most tests were expected to fail, as most either utilize text, paths, or shapes, and sometimes all three together. LBSE render tree text dumps (dumping the parsed render tree structure in a text file) were added for all tests in the LayoutTests/svg subdirectory, as well as a new pixel test baseline (screenshots of the rendering as PNGs), generated using the legacy SVG engine, to verify that LBSE produces pixel-accurate results. All upcoming LBSE patches are expected to change the expected layout test result baseline, and/or the TestExpectations file, depending on the type of patch. This will ease the reviewing process a lot for future patches.

To further proceed, a test-driven approach was used to prioritize the implementation of the missing functionality. At that time, missing viewBox support for outer <svg> elements was causing many broken tests. The effect of the transformation induced by the viewBox attribute, specified on outer <svg> elements, cannot be implemented as an additional CSS transformation applied to the outermost <svg> element, as that would affect the painted dimensions of the SVG document, which are subject to the CSS width/height properties and the size negotiation logic only. The viewBox attribute is supposed to only affect the visual appearance of the descendants, by establishing a new local coordinate system for them. The legacy SVG engine manually handled the viewBox-induced transformation in various places throughout LegacyRenderSVGRoot, to only affect the painting of the descendants and not e.g. the position/dimension of the border surrounding the <svg>, if the CSS border property is specified. In LBSE, transformations are handled on RenderLayer-level and not in the renderers anymore.

By July 2022, after testing different approaches, a proper solution to add viewBox support was upstreamed. The chosen solution makes use of another CSS concept that arises in the context of generated content: “anonymous boxes”. The idea is to wrap the direct descendants of RenderSVGRoot in an anonymous RenderSVGViewportContainer (“anonymous” = no associated DOM element) and apply the viewBox transformation as a regular CSS transformation on the anonymous renderer. With that approach, LBSE is left with just a single, unified viewBox implementation, without error-prone special cases in RenderSVGRoot, unlike the legacy SVG engine which has two disjoint implementations in LegacyRenderSVGViewportContainer and LegacyRenderSVGRoot.

After the summer holidays, in August 2022, the next major milestone was reached: enabling compositing support for arbitrary SVG elements, bringing z-index support, hardware-accelerated compositing and 3D transforms to SVG. This time all lessons learned from the previous LBSE prototypes were taken into account, resulting in a complete compositing implementation, that works in various scenarios: different transform-box / transform-origin combinations, inline SVG enclosed by absolute/relative positioned CSS boxes and many more, all way more polished than in the “final” LBSE prototype.

The aforementioned patch contained a fix for a long-standing bug (“Composited elements appear pixelated when scaled up using transform”), that made composited elements look blurry when scaling up with a CSS transform animation. The so-called “backing scale factor” of the associated GraphicLayers (see here for details about the role of GraphicLayer in the compositing system) never changes during the animation. Therefore, the rendered image was scaled up instead of re-rendering the content at the right scale. LBSE now enforces updates of that scale factor, to avoid blurry SVGs. The fix is not activated yet for HTML as that requires more thought - see the previously-linked bug report for details.

With all the new features in place and covered by tests, it was time to finish the remaining SVG renderers: RenderSVGEllipse, RenderSVGPath and RenderSVGViewportContainer (for inner <svg> elements), RenderSVGHiddenContainer, RenderSVGImage, and RenderSVGForeignObject. A proper <foreignObject> implementation was lacking in WebKit for 15+ years, due to the fundamental problem that the layer tree was not aware of the SVG subtree. The LBSE variant of RenderSVGForeignObject looks trivial, yet offers a fully compatible <foreignObject> implementation - for the first time without issues with non-static positioned content as a direct child of <foreignObject>, at least a few weeks later after it landed.

Returning to the test-driven approach, the next best target to fix was text rendering, which was working but not pixel-perfect. The legacy SVG engine takes into account the transformation from the text element up to the topmost renderer when computing the effective “on-screen” font size used to select a font for drawing/measuring, during layout time. LBSE needed a way to calculate the CTM for a given SVG renderer, up to a given ancestor renderer (or root), taking into account all possible transformation scenarios, including CSS transform, translate, rotate, SVG transform attribute, shifts due to transform-origin, perspective transformations, and much more. The same functionality is required to implement getCTM() / getScreenCTM().

By the end of August 2022, SVGLayerTransformComputation was added that re-used the existing mapLocalToContainer() / TranformState API to obtain the CTM. The CTM construction and ancestor chain walk - to accumulate the final transformation matrix - is performed by mapLocalToContainer() and no longer needs a special, incomplete SVG approach: the existing general approach now works for SVG too.

September 2022 was mostly devoted to bug fixes related to pixel-snapping. Outermost <svg> elements were not always enforcing stacking contexts and failed to align to device pixels. All other elements behaved fine with respect to pixel snapping (not applied for SVG elements) unless compositing layers were active. In that case, a RenderLayerBacking code path was used that unconditionally applied pixel-snapping - avoid that for SVG.

By October 2022 LBSE could properly display SVGs embedded into HTML host documents via <object> elements – the size negotiation logic failed to take into account the LBSE-specific renderers before. CSS background-image / list-image / HTML <img> / etc. were fixed as well. Zooming and panning support were implemented and improved compared to the legacy engine. Along the way an important bug was fixed, one that other browsers had already fixed back in 2014. The bug caused percentage-sized documents (e.g. width: 100%; height: 100%) that also specify a viewBox to always keep the document size, regardless of the zoom level. Thus, upon zooming, only the stroke width enlarged, but not the boundaries of the document, and thus scrollbars never appeared.

Over the following weeks, text-related issues had to be fixed, which were responsible for a bunch of the remaining test issues. Transformed text did not render, which turned out to be a simple mistake. More tests were upstreamed, related to compositing and transformations. More test coverage revealed that transform changes were not handled consistently – it took a period of investigation to land a proper fix. SVG transform / SMIL <animateMotion> / SMIL <animateTransform> / CSS transform changes are now handled consistently in LBSE, leading to proper repaints, as expected.

Transformation support can be considered complete and properly handled both during the painting and layout phases. Dynamic changes at runtime are correctly triggering invalidations. However, the Web-exposed SVG DOM API that allows querying the transformation matrices of SVG elements, such as getCTM() and getScreenCTM(), was still missing. By November 2022 a complete implementation was upstreamed, that utilized the new SVGLayerTransformComputation class to construct the desired transformation matrices. This way the same internal API is used for painting/layout/hit-testing and implementing the SVG DOM accessors.

By December 2022 LBSE was in a good shape: most important architectural changes were upstreamed and the most basic features were implemented. The year closed with a proposed patch that will avoid re-layout when an element’s transform changes. The legacy SVG engine always needs a re-layout if transform changes, as the size of each ancestor can depend on the presence of transformations on the child elements – a bad design decision two decades ago that LBSE will resolve. Only repainting should happen, but no layouts, in LBSE.

Let’s move on to 2023, and recap what’s still missing in LBSE.

Next steps

Besides fixing all remaining test regressions (see LayoutTests/platform/mac-ventura-wk2-lbse-text/TestExpectations) “SVG resources” are missing in LBSE. That includes all “paint servers” and advanced painting operations: there is no support for linear/radial gradients, no support for patterns, and no support for clipping/masking and filters.

From the painting capabilities, LBSE is still in a basic shape. However, this was intentional, since a lot of the existing code for SVG resource handling is no longer needed in LBSE. Clipping/masking and filters will be handled via RenderLayer, reusing the existing HTML/CSS implementations. Temporary ImageBuffers are no longer needed for clipping, and thus there is no need to cache the “per client” state in the resource system (e.g. re-using the cached clipping mask for repainting). This will simplify the implementation of the “SVG resources” a lot.

Therefore the first task in 2023 is to implement clipping, then masking, gradients, patterns, and as the last item, filters, since they require a substantial amount of refactoring in RenderLayerFilters. Note that these implementations are already complete in LBSE downstream and do not need to be invented from scratch. The first patches in that direction should be up for review by February 2023.

After all “SVG resources” are implemented in LBSE, feature parity is almost there and performance work will follow afterward. WebKit has a golden rule to never ship a performance regression; therefore, LBSE needs to be at least as fast in the standard performance tests, such as MotionMark, before it can replace the legacy engine. Currently, LBSE is slower than the legacy engine with respect to static rendering performance. Quoting numbers does not help at present, since the problem is well understood and will be resolved in the following months.

LBSE currently creates more RenderLayer objects than necessary: for each renderer, unconditionally. This is a great stress test of the layer system, and helpful for bootstrapping, but the associated overhead and complexity are simply not necessary for many cases, and actively hurt performance. LBSE already outperforms the legacy SVG engine whenever animated content is viewed, if it benefits from the hardware acceleration in LBSE.

2023 will be an exciting year, and hopefully brings LBSE to the masses, stay tuned!


“A picture is worth a thousand words”, so we’d like to share with you the videos shown during the WebKit contributors meeting in 2022 that demo the LBSE capabilities. Be sure to check them out so you can get a good picture of the state of the work. Enjoy!

  1. Accelerated 2D transforms (Tiger)

  2. Accelerated 3D transform (Tiger)

  3. Transition storm (Tiger)

  4. Vibrant example

Final thoughts

We at Igalia are doing our best to fulfill the mission and complete the LBSE upstreaming as fast as possible. In the meanwhile, let us know about your thoughts:

  • What would you do with a performant, next-level SVG engine?
  • Any particular desktop / embedded project that would benefit from it?
  • Anything in reach now, that seemed impossible before with the given constraints in WebKit?

Thanks for your attention! Be sure to keep an eye on our “Upstreaming status” page at GitHub to follow LBSE development.

January 19, 2023 12:00 AM

January 17, 2023

Manuel Rego: 10 years ago

Igalia WebKit

Once upon a time…

10 years ago I landed my first WebKit patch 🎂:

Bug 107275 - [GTK] Implement LayoutTestController::addUserScript

That was my first patch to a web engine related project, and also my first professional C++ patch. My previous work at Igalia was around web applications development with PHP and Java. At that time, 2013, Igalia had been already involved on web rendering engines for several years, and the work around web applications was fading out inside the company, so moving to the other side of the platform looked like a good idea. 10 years have passed and lots of great things have happened.

Since that first patch many more have come mostly in Chromium/Blink and WebKit; but also in WPT, CSS, HTML and other specs; and just a few, sadly, in Gecko (I’d love to find the opportunity to contribute there more at some point). I’ve became committer and reviewer in both Chromium and WebKit projects. I’m also member of the CSS Working Group (though not very active lately) and Blink API owner.

During these years I have had the chance to attend several events, spoke at a few conferences, got some interviews. I’ve been also helping to organize the Web Engines Hackfest since 2014 and a CSSWG face-to-face meeting at Igalia headquarters in A Coruña in January 2020 (I have so great memories of the last dinner).

These years have allowed me to meet lots of wonderful people from which I’ve learnt, and still learn every day, many things. I have the pleasure to work with amazing folks on a daily basis in the open. Every new feature or project in which I have to work, it’s again a new learning experience, and that’s something I really like about this kind of work.

In this period I’ve seen Igalia grow a lot in the web platform community, to the point that these days we’re the top world consultancy on the web platform, with an important position in several projects and standards bodies. We’re getting fairly well know in this ecosystem, and we’re very proud about having achieved that.

Looking back, I’m so grateful for the opportunity given by Igalia. Thanks to the amazing colleagues and the community and how they have helped me to contribute work on the different projects. Also thanks to the different customers that have allowed me to work upstream and develop my career around web browsers. 🙏 These days the source code I write (together with many others) is being used daily by millions of people, that’s totally unbelievable if you stop for a minute to think about it.

Looking forward to the next decade of involvement in the web platform. See you all on the web! 🚀

January 17, 2023 11:00 PM

Amanda Falke: Tutorial: Building WPE WebKit for Raspberry Pi 3

Igalia WebKit

A lightning guide for building WPE WebKit with buildroot

This tutorial will be for getting “up and running” with WPE WebKit using a Raspberry Pi 3 using a laptop/desktop with Linux Fedora installed. WPE WebKit has many benefits; you may read here about why WPE WebKit is a great choice for embedded devices. WPE WebKit has minimal dependencies and it displays high-quality animations, WebGL and videos on embedded devices.

WebPlatformForEmbedded is our focus; for this tutorial, we’ll be building WPE WebKit with buildroot to build our image, so, make sure to clone the buildroot repository.

You will need:

Raspberry pi 3 items:

  • A raspberry pi 3.
  • A microSD card for the pi. (I usually choose 32GB microSD cards).
  • An external monitor, extra mouse, and extra keyboard for our rpi3, separately from the laptop.
  • An HDMI cable to connect the rpi3 to its own external monitor.

Laptop items:

  • Linux laptop/desktop.
    • This tutorial will be based on Fedora, but you can use Debian or any distro of your choice.
  • You also need a way to interface the microSD card with your laptop. You can get an SD Adapter for laptops that have an SD Card adapter slot, or you can use an external SD Card adapter interface for your computer.
    • This tutorial will be based on having a laptop with an SD card slot, and hence an SD Card Adapter will work just fine.

Items for laptop to communicate with rpi3:

  • An ethernet cable to connect the rpi3 to your laptop.
  • You need some way to get ethernet into your laptop. This is either in the form of an ethernet port on your laptop (not likely), or an adapter of some sort (likely a USB adapter).

Steps: High level overview

This is a high level overview of the steps we will be taking.

  1. Partition the blank SD card.
  2. In the buildroot repository, make <desired_config>.
  3. Run the buildroot menuconfig with make menuconfig to set up .config file.
  4. Run make to build sdcard.img in buildroot/output dir; change .config settings as needed.
  5. Write sdcard.img file to the SD card.
  6. Connect the rpi3 to its own external monitor, and its own mouse and keyboard.
  7. Connect the rpi3 to the laptop using ethernet cable.
  8. Put the SD card into the rpi3.
  9. Setup a shared ethernet connection between the laptop and rpi to get the IP address of rpi.
  10. ssh into the rpi and start WPE WebKit.

Steps: Detailed overview/sequence

1. Partition the blank SD card using fdisk. Create a boot partition and a root partition.

  • Note: this is only needed in case the output image format is root.tar. If it’s sdcard.img, then that is dumped directly to the sdcard, that image is already partitioned internally.
  • If you’re unfamiliar with fdisk, this is a good tutorial.

2. In the buildroot repository root directory, make the desired config.

  • Make sure to clone the buildroot repository.
  • Since things change a lot over time, it’s important to note the specific buildroot commit this tutorial was built on, and that this tutorial was built on January 12th, 2023. It is recommended to build from that commit for consistency to ensure that the tutorial works for you.
  • We are building the cog 2.28 wpe with buildroot. See the build options from the buildroot repository.
  • Run make list-defconfigs to get a list of configurations.
  • Copy raspberrypi3_wpe_2_28_cog_defconfig and run it: make raspberrypi3_wpe_2_28_cog_defconfig.
  • You will quickly get output which indicates that a .config file has been written in the root directory of the buildroot repository.

3. Run the buildroot menuconfig with make menuconfig to set up .config file.

  • Run make menuconfig. You’ll see options here for configuration. Go slowly and be careful.
  • Change these settings. Help menus are available for menuconfig, you’ll see them displayed on the screen.
Operation in menuconfig Location Value
ENABLE Target packages -> Filesystem and flash utilities dosfstools
ENABLE Target packages -> Filesystem and flash utilities mtools
ENABLE Filesystem images ext2/3/4 root filesystem
SET VALUE Filesystem images -> ext2/3/4 root filesystem -> ext2/3/4 variant ext4
DISABLE Filesystem images initial RAM filesystem linked into linux kernel

4. Run make to build sdcard.img in buildroot/output dir; change .config settings as needed.

  • Run make. Then get a coffee as the build and cross-compilation will take awhile.

  • In reality, you may encounter some errors along the way, as cross-compilation can be an intricate matter. This tutorial will guide you through those potential errors.
  • When you encounter errors, you’ll follow a “loop” of sorts:

    Run make -> encounter errors -> manually edit .config file -> -> remove buildroot/output dir -> run make again until sdcard.img is built successfully.

  • If you encounter CMake errors, such as fatal error: stdlib.h: No such file or directory, compilation terminated, and you have a relatively new version of CMake on your system, the reason for the error may be that buildroot is using your local CMake instead of the one specified in the buildroot configuration.
    • We will fix this error by setting in .config file: BR2_FORCE_HOST_BUILD=y. Then remove buildroot/output dir, and run make again.
  • If you encounter error such as path/to/buildroot/output/host/lib/gcc/arm-buildroot-linux-gnueabihf/9.2.0/plugin/include/builtins.h:23:10: fatal error: mpc.h: No such file or directory:
  • then we can fix this error by changing Makefile in ./output/build/linux-rpi-5.10.y/scripts/gcc-plugins/Makefile, by adding -I path/to/buildroot/output/host/include in plugin_cxxflags stanza. Then, as usual, remove buildroot/output dir, and run make again.

5. Write sdcard.img file to the SD card.

  • At this point after the make process, we should have sdcard.img file in buildroot/output/images directory.
  • Write this file to the SD card.
  • Consider using Etcher to do so.

6. Connect the rpi3 to its own external monitor, and its own mouse and keyboard.

  • We’ll have separate monitor, mouse and keyboard all connected to the raspberry pi so that we can use it independently from the laptop.

7. Connect the rpi3 to the laptop using ethernet cable.

8. Put the SD card into the rpi3.

9. Setup a shared ethernet connection between the laptop and rpi to get the IP address of rpi.

In general, one of the main problems for connecting via ssh to the Raspberry Pi is to know the IP address of the device. This is very simple with Raspbian OS; simply turn on the raspberry pi and edit configurations to enable ssh, often over wifi.

This is where the ethernet capabilities of the raspberry pi come in.

Goal: To find syslog message DHCPACK acknowledgement and assignment of the IP address after setting up shared connection between raspberry pi and the laptop.

Throughout this process, continually look at logs. Eventually we will see a message DHCPACK which will likely be preceded by several DHCP handshake related messages such as DHCP DISCOVER, REQUEST etc. The DHCPACK message will contain the IP address of the ethernet device, and we will then be able to ssh into it.

    1. Tail the syslogs of the laptop. On Debian distributions, this is often /var/log/syslog. Since we are using Fedora, we’ll be using systemd's journald with the journactl command:
      • sudo journalctl -f
      • Keep this open in a terminal window.
      • You can also come up with a better solution like grepping logs, if you like, or piping output of stdout elsewhere.
    1. In a second terminal window, open up the NetworkManager.
      • Become familiar with existing devices prior to powering on the raspberry pi, by running nmcli.
    1. Power on the raspberry pi. Watch your system logs.
      • Syslogs will detail the raspberry pi’s name.
    1. Look for that name in NetworkManager nmcli device.
      • Using NetworkManager nmcli, set up shared connection for the ethernet device.
      • Setting up a shared connection is as simple as nmcli connection add type ethernet ifname $ETHERNET_DEVICE_NAME ipv4.method shared con-name local
      • This is a good tutorial for setting up a shared connection with NetworkManager.
    1. Once the connection is shared, syslogs will show a DHCPACK message acknowledging the ethernet device and its IP address. (You may need to power cycle the rpi to see this message, but it will happen).

10. ssh into the rpi and start WPE WebKit.

  • Now that we have the IP address of the raspberry pi, we can ssh into it from the laptop: ssh root@<RPI3_IP_ADDRESS>. (The default password is ‘root’. You can also add your user public key to /root/.ssh/authorized_keys on the pi. You can simplify this process by creating an overlay/root/.ssh/authorized_keys on your computer and by specifying the path to the overlay directory in the BR2_ROOTFS_OVERLAY config variable. That will copy everything in the overlay dir to the image.)
  • After that, export these env variables WPE_BCMRPI_TOUCH=1 and WPE_BCMRPI_CURSOR=1 to enable keyboard and mouse control.
    • Why: Recall that generally WPE WebKit is for embedded devices, such as kioks, or set top boxes requiring control with a remote control or similar device or touch interaction. We are exporting these environment variables so that we can “test” WPE WebKit with our separate mouse and keyboard for our raspberry pi without the need for a touch screen or special hardware targets, or a Wayland compositor such as weston. If this piques your curiosity, please see the WPE WebKit FAQ on Wayland.
  • Start WPE WebKit with cog: cog "http://www.igalia.com/"
  • A browser will launch in the external monitor connected to the raspberry pi 3, and we can control the browser with the raspberry pi’s mouse and keyboard!

That’s all for now. Feel free to reach out in the support channels for WPE on Matrix.

WPE’s Frequently Asked Questions

By Amanda Falke at January 17, 2023 08:03 AM

January 12, 2023

Release Notes for Safari Technology Preview 161

Surfin’ Safari

Safari Technology Preview Release 161 is now available for download for macOS Monterey 12.3 or later and macOS Ventura. If you already have Safari Technology Preview installed, you can update in the Software Update pane of System Preferences on macOS Monterey, or System Settings under General → Software Update on macOS Ventura.

This release includes WebKit changes between: 257351@main…258382@main

Note: Shared Tab Groups and syncing for Tab Groups, Website Settings, and Web Extensions are not enabled in this release.

Web Inspector

  • Added emulation toggles for prefers-reduced-motion and prefers-contrast in the Elements tab (257383@main)
  • Changed to show the “Device” menu for all sessions (257426@main)
  • Relocated the toggle for media feature prefers-color-scheme and appearance (257744@main)

CSS Custom Properties

CSS Typed OM

  • Enabled CSS Typed OM (258269@main)
  • Allowed setting custom identifiers via the CSS Typed OM API (257859@main)
  • Made transition-duration property not allow negative values (258295@main)
  • Made sure the z-index property is able to be set to -3.14 (258265@main)
  • Made sure column-count value gets clamped to [1, inf] (258218@main)
  • Made sure orphans and widows value gets clamped to [1, inf] (258243@main)
  • Made StylePropertyMap return CSS values exactly as they were set (257815@main)
  • Made StylePropertyMap.set() wrap a value in a calc() if the value is outside the allowed range (257485@main)
  • Made StylePropertyMap.set() throw when trying to set a number for a property which doesn’t allow it (258242@main)

:has() pseudo-class

  • Added invalidation support for :picture-in-picture pseudo-class (257995@main)
  • Added invalidation support for :playing, :paused, :seeking, :muted and :volume-locked pseudo-classes (257991@main)


  • Added support for :user-invalid and :user-valid pseudo-classes (257997@main)
  • Aligned stroke-dasharray CSS property parsing with the specification (258136@main)
  • Fixed length values in gradients to take effective zoom into account (257659@main)
  • Fixed CSS ::marker to support defining CSS variables (257711@main)
  • Fixed font-variant-alternates: historical-forms to properly reflect via StylePropertyMap (257955@main)
  • Fixed the computed value for stroke-dasharray to be in px (258300@main)
  • Fixed :out-of-range pseudo class matching for empty input[type=number] (258165@main)
  • Fixed computed value for transform property (257964@main)
  • Fixed calc() values for the perspective property aren’t clipped to 0 (257779@main)
  • Made changes to transform-style: preserve-3d and perspective so they only apply to direct DOM children (257509@main, 257432@main)
  • Made sure computed values for baseline-shift CSS property have px unit for lengths (257928@main)
  • Stopped allowing numbers during parsing of baseline-shift CSS property (258025@main)
  • Stopped allowing numbers during parsing of cx, cy, x, and y CSS properties (258029@main)

Web Animations

  • Account for iterationComposite when interpolating custom properties (257925@main)
  • Added basic interpolation support for <length> custom properties (257906@main)
  • Added interpolation support for <transform-function> custom properties (258009@main)
  • Added interpolation support for <transform-list>, + and # custom properties (258039@main)
  • Added tests for <length-percentage> custom property interpolation (257931@main)
  • Made custom properties support interpolation with a single keyframe (257911@main)
  • Supported additivity when interpolating custom properties (257920@main)
  • Supported interpolation of <color> custom properties (257929@main)
  • Supported interpolation of numeric custom properties (257930@main)
  • Fixed composite animations with more than 2 keyframes (257731@main)


  • Added a non-breaking space at the the end of the text when the next text has a leading space (257622@main)
  • Adjusted nested list markers when an intrusive float is present (258372@main)
  • Changed to use the intrinsic ratio of replaced elements when computing flex sizes (257474@main)
  • Made ::backdrop renderers use background layers when possible (257538@main)
  • Fixed button elements clipping overflow by default (257439@main)
  • Fixed rendering lazy loaded images inside an inline element with no height (257565@main)
  • Fixed the logical width computation for box-sizing (258342@main)
  • Fixed lines with 0px constraints to still be considered a non-empty line if it has content (257528@main)
  • Recalculated intrinsic widths in the old containing block chain when going out of flow (257980@main)


  • Added support for RegExp lookbehind assertions (257823@main)
  • Enabled AVX JIT code generation (257884@main)
  • Fixed a race condition in Atomics.wait and Atomics.waitAsync (257423@main)
  • Fixed ResizableArrayBuffer and lastIndexOf (258164@main)
  • Fixed WASM SIMD functions to throw a TypeError when called from JavaScript (257494@main)
  • Made Object.values faster (257382@main)

WebAssembly SIMD

  • Enabled WASM SIMD on ARM (257632@main)
  • Enabled WASM SIMD on x64 (258309@main)
  • Added support for conversions on Intel (257592@main)
  • Added support for extended integer arithmetic on Intel, and also fix a bitmask operation (257657@main)
  • Added support for floating-point absolute value, negate, min, max, and square-root on Intel (257880@main)
  • Added Intel support for load and store operations and fix operation shuffle (257818@main)
  • Added support for saturating integer arithmetic operations on Intel (257468@main)
  • Added support for swizzle and shuffle on Intel and fixed extract_lane and replace_lane (257400@main)
  • Added support for bitwise operations on Intel (257640@main)
  • Added support for integer and floating-point arithmetic on Intel (257511@main)
  • Added support for vector comparisons on Intel (257532@main)
  • Added Intel support for the remaining conversion opcodes (257965@main)
  • Made SIMD functions support Linear Scan and Graph Coloring register allocators (257519@main)
  • Emulated 8-bit shift instructions and i8x16.popcnt on Intel (258089@main)
  • Emulated vector floating-point absolute value on Intel (257806@main)
  • Fixed min, max, and CompareIntegerVector operations (257935@main)



  • Changed to use the dav1d decoder instead of libaom decoder (257357@main)
  • Fixed the progress bar continuing to move when playback is stopped (257403@main)

Fullscreen API

  • Enabled the unprefixed version of the Fullscreen API (257658@main)
  • Added support for the ::backdrop pseudo-element on fullscreen elements (257337@main)
  • Fixed properly resolving fullscreen API promises (257668@main)
  • Implemented the unprefixed :fullscreen pseudo-class (257542@main)
  • Implemented ShadowRoot.fullscreenElement (257457@main)
  • Made the fullscreen API use the top layer (257456@main)
  • Made fullscreen elements match the :modal pseudo-class (257572@main)
  • Made requestFullscreen() consume user activation (257554@main)
  • Used the fullscreen preferred size when reporting screen dimensions (258005@main)
  • Stopped adjusting position to absolute for the root element in fullscreen (257946@main)


  • Added support for <model src> and honor <source type> attributes (257518@main)


  • Enabled 2D OffscreenCanvas (257672@main, 258237@main)
  • Added an iframe depth limit (257550@main)
  • Added support to return an adjusted URL when accessed from JavaScript bindings (257490@main)
  • Ensured video color space is consistent when drawing videos to a canvas (258030@main)
  • Ensured negative letter-spacing does not pull content oustisde of the inline box (258356@main)
  • Escaped ampersands (&) in JavaScript URLs for innerHTML and outerHTML (258112@main)
  • Fixed a bug where mousedown without mouseup in a frame disturbs the click event in another frame (258055@main)
  • Fixed behavior of nested click event on label element with checkbox (258287@main)
  • Fixed BroadcastChannel not always correctly computing its origin (257551@main)
  • Fixed legend.focus() to not delegate focus (258074@main)
  • Improved <textarea> validation performance (257417@main)
  • Made site-isolated cross-origin iframes load in their own process (257435@main)
  • Removed deprecated uppercase URL attribute alias on WebSocket interface (257467@main)


  • Fixed checkboxes not respecting the indeterminate attribute state (258314@main)
  • Fixed control values not updated after dynamic changes to color <input> elements, <textarea> elements, or <progress> elements (257976@main)
  • Expose bold and italic font styling as text attributes for macOS (258212@main)
  • Fixed indeterminate progress elements not reported as indeterminate by VoiceOver (258332@main)

Intelligent Tracking Prevention

  • Fixed user initiated cross-domain link navigations getting counted as Top Frame Redirects (258382@main)


  • Stopped auto-wrapping svg:text (257993@main)
  • Restricted floats over setCurrentTime and setCurrentScale to finite values (258322@main)


  • Changed the user gesture requirement to give back the user gesture freebie after a successful assertion or registration (257940@main)
  • Improved handling of security keys with a full key store (257989@main)
  • Fixed an issue where WebAuthn timeouts lead to an incorrect error (258116@main)
  • Fixed an issue where authenticatorAttachment would always be "platform" when performing operations over the hybrid transport (257576@main)


  • Fixed Get Element Rect command to no longer round to integer values (257498@main)


  • Added support for creating WebGL contexts for OffscreenCanvas in a web worker (257541@main)
  • Fixed a video texture set to repeat getting clamped (257365@main)
  • Fixed WebGL failing to initialize within an OffscreenCanvas on the main thread (258222@main)

January 12, 2023 11:28 PM

December 15, 2022

Help choose the syntax for CSS Nesting

Surfin’ Safari

The CSS Working Group is continuing a debate over the best way to define nesting in CSS. And if you are someone who writes CSS, we’d like your help.

Nesting is a super-popular feature of tools like Sass. It can save web developers time otherwise spent writing the same selectors over and over. And it can make code cleaner and easier to understand.

Unnested CSS

.class1 {
  color: green;
.class1 .class2 {
  border: 5px solid black;

Nesting in Sass

.class1 {
  color: green;
  .class2 {
    border: 5px solid black;

Everyone wishes CSS nesting could use the same kind of simple syntax that Sass does. That’s impossible, however, because of the way browser parsing engines work. If they see a sequence like element:pseudo, they’ll parse the entire style rule as if it were a property: value declaration.

So, a lengthy discussion began about what to do instead. Earlier this summer, the CSSWG debated between Option 1, Option 2 and Option 3. Of those, Option 3 won. Since then, two more options have been proposed, Option 4 and Option 5. If you remember various details discussed across 53+ issues, put all of those older ideas aside. At this point, we are only debating between Option 3, 4 and 5, as described in this article through the set of examples below.

To help us decide which option to choose, we’d like you to read these examples and answer a one-question survey.

Please look at these examples, consider how you write and maintain style sheets, and think deeply about which syntax you prefer. Then vote for the one you think is best.

In all three options, the & symbol is a marker that means “put the selector that’s outside of the nest [here]”. For example…


.foo {
  & .bar {
    color: blue;

… becomes this.

.foo .bar {
  color: blue;

And this…

.foo {
  .bar & {
    color: blue;

… becomes this.

.bar .foo {
  color: blue;

Got it?

In many of the following examples, the & is optional. Some developers will use it because it helps make their code more readable. Other developers will opt to leave it out, especially when copying & pasting code from unnested contexts. When the & is left out, the outside selector is added at the beginning, as an ancestor. (When we surveyed authors, their opinions on use of optional & were split 50/50.)

But here’s the key trick to Option 3 (and only Option 3) — if you are using an element selector (like p, article, or div), the & is required. If you are using any other selector, like a class or ID, you can choose to leave the & out. The easiest way to remember this: the selector can never begin with a letter. It must begin with a symbol. Some people in the CSSWG believe this will be easy to remember and do. Others wonder, given that style rules placed anywhere else in CSS don’t have such a syntactic restriction, if it will create confusion, tripping up developers in a way that is hard to debug.

As you compare the options, think about how your whole team will handle nested code. Think about what it might be like to copy & paste code from one project to another. Which option will make it easy to code inside and outside a nested context? Which will make it easiest to read, write, and edit large quantities of CSS?

Which is best for the future of CSS? When people write CSS thirty years from now — long after today’s habits and expectations are completely forgotten, when future generations have never heard of Sass — which option will make writing this language easy and elegant?

Do be sure to read through all the examples. One option might stand out as your favorite in one example, and yet, have problems that you don’t like in another example.

Comparing the Options

  • Option 5: Top-level @nest: Nested style rules are declared in a dedicated, independent at-rule that accepts only style rules. Declarations can be nested using & { .. }.
  • Option 4: Postfix block: Style rules allow for an optional, second block after the declaration block that contains only style rules.
  • Option 3: Non-letter start: Nested style rules can be added directly into a declaration block, but cannot start with a letter.

Example A: The Basics

Unnested CSS

article {
  font-family: avenir;
article aside {
  font-size: 1rem;

Option 5

@nest article {
  & {
    font-family: avenir;
  aside {
    font-size: 1rem;

Option 4

article {
  font-family: avenir;
} {
  aside {
    font-size: 1rem;

Option 3

article {
  font-family: avenir;
  & aside {
    font-size: 1rem;

Example B: With syntax variations

There are a lot of different ways developers like to structure their CSS — using tabs vs spaces, putting the { } braces on the same line as a rule or on separate lines, ordering rules in a certain order. This will also be true when writing nested CSS. Example B articulates a few of the possible variations of how you might format nested code for each option. It’s totally up to your personal preference.

Unnested CSS

.foo {
  color: red;
.foo .bar {
  color: blue;
.foo p {
  color: yellow;

Option 5

@nest .foo {
  & {
    color: red;
  .bar {
    color: blue;
  p {
    color: yellow;

Or you can use this syntax:

@nest .foo {{
  color: red; }
  .bar {
    color: blue;
  p {
    color: yellow;

Option 4

.foo {
  color: red;
} {
  .bar {
    color: blue;
  p {
    color: yellow;

Or you can format it like this:

.foo {
  color: red; } {
  .bar {
    color: blue;
  p {
    color: yellow;

Option 3

.foo {
  color: red;
  .bar {
    color: blue;
  & p {
    color: yellow;

Or you can use this syntax:

.foo {
  color: red;
  & .bar {
    color: blue;
  & p {
    color: yellow;

Example C: Re-nesting inside an element selector

There is a situation for Option 3 where just using an & is not enough — when we want the parent selectors referenced by & to come after the nested selector. Since we can’t start with &, we need to use something like :is() or :where() in order to start with a symbol instead of a letter.

Unnested CSS

a:hover {
  color: hotpink;
aside a:hover {
  color: red;

Option 5

@nest a:hover {
  & {
    color: hotpink;
  aside & {
    color: red;

Option 4

a:hover {
  color: hotpink;
} {
  aside & {
    color: red;

Option 3

a:hover {
  color: hotpink;
  :is(aside) & {
    color: red;

Example D: Zero unnested declarations + various selectors

Unnested CSS

:has(img) .product {
  margin-left: 1rem;
:has(img) h2 {
  font-size: 1.2rem;
:has(img) > h3 {
  font-size: 1rem;
:has(img):hover {
  box-shadow: 10px 10px;
a:has(img) {
  border: none;

Option 5

@nest :has(img) {
  .product {
    margin-left: 1rem;
  h2 {
    font-size: 1.2rem;
  > h3 {
    font-size: 1rem;
  &:hover {
    box-shadow: 10px 10px;
  a& {
    border: none;

Option 4

:has(img) {} {
  .product {
    margin-left: 1rem;
  h2 {
    font-size: 1.2rem;
  > h3 {
    font-size: 1rem;
  &:hover {
    box-shadow: 10px 10px;
  a& {
    border: none;

Option 3

:has(img) {
  .product {
    margin-left: 1rem;
  & h2 {
    font-size: 1.2rem;
  > h3 {
    font-size: 1rem;
  &:hover {
    box-shadow: 10px 10px;
  :is(a&) {
    border: none;

Example E: Nesting inside of nesting

Unnested CSS

table.colortable td {
  text-align: center;
table.colortable td .c {
  text-transform: uppercase;
table.colortable td:first-child,
table.colortable td:first-child + td {
  border: 1px solid black;
table.colortable th {
  text-align: center;
  background: black;
  color: white;

Option 5

@nest table.colortable {
  @nest td {
    & {
      text-align: center;
    .c {
      text-transform: uppercase;
    &:first-child + td {
       border: 1px solid black;
  th {
    text-align: center;
    background: black;
    color: white;

Option 4

table.colortable {} {
  td {
    text-align: center; }{
    .c {
      text-transform: uppercase;
    &:first-child + td {
       border: 1px solid black;
  th {
    text-align: center;
    background: black;
    color: white;

Option 3

table.colortable {
  & td {
    text-align: center;
    .c {
      text-transform: uppercase;
    &:first-child + td {
       border: 1px solid black;
  & th {
    text-align: center;
    background: black;
    color: white;

Example F: Integration with Media Queries

Unnested CSS

ol, ul {
  padding-left: 1em;

@media (max-width: 30em){
  .type ul,
  .type ol {
    padding-left: 0;

Option 5

@nest ol, ul {
  & {
    padding-left: 1em;
  @media (max-width: 30em){
    .type & {
      padding-left: 0;

Option 4

ol, ul {
  padding-left: 1em;
} {
  @media (max-width: 30em){
    .type & {
      padding-left: 0;

Option 3

ol, ul {
  padding-left: 1em;
  @media (max-width: 30em){
    .type & {
      padding-left: 0;

Example G: Integration with Cascade Layers

Unnested CSS

@layer base {
  html {
    width: 100%;
  @layer support {
    html body {
      min-width: 100%;

Option 5

@layer base {
  @nest html {
    & {
      width: 100%;
    @layer support {
      body {
        min-width: 100%;

Option 4

@layer base {
  html {
    width: 100%;
  } {
    @layer support {
      body {
        min-width: 100%;

Option 3

@layer base {
  html {
    width: 100%;
    @layer support {
      & body {
        min-width: 100%;

Now that you’ve had a chance to absorb examples of the three options, and maybe play around with a few of your own, which do you believe should become the way CSS is written in the future?

Which option is best for the future of CSS?

  • Option 5
  • Option 4
  • Option 3

If you’d like to describe more about your thoughts, reply to @webkit on Twitter, or @jensimmons@front-end.social on Mastodon.

Thank you for your feedback. There’s a lot that goes into designing a programming language, not just the results of a survey like this. But knowing what web developers think after reading examples will help us with our ongoing discussions.

Please pass along this survey to other people you know who also write CSS, post it to social media, and help us get the word out. The more people who voice their opinion, the better.

We especially want to hear from developers working on a wide variety of projects — from websites to web apps, native apps to digital signage to printed books. Whether large and small projects, huge or tiny teams, brand-new or decades-old codebases. Built on any variety of frameworks, CMSes, build systems… dynamic or static, rendered server-side or client-side… there are a lot of ways people use CSS, all around the globe. We need to consider them all.

December 15, 2022 06:00 PM

December 14, 2022

Release Notes for Safari Technology Preview 160

Surfin’ Safari

Safari Technology Preview Release 160 is now available for download for macOS Monterey 12.3 or later and macOS Ventura. If you already have Safari Technology Preview installed, you can update in the Software Update pane of System Preferences on macOS Monterey, or System Settings under General → Software Update on macOS Ventura.

This release includes WebKit changes between: 256265@main…257350@main

Note: Shared Tab Groups and syncing for Tab Groups, Website Settings, and Web Extensions are not enabled in this release.

Web Inspector

  • Elements Tab
    • Fixed corrupted styles when adding a new property to a rule with a commented-out property in the Styles sidebar (256410@main)
  • Storage Tab
    • Fixed extensions showing a UUID instead of their name for cookie entries (256695@main)


  • Added support for media queries level 4 including range queries (257252@main)
  • Fixed -webkit-radial-gradient parsing that treated a number of mandatory commas as optional (256468@main)
  • Fixed transition-property: none to disassociate CSS Transition from owning the element (256666@main)
  • Fixed border-image-* returning the initial keyword instead of the initial value when setting the border-image shorthand (257119@main)
  • Fixed @font-face src descriptor format parsing to only allow identifiers for specified formats (256382@main)
  • Fixed font shorthand to reset more longhand properties (256349@main)
  • Fixed legend tags not accepting the full range of display values (256841@main)


  • Added width and height content attributes to <model> (257294@main)
  • Changed to not apply aspect ratio scaling to gradient background images that don’t have a natural aspect ratio (256256@main)
  • Changed to use device pixel scaled backing store for <canvas> with image-rendering: pixelated (256299@main)
  • Changed to not paint a focus ring for anonymous block continuations (257199@main)
  • Changed to use unclamped subgrid track sizes to compute track positions, so that gap is accounted for correctly (256621@main)
  • Fixed Grid track sizing to reset the override width as well as height to compute intrinsic sizing (256622@main)
  • Fixed incorrect clipping when a layer is present between the column and the content layer (256953@main)
  • Fixed pixel-moving CSS filters with clipping (256825@main)
  • Fixed <textarea> placeholder text that does not disappear when inserting text without a user gesture (257210@main)
  • Fixed the incorrect static position of absolute-positioned elements inside relative-positioned containers (256722@main)
  • Fixed rendering for extreme border-radius (256943@main)
  • Fixed a positioned element with percentage padding to recalculate width when the containing block is changed (256315@main)

Web Animations

  • Implement KeyframeEffect.iterationComposite (257059@main)
  • Fixed opacity to use unclamped values for from and to keyframes with iterationComposite (257033@main)
  • Implemented correct accumulation support for the filter property (256952@main)
  • Implemented correct additivity support for the filter property (256955@main)
  • Fixed to correctly accumulate and clamp filter values when blending with "none" (256976@main)
  • Fixed filter values containing a url() to animate discretely (256970@main)
  • Fixed support for blending mismatched filter lists (256975@main)
  • Fixed baseline-shift animation is incorrect (256934@main)
  • Fixed changing writing-mode or direction on an element that has an animation targeting a logical property to ensure animation resolution is scheduled (256667@main)
  • Fixed keyframes to be recomputed if the CSS variable that is used changes (256893@main)
  • Fixed word-spacing to support animating between percentage and fixed values (256951@main)
  • Fixed Animation.commitStyles() not changing the style attribute for individual CSS transform properties (256728@main)


  • Changed the default for the x1, y1, and y2 attributes to 0% for LinearGradient (257032@main)


  • Changed to keep MediaKeySystemAccess alive in a createMediaKeys() async task (256442@main)
  • Changed to ensure current time is not removed during automatic eviction (256939@main)
  • Changed to not seek with no seekable range (256759@main)
  • Changed to explicitly close an RTCNetworkManager on document teardown (256319@main)
  • Fixed web audio rendering becoming garbled when switching from speakers to headphones and vice-versa (256712@main)
  • Fixed rendering artifacts when presenting fullscreen video (256251@main)
  • Fixed RGBA data VideoFrame copyTo (256534@main)
  • Fixed enabling subtitles when tracks are added after the video is loaded (256408@main)
  • Fixed the incorrect size of a video track’s settings in the second MediaStream created when the aspectRatio constraint is applied (256433@main)
  • Improved the coded frame eviction algorithm (256441@main)


  • Enabled resizable ArrayBuffer (257005@main, 256998@main, 256826@main)
  • Added JIT optimizations for ResizableArrayBuffers (257001@main)
  • Added support for Atomics.waitAsync (257061@main)
  • Added binding generator support for async iterable (257021@main)
  • Aligned Function#name behavior with spec (257114@main)
  • Relaxed Date parsing to accept narrow-no-break-space (256754@main)
  • Fixed the thrown error type for WebAssembly.Tag.getArg (256158@main)
  • Fixed WeakMap and WeakSet constructors to accept symbols (256758@main)
  • Fixed Array.prototype.indexOf constant-folding to account for non-numeric index (256590@main)
  • Fixed in operator parsing inside for statement destructuring (256497@main)
  • Implemented Array.fromAsync (257177@main)
  • Implemented growable SharedArrayBuffer (256524@main, 256766@main)
  • Implemented String#isWellFormed and String#toWellFormed (257250@main)
  • Improved resizable TypedArray’s slice implementation’s spec conformance (257018@main)
  • Updated resizable ArrayBuffer based on spec update (257178@main)
  • Wired memory allocation reporting to ArrayBuffer resize and grow (257042@main)


  • Added support for subtyping declarations (256243@main)
  • Changed call_ref to take a type index (256285@main)
  • Fixed incorrect text in WASM error message (256176@main)

Service Workers

  • Changed to make sure nested worker gets controlled if matching a service worker registration (256637@main)
  • Changed to not use the service worker preload for modified requests (257110@main)
  • Fixed service worker download in case of preloads (256731@main)
  • Removed the “Frame load interrupted” warning in Web Inspector when clicking a link to download a file served by a service worker with a fetch event handler (256725@main)


  • Fixed dynamic aria-disabled changes not updating enabled status for descendants (257159@main)
  • Fixed to include AXKeyShortcutsValue in accessibilityAttributeNames when there is an aria-keyshortcuts attribute (257274@main)
  • Fixed listed size announced by VoiceOver despite use of aria-setsize=-1 (256861@main)
  • Fixed a bug preventing Shadow DOM content from being exposed to accessibility clients when used in an aria-modal or dialog (256531@main)


  • Fixed non-breaking space getting inserted instead of a normal space character between text nodes in contenteditable (257136@main)


  • Enabled UserActivation API (257214@main, 256572@main)
  • Changed to only require a “transient” user activation for Web Audio rendering (256721@main)
  • Changed to not detach whitespace nodes when the previous sibling is an out-of-flow block (256602@main)
  • Changed to keep br element while replacing plain texts with content ending with newline (257205@main)
  • Changed to prevent hidden documents from locking the screen orientation (257019@main)
  • Changed to use 'self' as the permission policy for Web Share (256556@main)
  • Fixed clearing floats added dynamically to previous siblings (256238@main)
  • Fixed content downloaded with fetch() API when Content-Encoding: gzip is set is not decompressed (256755@main)
  • Fixed dedicated worker and shared worker global scope to use the response URL (256532@main)
  • Fixed elements with position: sticky that jitter inside a container with overflow-x: clip (256618@main)
  • Fixed broken preferred widths optimization involving subtree layout roots (256623@main)
  • Fixed CSS.supports behaviour with regards to !important and whitespace (257196@main, 257280@main, 257313@main)
  • Fixed CSSStyleValue.parse() and CSSStyleValue.parseAll() for shorthand CSS properties (256228@main)
  • Fixed form association behavior when a form and a control with form= are removed from a document together (256620@main)
  • Fixed form-association for <img> (256629@main)
  • Fixed hidden buttons that can’t be used as the submitter in an implicit submission (256813@main)
  • Fixed screen sharing when constraints passed by getDisplayMedia contains the ideal parameter (256458@main)
  • Fixed notification.close() (257108@main)
  • Fixed overlay regions sometimes getting stuck in the wrong place (256504@main)
  • Fixed clicking an email field on a sign-up form not allowing input until clicked a second time (256581@main)
  • Fixed WebSocket requests to include Sec-Fetch-Mode=websocket for FetchMetadata (256527@main)
  • Implemented input validation for CSSColorValues (256229@main)
  • Implemented messageerror event (256896@main)
  • Implemented support for StylePropertyMap.append() (257123@main)
  • Improved the speed of setting the value of <textarea> (256596@main)
  • Simplified early dedicated worker termination (256949@main)
  • Updated the streams WebIDL to match the latest specifications (257279@main)

December 14, 2022 09:30 PM

December 13, 2022

WebKit Features in Safari 16.2

Surfin’ Safari

We are pleased today to announce the release of Safari 16.2. It focuses on improving interoperability with other browsers as part of WebKit’s contribution to Interop in 2022.

Interop 2022

A year ago, representatives from Apple, Bocoup, Google, Igalia, Microsoft, and Mozilla came together with a commitment to improve interoperability between browsers. The group chose 15 focus areas that would have the most positive impact for web development and named the effort Interop 2022. The project runs automated tests for a specific set of web technologies and encourages browsers to align with the web standards for those technologies.

As of today, Safari Technology Preview 159 passes 98.5% of the tests for Interop 2022. (This results in a score of “94” on the Interop dashboard, after subtracting 3.8 due to lagging progress on group Investigation Projects and rounding down from 94.7.)

A line graph showing improvements to Interop 2022 scores across the year. Safari started at 59%, now at 94.7%. Firefox started at 70%, now at 89.1%. Chrome started at 60.7%, now at 89%. All three browsers were about even in the spring. Firefox and Safari pulled ahead for most of the summer. Then Safari pulled into first place in the fall.WebKit has made steady progress in improving our test pass rate for Interop 2022 tests, as seen in the results for Safari Technology Preview. More details at wpt.fyi/interop-2022.

After an exciting year of shipping new features in WebKit, we have only two left to further improve our Interop 2022 score.

Font Features

Safari 16.2 adds support of additional values for the font-variant-alternates property: annotation(), character-variant(), ornaments(), styleset(), stylistic(), swash(), along with the associated @font-feature-values at-rules.

These additional values round out Safari’s support for font-variant-alternates, a powerful tool for creating fantastic typography. It gives developers a way to specify which features of a web font to activate — to modify a span of text to use an historical form of the font, or to add swashes, ornaments, or more. What exactly font-variant-alternates can do depends on the features each web font contains.

Hopefully, once all browsers support font-variant-alternates due to the advocacy of Interop 2022, web developers and designers will start relying on Font Features more often.

Last Baseline

CSS Alignment allows web developers to describe how space should be allocated around or between items in both Flexbox and Grid formatting contexts. It includes multiple properties like justify-content, align-items, and place-self. There are many values that these properties support, including three for baseline alignment: baseline, first baseline, and last baseline. Safari has supported the first two since implementing support for CSS Alignment.

Safari 16.2 adds support for last baseline, making it possible to align Flexbox and Grid items along the baseline of the last line of text they contain. This means the following rules are now supported:

align-items: last baseline;
align-content: last baseline;
align-self: last baseline;
justify-items: last baseline;
justify-self: last baseline;
place-items: last baseline normal;
place-self: last baseline normal;

Fixes and Polish

Safari 16.2 also includes bug fixes that improve interoperability.


  • Fixed backgrounds with a fixed attachment to behave like scroll inside transformed elements.
  • Fixed calculating inline min-content size to include the aspect-ratio and add the min-content block computation.
  • Fixed flexbox cases where border and padding are added twice to the computed min and max sizes.
  • Fixed flex base size width calculation to not consider min and max sizes.
  • Fixed focus behavior to not take into account scroll margin when checking visibility.
  • Fixed layout containment to not propagate forced breaks to the parent.
  • Fixed perspective: 0 behavior.
  • Fixed percentage based translations not working with SVG <text> elements.
  • Fixed re-snap to follow scroll snap target if necessary.
  • Fixed scroll snap to choose the closest snap target if targets on each axes aren’t visible.
  • Fixed transforms on SVG shapes and groups when the root element size is changed.
  • Fixed text-decoration location for superscripts and subscripts when the text string contains both regular text and either superscript or subscript.
  • Fixed text-decoration pixel alignment when the content is truncated.
  • Fixed text-decoration-thickness property to not be inherited.
  • Fixed removing the intrinsic margin when specifying the width or height of an <input> element.
  • Fixed rounding for rgba() channels.
  • Fixed font-variant shorthand parsing to allow the font-variant-east-asian property in any position.
  • Fixed scroll snapping on a date input with scroll-margin applied.


  • Fixed transform changes to recompute overflow.
  • Fixed applying lineWidth and strokeStyle when drawing on <canvas>.
  • Fixed contain: content breaking scrolling when applied to the body.
  • Fixed applying transform-origin with a z-component.
  • Fixed computing the baseline position for tables when margins are applied.
  • Fixed applying transforms to table sections: tbody, thead, and tfoot.


  • Fixed updating MediaSessionInfo for a media element when a srcObject is used.


  • Fixed SharedWorker to honor Upgrade-Insecure-Request.


  • Fixed Element Click command failing on iOS.
  • Fixed: Enabled touch pointer input source subtype on iOS.


We love hearing from you. Send a tweet to @webkit to share your thoughts on Safari 16.2. Find us on Mastodon at @jensimmons@front-end.social and @jondavis@mastodon.social. If you run into any issues, we welcome your feedback on Safari UI, or your WebKit bug report about web technology or Web Inspector. Filing issues really does make a difference.

Download the latest Safari Technology Preview to stay at the forefront of the web platform and to use the latest Web Inspector features. You can also read the Safari 16.2 release notes.

Updating to Safari 16.2

Safari 16.2 is available for macOS Ventura, macOS Big Sur, macOS Catalina, iPadOS 16, and iOS 16. You can update to Safari 16.2 on macOS Monterey or macOS Big Sur by going to System Preferences → Software Update → More info, and choosing to update Safari. To update macOS Ventura, iOS or iPadOS, go to Settings → General → Software Update.

December 13, 2022 07:00 PM

November 30, 2022

Release Notes for Safari Technology Preview 159

Surfin’ Safari

Safari Technology Preview Release 159 is now available for download for macOS Monterey 12.3 or later and macOS Ventura. If you already have Safari Technology Preview installed, you can update in the Software Update pane of System Preferences on macOS Monterey, or System Settings under General → Software Update on macOS Ventura.

This release includes WebKit changes between: 256139@main…256265@main

Note: Shared Tab Groups and syncing for Tab Groups, Website Settings, and Web Extensions are not enabled in this release.



  • Changed to allow variables with the same name as the class in its static block (256311@main)


  • Fixed floating boxes overlapping their margin boxes (256183@main)
  • Fixed rendering artifacts when presenting a fullscreen video (256251@main)

November 30, 2022 09:47 PM

November 16, 2022

Release Notes for Safari Technology Preview 158

Surfin’ Safari

Safari Technology Preview Release 158 is now available for download for macOS Monterey 12.3 or later and macOS Ventura. If you already have Safari Technology Preview installed, you can update in the Software Update pane of System Preferences on macOS Monterey, or System Settings under General → Software Update on macOS Ventura.

This release includes WebKit changes between: 255892@main…256138@main

Note: Shared Tab Groups and syncing for Tab Groups, Website Settings, and Web Extensions are not enabled in this release.

Web Inspector

  • Added support for editing @-rules in the Styles sidebar of the Elements tab (256043@main)


  • Implemented CSS font-size-adjust property (255927@main)
  • Implemented font-variant-alternates functions, along with matching @font-feature-values at-rule (256002@main, 255677@main)
  • Implemented CSS property contain-intrinsic-size behind a flag (255971@main)
  • Changed to allow calc() with combined percentages and lengths for line-height (256095@main)
  • Changed to always use percentages for computed values of font-stretch, never keywords (256094@main)
  • Fixed font shorthand to not reject values that happen to have CSS-wide keywords as non-first identifiers in a font family name (255894@main)
  • Fixed font-style descriptor for @font-face to accept angle ranges in reverse order (255893@main)
  • Fixed font-style: oblique with calc() to allow out-of-range angles and clamp them for computed style (255925@main)
  • Fixed computed value CSS gradients to serialize colors in their computed form (256073@main)
  • Fixed text-shadow positioning on text with text-combine-upright (255892@main)
  • Fixed line-height to allow calc() with combined percentages and lengths (256095@main)


  • Changed to check for overflow content after trimming trailing content (256045@main)
  • Fixed a table cell overflowing its contents when it has inline children that change the writing-mode (255919@main)
  • Fixed elements with negative margins to not avoid floats when appropriate (256132@main)


  • Enabled AVIF image decoding for macOS Monterey and macOS Big Sur (255984@main)
  • Fixed “A MediaStreamTrack ended due to a capture failure” when selecting bluetooth headphones as audio input device (256091@main)


  • Accelerated Array.prototype.slice on DirectArguments (256027@main)
  • Accelerated Array.prototype.concat when applied to the self array (256040@main)


  • Enabled WebCodecs by default (256060@main)
  • Added WebCodecsVideoFrame initial support for serialisation and transfer (255949@main)
  • Changed to schedule dequeue event when the encoder queue size decreases (255962@main)
  • Changed to set VPx decoder frame type based on given parameter (255963@main)
  • Changed to prevent garbage collecting an encoder or decoder with content being processed (256007@main)
  • Exposed decoded video frames colorSpace (256068@main)
  • Exposed encoder color space in decoder config (256052@main)
  • Flushed before reconfiguring the encoder (255957@main)
  • Implemented pixel buffer conversion for video frames produced by libwebrtc VPX decoders (255958@main)


  • Aligned fetch header handling with fetch specification (256003@main)
  • Changed calling CSSStyleValue.parseAll() on a list-valued CSS property to split its value list (256070@main)
  • Changed CSSStyleValue.parse() to throw when passed an empty string as custom property value (256011@main)
  • Changed creating a shared worker connection to retry without providing a specific webprocess (255968@main)
  • Implemented input validation for CSSRGB constructor and setters (256024@main)
  • Optimized postMessage between two MessageChannel ports living in the same process (255948@main)

November 16, 2022 09:33 PM

November 07, 2022

Release Notes for Safari Technology Preview 157

Surfin’ Safari

Safari Technology Preview Release 157 is now available for download for macOS Monterey 12.3 or later and macOS Ventura. If you already have Safari Technology Preview installed, you can update in the Software Update pane of System Preferences on macOS Monterey, or System Settings under General → Software Update on macOS Ventura.

This release includes WebKit changes between: 255077@main…255891@main

Note: Shared Tab Groups and syncing for Tab Groups, Website Settings, and Web Extensions are not enabled in this release.

Web Inspector

  • Elements Tab
    • Added support for event breakpoints to be case-insensitive and regular expression matching (255196@main)
    • Fixed disabling inline breakpoints unexpectedly removing them (255292@main)
    • Fixed inline breakpoints appearing for minified resources before they are pretty-printed (255200@main)


  • Added support for font-synthesis longhand properties (255171@main)
  • Added support for last baseline alignment for CSS Grid (255455@main)
  • Added support for last baseline alignment for Flexbox containers (255383@main)
  • Added support for lh and rlh units (255540@main)
  • Added margin when computing the baseline position for tables (255357@main)
  • Changed outline to follow border-radius (255314@main, 255300@main)
  • Changed to treat rem and rlh as absolute units for font size (255594@main)
  • Changed to allow the font-variant-east-asian shorthand property in any position (255134@main)
  • Changed to only preserve a scroll snap target if there are targets for both axes (255493@main)
  • Changed CSS Keyframe name handling to not allow CSS-wide keywords (255640@main)
  • Changed to use min-intrinsic size to compute min-content size for non-replaced flex items (255858@main)
  • Fixed the display property value of a computed style to be "none" instead of "inline" for an <audio> element without controls (255528@main)
  • Fixed font-style: oblique to allow angles equal to 90deg or -90deg (255875@main)
  • Fixed font-weight to be clamped to 1 as a minimum (255873@main)
  • Fixed the left-aligned contentEditable caret instead of centered when the :before pseudo-element is used (255333@main)
  • Fixed CSS 3D transform by matrix3d() with translations to take page zoom into account (255416@main)
  • Unprefixed font-size: -webkit-xxx-large (255602@main)
  • Updated @font-palette-values override-colors order (255604@main)


  • Fixed flickering while scrolling when the keyboard scrolling spring damping animation doesn’t finish (255306@main, 255099@main)


  • Added support for class static initialization blocks (255173@main)
  • Changed the default style of Intl.DurationFormat from “digital” to “short” (255255@main)
  • Fixed Intl.NumberFormat ignoring maximumFractionDigits with compact notation for currency and decimal (255691@main)
  • Improved Object.entries runtime function performance (255470@main)
  • Updated useGrouping handling for Intl.NumberFormat (255275@main)


  • Added support for WebCodecs encoder bitrate related parameters (255476@main)
  • Added support for WebCodecs video encoder flush (255785@main)
  • Added support for WebCodecs Validate VideoFrameInit algorithm (255786@main)
  • Added support for WebCodecs VideoFrame allocationSize (255313@main)
  • Added support for WebCodecsVideoEncoder (255316@main, 255262@main)
  • Added support for WebCodecsVideoDecoder (255215@main, 255138@main)
  • Added support for WebCodecs VideoFrame copyTo (255429@main)
  • Added support for WebCodecsVideoDecoder with VPx backend (255138@main)
  • Added support for AVC H.264 WebCodecsVideoEncoder and WebCodecsVideoDecoder (255430@main, 255422@main)
  • Added support for GPU-based WebCodecsVideoDecoder flush (255388@main)
  • Added cropping support to WebCodecsVideoFrame copyTo (255716@main)
  • Added initial implementation to VideoFrame (255259@main)
  • Added support for RGBX and BGRX pixel formats (255390@main)
  • Added WebCodecs VideoFrame support for createImageBitmap (255776@main)
  • Ensured VPx WebCodecs encoders and decoders are created asynchronously (255478@main)
  • Ensured the bitrate and framerate are set for VPx encoders (255666@main)
  • Fixed canvas to be able to draw a WebCodecsVideoFrame (255720@main)
  • Validated width, height, x and y for I420 and NV12 video frames (255489@main)


  • Added support for CSSNumericValue.toSum() (255679@main)
  • Added support for CSSNumericValue.parse() (255791@main)
  • Added support for CSSTransformValue.toMatrix (255299@main)
  • Added support for EXT_provoking_vertex draft extension (255261@main)
  • Added support for the Sec-Fetch-Site header (255810@main)
  • Added support for cancel event support on <input type=file> (255394@main)
  • Added support for referrerpolicy in link headers (255354@main)
  • Added a log channel for IntersectionObserver (255197@main)
  • Added the class FilterTargetSwitcher (255802@main)
  • Changed to fire an error event when CSP blocks inline stylesheets (255744@main)
  • Changed to fire an error event when link preload fails synchronously (255740@main)
  • Fixed CSSPerspective.toMatrix() to throw an exception if its length is not compatible with a px unit (255876@main)
  • Fixed CSSTransformComponent.toMatrix() to flatten to two-dimenions if necessary (255290@main)
  • Fixed headers iteration to not happen on the cached headers list (255639@main)
  • Made onpointerlockchange and onpointerlockerror enumerable (255153@main)
  • Updated ResizeObserver and IntersectionObserver timing to match other browsers (255132@main)


  • Accept image/jpg for compatibility (255268@main)
  • Changed to enforce Low Power Mode and Optimize Video Streaming setting by tone mapping HDR video to SDR (255127@main)
  • Changed sizing of video element to use width and height HTML attributes to calculate a natural aspect ratio before the video file loads (255743@main)
  • Changed to switch to an alternate <source> element for AirPlay when necessary (255624@main)
  • Fixed the display able to go to sleep when the camera is on (255636@main)

Web Animations

  • Fixed Animation.commitStyles() triggering a mutation even when the styles are unchanged (255129@main)
  • Fixed updating timing to invalidate the effect (255863@main)
  • Updated to account for iterationComposite when blending (255834@main)


  • Added the display of a thumbnail of selected file for <input type=file> on macOS (255355@main)


  • Fixed accessibility for the <meter> and <progress> elements when -webkit-appearance: none or appearance: none is set (255836@main)
  • Fixed accessibility to not limit navigation when focus is explicitly moved outside of a modal (255665@main)
  • Fixed a bug causing VoiceOver to double-read list markers and not output braille for list items (255276@main)


  • Fixed Cross-Origin-Embedder-Policy incorrectly blocking scripts on a cache hit (255302@main)


  • Capped cookie lifetimes to 7 days for responses from third-party IP addresses (255849@main)
  • Omitted document.referrer for third-party requests while in ephemeral mode (255649@main)

Safari Web Extensions

  • Added support for the modifyHeaders action type in Declarative Net Request rules
  • Fixed Declarative Net Request rules not loading after an extension was turned off and then back on

November 07, 2022 09:42 PM

October 24, 2022

WebKit Features in Safari 16.1

Surfin’ Safari

Today, Safari 16 arrives for macOS Ventura and iPadOS 16. Numbered Safari 16.1, this release is also available for iOS 16, macOS Monterey, and macOS Big Sur.

To update to Safari 16.1 on macOS Monterey or macOS Big Sur, go to System Preferences → Software Update → More info. To update your Mac to macOS Ventura, go to System Settings → Software Update. To update to Safari 16.1 on iPad and iPhone, update iPadOS 16 and iOS 16 in Settings → General → Software Update.

Features that shipped in September’s Safari 16.0 include Container Queries, Subgrid, Web Inspector Extensions, Flexbox Inspector, Offset Path, Overscroll Behavior, Shared Workers, Shadow Realms, resolution media query, :has(:target), text-align-last, animation-composition, discrete animation, accessibility improvements for display: contents, improved VoiceOver performance, additional Apple Pay support, new Web Extension APIs, Manifest version 3 support, and much more. Safari 16.1 brings all of these features to iPadOS 16 and macOS Ventura.

Now let’s look at the new features and fixes arriving with Safari 16.1.

Web Push for macOS Ventura

a push notification on macOS

Safari 16.1 for macOS Ventura brings support for Web Push to Safari. Websites and web apps can now remotely send notifications using the same standards supported in other browsers — Push API and Notifications API, along with Service Workers — and deliver those notifications even when Safari isn’t running.

In Safari, users of your website or web app opt into notifications by first indicating interest through a user gesture — such as clicking a button. Then they’ll be prompted to give permission for your site or app to send notifications. Users can view and manage notifications in Notifications Center. And they can customize styles and turn notifications off per website in Notifications Settings.

If you’ve already implemented Web Push for your web app or website using industry best practices, it will automatically work in Safari. You do not need to be an Apple Developer Program member. However, if you’ve excluded Safari through browser detection, you’ll need to switch to feature detection to get it working. Web Push in Safari uses the same Apple Push Notification service that powers native push on all Apple devices. If you tightly manage push endpoints on your server, be sure to allow URLs from any subdomain of push.apple.com.

To learn more, watch the WWDC session Meet Web Push for Safari (15 min video), or read the article Meet Web Push on webkit.org.

Animated AVIF

Safari 16.0 brought support for AVIF still images to iOS 16. Safari 16.1 adds support for AVIF animated image sequences. Now both still and moving images saved in the AVIF format are supported on iOS 16, iPadOS 16, and macOS Ventura.


In September, iOS 16 introduced passkeys. Now with Safari 16.1, passkeys are supported everywhere Safari 16 is supported — including iPadOS 16, macOS Monterey, macOS Big Sur, and macOS Ventura, as well as iOS 16. Passkeys provide users with an incredibly easy way to log in, while delivering a profound increase in security.

The technology that makes passkeys possible is defined in open standards from the FIDO Alliance and the W3C, including the WebAuthn standard, which already has widespread support in browsers. Passkeys are an industry-wide effort, and “passkeys” is a common noun, to be used by anyone. You can offer passkeys alongside your existing authentication options. First, teach your backend to store public keys and issue authentication challenges. Then, on your website or web app, offer passkeys to users by adopting the APIs for creating new passkeys and allowing users to sign in with their passkey. If your website or web app already supports using a platform authenticator with WebAuthn, there are a few things to note as you add support for passkeys. Make sure you aren’t limiting signing in to the device that saved the passkey; that is, don’t use a cookie to “remember” that a user set up a key on a particular device. Also, make sure the username fields in your existing sign-in forms are compatible with AutoFill by adopting “conditional mediation”. Finally, start to refer to passkeys, and treat them as a primary way to sign in.

To learn more, watch the WWDC22 session, Meet Passkeys (27 min video) or read Supporting passkeys.

New viewport sizes on iPadOS

Three Safari browser windows, layered over one another, floating in space. One tall and very narrow. One medium and square. One bigger and wide.

iPadOS 16 introduces an entirely new multitasking experience with Stage Manager. This means browser windows on iPadOS can be resized to many different viewport sizes and aspect ratios. Responsive web design techniques, including the use of CSS media queries and container queries, are key. There’s never been a single “tablet size” for layout, and now that’s more true than ever.

Hover on iPadOS with Apple Pencil

The new iPad Pro supports hover with Apple Pencil. In web browsers, users see hover states for links, animations, and more. Hover on iPadOS is yet another example of how structuring code using feature detection, instead of device or UA detection, helps future-proof websites and web apps.

Scroll to Text Fragment

Safari 16.1 adds support for Scroll to Text Fragment, making it possible to include a text directive for finding a text fragment as part of a URL. When a user navigates to a URL that includes such a directive, the browser scrolls the text fragment into view and marks it with a persistent highlight.

Screen capture improvements

screenshot of dialog message asking Allow webkit.org to share your screen?

On macOS Ventura, Safari 16.1 adds support for capturing a specific Safari window with getDisplayMedia(). Calling getDisplayMedia in response to a user action will show the user a prompt asking for permission to allow the sharing of their screen or a specific window of an application, including Safari windows. The MediaStream provided by getDisplayMedia contains a video stream of the screen or window that can be recorded, or used as part of a WebRTC session.

And More

Safari 16.1 adds support for web-to-App Store advertising with SKAdNetwork. It also adds support for WebDriver Wheel input source and actions. Safari Web Inspector adds support for the color picker to pick a color from any pixel on the screen.

Fixes and Polish

Safari 16.1 also contains bug fixes and feature polish. Many of these fixes improve the Interop 2022 score for Safari. The test pass rate for Safari 16.1 is 93.3%. That’s calculated from 84.3 points of a possible 90. The remaining 10 points are joint “investigation projects”.


  • Fixed display:contents buttons failing to expose their accessible name.


  • Fixed dynamic viewport height units (dvh) not matching the actual viewport height.
  • Fixed scroll-snap properties set on <body> to stop propagating to the viewport.
  • Fixed logical viewport units to properly resolve for font-size.
  • Fixed containing blocks with a non-visible overflow incorrectly clipping position: fixed descendants.
  • Fixed table user-agent styles to use box-sizing: border-box.
  • Fixed <select> elements with contain: size.
  • Fixed handling layout and paint containment.
  • Fixed handling font-variant: normal and font-variant: none shorthands to reset font-variant-numeric and font-variant-alternates.
  • Fixed small caps handling to prevent synthesizing if any character in the font supports small caps.


  • Fixed the ignored CSS color property on <select> elements.
  • Fixed hiding icons on <input type="search"> when appearance: textfield is set.
  • Fixed applying the readonly attribute to the correct <input> types and <textarea> element.
  • Fixed the content width for <input type="search"> to not include decorations.
  • Fixed input type state changes to correctly handle missing or empty string value attributes.
  • Fixed form.submit() to submit a single form to multiple frames concurrently.
  • Fixed cloning a <textarea> to not set the initial selection at the end of the text content.
  • Fixed not firing a select event when setting a selection range results in no change to the selection.


  • Fixed some AVIF images not rendering because of their container format.


  • Fixed preventing background propagation on <html> with any containment.


  • Fixed COOP same-origin breaking forms after a back navigation.
  • Fixed script-src-elem CSP in Workers.


  • Fixed focus behavior for shadow DOM and the <dialog> element to align with specifications.


We love hearing from you. Send a tweet to @webkit, @jensimmons, or @jonathandavis to share your thoughts on Safari 16.1. If you run into any issues, we welcome your feedback on Safari UI, or your WebKit bug report about web technology or Web Inspector. Filing issues really does make a difference.

Download the latest Safari Technology Preview to stay at the forefront of the web platform and to use the latest Web Inspector features. You can also use the WebKit Feature Status page to watch for new information about the web features that interest you the most.

To learn more about what’s in Safari 16.1 for web developers, read the Safari 16.1 release notes.

October 24, 2022 05:42 PM

October 19, 2022

Release Notes for Safari Technology Preview 156

Surfin’ Safari

Safari Technology Preview Release 156 is now available for download for macOS Monterey 12.3 or later and macOS Ventura beta. If you already have Safari Technology Preview installed, you can update in the Software Update pane of System Preferences on macOS Monterey, or System Settings under General → Software Update on macOS Ventura.

This release includes WebKit changes between: 254352@main…255076@main

Note: Shared Tab Groups and syncing for Tab Groups, Website Settings, and Web Extensions are not enabled in this release.

Web Inspector

  • Elements Tab
    • Fixed Computed details sidebar panel scrolling back to the top when <style> is added to page (255001@main)
    • Fixed the DOM tree missing parts of the tree when inspecting iOS (254744@main)
    • Improved the visual hierarchy of the Layout details sidebar panel (254637@main)
  • Console Tab


  • Changed to not consider min- or max-sizes when computing width as flex base size (255002@main)
  • Changed to omit the integer value for grid-lines when it’s the default value (254821@main)
  • Changed to choose the closest snap target if neither are visible (254982@main)
  • Fixed focus to not take into account scroll margin for visibility check (254732@main)
  • Fixed text-align-last causing a table to take full space (254725@main)
  • Made resnap follow scroll snap target if necessary (254773@main)
  • Updated the named colors list to match CSS Color 4 (254840@main)


  • Added support for all rounding modes in Temporal (Behind the --useTemporal flag) (255068@main)
  • Accelerated baseline String#replace performance (254659@main, 254717@main)
  • Implemented Intl.DurationFormat (254791@main)
  • Implemented Temporal.PlainDate#{since, until} (Behind the --useTemporal flag) (254780@main)
  • Optimized String#substring (255030@main)


  • Changed to avoid line breaks before whitespace content when line-break: after-white-space is present (254826@main)
  • Fixed content placement when first-line style is present in non-quirks mode (255069@main)
  • Fixed <select> controls rendering for size=2 or size=3 (254698@main)
  • Fixed negative z-index layers from triggering unnecessary compositing of foreground layers (254746@main)


  • Adjusted buffering rate monitor to react faster (254781@main)
  • Implemented EncodedVideoChunk (254953@main)
  • Updated MediaSessionInfo media elements with a srcObject (254948@main)
  • Fixed returning animation from picture-in-picture to Element Fullscreen sometimes breaking (255041@main)

Web Animations

  • Fixed additive and accumulative color blending to yield intermediary out-of-bounds values (254850@main)


  • Ignored <option> element while building accessibility tree when <select> is hidden (254970@main)
  • Integrated ARIA element reflection in the Accessibility Tree (254905@main, 254985@main)
  • Implemented ARIA id-ref reflection for ElementInternals (254709@main)
  • Made custom element’s default ARIA id-ref work with shadow DOM (254762@main)


  • Enabled constructible and adoptable CSSStyleSheet objects (255067@main)
  • Enabled smooth keyboard scrolling by default (255031@main)
  • Added support for extended color animation interpolation (254960@main)
  • Added ImageBitmapRenderingContext support to OffscreenCanvas (254697@main)
  • Aligned the user-agent stylesheet for <abbr> and <acronym> with the HTML Spec (254710@main)
  • Consider Container Percentage Sizes When Determining Definite Cross Size (254758@main)
  • Convert HDR video frames to SDR when drawing to canvas (254973@main)
  • Changed to not suppress the click event on <textarea> resize (254843@main)
  • Changed to recompute transforms on SVG containers if the bounds changed during layout (255060@main)
  • Exposed the Notification API to dedicated workers (254805@main)
  • Fixed smooth keyboard scrolling to account for fixed content (254963@main)
  • Fixed document.open() to abort all loads when the document is navigating (254699@main)
  • Fixed document.open() to remove the initial about:blank-ness of the document (254747@main)
  • Fixed FetchEvent to not start its navigation preload response load if the preload was already used (254992@main)
  • Fixed Clear-Site-Data: "cache" HTTP header to clear the back-forward cache (254798@main)
  • Fixed calculation of direction for text form control elements with dir="auto" (254943@main)
  • Fixed mutating keyframes via CSSOM to not set disabled properties (254998@main)
  • Fixed strokeStyle changes not being applied for successive stroke line operations (254889@main)
  • Fixed elements with background-attachment: fixed to behave like background-attachment: scroll inside transformed elements (255055@main)
  • Fixed getBoundingClientRect() returning the wrong value for <tr>, <td> and its descendants for a vertical table (254918@main)
  • Fixed getComputedStyle() on a transform property to return the function list (254760@main)
  • Fixed click() for invisible <summary> elements to toggle the <details> element (255073@main)
  • Fixed percentage-based translations for SVG <text> (254656@main, 254777@main)
  • Fixed specified hue interpolation method for hues less than 0 or greater than 360 (254833@main)
  • Implemented import.meta.resolve() (254691@main)
  • Implemented importmaps (254987@main)
  • Implemented support for the Clear-Site-Data HTTP header (254745@main)
  • Made ElementInternals conditional on the form associated custom elements (254920@main)
  • Restricted transferSize, encodedBodySize, and decodedBodySize methods of PerformanceServerTiming and PerformanceResourceTiming to same-origin requests (254922@main)
  • Fixed SVG.currentScale to only set the page zoom for a standalone SVG (254787@main)
  • Prototyped declarative Shadow DOM (254964@main)
  • Prototyped streaming for declarative Shadow DOM (255020@main)

Safari Extensions

  • Fixed an issue where browser.tabs sometimes returned an incorrect URL for pinned tabs.

Bug Fixes

  • Fixed the Share Menu when sharing an image to show a preview of the image and a title (254976@main)

October 19, 2022 10:45 PM

October 15, 2022

WPE WebKit Blog: Success Story: Metrological

Igalia WebKit

Metrological: A Comcast Company WPE

WPE WebKit brought RDK (Reference Design Kit), a modern, performant web browser, to millions of screens. It enables operators to manage devices and easily customize their UIs and apps and provides analytics to improve the customer experience and drive business results.

Delivering a fast and memory-efficient browser for embbedded systems is a challenging task, so Igalia helped Metrological build a new full-screen browser engine which stripped away all unecessary toolkit elements.

With years of experience around WebKit platform integration, Igalia worked to produce a new WebKit port, WPE, which interfaced directly with Wayland and the graphics driver. Additionally, Igalia pushed forward the implementation of a multi-platform multi-threaded compositer, enabling better performance on low-end multicore processors. WPE is an official port of WebKit.

October 15, 2022 12:00 AM

October 05, 2022

Release Notes for Safari Technology Preview 155

Surfin’ Safari

Safari Technology Preview Release 155 is now available for download for macOS Monterey 12.3 or later and macOS Ventura beta. If you already have Safari Technology Preview installed, you can update in the Software Update pane of System Preferences on macOS Monterey, or System Settings under General → Software Update on macOS Ventura.

This release includes WebKit changes between: 254352@main…254623@main

Note: Shared Tab Groups and syncing for Tab Groups, Website Settings, and Web Extensions are not enabled in this release.

Web Inspector

  • Sources Tab
    • Changed URL breakpoints to also pause when an HTML attribute is set that triggers a load (254488@main)


  • Changed animation-* declarations in @keyframes to be a parse error (254468@main)
  • Enabled new perspective: 0 behavior of clamping to 1 (254420@main)
  • Fixed forced breaks in layout containment (254432@main)
  • Fixed contain: content on the body breaking scrolling (254506@main)
  • Fixed ::placeholder to not support writing-mode, direction, and text-orientation (254416@main)
  • Removed CSS display and float quirks on table and table cell elements (254475@main)


  • Fixed inline box decoration position when the content box is vertically shifted with text-underline-position: under in a vertical writing mode (254554@main, 254593@main)
  • Updated transforms on SVG shapes and groups when the root element size is changed (254538@main)
  • Stopped ignoring nowrap for table cells with nowrap="nowrap" and absolute widths (254505@main)


  • Disabled ShadowRealm for now (the --useShadowRealm flag can enable it) (254483@main)
  • Implemented Temporal.PlainDate[Time].{equals, add, subtract} (Behind the --useTemporal flag) (254366@main)
  • Implemented with and round methods for TemporalPlainDate[Time] (Behind the --useTemporal flag) (254565@main)
  • Optimized eval call in DFG / FTL compilers (254367@main)


  • Added support for WebVTT-based extended audio descriptions (254502@main)
  • Changed to round the SourceBuffer removal range (254472@main)
  • Fixed incorrect fullscreen video frame in some cases (254462@main)

Scroll to Text Fragment

  • Fixed Scroll To Text Fragment indicator to not show through popup layers (254494@main)
  • Fixed Scroll To Text Fragments to always be scrolled to the center of the frame (254477@main)
  • Fixed maintaining the Scroll to the Text Fragment until a user scroll happens (254403@main, 254507@main)
  • Fixed nodes with display: none to be considered invisible to search (254498@main)


  • Enabled the Reporting API by default (254520@main)
  • Implemented nested Dedicated Workers (254597@main)
  • Implemented no-quirks mode for media, plugin, and UA-inline documents (254526@main)
  • Added support for Cross-Origin-EmbedderPolicy (COEP) violation reporting (254466@main)
  • Added support for PermissionStatus.onchange in workers (254490@main)
  • Fixed the screen size of fullscreen video based on the aspect ratio (254528@main)
  • Fixed erroneous forgiving selectors to not be reported as supported with CSS.supports("selector(...)") (254489@main)
  • Fixed parsing of negative age values in CORS prefetch responses (254410@main)
  • Fixed handling text documents to comply with modern HTML specs (254389@main)
  • Incorrect image srcset candidate chosen for <img> cloned from <template> (254361@main)
  • Fixed lazy-loaded images sometimes not loading (254471@main)
  • Fixed navigating a cross-origin iframe to the same URL to not replace the current HistoryItem (254563@main)
  • Fixed element.removeAttribute("style") to not cause a style-src CSP violation message (254409@main)
  • Fixed text selection on flex and grid box items (254602@main)
  • Fixed wheel events to not stop macOS smooth keyboard scroll (254561@main)


  • Disallowed redirecting to data: or about: URLs (254619@main)


  • Fixed automation session terminating during navigation process swap (254386@main)

October 05, 2022 08:50 PM

October 03, 2022

Claudio Saavedra: Mon 2022/Oct/03

Igalia WebKit

The series on the WPE port by the WebKit team at Igalia grows, with several new articles that go deep into different areas of the engine:

These articles are an interesting read not only if you're working on WebKit, but also if you are curious on how a modern browser engine works and some of the moving parts beneath the surface. So go check them out!

On a related note, the WebKit team is always on the lookout for talent to join us. Experience with WebKit or browsers is not necessarily a must, as we know from experience that anyone with a strong C/C++ background and enough curiosity will be able to ramp up and start contributing soon enough. If these articles spark your curiosity, feel free to reach out to me to find out more or to apply directly!

October 03, 2022 11:28 AM

October 02, 2022

Manuel Rego: Igalia Web Platform team is hiring

Igalia WebKit

Igalia’s Web Platform team is looking for new members. In this blog post, I’ll explore the kinds of work our team does, plus a little about what working at Igalia is like.

If you’re interested in the position, please apply using the following form: https://www.igalia.com/jobs/web_platform_engineer

Working at Igalia

Igalia has more than two decades of experience working on free software, actively participating in open source communities, and contributing code to many upstream projects. We are now in a position that allows us to commit and own new features in many of those communities, while becoming a trusted partner that people know they can rely on.

That’s cool and all, but the best part is how we organize ourselves in a cooperative with a flat structure, where we all take part in the decisions that affect us, and (eventually) we all become co-owners of the company. Our model is based on strong values, and focused on building a new way to understand the IT industry and run a company. At Igalia, everyone gets paid the same, we all share responsibility for the company’s success and the rewards for our work.

At Igalia, we provide a remote-friendly, collaborative, and supportive environment, driven by principles of diversity and inclusion. There are currently over 120 Igalians from all over the world, and we have been a remote-friendly company for more than a decade.

Picture of a group of Igalians attending Igalia Summit in June 2022 Picture of a group of Igalians attending Igalia Summit in June 2022

About the Web Platform team

If I had to describe the work we do in the Web Platform team in one sentence, I’d say something like: implementing web platform features in the different open source browser engines. That’s quite a high level definition, so let’s go into some more specific examples of what we’ve done this year (though this is not an exhaustive list):

  • Shipped some features: :has() and inert in Chromium, CSS Containment and :focus-visible in WebKit.
  • Got MathML ready to ship in Chromium (hopefully shipping by the end of the year), and improved its interoperability in other rendering engines.
  • Worked on Interop 2022 in WebKit and Gecko: Cascade Layers, CSS Containment, Forms, etc.
  • Landed a variety of accessibility features and improvements: accessible name calculation, AOM (accessible actions and attribute reflection), Orca screen reader maintenance, etc.
  • Helped ship the Custom Highlight API in Chromium and implement the ::spelling-error and ::grammar-error pseudos.
  • Added support for Custom Protocol Handlers in Chromium.
  • Took over Firefox Reality development and released Wolvic, the open source WebXR browser.

“Implementing” the features is not the whole story though, as they usually involve a bunch of other work like proposals, specs, and tests. It’s really important to be able to navigate those situations, and seek consensus and agreement from the parties involved, so our team has a great deal of experience working on specs and participating in the relevant standards bodies.

Picture of some members of the Web Platform team during Igalia Summit in June 2022. From left to right: Brenna Brown, Rob Buis, Cathie Chen, Frédéric Wang, Valerie Young, Manuel Rego, Javier Fernández, Andreu Botella, Sergio Villar, Ziran Sun Picture of some members of the Web Platform team during Igalia Summit in June 2022. From left to right: Brenna Brown, Rob Buis, Cathie Chen, Frédéric Wang, Valerie Young, Manuel Rego, Javier Fernández, Andreu Botella, Sergio Villar, Ziran Sun

We meet twice a year at Igalia Summit. Not everyone can always make it to A Coruña (Galicia, Spain) in person, but we look forward to everyone visiting HQ eventually.

We have around 20 team members with a variety of backgrounds and locations, from Australia to Brazil to San Francisco and beyond. We collaborate with many others in the company, including some well known folks like Brian Kardell and Eric Meyer, who are always spreading the word about the great work we do.

Send your application

So if you’re interested in joining the Web Platform team at Igalia, please fill the form on our website.

Just in case you’re wondering about the interview process, you won’t be asked to do a live coding exercise or anything like that. The interviews are intended to allow both you and Igalia to get to know each other better.

If the Web Platform team doesn’t sound right for you, it might be worth checking out some of our other open positions.

Feel free to contact me if you have any questions about the position or Igalia as a whole.

October 02, 2022 10:00 PM

September 29, 2022

WPE WebKit Blog: WPE Networking Overview

Igalia WebKit

At the heart of any browser engine is networking: Connecting with services and other users. Unlike other engines, WebKit approaches this more abstractly by leaving a large portion of the networking up to individual ports. This includes network protocols such as HTTP, WebSockets, and WebRTC. The upside to this approach is a higher level of integration with the system-provided libraries and features so WebKit will behave similarly to other software on the platform often with more centralized configuration.

Due to this abstraction there are a few independent layers that make up the networking stack of WPE. In this post, I’ll break down what each layer accomplishes as well as give some insight into the codebase’s structure.

Networking Layers

WebKit Network Layers


Before we get into the libraries used for WPE, let’s discuss WebKit itself. Despite abstracting out a lot of the protocol handling, WebKit itself still needs to understand a lot of fundamentals of HTTP.

WebCore (discussed in WPE Overview) understands HTTP requests, headers, and cookies, as they are required to implement many higher-level features. What it does not do is the network operations, most parsing, or on-disk storage. In the codebase, these are represented by ResourceRequest and ResourceResponse objects, which map to general HTTP functionality.


A core part of modern web engine security is the multi-process model. In order to defend against exploits, each website runs in its own isolated process that does not have network access. In order to allow for network access, they must talk over IPC to a dedicated NetworkProcess, typically one per browser instance. The NetworkProcess receives a ResourceRequest, creates a NetworkDataTask with it to download the data, and responds with a ResourceResponse to the WebProcess which looks like this:

WebKit Network Flowchart


WPE implements the platform-specific versions of the classes above as ResourceRequestSoup and NetworkDataTaskSoup, primarily using a library called libsoup.

The libsoup library was originally created for the GNOME project’s email client and has since grown to be a very featureful HTTP implementation, now maintained by Igalia.

At a high level, the main task that libsoup does is manage connections and queued requests to websites and then efficiently streams the responses back to WPE. Properly implementing HTTP is a fairly large task, and this is a non-exhaustive list of features it implements: HTTP/1.1, HTTP/2, WebSockets, cookies, decompression, multiple authentication standards, HSTS, and HTTP proxies.

On its own, libsoup is really focused on the HTTP layer and uses the GLib library to implement many of its networking features in a portable way. This is where TCP, DNS, and TLS are handled. It is also directly used by WebKit for URI parsing and DNS pre-caching.

Using GLib also helps standardize behavior across modern Linux systems. It allows configuration of a global proxy resolver that WebKit, along with other applications, can use.


Another unique detail of our stack is that TLS is fully abstracted inside of GLib by a project called GLib-Networking. This project provides multiple implementations of TLS that can be chosen at runtime, including OpenSSL and gnutls on Linux. The benefit here is that clients can choose the implementation they prefer—whether for licensing, certification, or technical reasons.


Let’s go step by step to see some real world usage. If we call webkit_web_view_load_uri() for a new domain it will:

  1. Create a ResourceRequest in WebCore that represents an HTTP request with a few basic headers set.
    • ResourceRequestSoup will create its own internal representation for the request using soup_message_new_for_uri().
  2. This is passed to the NetworkProcess to load this request as a NetworkDataTask.
  3. NetworkDataTaskSoup will send/receive the request/response with soup_session_send() which queues the message to be sent.
  4. libsoup will connect to the host using GSocketClient which does a DNS lookup and TCP connection.
    • If this is a TLS connection GTlsClientConnection will use a library such as gnutls to do a TLS handshake.
  5. libsoup will write the HTTP request and read from the socket parsing the HTTP responses eventually returning the data to WebKit.
  6. WebKit receives this data, along with periodic updates about the state of the request, and sends it out of the NetworkProcess back to the main process as a ResourceResponse eventually loading the data in the WebProcess.


In conclusion, WebKit provides a very flexible abstraction for platforms, and WPE leverages mature system libraries to provide a portable implementation. It has many layers, but they are all well organized and suited to their tasks.

If you are working with WPE and are interested in collaborating, feel free to contact us. If you are interested in working with Igalia, you can apply here.

September 29, 2022 12:00 AM

September 27, 2022

Manuel Rego: TPAC 2022

Igalia WebKit

A few weeks ago the W3C arranged a new edition of TPAC, this time it was an hybrid event. I had the chance to attend onsite in Vancouver (Canada).

This is the second conference for me this year after the Web Engines Hackfest, and the first one travelling away. It was awesome to meet so many people in real life again, some of them for the first time face to face. Also it was great spending some days with the other igalians attending (Andreu Botella, Brian Kardell and Valerie Young).

This is my third TPAC and I’ve experienced an evolution since my first one back in 2016 in Lisbon. At that time Igalia started to be known in some specific groups, mostly ARIA and CSS Working Groups, but many people didn’t know us at all. However nowadays lots of people know us, Igalia is mentioned every now and then in conversations, in presentations, etc. When someone asks where you work and you reply Igalia, they only have good words about the work we do. “You should hire Igalia to implement that” is a sentence that we heard several times during the whole week. It’s clear how we’ve grown into the ecosystem and how we can have an important impact on the web platform evolution. These days many companies understand the benefits of contributing to the web platform bringing new priorities to the table. And Igalia is ready to help pushing some features forward on the different standard bodies and browser engines.

Igalia sponsored TPAC in bronze level and also the inclusion fund.

The rest of this blog post is about some brief highlights related to my participation on the event.

Web Developers Meetup

On Tuesday evening there was the developer meetup with 4 talks and some demos. The talks were very nice, recordings will be published soon but meanwhile you can check slides at the meetup website. It’s worth to highlight that Igalia is somehow involved in topics related to the four presentations, some of them are probably better known than others. But some examples so you can connect the dots:

Wolvic logo Wolvic logo

On top of the talks, Igalia was showing a demo of Wolvic, the open source browser for WebXR devices. A bunch of people asked questions and got interested on it, and everyone liked the stickers with the Wolvic logo.

Igalia also sponsored this meetup.


Lots of amazing things have been happening to CSS recently like :has() and Container Queries. But these folks are always thinking in the next steps and during the CSSWG meeting there were discussions about some new proposals:

  • CSS Anchoring: This is about positioning things like pop-ups relative to other elements. The goal is to simplify current situation so it can be done with some CSS lines instead of having to deal manually with some JavaScript code.
  • CSS Toggles: This is a proposal to properly add the toggle concept in CSS, similar to what people have been doing with the “Checkbox Hack”.

Picture of the CSSWG meeting by Rossen Atanassov Picture of the CSSWG meeting by Rossen Atanassov

On the breaks there were lots of informal discussions about the line-clamp property and how to unprefix it. There different proposals about how to address this issue, let’s hope there’s some sort of agreement and this can be implemented soon.

Accessibility and Shadow DOM

Shadow DOM is cool but also quite complex, and right now the accessibility story with Shadow DOM is mostly broken. The Accessibility Object Model (AOM) proposals aim to solve some of these issues.

At TPAC a bunch of folks interested on AOM arranged an informal meeting followed by a number of conversations around some of these topics. On one side, there’s the ARIA reflection proposal that is being worked on in different browsers, which will allow setting ARIA attributes via JavaScript. In addition, there were lots of discussions around Cross-root ARIA Delegation proposal, and its counterpart Cross-root ARIA Reflection, thinking about the best way to solve these kind of issues. We now have some kind of agreement on an initial proposal design that would need to be discussed with the different groups involved. Let’s hope we’re on the right path to find a proper solution to help making Shadow DOM more accessible.

Maps on the Web

This is one of those problems that don’t have a proper solution on the web platform. Igalia has been in conversations around this for a while, for example you can check this talk by Brian Kardell at a W3C workshop. This year Bocoup together with the Natural Resources Canada did a research on the topic, defining a long term roadmap to add support for maps on the Web.

There were a few sessions at TPAC about maps where Igalia participated. Things are still in a kind of early stage, but some of the features described on the roadmap are very interesting and have a broader scope than only maps (for example pan and zoom would be very useful for other more generic use cases too). Let’s see how all this evolves in the future.


And that’s all from my side after a really great week in the nice city of Vancouver. As usual in this kind of event, the most valuable part was meeting people and having lots of informal conversations all over the place. The hybrid setup was really nice, but still those face-to-face conversations are something different to what you can do attending remotely.

See you all in the next editions!

September 27, 2022 10:00 PM

September 21, 2022

Release Notes for Safari Technology Preview 154

Surfin’ Safari

Safari Technology Preview Release 154 is now available for download for macOS Monterey 12.3 or later and macOS Ventura beta. If you already have Safari Technology Preview installed, you can update in the Software Update pane of System Preferences on macOS Monterey, or System Settings under General → Software Update on macOS Ventura.

This release includes WebKit changes between: 253848@main…254351@main

Note: Shared Tab Groups and syncing for Tab Groups, Website Settings, and Web Extensions are not enabled in this release.

Web Inspector

  • Sources Tab
  • Elements Tab
    • Added “Scroll” labels in the element tree for scrollable elements (254061@main)
    • Added warnings in the Font details sidebar for synthesized boldness or obliqueness (254188@main)
    • Fixed DOM Tree to update when a top-level item in the DOM tree is added or removed (254062@main)
    • Prevented showing the Target in the Event badge popover (254018@main)
  • Timelines Tab
    • Fixed selecting timeline records from a coalesced record bar selecting the first record in the group, not the record nearest the cursor. (254056@main)
  • Settings
    • Added a setting to control whether nodes that are not rendered are de-emphasized (254022@main)



  • Fixed ShadowRealm test262 failures (253977@main)
  • Finished to and from methods for Temporal.PlainDate[Time] (Behind the --useTemporal flag) (253876@main)
  • Optimized Proxy [[Get]] operations (254092@main)
  • Optimized String#replace(String, String) (254156@main)
  • Optimizde String#replace with constant String via Boyer-Moore-Horspool search algorithm (254342@main)


  • Fixed incorrect bidi visual direction after forced line break (253872@main)
  • Fixed <div> with border-radius not getting repainted correctly when the bounds change (254041@main)
  • Fixed border-radius clipping of composited layers (254253@main)
  • Fixed updating transforms on table sections (254351@main)

Reporting API

  • Added support for generateTestReport in WebDriver (254122@main)
  • Hooked up to Content-Security-Policy 'report-to' directive (253966@main)
  • Refactored network send logic for Report-related code (254208@main)


  • Added support for COOP navigation violation reporting (254291@main)
  • Added support for ElementInternals.role, ariaLabel, and ariaRoleDescription (254278@main)
  • Added support for PermissionStatus.onchange (254193@main)
  • Added support for InputEvent.isComposing (254131@main)
  • Added ReferrerPolicy to the PolicyContainer (254003@main)
  • Added generation of IndexedDB object serializers (254196@main)
  • Enabled Scroll To Text Fragment by default (253855@main)
  • Enabled SKAttributionEnabled by default (254328@main)
  • Changed to not parse or scroll to text fragments in iframe URLs (254073@main)
  • Fixed memory usage scaling for Compression Streams to handle out-of-memory conditions (253930@main)
  • Fixed deleting a button element leaving the style inside the button element (254285@main)
  • Fixed matching fancy quotes and apostrophes for Scroll To Text Fragment fragments (254275@main)
  • Fixed link elements to be able to fire more than one load or error event (254290@main)
  • Fixed String.prototype.includes incorrectly returning false when the string is empty and the position is past end of string (254319@main)
  • Fixed opening the share sheet to not clear the text selection (254136@main)
  • Fixed <canvas> ConicGradient angle to start at the x-axis, not at the top (254038@main)
  • Fixed X-Frame-Options HTTP headers with an empty value being incorrectly ignored (254245@main)
  • Stopped painting a border for images with loading="lazy" before it loaded (253960@main)


  • Implemented WebVTT-based audio descriptions with text-to-speech (253931@main, 254266@main)
  • Implemented the ARIA 1.3 mark role, which provides parity with the <mark> tag (254008@main)


  • Fixed AudioWorklet scripts to inherit their owner document’s referrer policy (254306@main)
  • Fixed canPlayType for WebM VP8 on older Macs without VP9 (254013@main)
  • Fixed WebM files that fail to play (254219@main)
  • Fixed WebVTT styles not getting applied with in-band tracks (254109@main)

Intelligent Tracking Prevention

  • Updated to wait longer before deleting website data for domains where a user interacted with a Web Push notification (254048@main)

September 21, 2022 08:00 PM

September 12, 2022

WebKit Features in Safari 16.0

Surfin’ Safari

Today, we are excited to announce the release of Safari 16.0 for iOS 16, macOS Monterey and macOS Big Sur. This release contains quite a few new web technologies that web developers can use to make their sites and web apps even better.

To update to Safari 16.0 on macOS Monterey and macOS Big Sur, go to System Preferences → Software Update → More info. To update to Safari 16.0 on iOS, install iOS 16. Safari 16 for macOS Ventura and iPadOS 16 are coming this October, and will include Web Push on macOS Ventura.

a word cloud of everything that shipped in Safari this year, including what's in Safari 16

We announced many details about what’s in Safari 16 in our article, News from WWDC22: WebKit Features in Safari 16 Beta, and the WWDC22 session, What’s new in Safari and WebKit (32 min video). But that’s not all. In the months since WWDC, we’ve added even more.

New since Safari 16 Beta 1

Safari for iOS 16 includes support for still images compressed using the AVIF format. Developed by the Alliance for Open Media, AVIF is an alternative to image formats like JPEG, PNG, GIF, or WebP. It offers multiple color spaces, lossless and lossy compression, and more. Support for AVIF will also come to macOS Ventura and iPadOS in October.

WebKit now fully supports the resolution media query. This media query provides a way for web developers to conditionally apply CSS based on the pixel density of a screen. For example: @media (min-resolution: 326dpi) { }.

WebKit now supports text-align-last, a CSS property that sets how the last line of a text block is aligned. For instance, a paragraph could have text-align: center applied to most its lines, while the last line of that paragraph is aligned right with text-align-last: right.

The :has() pseudo-class in WebKit now supports :target. The CSS :target pseudo-class selects an element when that element has an id that matches a fragment in the URL. For example, if a user clicks on a link that takes them to example.com/#chapter2, and an element on that page has the ID #chapter2, then the :target pseudo-class will select that element. In Safari 16, :has(:target) opens up new possibilities when using URLs with fragments. For an in-depth look at :has, read Using :has() as a CSS Parent Selector and much more.


Safari on iOS 16 adds support for passkeys. They provide users with an incredibly easy way to log in, while delivering a profound increase in security.

To sign in with a passkey, fill in your username (or email, depending on the site) and tap the button. Your device authenticates that it’s you, and you’re in.

The technology that makes passkeys possible is defined in open standards from the FIDO Alliance and the W3C, including the WebAuthn standard, which already has widespread support in browsers. Passkeys are an industry-wide effort, and “passkeys” is a common noun, to be used by anyone. You can offer passkeys alongside your existing authentication options. First, teach your backend to store public keys and issue authentication challenges. Then, on your website or web app, offer passkeys to users by adopting the APIs for creating new passkeys and allowing users to sign in with their passkey.

If your website or web app already supports using a platform authenticator with WebAuthn, there are a few things to note as you add support for passkeys. Make sure you aren’t limiting signing in to the device that saved the passkey; that is, don’t use a cookie to “remember” that a user set up a key on a particular device. Also, make sure the username fields in your existing sign-in forms are compatible with AutoFill by adopting “conditional mediation”. Finally, start to refer to passkeys, and treat them as a primary way to sign in.

To learn more, watch the WWDC22 session, Meet Passkeys (27 min video) or read Supporting passkeys. In October, support for passkeys will come to macOS Monterey and macOS Big Sur, as well as macOS Ventura and iPadOS.

Apple Pay

Safari 16 adds Apple Pay support for Merchant Tokens, a more efficient way to support recurring payments, and support for multi-merchant payments, a way to pay multiple merchants of record in one transaction. Safari 16 also supports Order Tracking to enable merchants on the web to provide detailed order and shipping information in Wallet. Apple Pay can now be used in all WKWebView.

Web Inspector Extensions

Safari 16 brings support for Web Inspector Extensions, enabling you to enhance Safari’s built-in web developer tools. Download these extensions on macOS by going to Safari > Safari Extensions and looking for Web Inspector Extensions in the App Store. Search for developer tools from your favorite third-party developer services, test suites, and frameworks — including Angular DevTools, which recently announced support. If you’d like to learn how to make such extensions, watch the WWDC22 session, Create Safari Web Inspector Extensions (18 min video).

Safari 16 includes even more for Safari Web Extensions, including the ability to sync which extensions are enabled across iOS, iPadOS, and macOS. Safari 16 supports both manifest version 2 and manifest version 3. Watch What’s new in Safari Web Extensions from WWDC22 to learn about the differences, and how to upgrade your extension. Web Extensions in Safari 16 also add support for declarativeNetRequestWithHostAccess permission and browser.runtime.getFrameID.

Container Queries

Similar to Media Queries, Container Queries allow you to adjust the layout or styling of a particular item on your web page based on the size of its container rather than the size of the viewport. Safari 16 supports size queries and container query units. “Size queries” are what web developers imagine when they talk about Container Queries — the opportunity to write CSS that only applies if a container is a certain size. Container Query Units are similar to Viewport Units, but they specify a length relative to the dimensions of a query container instead of the viewport. These include cqw, cqh, cqi, cqb, cqmin, and cqmax.


CSS Grid revolutionized what’s possible in layout design on the web. Subgrid takes Grid to another level, providing an easy way to put grandchildren of a grid container on that grid. It makes it possible to line up items across complex layouts without being constrained by the HTML structure. And Safari’s Grid Inspector lets you turn on the overlays for as many grids as you want — which is especially helpful when coding subgrid.

Web Inspector

Following last year’s addition of Grid Inspector, Safari 16.0 adds Flexbox Inspector. It pairs perfectly with the addition of Alignment Editor in Safari 15.4.

a screenshot of the Flexbox Inspector in action, drawing lines around the container, around each item, and marking gaps and free spaceOverlays for Flexbox containers make it easier to visualize the effects your CSS.

Safari’s Flexbox Inspector visually distinguishes between excess free space and Flex gaps. It also shows the boundaries of items, revealing how they are distributed both on the main axis and the cross axis of your Flexbox containers. The toggleable “Order Numbers” option show the layout order of elements in the container, which can be helpful when using the order property. And just like our overlays for Grid last year, you can simultaneously show as many Flexbox overlays as you want, without any impact on scrolling performance. A single checkbox turns them all on.

In the Timelines Tab there are additional links to reference documentation, and a new experimental Screenshots timeline that captures screenshots of the viewport when content changes are painted.

The Elements Tab now supports showing Container Queries in the Styles sidebar.

The Sources Tab brings new improvements including allowing local overrides for requests to use regular expression matches in the redirect URL and local overrides for responses now being able to be mapped to a file on disk.

The Network Tab includes a new proxy indicator, and provides a way to entirely block network requests.

Accessibility Improvements

Safari 16 introduces a re-architecture of WebKit’s accessibility support on macOS. By adding Isolated Tree Mode, WebKit reduces VoiceOver hangs by offloading accessibility work to a secondary thread, improving performance and increasing responsiveness. This change allows WebKit to service more accessibility requests from clients like VoiceOver in less time than before. On some complex webpages, we’ve measured twice the number of accessibility requests served in twenty-five percent less time. Safari 16 also greatly improves accessibility support for elements with display:contents by ensuring they are properly represented in the accessibility tree.

Animation Improvements

WebKit now supports CSS Offset Path (also known as Motion Path), providing web developers the ability to animate objects along a custom path of any shape. The offset-path property lets you define a geometrical path along which to animate. The offset-anchor, offset-distance, offset-position, and offset-rotate properties give you additional abilities to refine the exact movement of the object being animated. While the offset property acts as a shorthand for combining these properties.

In Safari 16, you can now animate track sizes in CSS Grid, dynamically changing the size of rows and columns.

Safari 16 also adds support for composite operations, resolving how an element’s animation impacts its underlying property values. And it adds support for discrete animation to thirty-nine CSS properties.

Overscroll Behavior

CSS Overscroll Behavior determines what happens when a user scrolls and reaches the boundary of a scrolling area. It’s useful when you want to stop scroll chaining — when a user scrolls inside a box and hits the end, you now have control over stopping or allowing scrolling on the rest of the page.

Shared Workers

WebKit now supports Shared Workers. It’s similar to Service Workers, running JavaScript in the background, but its lifetime is slightly different. Your Shared Worker runs as long as the user has any tab open to your domain. All the tabs open to the same domain can share the same Shared Worker.

Additional Features

Safari 16 adds support for Shadow Realms, <form>.requestSubmit(), the showPicker() method for HTML input elements, and the worker-src Content Security Policy directive.

Fixes and Polish

Safari 16.0 also contains quite a few bug fixes and feature polish.


  • Fixed gradient color interpolation with alpha.
  • Removed most non-standard CSS appearance values.
  • Polished the implementation of the :has() pseudo-class, updated to match the evolving web standard.
  • Polished the implementation of Cascade Layers.


  • Fixed firing the load event after a form is submitted with a "_blank" target.
  • Fixed contenteditable anchors getting stuck with an :active state.
  • Fixed changing the value for stepUp() and stepDown() with out-of-range values.
  • Fixed using min as the default value when min is greater than max for <input type="range">.
  • Fixed making value updates visible for <input type="email">.
  • Fixed making sure :active is removed on keyup event for radio inputs.
  • Fixed applyStep() behavior to align with specifications.
  • Fixed the select() method returns to align with specifications.
  • Fixed form data generated by <input type="image"> when a value attribute is present.
  • Fixed the FormData object to not include an entry for the submit button used to submit the form.
  • Fixed returning an empty string for invalid floating-point numbers that end with a ".".
  • Fixed selection range after the type attribute of an <input> changes.
  • Fixed selection range to be limited by the length of the current value.
  • Fixed the user-agent stylesheet to include table { text-indent: initial } to align with specifications.
  • Fixed the user-agent stylesheet to include box-sizing: border-box for <input type="color">.
  • Fixed the line-height declaration to use !important for the placeholder of an input.


  • Fixed blocking image content in object elements.
  • Fixed incorrect CORP/COEP check in 304 responses.
  • Fixed mixing strict-dynamic and unsafe-inline policies.
  • Fixed script-src-elem policies in Workers.
  • Fixed incorrect blocked-uri for inline scripts and strict-dynamic policies.

WebGL 2

  • Fixed handling AllowShared TypedArray.

Web Inspector

  • Fixed breakpoints not triggering, breakpoints occurring at incorrect locations in scripts, and incorrect error/stack trace line/column numbers when inspecting minified sources with multi-line strings.
  • Fixed importing Timelines sometimes not scrolling.
  • Fixed importing Audits sometimes crashing.
  • Fixed CSS autocomplete to suggest the most commonly-used property, not the alphabetical one.

Web Driver

  • Fixed pointerMove actions to correctly fire mouse events.
  • Fixed rapid session creation and deletion leading to timeouts in session creation.

Safari Web Extensions

  • Fixed incorrect counts being returned from getBytesInUse.
  • Extensions that request the unlimitedStorage permission no longer also need the storage permission.
  • Updated the maximum number of static rulesets to 50 and the maximum number of enabled static rulesets to 10.
  • Service workers are no longer returned from extension.getBackgroundPage and extension.getViews


We love hearing from you. Send a tweet to @webkit, @jensimmons, or @jonathandavis to share your thoughts on Safari 16. If you run into any issues, we welcome your feedback on Safari UI, or your WebKit bug report about web technology or Web Inspector. Filing issues really does make a difference.

Download the latest Safari Technology Preview to stay at the forefront of the web platform and to use the latest Web Inspector features. You can also use the WebKit Feature Status page to watch for new information about the web features that interest you the most.

To learn more about what’s in Safari 16 for web developers, read the Safari 16 Release Notes.

September 12, 2022 05:45 PM

Introducing JetStream 2.1

Surfin’ Safari

JetStream 2 is a JavaScript benchmark suite that runs 64 subtests. We recently discovered that the benchmark score of JetStream 2 may be influenced by pause times between individual subtests because of second order effects, like CPU ramping. Network latency is one source of such pause times. As a result, depending on the speed of one’s network, JetStream 2’s benchmark score can vary. This is undesirable since the goal of JetStream 2 is to measure JavaScript performance, not the second order effects of network latency.

We’re introducing JetStream 2.1 which runs the same subtests as JetStream 2. However, JetStream 2.1 updates the benchmark driver to pre-fetch network resources into Blobs, and create URLs from them. The subtests will now load resources from these blob URLs instead.

With this change, we measured JetStream 2.1’s benchmark scores on both Chrome and Safari to be more stable and is less perturbed by pause times due to network latency. Scores produced from JetStream 2.1 are not comparable to other versions of any JetStream benchmark.

September 12, 2022 04:50 PM

September 07, 2022

Release Notes for Safari Technology Preview 153

Surfin’ Safari

Safari Technology Preview Release 153 is now available for download for macOS Monterey 12.3 or later and macOS Ventura beta. If you already have Safari Technology Preview installed, you can update in the Software Update pane of System Preferences on macOS Monterey, or System Settings under General → Software Update on macOS Ventura.

This release includes WebKit changes between: 253169@main…253847@main

Note: Shared Tab Groups and syncing for Tab Groups, Website Settings, and Web Extensions are not enabled in this release.

Web Inspector

  • Sources Tab
  • Elements Tab
    • Added a way to control what badges are shown in the main DOM tree (253579@main)
    • Added Event badges for nodes that directly have event listeners in the main DOM tree (253727@main)
    • Changed the Computed panel to no longer show the Variables section when the selected element has no CSS variables (253562@main)
    • Changed the Computed panel to sort prefixed properties below non-prefixed properties (253789@main)
    • Changed the Computed panel to only show inline swatches that actually preview the value (253214@main)
  • Network Tab
    • Fixed highlighting only the initiated resources when a row is hovered (253476@main)


  • Added support for background images on ::first-line (253553@main)
  • Added right-to-left direction support for text-overflow: ellipsis (253689@main)
  • Implemented forced-colors media query (253290@main)
  • Fixed text-decoration location for superscripts when the text string contains both superscript and regular text (253406@main)
  • Fixed handling of layout and paint containment with internal ruby boxes (253354@main)
  • Fixed :has(:lang(~)) invalidation with dynamic changes (253764@main)
  • Fixed @supports to not work if “not”, “or”, or “and” isn’t follow by a space (253194@main)
  • Fixed handling of font-variant: normal and font-variant: none shorthand (253731@main)
  • Fixed behavior of cursor: auto over links (253685@main)
  • Fixed color-scheme to not propagate to the viewport background if set on the <body> (253565@main)
  • Fixed tiled layer flicker when an animation ends (253549@main)
  • Fixed the transferred min and max sizes to be constrained by defined sizes (253262@main)
  • Fixed pseudo-elements not treated as ASCII case-insensitive (253631@main)
  • Fixed the title of non-CSS stylesheets to be not preferred (253632@main)
  • Fixed input[type=search] to hide icons when appearance: textfield is set (253691@main)
  • Included aspect-ratio when calculating inline min-content size and add min-content block computation (253740@main)
  • Renamed initial value of color-scheme from auto to normal (253659@main)
  • Used align-content when calculating the static position of absolutely-positioned flexbox children (253389@main)
  • Used logical top, bottom, and height when computing the available height for an out-of-flow block (253312@main)


  • Implemented import-assertion and JSON module (253234@main)
  • Implemented Temporal.PlainDateTime to the extent of the current PlainDate implementation (Behind the --useTemporal flag) (253623@main)
  • Fixed not generating import.meta object if it is not referenced (253636@main)
  • Optimized async and await and microtask queue (253651@main)
  • Optimized Promise.all (253716@main)
  • Added support for WebAssembly GC recursion groups (253491@main)


  • Changed to not generate text runs for empty text content (253569@main)
  • Fixed text-overflow: ellipsis to change the text content to render (253607@main)
  • Fixed text-overflow: ellipsis to not affect geometries (253650@main)
  • Fixed underline thickness to align with device pixels (253182@main)
  • Stopped propagating scroll-snap style from <body> to viewport (253430@main)

Screen Capture

  • Changed to reject the getDisplayMedia prompt if the system picker times out (253260@main)


  • Included explicit !important min, max properties, and explicit width and height for full-screen elements (253790@main)
  • Fixed MediaRecorder.stop() firing an additional dataavailable event with bytes after MediaRecorder.pause() (253529@main)
  • Fixed audio pitch changes on enabling or disabling the mic capture (253673@main)
  • Fixed screen recording in a background tab working for only about a minute (253769@main)


  • Stopped applying the buffer offset twice in getBufferSubData (253175@main)


  • Implemented the Imperative Slot API (253187@main, 253198@main, 253199@main, 253202@main, 253266@main, 253320@main, 253359@main, 253365@main, 253392@main, 253396@main, 253402@main)
  • Implemented full search for text directives for Scroll to Text Fragment spec (253383@main)
  • Added Set-Cookie as a forbidden header name (253325@main)
  • Added generic media query parser and evaluator (253298@main)
  • Added support to the Permissions API for dedicated workers (253447@main)
  • Added support to the Permissions API for Service Workers and Shared Workers (253752@main)
  • Added way to get parent inline box to the inline iterator (253304@main)
  • Added box-sizing: border-box to table in the User-Agent stylesheet (253581@main)
  • Fixed blob URLs with a fragment from opaque origins cannot be loaded (253498@main)
  • Fixed ignored charset of blobs (253458@main)
  • Fixed composited canvas element to update the layer configuration after creating a WebGL context (253231@main)
  • Fixed position elements should layout relative to transformed container (253809@main)
  • Fixed Navigator.share() rejecting with the wrong exception when called multiple times (253419@main)
  • Fixed iframe srcdoc with a quirky doctype to use no-quirks mode (253326@main)
  • Fixed input[type=search] preferred content width to not include decorations (253595@main)
  • Fixed Permissions.query to return “prompt“ for opaque origins (253785@main)
  • Fixed scheduling a navigation to a Blob URL to keep the URL alive until the navigation actually occurs (253435@main)
  • Fixed forms with a disabled submit button from being posted with the Enter key (253228@main)
  • Fixed the HTML parser to ignore starting <head> tags in the “in head noscript” state (253489@main)
  • Fixed the HTML parser’s foster-parenting algorithm to not require foster parents to be elements (253504@main)
  • Fixed the HTML parser’s adoption agency algorithm to not reverse the order of nodes (253505@main)
  • Fixed an issue where data-x-2="" is not included in the dataset if it’s the only data attribute (253625@main)


  • Added support for the ARIA 1.3 property aria-description (253184@main)
  • Fixed updating accessibility objects role after a dynamic contenteditable change (253630@main)


  • Added support for Wheel input source and actions (253578@main)
  • Added support for “Get Computed Role” and “Get Computed Label” commands (253732@main)
  • Fixed automation hanging indefinitely when dismissing alerts

September 07, 2022 08:19 PM

July 28, 2022

WPE WebKit Blog: WPE QA and tooling

Igalia WebKit

In the previous posts, my colleagues Claudio and Miguel wrote respectively about the major components of the project and, specifically, the graphics architecture of WPE. Today, you’ll see our efforts to improve the quality of both WPE and the experience of working and using it. While the previous entries in this blog post series about WPE aren’t necessarily required in order to read this one, we recommend you to starting with the first post in the series.

Automated testing

Testing is an essential part of the WebKit project, primarily due to the large number of use cases covered by HTML/CSS/Javascript specifications and the need for the project to work correctly in a wide range of configurations.

As an official port of WebKit, WPE uses the former’s testing infrastructure, based on BuildBot. There are two primary servers, one working as an early warning system by testing the patches before they’re committed to the main repository, and another for more extensive testing after accepting the incoming changes.

build.webkit.org screenshot

Currently, the WPE testing bots target debug and release configurations using the Flatpak SDK (more on it later in this article) on 64bit Intel-based Linux Debian systems. We have plans of adding bots running on Raspberry Pi boards in the future. Alongside nightly testing, we keep builder bots covering the Ubuntu LTS/Debian versions we support. After August 14th, 2022, the earliest supported versions will be Ubuntu 20.04 LTS and Debian 11 (Bullseye).

Test suites

Initially, the WPE builder bots build WPE in both release and debug configurations and feed the built packages into the tester bots, which run some test suites according to their configuration, each suite focused in one aspect of the project:

  • Layout tests: The main suite tests whether WebKit correctly renders web pages and its implementation of web APIs. This suite comprises both WebKit’s test cases and the imported tests from Web Platform Test. At the time of writing, it runs over 50,000 test cases.
  • API Tests: This suite tests the API provided to developers by WebKit and its ports. For example, this step tests the WPE API used in Cog.
  • Javascriptcore tests: Covers the JavascriptCore engine, running WebKit’s tests alongside test262, the reference test suite for JS/ECMAScript implementations.
  • WebDriver: Tests from Selenium and W3C WebDriver APIs for browser automation.
  • Other small suites: Tests for WebKit’s tooling components.

Due to a large number of tests and the fast development of both WebKit and the specifications—it’s not uncommon to have dozens of daily commits touching dozens of tests—it’s hard to keep the testing bots green.

For example, while we try to make the tests work on all platforms, many old layout tests use the -expected.txt scheme, where the render tree is printed in a textual format with the text sized in pixels for every node. While this works fine in most cases, many tests have minor differences between the expected result in the Mac platform and the WPE/GTK platform. One of the causes is the font rendering particularities of each port.

Thankfully, this situation improved significantly since the beginning of the project. Among the efforts, many tests are now using a “reference” HTML file, which are HTML files that render to the same expected result as the test case, so both the test case and the reference will use the same font rendering scheme and can be compared pixel by pixel.

Building and running WPE

This section focuses on the experience of building and running WPE in a regular Linux x86–64 system. In a future post, we’ll cover building for and running on embedded devices.

Checking out the code

Recently, WebKit moved to GitHub, so you can clone it directly from there:

$ mkdir ~/dev
$ git clone https://github.com/WebKit/WebKit.git

Note: Due to the size of the project history, you might want to use --depth=1 to clone a single revision, followed by git pull --unshallow from inside the cloned repository to fetch the history if needed.

There’s more information in WebKit’s GitHub wiki about setting up the git checkout for contributing code back to WebKit. It’ll set up some git hooks to do some tasks required by the project, like formatting the commit message and automatically linking the pull request to the Bugzilla issue.

All commands in the following sections are run from inside the cloned repository.

Updating the dependencies (aka The WebKit Flatpak SDK)

Like most complex software projects, WebKit has a reasonably extensive list of dependencies. Keeping a reference set of their versions frozen during development is desirable to make it easier to reproduce bugs and test results. In older times, WPE and WebKitGTK used JHBuild to freeze a set of dependencies. While this worked for a long time, it did not cover all dependencies. Sometimes, there could be minor differences in the layout tests between the reference test bots and the developer machine due to some dependency resolved by the host system outside JHBuild.

To improve reproducibility, since 2020, WPE and WebKitGTK have been using an SDK based on Flatpak (kudos to my colleagues Thibault Saunier and Philippe Normand), with a much more extensive dependency coverage and isolation from the host system. Alongside the dependencies, it ships some tools like rr and supports tools like clangd. Almost all bots enable this SDK, the exception being the LTS/Stable bots; as in the latter, we want to build with the already available packages in each distribution.

$ ./Tools/Scripts/update-webkit-flatpak

The command will set up the local flatpak repository at ./WebKitBuild/UserFlatpak with the downloaded SDK and create some bundled icecc toolchains. This enables distributed builds in local networks…


Once the SDK download finishes, you can use the helper script ./Tools/Scripts/build-webkit, which wraps the cmake command with some pre-set options commonly used in normal development, like enabling developer-only features usually disabled in regular builds. Manually invoking cmake is possible, although usually only when you want more control over the build. To build WPE in release mode, use:

$ ./Tools/Scripts/build-webkit --release --wpe

Optionally, you can pass it multiple arguments to be fed directly to make or cmake with the switches --makeargs=... and --cmakeargs=..., respectively. For example, --makeargs="-j8" will limit make to 8 parallel jobs and --cmakeargs="-DENABLE_GAMEPAD=1" will enable gamepad support (requires libmanette, bundled in the SDK).

The first build might take a while (up to almost one hour in a regular laptop). Fortunately, the SDK uses ccache to avoid recompiling the same object files, so subsequent builds without significant changes usually are faster. For more info on speeding the build, check the wiki.

Running the browser (Cog)

To run Cog, the reference WPE browser, you need a Wayland server, which is common in most Linux systems nowadays.

$ ./Tools/Scripts/run-minibrowser --wpe --release https://wpewebkit.org/
Cog with GTK4 shell screenshot

Running some tests

To run the API tests, which reside in Tools/TestWebKitAPI/Tests/, you can use the following command:

$ ./Tools/Scripts/run-wpe-tests --release --display-server=headless

Other test suites:

  • Layout tests: ./Tools/Scripts/run-wpe-tests
  • JSC tests: ./Tools/Scripts/run-javascriptcore-tests
  • WebDriver: ./Tools/Scripts/run-webdriver-tests

As stated when we described the test suites, the main challenge in testing is keeping up with the fast pace of development, as it’s not uncommon to have some revisions updating hundreds of tests.

Contributing code to WPE

After hacking locally, you can submit your changes following the workflow listed in the WebKit wiki.

Testing WPE in the wild

If you don’t want to build your WPE build or image, there are some options to get a taste of WPE listed on our website, including:

Some of these options, like the prebuilt images and the Balena blocks, will be the subject of future blog posts in this series.

Final thoughts

With this, we conclude this brief overview of WPE automated testing and the main tools we use in our daily work with WPE. In future posts in this area we’ll go deeper in other subjects like testing on embedded boards and debugging practices.

If this post got you interested in collaborating with WPE development, or you are in need of a web engine to run on your embedded device, feel free to contact us. We’ll be pleased to help!

We also have open positions at the WebKit team at Igalia. If you’re motivated by this field and you’re interested in developing your career around it, you can apply here!

July 28, 2022 12:00 AM

July 20, 2022

Víctor Jáquez: Gamepad in WPEWebkit

Igalia WebKit

This is the brief story of the Gamepad implementation in WPEWebKit.

It started with an early development done by Eugene Mutavchi (kudos!). Later, by the end of 2021, I retook those patches and dicussed them with my fellow igalian Adrián, and we decided to come with a slightly different approach.

Before going into the details, let’s quickly review the WPE architecture:

  1. cog library — it’s a shell library that simplifies the task of writing a WPE browser from the scratch, by providing common functionality and helper APIs.
  2. WebKit library — that’s the web engine that, given an URI and other following inputs, returns, among other ouputs, graphic buffers with the page rendered.
  3. WPE library — it’s the API that bridges cog (1) (or whatever other browser application) and WebKit (2).
  4. WPE backend — it’s main duty is to provide graphic buffers to WebKit, buffers supported by the hardware, the operating system, windowing system, etc.

Eugene’s implementation has code in WebKit (implementing the gamepad support for WPE port); code in WPE library with an API to communicate WebKit’s gamepad and WPE backend, which provided a custom implementation of gamepad, reading directly the event in the Linux device. Almost everything was there, but there were some issues:

  • WPE backend is mainly designed as a set of protocols, similar to Wayland, to deal with graphic buffers or audio buffers, but not for input events. Cog library is the place where input events are handled and injected to WebKit, such as keyboard.
  • The gamepad handling in a WPE backend was ad-hoc and low level, reading directly the events from Linux devices. This approach is problematic since there are plenty gamepads in the market and each has its own axis and buttons, so remapping them to the standard map is required. To overcome this issue and many others, there’s a GNOME library: libmanette, which is already used by WebKitGTK port.

Today’s status of the gamepad support is that it works but it’s not yet fully upstreamed.

  • merged ">">libwpe pull request.
  • cog pull request — there are two implementations: none and libmanette. None is just a dummy implementation which will ignore any request for a gamepad provider; it’s provided if libmanette is not available or if available libwpe hasn’t gamepad support.
  • WebKit pull request.

To prove you all that it works my exhibit A is this video, where I play asteroids in a RasberryPi 4 64 bits:

The image was done with buildroot, using its master branch (from a week ago) with a bunch of modifications, such as adding libmanette, a kernel patch for my gamepad device, kernel 5.15.55 and its corresponding firmware, etc.

By vjaquez at July 20, 2022 10:08 AM

July 19, 2022

Manuel Rego: Some highlights of the Web Engines Hackfest 2022

Igalia WebKit

Last month Igalia arranged a new edition of the Web Engines Hackfest in A Coruña (Galicia, Spain), where brought together more than 70 people working on the web platform during 2 days, with lots of discussions and conversations around different features.

This was my first onsite event since “before times”, it was amazing seeing people for real after such a long time, meeting again some old colleagues and also a bunch of people for the first time. Being an organizer of the event meant that they were very busy days for me, but it looks like people were happy with the result and enjoyed the event quite a lot.

This is a brief post about my personal highlights during the event.


During the hackfest we had an afternoon with 5 talks, the talks were live streamed on YouTube and people could follow them remotely and also ask questions through the event matrix channel.

Leo Balter's Talk

Leo Balter’s Talk

  • Leo Balter talked about how Salesforce participates on the web platform as partner, working with browsers and web standards.
    I really liked this talk, because it explains how companies that use the web platform, can collaborate and have a direct impact on the evolution of the web. And there are many ways to do that: reporting bugs that affect your company, explaining use cases that are important for you and the things you miss from the platform, providing feedback about different features, looking for partners to fix outstanding issues or add support for new stuff, etc.
    Igalia has been showing during the last decade that there’s a way to have an impact on the web platform outside of the big companies and browser vendors. Thanks to our position on the different communities, we can help companies to push features they’re interested in and that would benefit the entire web platform in the future.
  • Dominik Röttsches gave a talk about COLRv1 fonts giving details on Chromium implementation and the different open-source software components involved.
    This new font format allows to do really amazing things and Dominik showed how to create a Galician emoji font with popular things like Tower of Hercules or Polbo á feira. With some early demos on variable COLRv1 and the beginnings of the first Galician emoji font…
  • Daniel Minor explained the work done in Gecko and SpiderMonkey to refactor the internationalization system.
    Very interesting talk with lots of information and details about internationalization, going deep on text segmentation and how it works on different languages, and also introducing the ICU4X project.
  • Ada Rose Cannon did a great introduction to WebXR and Augmented Reality.
    Despite not being onsite, this was an awesome talk and the video was actually a very immersive experience. Ada explained many concepts and features around WebXR and Augmented Reality with a bunch of cool examples and demos.
  • Thomas Steiner talked about Project Fugu APIs that have been implemented in Chromium.
    Using the Web Engines Hackfest logo as example, he explained different new capabilities that Project Fugu is adding to the web through a real application called SVGcode.

It was a great set of talks, and you can now watch them all on YouTube. We hope you enjoy them if you haven’t the chance to watch them yet.

CSS & Interop 2022

On the CSS breakout session we talked about all the new big features that are arriving to browsers these days. Container Queries and :has being probably the most notable examples, features that people have been requesting since the early days and that are shipping into browsers this year.

Apart from that, we talked about the Interop 2022 effort. How the target areas to improve interoperability are defined, and how much it implies the work in some of them.

MathML & Fonts

Frédéric Wang did a nice presentation about MathML and all the work that has been done in the recent years. The feature is close to shipping in Chromium (modulo finding some solution regarding printing or waiting for LayoutNG to be ready to print), that will be a huge step forward for MathML becoming it a feature supported in the major browser engines.

Related to the MathML work there were some discussion around fonts, particularly OpenType MATH fonts, you can read Fred’s post for more details. There are some good news regarding this topic, new macOS version includes STIX Two Math installed by default, and there are ongoing conversations to get some OpenType MATH font by default in Android too.

MathML Breakout Session MathML Breakout Session

Accessibility & AOM

Valerie Young, who has recently started acting as co-chair of the ARIA Working Group, was leading a session around accessibility where we talked about ARIA and related things like AOM.

The Accessibility Object Model (AOM) is an effort that involves a lot of different things. In this session we talked about ARIA Attribute Reflection and the issues making accessible custom elements that use Shadow DOM, and that proposals like Cross-root ARIA Delegation are trying to solve.

Accessibility Breakout Session Accessibility Breakout Session


To close this post I’d like to say thank you to everyone that participated in the Web Engines Hackfest, without your presence this event wouldn’t make any sense. Also I’d like to thank the speakers for the great talks and the time devoted to work on them for this event. As usual big thanks to the sponsors Arm, Google and Igalia to make this event possible once more. And thanks again to Igalia for letting me be part of the event organization.

Web Engines Hackfest 2022 Sponsors - Host & Organizer: Igalia. Gold Sponsors: Arm, Google and Igalia. Other Sponsors: Arm (Lunch sponsor) Web Engines Hackfest 2022 Sponsors

July 19, 2022 10:00 PM

July 15, 2022

WPE WebKit Blog: WPE Graphics architecture

Igalia WebKit

Following the previous post in the series about WPE where we talked about the WPE components, this post will explain briefly the WPE graphics architecture, and how the engine is able to render HTML content into the display. If you haven’t read the previous entries in this blog post series about WPE, we recommend you to start with the first post in the series for an introduction, and then come back to this.

DOM + CSS = RenderTree

As the document is parsed, it will begin building the DOM tree and load-blocking CSS resources. At some point, possibly before the entire DOM tree is built, it’s time to draw things on the screen. The first step to render the content of a page is to perform what’s called the attachment, which is merging the DOM tree with the CSS rules, in order to create the RenderTree. This RenderTree is a collection of RenderObjects, structured into a tree, and each of these RenderObjects represent the elements in the DOM tree that have visual output. RenderObjects have the capability to render the associated DOM tree node into a surface by using the GraphicsContext class (in the case of WPE, this GraphicsContext uses Cairo to perform the rendering).

Once the RenderTree is created, the layout is performed, ensuring that each of the RenderObjects have their proper size and position set.

Going from source content to displayed content

It would be possible to render the content of the web page just traversing this RenderTree and painting each of the RenderObjects, but there would be problems when rendering elements that overlap each other, because the order of the elements in the RenderTree doesn’t necessarily match the order in which they must be painted in order to get the appropriate result. For example, an element with a big z-index value should be painted last, no matter its position in the RenderTree.

This is an example of how some HTML content is translated into the RenderTree (there are some RenderObjects missing here that are not relevant for the explanation).

RenderTree generated from example HTML


In order to ensure that the elements of the RenderTree are rendered in the appropriate order, the concept of RenderLayer is added. A RenderLayer represents a layer in the document containing some elements that have to be rendered at the same depth (even though this is not exactly the case, you can think of each RenderLayer as a group of RenderObjects that are at a certain z-index). Each RenderObject is associated to a RenderLayer either directly or indirectly via an ancestor RenderObject.

RenderLayers are grouped into a tree, which is called the RenderLayer tree, and RenderLayer children are sorted into two lists: those that are below the RenderLayer, and those that are above. With this we have a structure that has grouped all the RenderObjects that have to be rendered together: they will be on top of the content that has been rendered by the RenderLayers below this one, and below the content rendered by the RenderLayers over this one.

There are several conditions that can decide whether a RenderLayer is needed for some element, it doesn’t necessarily needs to be due to the usage of z-index. It can be required due to transparency, CSS filters, overflow, transformations, and so on.

Continuing with the example, these are RenderLayers that we would get for that HTML code:

RenderLayer tree generated from example HTML

We can see that there are four RenderLayers:

  • The root one, corresponding to the RenderView element. This is mandatory.
  • Another one corresponding to the first RenderBlock.
  • One corresponding to the RenderVideo element, because video elements always get their own RenderLayer.
  • One corresponding to the transformed RenderBlock.

RenderLayers have a paint method that is able to paint all the RenderObjects associated to the layer into a GraphicsContext (as mentioned, WPE uses Cairo for this). As in the previous case, it’s possible to paint the content of the page at this point just by traversing the RenderLayer tree and requesting the RenderLayers to paint their content, but in this case the result will be the correct one. Actually this is what WebKitGTK does when it’s run with accelerated compositing disabled.

Layer composition

While with the previous step we are already able to render the page contents, this approach is not very efficient, especially when the page contains animations, elements with transparency, etc. This is because in order to paint a single pixel, all the RenderLayers need to be traversed, and those that are contributing to that pixel need to be repainted (totally or partially), even if the content of those RenderLayers hasn’t changed. For example, think about an animation that’s moving an element. For each frame of that animation, the animated element needs to be repainted, but the area that was covered by the animated element in the last frame needs to be repainted as well. The same happens if there’s a translucent element on top of other content. If the translucent element changes, it needs to be repainted, but the content below the translucent element needs to be repainted as well because the blend needs to be performed again.

This would be much more efficient if the content that doesn’t change was somehow separated from the content that’s changing, and we could render those two types of content separately. This is where the composition stage comes into action.

The idea here is that we’re going to paint the RenderLayer contents into intermediate buffers, and then compose those buffers one on top of the other to get the final result. This last step is what we call composition. And it fixes the problems we mentioned with animations of transparency: animations don’t require repainting several RenderLayers. Actually moving an element just means painting one buffer with an offset during the composition. And for transparency, we just need to perform the new blending of the two buffers during the composition, but the RenderLayers of the content below the translucent element don’t need to be repainted.

Once we have the RenderLayer tree, we could just paint each RenderLayer in its own buffer in order to perform the composition. But this would be a waste of memory, as not every RenderLayer needs a buffer. We introduce here a new component, the GraphicsLayer.

GraphicsLayers are a structure used to group those RenderLayers that will render into the same buffer, and it will also contain all the information required to perform the composition of these buffers. A RenderLayer may have a GraphicsLayer associated to it if it requires its own buffer to render. Otherwise, it will render into an ancestor’s buffer (specifically, the first ancestor that has a GraphicsLayer). As usual, GraphicsLayers are structured into a tree.

This is how the example code would be translated into GraphicsLayers.

GraphicsLayer tree generated from example HTML

We can see that we have now three GraphicsLayers:

  • The root one, which is mandatory. It belongs to the RenderView element, but the first RenderBlock will render into this GraphicsLayer's buffer as well.
  • The one for the RenderVideo element, as videos are updated independently from the rest of the content.
  • The one for the transformed element, as the transformed elements are updated independently from the rest of the content.

With this structure, now we can render the intermediate buffers of the RenderView and the transformed RenderBlock, and we don’t need to update them any more. For each frame, those buffers will be composited together with the RenderVideo buffer. This RenderVideo will be updating its buffer whenever a new video frame arrives, but it won’t affect the content of the other GraphicsLayers.

So now we have successfully separated the content that is changing and needs to be updated from the content that remains constant and doesn’t need to be repainted anymore, just composited.

Accelerated compositing and threaded accelerated compositing

There’s something else that be done in order to increase the rendering performance, and it’s using the GPU to perform the composition. The GPU is highly optimized to perform operations like the buffer composition that we need to do, as well as handle 3D transforms, blending, etc. We just need to upload the buffers into textures and let the GPU handle the required operations. WPE does this though the usage of the EGL and GLES2 graphics APIs. In order to perform the composition, EGL is used to create a GLES2 EGLContext. Using that context, the intermediate buffers are uploaded to textures, and then those textures are positioned and composited according to their appropriate positions. This leverages the GPU for the composition work, leaving the CPU free to perform other tasks.

This is why this step is called accelerated compositing.

But there’s more.

Until this point, all the steps that are needed to render the content of the page are performed in the main thread. This means that while the main thread is rendering and compositing, it’s not able to perform other tasks, like run JS code.

WPE improves this by using a parallel thread whose only mission is to perform the composition. You can think of it as a thread that runs a loop that composites the incoming buffers using the GPU when there’s content to render. This is what we call threaded accelerated compositing.

This is specially useful when there’s a video or an animation running on the page:

  • If there’s a video running in the page, in the non-threaded case, for each video frame the main thread would need to get the frame and perform the composition with the rest of the page content. In the threaded case, the video element delivers the frames directly to the compositor thread, and requests a composition to be done, without the main thread being involved at all.

  • If there’s an animation, in the non-threaded case, for each frame of the animation the main thread would need to calculate the animation step and then perform the composition of the animated element with the rest of the page content. In the threaded case, the animation is passed to the compositor thread, and the animation steps are calculated on that thread, triggering a composition when needed. The main thread doesn’t need to do anything besides starting the animation.

It would take another post to explain in detail how the threaded accelerated composition is implemented on WPE, but if you’re curious about it, know that WPE uses an specialization of the GraphicsLayer called CoordinatedGraphicsLayer in order to implement this. You can use that as an starting point.

So this is the whole process that’s performed in WPE in order to display the content of a page. We hope it’s useful!


At Igalia we’re constantly evolving and improving WPE, and have ongoing efforts to improve the graphics architecture as well. Besides small optimizations and refactors here and there, the most important goals that we have are:

  • Add a GPU process. Currently the EGL and GLES2 operations are performed in the web process. As there can be several web processes running when several pages are open, this means the browser can be using a lot of EGL contexts in total, which is a waste of memory. Also, all these processes could potentially be affected by errors, leaks, etc., in the code that handles the GPU operations. The idea is to centralize all the GPU operations into a single process, the GPU one, so all the web processes will issue paint requests to the GPU process instead of painting their content themselves. This will reduce the memory usage and improve the software’s robustness.

  • Remove CPU rasterization and paint all the content with GLES2. Using the CPU to paint the layer contents with cairo is expensive, especially in platforms with slow CPUs, as embedded devices sometimes do. Our goal here is to completely remove the cairo rasterization and use GLES2 calls to render the 2D primitives. This will greatly improve the rendering performance.

  • Use ANGLE to perform WebGL operations. WPE currently implements the WebGL 1.0 specification through direct calls to GLES2 methods. We are changing this in order to perform the operations using ANGLE, which will allow WPE to support the WebGL 2.0 specification as well.

But what about the backends?

In the previous post there was a mention of backends that are used to integrate with the underlying platform. How is this relevant to the graphics architecture?

Backends have several missions when it comes to communicate with the platform, but regarding graphics, they have two functions to achieve:

  • Provide a platform dependent surface that WPE will render to. This can be a normal buffer, a Wayland buffer, a native window, or whatever, as long as the system EGL implementation allows creating an EGLContext to render to it.

  • Process WPE indications that a new frame has been rendered, performing whatever tasks are necessary to take that frame to the display. Also notify WPE when that frame was been displayed.

The most common example of this is a Wayland backend, which provides a buffer to WPE for rendering. When WPE has finished rendering the content, it notifies the backend, which sends the buffer to the Wayland compositor, and notifies back to WPE when the frame has been displayed.

So, whatever platform you want to run WPE on, you need to have a backend providing at least these capabilities.

Final thoughts

This was a brief overview of how WPE rendering works, and also what are the major improvements we’re trying to achieve at Igalia. We’re constantly putting in a lot of work to keep WPE the best web engine available for embedded devices.

If this post got you interested in collaborating with WPE development, or you are in need of a web engine to run on your embedded device, feel free to contact us. We’ll be pleased to help!

We also have open positions at the WebKit team at Igalia. If you’re motivated by this field and you’re interested in developing your career around it, you can apply here!

July 15, 2022 12:00 AM

July 01, 2022

Claudio Saavedra: Fri 2022/Jul/01

Igalia WebKit

I wrote a technical overview of the WebKit WPE project for the WPE WebKit blog, for those interested in WPE as a potential solution to the problem of browsers in embedded devices.

This article begins a series of technical writeups on the architecture of WPE, and we hope to publish during the rest of the year further articles breaking down different components of WebKit, including graphics and other subsystems, that will surely be of great help for those interested in getting more familiar with WebKit and its internals.

July 01, 2022 10:39 AM

WPE WebKit Blog: An overview of the WPE WebKit project

Igalia WebKit

In the previous post in this series, we explained that WPE is a WebKit port optimized for embedded devices. In this post, we’ll dive into a more technical overview of the different components of WPE, WebKit, and how they all fit together. If you’re still wondering what a web engine is or how WPE came to be, we recommend you to go back to the first post in the series and then come back here.

WebKit architecture in a nutshell

To understand what makes WPE special, we first need to have a basic understanding of the architecture of WebKit itself, and how it ties together a given architecture/platform and a user-facing web browser.

WebKit, the engine, is split into different components that encapsulate its different parts. At the heart of it is WebCore. As the name suggests, this contains the core features of the engine (rendering, layout, platform access, HTML and DOM support, the graphics layer, etc). However, some of these ultimately depend heavily on the OS and underlying software platform in order to function. For example: how do we actually do any I/O on different platforms? How do we render onscreen? What’s the underlying multimedia platform and how does it decode media and play it?

WebCore handles the multitude of potential answers to these questions by abstracting the implementation of each component and allowing port developers to fill the gaps for each supported platforms. For example, for rendering on Mac, Cocoa APIs implement the graphics APIs needed. On Linux, this can be done through different implementations via Wayland, Vulkan, etc. For networking I/O on Mac, the networking APIs in the Foundation framework are used. On Linux, libsoup fills that gap, and so on.

On the opposite side, for browser implementors to be able to write a browser using WebKit, an API is needed. WebKit, after all, is a library. WebKit ports, besides providing the platform support described above, also provide APIs that suit the target environments: The Apple ports provide Objective-C APIs (which are then used to write Safari and the iOS browsers, for instance), while the GTK+ port provides a GObject-based APIs for Linux (that are used in Epiphany, the GNOME browser, and other GNOME applications that rely on WebKit to render HTML). All of these APIs are built on top of an internal, middle-man, C API that is meant to make it easy for each port to provide a high-level API for browser developers.

With all this in place, it would seem that it shouldn’t be so difficult for any vendor trying to reuse WebKit in a new platform to support new hardware and implement a browser, right? All that you need to do is:

  • Implement backends that integrate with your hardware platform: for multimedia, IO, OS support, networking, graphics, etc.
  • Write an API that you can use to plug the engine into your browser.
  • Maintain the changes needed off-tree, that is, outside the source code tree of WebKit.
  • Keep your implementation up-to-date with the many changes that happen in the WebKit codebase on a daily basis, so that you can update WebKit regularly and take advantage of the many bug fixes, improvements, and new features that land on WebKit continuously.

Does that sound easy? No, it’s not easy at all! In fact, implementation of ports in this fashion is strongly discouraged and vendors who have tried this approach in the past have had to do a huge effort just to play catch-up with the fast-paced development of WebKit. This is where WPE comes to the rescue.

Simplifying browsers development in the diverse embedded world

To simplify the task of porting WebKit to different platforms, Igalia started working on a platform-agnostic, Linux-based, and full-featured port of WebKit. This port relies on existing and mature platform backends for everything that can be easily reused across platforms: multimedia, networking, and I/O, which are already present in-tree and are used by Linux ports, like the GTK one. For the areas that are most likely to require hardware-specific support (that is, graphics and input), WPE abstracts the implementation so that it can be more easily provided out of tree, allowing implementors to avoid having to deal with the WebKit internals more than what’s strictly needed.

Additionally, WPE provides a high-level API that can be used to implement actual browsers. This API is very similar to the WebKitGTK API, making it easy for developers already familiar with the latter to start working with WPE. The cog library also serves as a wrapper around WPE to make it easier still. Once WPE was mature enough, it was accepted by Apple as an official WebKit port, meaning that the port lives now in-tree and takes immediate advantage of the many improvements that land on the WebKit repository on a daily basis.

How does WPE integrate with WebKit?

A diagram of the WPE WebKit architecture

The WPE port has several components. Some are in-tree (that is, are a part of WebKit itself), while others are out-of-tree. Let’s examine those components and how they relate to each other, from top to bottom:

  • The Cog library. While not an integral part of WPE, libcog is a shell library that simplifies the task of writing a WPE browser from the scratch, by providing common functionality and helper APIs. This component also includes the cog browser, a simple WPE browser built on top of libcog that can be used as a reference or a starting point for the development of a new browser for a specific use case.
  • The WPE WebKit API: the entry point for browser developers to the WebKit engine, provides a comprehensive GObject/C API. The cog library uses this API extensively and we recommend relying on it, but for more specific needs and more fine-tuning of the engine, working directly with the WebKit API can be often necessary. The API is stable and easy to use, especially, and for those familiar with the GTK/GNOME platform.
  • WPE’s WebCore implementation: This part, internal to WebKit, implements an abstraction of the graphics and input layers of WebKit. This implementation relies on the libwpe library to provide the functionality required in an abstract way. Thanks to the architecture of WPE, implementors don’t need to bother with the complexities of WebCore and WebKit internals.
  • The libwpe library. This is an out-of-tree library that provides the API required by the WPE port in a generic way to implement the graphical and input backends. Specific functionality for a concrete platform is not provided, but the library relies on the existence of a backend implementation, as is described next.
  • Finally, a WPE backend implementation. This is where all the platform-specific code lives. Backends are loadable modules that can be chosen depending on the underlying hardware. These should provide access to graphics and input depending on the specific architecture, platform, and operating system requirements. As a reference, WPEBackend-fdo is a freedesktop.org-based backend, which uses Wayland and freekdesktop.org technologies, and is supported for several architectures, including NXP and Broadcom chipsets, like the Raspberry Pi, and also regular PC architectures, easing testing and development.

An implementor interested in building a browser in a new architecture only needs to focus on the development of the last component – a WPE backend. Having a backend, starting the development of a WebKit-powered browser is already much easier than it ever was!

For a more detailed description of the architecture of WPE and WebKit, check this article on the architecture of WPE.

OK, sounds interesting, how do I get my hands dirty?

If you have made it this far, you should give WPE a try!

We have listed several on the exploring WPE page. From there, you will see that depending on how interested you are in the project, your background, and what you’d like to do with it, there are different ways!

It can be as easy as installing WPE directly from the most popular Linux distributions or downloading and flashing prebuilt images for the Raspberry Pi. There are easy and flexible options like Flatpak or Balena, which you can dig into to learn more. If you want to build WPE yourself, you can use Yocto and if you’d like to contribute—that’s very welcome!

Happy hacking!

July 01, 2022 12:00 AM

June 29, 2022

Patrick Griffis: WebExtension Support in Epiphany

Igalia WebKit

I’m excited to help bring WebExtensions to Epiphany (GNOME Web) thanks to investment from my employer Igalia. In this post, I’ll go over a summary of how extensions work and give details on what Epiphany supports.

Web browsers have supported extensions in some form for decades. They allow the creation of features that would otherwise be part of a browser but can be authored and experimented with more easily. They’ve helped develop and popularize ideas like ad blocking, password management, and reader modes. Sometimes, as in very popular cases like these, browsers themselves then begin trying to apply lessons upstream.

Toward universal support

For most of this history, web extensions have used incompatible browser-specific APIs. This began to change in 2015 with Firefox adopting an API similar to Chrome’s. In 2020, Safari also followed suit. We now have the foundations of an ecosystem-wide solution.

“The foundations of” is an important thing to understand: There are still plenty of existing extensions built with browser-specific APIs and this doesn’t magically make them all portable. It does, however, provide a way towards making portable extensions. In some cases, existing extensions might just need some porting. In other cases, they may utilize features that aren’t entirely universal yet (or, may never be).

Bringing Extensions to Epiphany

With version 43.alpha Epiphany users can begin to take advantage of some of the same powerful and portable extensions described above. Note that there are quite a few APIs that power this and with this release we’ve covered a meaningful segment of them but not all (details below). Over time our API coverage and interoperability will continue to grow.

What WebExtensions can do: Technical Details

At a high level, WebExtensions allow a private privileged web page to run in the browser. This is an invisible Background Page that has access to a browser JavaScript API. This API, given permission, can interact with browser tabs, cookies, downloads, bookmarks, and more.

Along with the invisible background page, it gives a few options to show a UI to the user. One such method is a Browser Action which is shown as a button in the browser’s toolbar that can popup an HTML view for the user to interact with. Another is an Options Page dedicated to configuring the extension.

Lastly, an extension can inject JavaScript directly into any website it has permissions to via Content Scripts. These scripts are given full access to the DOM of any web page they run in. However content scripts don’t have access to the majority of the browser API but, along with the above pages, it has the ability to send and receive custom JSON messages to all pages within an extension.

Example usage

For a real-world example, I use Bitwarden as my password manager which I’ll simplify how it roughly functions. Firstly there is a Background Page that does account management for your user. It has a Popup that the user can trigger to interface with your account, passwords, and options. Finally, it also injects Content Scripts into every website you open.

The Content Script can detect all input fields and then wait for a message to autofill information into them. The Popup can request the details of the active tab and, upon you selecting an account, send a message to the Content Script to fill this information. This flow does function in Epiphany now but there are still some issues to iron out for Bitwarden.

Epiphany’s current support

Epiphany 43.alpha supports the basic structure described above. We are currently modeling our behavior after Firefox’s ManifestV2 API which includes compatibility with Chrome extensions where possible. Supporting ManifestV3 is planned alongside V2 in the future.

As of today, we support the majority of:

  • alarms - Scheduling of events to trigger at specific dates or times.
  • commands - Keyboard shortcuts.
  • cookies - Management and querying of browser cookies.
  • downloads - Ability to start and manage downloads.
  • menus - Creation of context menu items.
  • notifications - Ability to show desktop notifications.
  • storage - Storage of extension private settings.
  • tabs - Control and monitoring of browser tabs, including creating, closing, etc.
  • windows - Control and monitoring of browser windows.

A notable missing API is webRequest which is commonly used by blocking extensions such as uBlock Origin or Privacy Badger. I would like to implement this API at some point however it requires WebKitGTK improvements.

For specific API details please see Epiphany’s documentation.

What this means today is that users of Epiphany can write powerful extensions using a well-documented and commonly used format and API. What this does not mean is that most extensions for other browsers will just work out of the box, at least not yet. Cross-browser extensions are possible but they will have to only require the subset of APIs and behaviors Epiphany currently supports.

How to install extensions

This support is still considered experimental so do understand this may lead to crashes or other unwanted behavior. Also please report issues you find to Epiphany rather than to extensions.

You can install the development release and test it like so:

flatpak remote-add --if-not-exists gnome-nightly https://nightly.gnome.org/gnome-nightly.flatpakrepo
flatpak install gnome-nightly org.gnome.Epiphany.Devel
flatpak run --command=gsettings org.gnome.Epiphany.Devel set org.gnome.Epiphany.web:/org/gnome/epiphany/web/ enable-webextensions true

You will now see Extensions in Epiphany’s menu and if you run it from the terminal it will print out any message logged by extensions for debugging. You can download extensions most easily from Mozilla’s website.

June 29, 2022 04:00 AM

June 20, 2022

Frédéric Wang: Update on OpenType MATH fonts

Igalia WebKit

I mentioned in a previous post that Igalia organized the Web Engines Hackfest 2022 last week. As usual, fonts were one of the topic discussed. Dominik Röttsches presented COLRv1 color vector fonts in Chrome and OSS (transcript) and we also settled a breakout session on Tuesday morning. Because one issue raised was the availability of OpenType MATH fonts on operating systems, I believe it’s worth giving an update on the latest status…

There are only a few fonts with an OpenType MATH table. Such fonts can be used for math layout e.g. modern TeX engines to render LaTeX, Microsoft Office to render OMML or Web engines to render MathML. Three of such fonts are interesting to consider, so I’m providing a quick overview together with screenshots generated by XeTeX from the LaTeX formula $${\sqrt{\sum_{n=1}^\infty {\frac{10}{n^4}}}} = {\int_0^\infty \frac{2x dx}{e^x-1}} = \frac{\pi^2}{3} \in {\mathbb R}$$:

Recently, Igalia has been in touch with Myles C. Maxfield who has helped with internal discussion at Apple regarding inclusion of STIX Two Math in the list of fonts on macOS. Last week he came back to us announcing it’s now the case on all the betas of macOS 13 Ventura 🎉 ! I just tested it this morning and indeed STIX Two Math is now showing up as expected in the Font Book. Here is the rendering of the last slide of my hackfest presentation in Safari 16.0:

Screenshot of a math formula rendered with STIX Two Math by Safari

Obviously, this is a good news for Chromium and Firefox too. For the former, we are preparing our MathML intent-to-ship and having decent rendering on macOS by default is important. As for the latter, we could in the future finally get rid of hardcoded tables to support the deprecated STIXGeneral set.

Another interesting platform to consider for Chromium is Android. Last week, there has been new activity on the Noto fonts bug and answers seem more encouraging now… So let’s hope we can get a proper math font on Android soon!

Finally, I’m not exactly sure about the situation on Linux and it may be different for the various distributions. STIX and Latin Modern should generally be available as system packages that can be easily installed. It would be nicer if they were pre-installed by default though…

June 20, 2022 12:00 AM