June 21, 2022

Release Notes for Safari Technology Preview 147 with Safari 16 Features

Surfin’ Safari

Safari Technology Preview Release 147 is now available for download for macOS Monterey 12.3 or later and macOS Ventura beta. Updates to Safari Technology Preview are no longer available for macOS Big Sur. 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.

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

Many of the new Safari 16 features are now available in Safari Technology Preview 147:

Live Text. Select and interact with text in videos or translate text in images on the web in macOS Ventura beta on Apple Silicon-based Macs.

Web technologies. Experience and test the HTML, CSS, JavaScript, and other web technologies that are available in Safari 16 Beta and included in previous Safari Technology Preview releases.

Web Push. Send notifications to people who opt-in on your website or web app with Safari Technology Preview on macOS Ventura beta.

Passkeys. Preview the new type of phishing-resistant credential that makes signing in to websites safer and easier. Available through Safari’s WebAuthn platform authenticator. To learn more about passkeys, see Meet passkeys.

Improved Safari Web Extensions. Test out API improvements including the ability to open a Safari Web Extension popover programmatically.

Web Inspector Extensions. Build custom tooling or convert existing developer tools extensions to use in Web Inspector.

Flexbox Inspector. Use the new visualization overlay in Web Inspector to help you more quickly and easily understand the layout of elements with Flexbox. It marks both the free space and gaps between flex items to reveal how they affect the result.

If you see bugs or unexpected behavior with the interface of Safari Technology Preview, please file feedback with Apple’s Feedback Assistant. If you come across an implementation bug in web technology, Web Inspector, or have a request, please file a ticket on the WebKit bug tracker.

June 21, 2022 08:40 PM

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

June 07, 2022

Meet Web Push

Surfin’ Safari

a push notification on macOS

Websites have many reasons to notify their users of time-sensitive or high-priority events, even if the user does not currently have the site open. This feature is called Web Push, and is enabled by the W3C standards for Push API, Notifications API, and Service Workers, all working together. WebKit now supports the relevant parts of those standards to enable Web Push.

Apple has made changes to macOS that deeply integrate with WebKit’s support to provide a great user experience, and we’re excited to announce that Web Push is supported in Safari 16 on macOS Ventura.

Keep an eye out for Web Push on iOS and iPadOS in 2023.

As long as you’ve coded your web application to the standards you will be able to reach Safari 16 users on macOS Ventura. You don’t need to join the Apple Developer Program to send Web Push notifications.

If you exclude Safari through browser detection, now would be a great time to switch to feature detection, which lets you take advantage of new features as soon as they’re supported. Additionally, if you tightly manage push end points on your server, be sure to allow URLs from any subdomain of push.apple.com.

All of this and more is covered in Meet Web Push (15 minute video) at WWDC22.

Standards overview

Most features of the web platform are described in a single web standard. Web Push is an exception, with multiple standards describing implementation requirements.

There are many resources on the web to help web application authors get up and running with these standards. But to further cover how WebKit’s support works, it is useful to cover the web standards at a high level.

The Push API standard is the most directly relevant to start with. It describes the JavaScript interface that allows a website to register a push subscription. That subscription enables sending push messages to your user’s browser using a push service.

The ServiceWorker API is extended to support these push messages. Once a push message is received from a domain, that domain’s registered service worker script receives an event representing the push message.

The Notifications API is extended to allow service worker scripts to post a notification even without an open browser tab.

When a web application registers a push subscription, they promise that pushes will always be user visible. When the service worker handles a push message, it is required to use the Notifications API to display a user visible notification. Finally, when the user activates that notification, the service worker is sent an event representing the notification activation.

Power and privacy

Both the WebKit open source project and Apple treat privacy as a fundamental human right. As with other privileged features of the web platform, requesting a push subscription requires an explicit user gesture. It also requires you set the userVisibleOnly flag to true, and fulfill that promise by always showing a notification in response to a push message.

The Web Push API is not an invitation for silent background runtime, as that would both violate a user’s trust and impact a user’s battery life.

Violations of the userVisibleOnly promise will result in a push subscription being revoked.

A little bit about WebKit

Some of you are interested in the implementation details of Web Push in WebKit.

One goal of the WebKit open source project is to make it easy to deliver a modern browser engine that integrates well with any modern platform.

Many web-facing features are implemented entirely within WebKit, and the maintainers of a given WebKit port do not have to do any additional work to add support on their platforms.

Occasionally features require relatively deep integration with a platform. That means a WebKit port needs to write a lot of custom code inside WebKit or integrate with platform specific libraries. For example, to support the HTML <audio> and <video> elements, Apple’s port leverages Apple’s Core Media framework, whereas the GTK port uses the GStreamer project.

A feature might also require deep enough customization on a per-Application basis that WebKit can’t do the work itself.

For example web content might call window.alert(). In a general purpose web browser like Safari, the browser wants to control the presentation of the alert itself. But an e-book reader that displays web content might want to suppress alerts altogether.

From WebKit’s perspective, supporting Web Push requires deep per-platform and per-application customization.

Web Push in Apple’s WebKit port

Apple’s WebKit port includes a new daemon called webpushd. It is installed as a LaunchAgent in macOS Ventura to support Web Push. This daemon takes push subscription requests from webpages in Safari 16 and turns them into actual push subscriptions with the Apple Push Notification service.

Incoming pushes to the system are delivered to webpushd, which then wakes the appropriate application to hand off any pending push messages to a service worker.

The promise of Web Push is that you can reach your users even if they don’t have your website open in a browser tab. Because of how we integrated webpushd with built-in push support in macOS Ventura, Safari doesn’t even need to be running for a push message to be delivered.

The requirement to display user visible notifications is another platform specific point. Different browsers might implement Notifications API support in different ways. Safari has always supported local notifications by relying on the macOS Notification Center and has made additional changes to handle activating these notifications when Safari is not running.

Integrating Apple Push Notification service’s new Web Push support with webpushd and supporting notifications while Safari isn’t running are both system-level changes, making our implementation require macOS Ventura and later.

More resources

Apple has a few more resources to learn more about Web Push support in Safari 16 on macOS Ventura:

MDN has some great resources on Web Push. You should start out with Web Push API Notifications best practices.

And of course you can always reference the W3C standards directly:

June 07, 2022 03:00 PM

June 06, 2022

Web technology sessions at WWDC22

Surfin’ Safari

WWDC22 is here, and with it, a host of announcements of new web technology shipping in WebKit on macOS, iOS and iPadOS, including advancements in privacy and security – plus new features for Safari, Web Inspector and Safari Web Extensions. Much of the news was announced on Monday during this year’s keynote, is listed in the Safari 16 Beta Release Notes, and is described in News from WWDC: WebKit Features in Safari 16 Beta. But that’s not all.

Ten sessions at WWDC22 go into greater detail, demonstrating new technology directly relevant to web developers. New videos will be released each day this week. You can watch them on the WWDC22 website, or in the Apple Developer app for macOS, iOS, iPadOS, and tvOS.

Be part of the conversation during WWDC on the Apple Developer Forums, or share your thoughts with @WebKit on Twitter.

Tuesday, June 7

What’s new in Safari and WebKit

Explore the latest features in Safari and WebKit and learn how you can make better and more powerful websites. We’ll take you on a tour through the latest updates to HTML, CSS enhancements, Web Inspector tooling, Web APIs, and more.

Watch What’s new in Safari and WebKit starting on Tuesday, June 7.

Meet Web Push for Safari

Bring better notifications to your websites and web apps in Safari on macOS with Web Push. We’ll show you how you can remotely send notifications to people through the web standards-based combination of Push API, Notifications API, and Service Workers.

Watch Meet Web Push for Safari starting on Tuesday, June 7.

Meet Passkeys

It’s time for a security upgrade: Learn how to add support for passkeys to create a quick and easy sign in experience for people, all while offering a radical increase to account security. Passkeys are simple and strong credentials built to eliminate phishing attacks. We’ll share how passkeys are designed with security in mind, show you how people will use them, go over how to integrate passkeys in your log in flow, and explore the platform and web APIs you need to adopt this feature.

Watch Meet Passkeys starting on Tuesday, June 7.

Wednesday, June 8

What’s new in Safari Web Extensions

Learn how you can use the latest improvements to Safari Web Extensions to create even better experiences for people browsing the web. We’ll show you how to upgrade to manifest version 3, adopt the latest APIs for Web Extensions, and sync extensions across devices.

Watch What’s new in Safari Web Extensions starting on Wednesday, June 8.

Replace CAPTCHAs with Private Access Tokens

Don’t be captured by CAPTCHAs! Private Access Tokens are a powerful alternative that help you identify HTTP requests from legitimate devices and people without compromising their identity or personal information. We’ll show you how your app and server can take advantage of this tool to add confidence to your online transactions and preserve privacy.

Watch Replace CAPTCHAs with Private Access Tokens starting on Wednesday, June 8.

Thursday, June 9

Create Safari Web Inspector Extensions

Learn how to add your own tools directly into Web Inspector using the latest Web Extensions APIs. We’ll show you how to create your own tab in Web Inspector, evaluate JavaScript in the inspected page, and use the result to help you troubleshoot and identify potential problems.

Watch Create Safari Web Inspector Extensions starting on Thursday, June 9.

What’s new in web accessibility

Discover techniques for building rich, accessible web apps with custom controls, SSML, and the dialog element. We’ll discuss different assistive technologies and help you learn how to use them when testing the accessibility of your web apps.

Watch What’s new in web accessibility starting on Thursday, June 9.

Enhance your Sign in with Apple experience

Learn how you can provide safe and fast authentication in your app using Sign in with Apple. We’ll show you how you can upgrade password-based accounts into secure, single-tap login credentials, and explore how you can seamlessly handle changes to user sessions in your app. We’ll also help you take advantage of Sign In with Apple across the web and on other platforms. To get the most out of this session, we recommend having familiarity with Sign In with Apple and REST API. We’d also recommend having a basic understanding of JavaScript.

Watch Enhance your Sign in with Apple experience starting on Thursday, June 9.

Friday, June 10

What’s new in WKWebView

Explore the latest updates to WKWebView, our framework for incorporating web content into your app’s interface. We’ll show you how to use the JavaScript fullscreen API, explore CSS viewport units, and learn more about find interactions. We’ll also take you through refinements to content blocking controls, embedding encrypted media, and using the Web Inspector.

Watch What’s new in WKWebView starting on Friday, June 10.

Improve DNS security for apps and servers

Discover the latest ways to ensure that DNS — the foundation of internet addressing — is secure within your app. Learn how to authenticate DNS responses in your app with DNSSEC and enable DNS encryption automatically with Discovery of Designated Resolvers (DDR).

Watch Improve DNS security for apps and servers starting on Friday, June 10.

June 06, 2022 09:30 PM

News from WWDC22: WebKit Features in Safari 16 Beta

Surfin’ Safari

WebKit has had a big year, with over 162 new features and improvements shipping in WebKit browsers — including Safari 15.2, Safari 15.4, and Safari 15.5. Features from earlier this year include dialog element, lazy loading, inert, :has() pseudo-class, new viewport units, Cascade Layers, focus visible, accent color, appearance, font palettes for color fonts, BroadcastChannel, Web Locks API, File System Access API, enhancements to WebAssembly, support for Display-P3 in canvas, additions to COOP and COEP, improved CSS autocompletion and new CSS variable tooling in Web Inspector, and much, much more.

We’re excited to announce today the major web technologies shipping in Safari 16 beta.

If you are an Apple Developer program member, you can test Safari 16 today by installing the developer betas of macOS Ventura, iOS or iPadOS 16.

Web Inspector Extensions

Safari 16 brings support for Web Inspector Extensions, so you can enhance Safari’s built-in browser developer tools. This can be especially helpful when using powerful third-party frameworks and services — perhaps your team uses React, Angular, Vue, or Ember; or maybe a popular test suite or another developer service. Now with Safari Web Inspector Extensions, you’ll be able install developer tools extensions from those frameworks and services to make your job developing with them faster and easier. Look for such extensions in the App Store this fall.

Extensions for popular third-party frameworks and services aren’t the only exciting use of Web Inspector Extensions. Often, a small enhancement to developer tools can make a huge difference in workflow. You might be the best person to imagine and create such an extension. Web extensions are made from HTML, CSS, and JS — a perfect project for web developers. To learn the basics of building a Safari Web Extension, either from a quick-start template or by converting an existing extension to work with Safari, along with how to package it for the App Store, watch the Tech Talk Build and deploy Safari Extensions.

Safari Web Inspector Extensions are made with the same JavaScript APIs as the developer tools extensions in other browsers. This makes it possible for the creators of your favorite developer tools extensions to easily port them to Safari.

Web Inspector Extensions join other improvements to Safari Web Extensions, including the ability to sync which extensions are enabled across iOS, iPadOS, and macOS.

Container Queries

After years of collaboration by engineers working on various browsers to figure out whether or not they would even be possible, Container Queries are finally here. 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. They’ll be an invaluable tool for creating reusable components in a design system.

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. Other ideas for style queries are also being discussed as part of Container Queries as something for the future.

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.

unit relative to
cqw 1% of a query container’s width
cqh 1% of a query container’s height
cqi 1% of a query container’s inline size
cqb 1% of a query container’s block size
cqmin The smaller value of cqi or cqb
cqmax The larger value of cqi or cqb

Web Push for macOS

a push notification on macOS

Web Push is coming to Safari 16 on macOS Ventura. This lets you remotely send notifications to users of your websites and web apps — and deliver those notifications even when Safari isn’t running. It uses the same combination of web standards you may be familiar with from other browsers: Push API and Notifications API, along with Service Worker.

Users 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 will be able to view and manage notifications in Notifications Center, and 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. Although, 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 Macs and iOS devices. If you tightly manage push endpoints on your server, be sure you allow URLs from any subdomain of push.apple.com. You do not need to be an Apple Developer Program member.

And look for Web Push for iOS and iPadOS in 2023.


CSS Grid shipped over five years ago, in March 2017, revolutionizing 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.

Flexbox Inspector

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

Overlays for Flexbox containers make it easier to visualize the effects your CSS has on Flexbox containers. The new overlay helps you visually distinguish between free space and gaps. It also shows the bounds of items revealing how they are distributed both on the main axis and cross axis of your Flexbox containers. The toggle-able “Order Numbers” option helps show the layout order of elements in the container, which can be helpful when using the order CSS property for items. And, just like our overlays for Grid last year, you can turn on as many Flexbox overlays as you need, without impacting performance.

Accessibility Improvements

Safari 16 introduces a re-architecture of WebKit’s accessibility support on macOS that delivers improved performance and increased 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.

This release also greatly improves accessibility support for elements with display:contents by ensuring they are properly represented in the accessibility tree.

Animation Improvements

CSS Offset Path (also known as Motion Path) provides web developers a way to animate things along a custom path of any shape. The offset-path property let’s 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.

With Safari 16, you can now animate a CSS Grid. That means changes in the size of rows and/or columns can be animated, opening up a whole new set of possibilities for movement on a page.

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 — see the full list in the Safari Technology Preview 143 release notes.

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 Worker

Just when you thought there weren’t enough different kinds of workers, there’s a new type of worker in Safari — Shared Worker. Like Service Worker, a Shared Worker runs 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, and all the tabs open to the same domain can share the same Shared Worker. So, if you want to do something like have one WebSocket connection open to a server that communicates on behalf of multiple tabs, try out Shared Worker.

And more

There’s much more, including fixes and improvements to form controls as well as support for <form>.requestSubmit() and the showPicker() method for HTML input elements. Plus support for Shadow Realms, as well as support for the worker-src Content Security Policy directive.

To learn more about what’s in Safari 16 for web developers, including a list of bug fixes, read the Safari 16 beta release notes.


We love hearing from you. Send a tweet to @webkit, @jensimmons, or @jonathandavis to share your thoughts on this release. What technology from Safari 16 are you most excited about? What features or fixes do you want to see next? 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.

June 06, 2022 07:00 PM

May 31, 2022

Happy birthday, WPE WebKit!

Surfin’ Safari

WebKit is the purring engine of Safari, it’s true, but it has numerous ports and many contributors. These ports are used for all sorts of things, from powering Sony PlayStations to driving millions of embedded devices all over the world. Embedded use cases like smart home appliances, digital signage, and automotive displays are largely possible thanks to WPE WebKit, the official port of WebKit specifically optimized for embedded devices. That port is maintained by Igalia, an open-source consultancy headquartered in Spain. Their work on WPE WebKit goes a long way toward explaining why Igalia is the most prolific external contributor to the WebKit codebase, accounting for almost 17% of all commits in 2021.

Igalia recently celebrated the fifth birthday of WPE WebKit with a blog post on their WPE web site, covering its evolution from a fork of WebKitGTK to a Wayland-based renderer to a framework compatible with almost any rendering backend before its public launch on 21 April 2017. They also promise a series of articles to come profiling the people who work on WPE WebKit and talking about some of the technical aspects of advancing such a project. You can read more about it in their post. Happy 5th birthday, WPE!

May 31, 2022 04:00 PM

May 25, 2022

Release Notes for Safari Technology Preview 146

Surfin’ Safari

Safari Technology Preview Release 146 is now available for download for macOS Big Sur and of macOS Monterey 12.3 or later. If you already have Safari Technology Preview installed, you can update in the Software Update pane of System Preferences on macOS.

This release covers WebKit revisions 293023-293745.

Note: Tab Groups do not sync in this release.

Web Inspector

  • Elements Tab
    • Fixed hovering over a node in the Layout panel to now highlight it on the page (r293189)
    • Fixed <button> and <select> elements appearing in the list of Flex containers (r293565)
  • Sources Tab
    • Added ability for local overrides to entirely block a request (r293409)
  • Timelines Tab
    • Fixed importing a timeline leaves the overview non-scrollable/non-zoomable until windows is resized (r293727)
  • Graphics Tab
    • Improved display of GLenums and GLbitfield in WebGL canvas recordings (r293541, r293706)


  • Fixed ::first-letter when used in shadow content (r293497)
  • Fixed revert-layer in shadow tree contexts (r293725)
  • Fixed cascade rollback for deferred properties (r293485)
  • Related properties sharing a computed value (r293602)
  • Made word-wrap CSS property an alias of overflow-wrap (r293521)
  • Made -webkit-transform-style an alias of transform-style (r293524)
  • Unprefixed the -webkit-user-select CSS property (r293089)
  • Removed some unimplemented -webkit-appearance keywords (r293511)
  • Updated the user-agent stylesheet to include table { text-indent: initial } to conform with the HTML standard (r293322)


  • Added ISO8601 based Temporal.PlainDate getters behind a flag (r293708)
  • Enabled change-array-by-copy (r293348)
  • Fixed WASM to throw consistent exceptions for memory.init and memory.copy (r293252)
  • Fixed JS stack traces to report the correct column number in CR-LF line ending style HTML files (r293672)


  • Fixed setting the correct selection range for textarea when updating the default value (r293673)
  • Fixed constructed FormData object to not contain an entry for the submit button that was used to submit the form (r293444)
  • Fixed user-select: none to have no effect on editability (r293028)


  • Fixed the media controls overflow button flickering sometimes (r293658)
  • Fixed HTMLMediaElement getting multiple interruptions for invisible autoplay (r293609)
  • Fixed MediaSession.setPositionState() (r293488)


  • Fixed the quirk to only stretch the percent height body when it is the document element’s child (r293647)
  • Made contain: layout on the html element change position: fixed behavior (r293209)


  • Fixed smooth scrolling behavior when focusing a scroll container before beginning to scroll (r293260)


  • Fixed <link rel=preconnect> always sending credentials to a different origin, ignoring crossorigin=anonymous (r293503)

Shared Worker

  • Fixed resuming a suspended remote shared worker when a new SharedWorker object is created (r293173)

Service Worker

  • Fixed Service Worker loads to not expose some ResourceTiming information (r293418)
  • Fixed Service Worker update to refresh imported scripts in addition to the main script (r293506)
  • Fixed Service Worker to not intercept embed- or object-related loads (r293417)
  • Fixed ServiceWorkerRegistration updates to fail if called from an installing Service Worker context (r293719)
  • Fixed URL.createObjectURL to not be exposed in Service Worker contexts (r293717)


  • Fixed Web Locks held in a Worker not getting released on page refresh or exit (r293329)


  • Changed to not expose ARIA roleDescription value on “generic” elements (e.g. div and span) unless an explicit role value is also defined (r293345)


  • Fixed mixing strict-dynamic and unsafe-inline Content Security Policies (r293603)
  • Set top origin of CORS preflight requests (r293591)

May 25, 2022 08:43 PM

Customizing Color Fonts on the Web

Surfin’ Safari

Color fonts provide a way to add richness to your designs without sacrificing any of the many benefits of using plain 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.

WebKit now supports CSS @font-palette-values. With this at-rule, you can access predefined color palettes provided by the font designer, and you can customize them in order to make the color font a perfect match for the colors in your designs.

ONCE upon a time in the middle of winter, when the flakes of snow were falling like feathers from the clouds, a Queen sat at her palace window, which had an ebony black frame, stitching her husband’s shirts. While she was thus engaged and looking out at the snow she pricked her finger, and three drops of blood fell upon the snow. Now the red looked so well upon the white that she thought to herself, “Oh, that I had a child as white as this snow, as red as this blood, and as black as the wood of this frame!” Soon afterwards a little daughter came to her, who was as white as snow, and with cheeks as red as blood, and with hair as black as ebony, and from this she was named “Snow-White.” And at the same time her mother died.

THIS answer so angered the Queen that she became quite yellow with envy. From that hour, whenever she saw Snow-White, her heart was hardened against her, and she hated the little girl. Her envy and jealousy increased so that she had no rest day or night, and she said to a Huntsman, “Take the child away into the forest. I will never look upon her again. You must kill her, and bring me her heart and tongue for a token.” The Huntsman listened and took the maiden away, but when he drew out his knife to kill her, she began to cry, saying, “Ah, dear Huntsman, give me my life! I will run into the wild forest, and never come home again.”

You can try out @font-palette-values today in Safari 15.4 or later.

Color palettes work great in WebKit with the COLRv0 font file format, and we are investigating other formats like SVG.

Background on the font above

The font in this demo is a revival of Bradley, a “fairytale blackletter” originally released in 1895. The typeface came with a special set of ornate Initial caps meant for drop caps (see also ::initial-letter) and other titling uses, which David digitized this past December for his Font of the Month Club, just in time for the holidays.

Each glyph is made up of a handful of distinct layers (letterform, backdrop, ornate linework, letter outline, and border). Making the layers different-yet-coordinated colors adds depth to the design, taking it beyond what a simple foreground/background can provide. It felt like the perfect use case for a color font with multiple color palettes, and a unique opportunity for a 127-year-old font to play a small part in an emerging font technology.

Palettes in CSS

Fonts can define one or more of their own color palettes inside the CPAL table inside the font file. The palettes are ordered, and so they are identified by index. For example, a font might define color palette #3 that uses blues and greens, but another palette #5 might use reds and oranges. Colors within a palette inside the font are also identified by index – all palettes contain the same number of colors within themselves.

These color palettes can be tweaked or overridden in CSS using font-palette-values. An example looks like this:

@font-palette-values --lilac-blossom {
    font-family: "Bradley Initials DJR Web";
    base-palette: 7;
    override-colors: 0 #fff, 1 #F3B0EB;

This example means “Make a color palette named Lilac Blossom, that, when applied to Bradley Initials DJR Web, is just like the 7th palette in the font, but overrides color #0 in that palette to be white, and color #1 in the palette to be #F3B0EB.” If you don’t want to override any colors, that’s no problem – just delete the entire override-colors descriptor.

You can then apply this color palette by simply supplying it to the font-palette property like this:

font-palette: --lilac-blossom;
The Round Table


Progressive Enhancement

If you’re using an older version of Safari, or a different browser which doesn’t understand the font-palette property, it will render the default (0th) color palette in the font. Here’s what the above example would look like in such a browser:

The Round Table


If the fallback behavior is undesirable for your particular font, you can detect browsers that understand CSS color palettes in your stylesheet by using the @supports media query, like so:

@supports (font-palette: --lilac-blossom) {
    .lilacblossom {
        font-palette: --lilac-blossom;

@font-palette-values --lilac-blossom {
    font-family: "Bradley Initials DJR Web";
    base-palette: 7;
    override-colors: 0 #fff, 1 #F3B0EB;

Dark Mode

Not all color palettes are clearly visible on all backgrounds. Without color fonts, the color used to render text was entirely determined by the CSS author, but now that fonts can have color palettes defined inside them, it’s up to CSS authors to pick or create a color palette that is legible on the background it’s being rendered on. This can be particularly tricky when font fallback occurs, or when the user has blocked some fonts from loading.

Fonts such as Bradley Initials DJR Web have an extra tool for helping with this, though. Fonts can indicate that certain palettes inside them are usable with light backgrounds or usable with dark backgrounds, and these palettes are hooked up to the font-palette property. You don’t even have to use @font-palette-values!

So, if you want to use a color palette on a dark background, you can simply say font-palette: dark, like this:


And the same thing for a light background: font-palette: light:


Because the font-palette property has no effect on non-color fonts, it’s safe to set it in conjunction with the prefers-color-scheme media query, like this:

@media (prefers-color-scheme: dark) {
    :root {
        background: black;
        color: white;
        font-palette: dark;


Because @font-palette-values blocks are scoped to a specific font, you can make multiple of them that share a name. This is really powerful – it means you can define a single color palette name, and have it applied differently to whatever font happens to be rendered with it. Here’s an example:

@font-palette-values --lilac-blossom {
    font-family: "Bradley Initials DJR Web";
    base-palette: 1;

@font-palette-values --lilac-blossom {
    font-family: "Megabase";
    base-palette: 2;

<div style="font-palette: --lilac-blossom;">
    <div style="font-family: 'Bradley Initials DJR Web';">Pizza is amazing!</div>
    <div style="font-family: 'Megabase Web';">Is there any food better than pizza?</div>

This will have Bradley Initials DJR Web’s Lilac Blossom palette applied to Bradley Initials DJR Web, and Megabase’s Lilac Blossom palette applied to Megabase. And you only had to specify the font-palette property once!

Contextual color

In addition to pulling colors from palettes, some color fonts set aside special shapes that are connected to the foreground color of the current element. This makes them extra flexible, but it also means that these shapes operate independently from font-palette. In these cases, you can simply use the color property to change their color, like in this demo using Megabase.

<div style="font-family: 'Megabase Web';">
    <div style="color: black;">They were just pushed into space.</div>
    <div style="color: blue;">As much as I care about you.</div>

They were just pushed into space.

As much as I care about you.


Of course, with power comes responsibility; just because you can change colors, doesn’t mean you always should. Often the colors in a palette are coordinated to harmonize aesthetically, so it’s good to have a sense of how they are meant to relate to one another. You can look at the font’s predefined color palettes to see how the font designer assigned the roles for each color in the palette, and tweak accordingly.

It is also important to choose colors that contrast strongly against the background in order to keep your text readable and your webpage accessible. Colors in the palette that are used to form the base of the letters should typically “pop” against the background, while supporting layers like shadows, outlines, and decorative elements might contrast less in order to keep them from overpowering the letterforms.

Color fonts are a great improvement over graphic images, because they work by default with screen readers, copy/paste, and find-in-page. Also, they gracefully show fallback text if the font somehow fails to load, and they reflow if the browser window resizes. Not only that, color fonts are more flexible than graphic images, because they can incorporate the foreground color of the element using them into the design of the font.

Color fonts are not meant to take the place of single-color fonts. But used in moderation, at a big enough size in the right circumstance, they can be the perfect icing on the cake!

You can contact Myles C. Maxfield at mmaxfield@apple.com or @Litherum, and you can contact David Jonathan Ross at david@djr.com or @djrrb, and you can find David’s work at djr.com.

May 25, 2022 02:00 PM

May 16, 2022

New WebKit Features in Safari 15.5

Surfin’ Safari

After the feature-packed release of Safari 15.4 two months ago, WebKit’s work for this version of Safari focused predominately on polishing existing features and fixing bugs.

Safari 15.5 does contain three new technologies for web developers — support for the inert property in HTML; support for the worker-src Content Security Policy directive; and the new minimumViewportInset and maximumViewportInset APIs for implementing new CSS Viewport Units in WKWebView-based apps.

Safari 15.5 is available for macOS Monterey 12.4, macOS Big Sur, macOS Catalina, iPadOS 15.5, and iOS 15.5. You can update to Safari 15.5 on macOS Big Sur and macOS Catalina by going to System Preferences → Software Update → More info, and choosing to update Safari.

Developer Features

Let’s look first at the HTML inert attribute. When set on an element, the attribute makes that element non-interactive by preventing mouse and keyboard focus, clicks, edits or text selection. It also hides the element from assistive technologies. For more information about inert, including a demo showing how inert can make the partially-offscreen content in a carousel visible, but inactive, read Non-interactive Elements with the inert Attribute.

Next, let’s look at support for worker-src from Content Security Policy Level 3. The worker-src directive provides web developers a way to restrict which URLs are allowed to be sources for worker scripts (Worker, SharedWorker, or ServiceWorker). This can be used to prevent already loaded scripts from loading more scripts in the form of workers, a situation that has potential to be susceptible to malicious attack through using excessive CPU for computation. We also updated Content Security Policy console logging in Web Inspector.

And last, we’ve added the minimumViewportInset and maximumViewportInset APIs to WKWebView so app developers can add support for all of the new CSS Viewport Units to their browser or other application on iOS, iPadOS and macOS. The minimumViewportInset corresponds to the large measurement, and maximumViewportInset corresponds to the small measurement. The new CSS Viewport Units, which shipped in Safari 15.4, include small (svw, svh, svi, svb, svmin, svmax), large (lvw, lvh, lvi, lvb, lvmin, lvmax), dynamic (dvw, dvh, dvi, dvb, dvmin, dvmax), and logical (vi, vb) units.

Fixes and Polish

Now, let’s get to the list of bug fixes and feature polish.


  • Fixed SVG tags behind modal dialogs to not be clickable
  • Fixed the Dialog element only animating once
  • Fixed rendering a USDZ loaded as the main resource
  • Fixed uploading “.pages” files to file inputs accepting “.pages” and “.jpeg” files


  • Prevented BroadcastChannel from communicating across distinct opaque origins
  • Fixed respecting website policies during COOP-based process swap
  • Fixed PointerEvent.movementX always 0
  • Fixed resolving a fetch promise when a page enters page cache
  • Fixed pointer events to perform a hit test only if there is not a pointer capture target override
  • Fixed computing the site for cookies when the document is created by window.open
  • Fixed Element.focus({preventScroll: true}) to correctly prevent scrolling on iOS


  • Fixed scrolling background-attachement: fixed
  • Fixed background-clip: text to work with display: flex
  • Fixed rendering for many position: sticky elements
  • Fixed position: sticky elements moving incorrectly while scrolling
  • Fixed text contents in <span> with opacity not updating when a sibling element has will-change: transform
  • Fixed :focus-visible matching on the wrong element when focused via script
  • Fixed text-shadow getting clipped
  • Fixed behavior of a position: sticky element within contain: paint
  • Fixed aspect-ratio with percentage widths
  • Fixed returning the default computed style for elements without the transition or animation shorthands


  • Aligned WebAuthn implementation to match specifications to use the default pubKeyCredParams list if the list in makeCredential is empty

Content Security Policy

  • Fixed blocking image content in object elements
  • Fixed sending violation reports to the document for a detached element
  • Improved nonce hiding from the DOM
  • Updated Content Security Policy handling of JavaScript URLs


  • Fixed key rotation for single key audio in modern EME paired with a native HLS player
  • Fixed disabled Control Center spatial control when playing a video in Safari
  • Fixed loading a model in QuickLook when passing extra parameters
  • Fixed muted video that sometimes becomes paused when taken to fullscreen
  • Fixed video playback on iPhone 7
  • Fixed video playback for HEVC content encodings that generate many b-frames with a wide sliding window
  • Fixed HLS stream currentTime sometimes jumping backwards
  • Fixed clicking on the progress bar often pausing a YouTube video
  • Fixed blob videos slowing to pause
  • Fixed audio echo after the camera us paused or unpaused
  • Fixed playback of HTML5 embedded audio with unbounded range requests
  • Fixed the video poster disappearing prematurely on play, leaving a transparent video element


  • Fixed incorrect label returned by getUserMedia regardless of language selected
  • Reduced perceived audio latency


  • Fixed text wrapping for windows that exceed a certain width
  • Fixed a Korean webfont rendering issue
  • Fixed an issue where a transform change sometimes resulted in bad rendering
  • Fixed a flash of missing text content with transform-related animations
  • Changed to use colgroup for table sizing when it comes after thead, tbody, tfoot, or tr elements
  • Fixed two bopomofo tone marks to move to the correct place in vertical text with a particular bopomofo font

Apple Pay

  • Fixed the Apple Pay Sheet to return billingContact on iOS


  • Fixed WebGL rendering when using preserveDrawingBuffer on iOS
  • Fixed a number of issues related to multisampling that were breaking a lot of WebGL content
  • Fixed handling TypedArray with AllowShared to be accepted
  • Fixed WEBGL_multi_draw validation

Web Inspector

  • Fixed large message handling from remote devices
  • Fixed repeated opening and closing


  • Fixed launching Microsoft Teams from Safari


  • Fixed a noticeable delay in playback when rotating a full screen YouTube video

Safari Extensions

  • Fixed a crash clicking on Safari App Extension toolbar items
  • Fixed an issue where SFContentBlockerManager.getStateOfContentBlocker() could return an incorrect value on iOS
  • Added support for optional_host_permissions for Safari Web Extensions


We love hearing from you. Send a tweet to @webkit, @jensimmons or @jonathandavis to share your thoughts on this release. If you run into any issues, we welcome your feedback on the Safari UI or your WebKit bug report about web technology. 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.

And More

For more information on what’s in WebKit for Safari 15.5, read the Safari 15.5 release notes.

These features were first released in Safari Technology Preview: 140, 141, 142, 143, 144, and 145.

May 16, 2022 05:30 PM

May 11, 2022

Release Notes for Safari Technology Preview 145

Surfin’ Safari

Safari Technology Preview Release 145 is now available for download for macOS Big Sur and of macOS Monterey. If you already have Safari Technology Preview installed, you can update in the Software Update pane of System Preferences on macOS.

This release covers WebKit revisions 291957-293023. This release of Safari Technology Preview does not support versions of macOS Monterey prior to 12.3. Please update to macOS Monterey 12.3 or later to continue using Safari Technology Preview.

Note: Tab Groups do not sync in this release.

Web Inspector

  • Sources tab
    • Allowed Response Local Overrides to map to a file on disk (r292084, r292120)

:has() pseudo-class

  • Added invalidation support for the pseudo-classes :autofill (r292531); :placeholder-shown (r292523); :indeterminate, :read-only, :read-write, :required and :optional (r292466, r292582)

Container Queries and Containment

  • Added CSSOM support (r292045)
  • Added support for contain: inline-size (r292394, r292416, r292465)
  • Added support for containment to disable the special handling of the HTML body element for overflow viewport propagation (r292127, r292157)
  • Corrected container selection for pseudo-elements (r292819)
  • Corrected container selection for ::slotted and ::part rules (r292635)
  • Disallowed invalid query range syntax (r292816)
  • Updated container shorthand order (r292759)

CSS Grid

  • Added support for transitions and animations on grid-template-columns and grid-template-rows (r292432)
  • Fixed grid items that establish an independent formatting context to not be subgrids (r292524)
  • Implemented support for aligning baselines through subgrids (r292973)


  • calc() functions
    • Added NaN propagation for min, max, clamp, and hypot (r292732)
    • Serialized top level min, max, hypot as calc() (r292893)
  • resize property
    • Added support for block/inline CSS values (r292222)
    • Corrected minimum size computation to allow resizing below initial size (r292559)
  • Added support for rendering url(), CSS basic shapes other than path(), and coord-box for offset-path (r292382)
  • Fixed scrollIntoView with scroll-snap-type on root element (r292812)
  • Fixed drop-shadow filter to work correctly in tiled backing layer (r292059)
  • Fixed issue with position: sticky within contain: paint (r292155)
  • Implemented units for CSS Typed OM (r292150)

Dialog Element

  • Dialog element now adapts to dark mode by default (r292029)


  • Allowed Wasm import from a JS Worker module behind the feature flag (r292799)
  • Changed ShadowRealm global object to have a mutable prototype (r292895)


  • Fixed full screen video progress bar flickering after dragging it (r292572)
  • Fixed MSE video not drawing onto canvas (r292811)
  • Fixed muted video that sometimes becomes paused when entering fullscreen (r292049)


  • Added support for all CTAP transports and remove gesture requirement for virtual authenticators (r292593)
  • Implemented getTransports() and getAuthenticatorData() (r292913)


  • Removed the 1ms minimum for setTimeout (r291998)

Content Security Policy

  • Improved compatibility of source matching (r292266)
  • Fixed WASM failing to execute after window.open (r292229)


  • Fixed incorrect CORP and COEP check in 304 responses (r292595)

Service Workers

  • Added support for ServiceWorkerClients.openWindow (r291979)
  • Implemented ServiceWorkerWindowClient.navigate (r292459)
  • Exposed workers as service worker clients and implemented registration matching for dedicated workers (r292861)
  • Fixed ensuring the document gets controlled by its matching service worker registration during a COOP-based process swap (r292468)
  • Fixed Service-Worker-Navigation-Preload header not being sent when Navigation Preload is enabled (r292296)
  • Fixed ServiceWorker.postMessage() not working from inside iframes (r292905)


  • Reduced perceived audio latency on streaming via WebRTC (r292563)

May 11, 2022 09:24 AM

May 02, 2022

Release Notes for Safari Technology Preview 144

Surfin’ Safari

Safari Technology Preview Release 144 is now available for download for macOS Big Sur and of macOS Monterey. If you already have Safari Technology Preview installed, you can update in the Software Update pane of System Preferences on macOS.

This release covers WebKit revisions 291506-291957. This release of Safari Technology Preview does not support versions of macOS Monterey prior to 12.3. Please update to macOS Monterey 12.3 or later to continue using Safari Technology Preview.

Note: Tab Groups do not sync in this release.

Web Inspector

  • Fixed page reloading and showing an empty inspector on pages with container queries (r291824)
  • Elements Tab
    • Fixed $0 not being displayed for the selected node after switching to another tab (r291729)
    • Fixed unwanted extra dash when autocompleting CSS variable names in the Styles panel (r291740)
    • Fixed inline swatch popovers not being hidden when the inline swatch is removed (r291628)
  • Console Tab
    • Fixed console.screenshot to no longer have extra transparent pixels at the bottom of viewport screenshots (r291519)


  • Added Typed OM support for container units (r291524)
  • Fixed CSS cascade regarding logical properties (r291546)
  • Fixed incorrect handling of NaN inside calc() for top-level calculation (r291911)
  • Let revert-layer roll back to presentational hints (r291594)
  • Implemented border-image serialization (r291537)
  • Preserved repeat() notation when serializing grid-templates (r291956)
  • Reduce memory usage for large, sparse grids (r291952)
  • Handled finite value with infinite step in round() for calc() (r291841)
  • Fixed incorrect resolution of percentage grid-gaps within subgrids (r291953)

Web Animations

  • Enabled support for mutable timelines by default (r291868)


  • Changed Date.parse to stop returning numbers with fractional part (r291603)
  • Fixed class field initializer with extra parentheses (r291577)


  • Added getAssertion support for virtual HID authenticators (r291624)
  • Specified correct ASCPublicKeyCredentialKind in configureAssertionOptions (r291761)
  • Updated to pass along timeout to ASA and ignore timeout for conditional mediation requests (r291625)


  • Added support for focused and visible ServiceWorkerWindowClient states (r291888)
  • Added a check for whether the origin can access storage in the Storage API (r291726)
  • Disabled custom storage paths for IndexedDB and LocalStorage by default (r291909)
  • Fixed PointerEvent.movementX to not always be 0 (r291886)
  • Fixed Context2D drawImage(img, x, y, w, h) to not throw IndexSizeError when width or height are 0 (r291748)
  • Fixed fetching a Blob URL with an unbounded Range header to correctly generate a Content-Range response header (r291622)
  • Implemented CSSNumericValue.mul, CSSNumericValue.div, CSSNumericValue.add, CSSNumericValue.sub, CSSNumericValue.max, and CSSNumericValue.min (r291597)
  • Implemented ServiceWorkerWindowClient.focus (r291938)


  • Included initial accessibility support for display: contents (r291570)


  • Fixed a bug where clicking anywhere on the progress bar pauses some MSE video implementations (r291629)
  • Fixed video playback for HEVC-encoded video with a lot of b-frames and a wide sliding window (r291813)

Security Policy

  • Fixed website policies not being respected when doing COOP-based process swap (r291606)

Web Extensions

  • Fixed a crash clicking on Safari App Extension toolbar items

May 02, 2022 08:19 PM

Víctor Jáquez: From gst-build to local-projects

Igalia WebKit

Two years ago I wrote a blog post about using gst-build inside of WebKit SDK flatpak. Well, all that has changed. That’s the true upstream spirit.

There were two main reason for the change:

  1. Since the switch to GStreamer mono repository, gst-build has been deprecated. The mechanism in WebKit were added, basically, to allow GStreamer upstream, so keeping gst-build directory just polluted the conceptual framework.
  2. By using gst-build one could override almost any other package in WebKit SDK. For example, for developing gamepad handling in WPE I added libmanette as a GStreamer subproject, to link a modified version of the library rather than the one in flatpak. But that approach added an unneeded conceptual depth in tree.

In order to simplify these operations, by taking advantage of Meson’s subproject support directly, gst-build handling were removed and new mechanism was set in place: Local Dependencies. With local dependencies, you can add or override almost any dependency, while flatting the tree layout, by placing at the same level GStreamer and any other library. Of course, in order add dependencies, they must be built with meson.

For example, to override libsoup and GStreamer, just clone both repositories below of Tools/flatpak/local-projects/subprojects, and declare them in WEBKIT_LOCAL_DEPS environment variable:

$ export WEBKIT_SDK_LOCAL_DEPS=libsoup,gstreamer-full
$ export WEBKIT_SDK_LOCAL_DEPS_OPTIONS="-Dgstreamer-full:introspection=disabled -Dgst-plugins-good:soup=disabled"
$ build-webkit --wpe

By vjaquez at May 02, 2022 11:11 AM

April 26, 2022

Non-interactive Elements with the inert attribute

Surfin’ Safari

Elements are interactive in multiple ways; they can be focused, clicked, edited or selected. Assistive technologies such as screen readers also interact with them. What if you wanted to disable all these interactions for a section of your webpage? The inert attribute covers this.

Pre-existing Solutions

The most basic way to disable all interactions is the disabled HTML attribute, it prevents focus, clicks, edition or selection. However, it only works on form controls, and does not necessarily hide the control from assistive technologies. What if you wanted to do this on elements other than form controls?

To prevent focus, tabindex="-1" is a popular option, but it isn’t ideal because setting the attribute on a container element will not prevent its children from being focused, and it also does not prevent click-focus with a mouse. If you want to prevent keyboard focus on a whole section, every single focusable element in the section needs the attribute set.

To prevent clicks, the pointer-events: none CSS property may be an option although, unless you’ve put tabindex="-1" on the element as well, tabbing to the element and interacting with it is still possible.

To prevent selection, the user-select: none CSS property is the most common option.

To prevent editing, if you’re using contenteditable, you would need to manually remove the contenteditable attribute. If it’s a form control, you need to manually set the disabled attribute.

All of this is heavy and also does not allow you to hide the section from assistive tools, which may be appropriate when making a whole section non-interactive. It is currently possible to do this by setting aria-hidden="true" on the relevant section.

This is why the inert attribute was added to HTML, it is an efficient way to disable all of the interactions above and hide elements from assistive technology.

What is the inert attribute?

The inert attribute was originally specified in the context of the dialog element about 10 years ago, where the main use-case was making the content behind a modal dialog non-interactive. It was later removed due to a lack of adoption. Recent developer requests lead it to be re-proposed a few years later. However, the main issue with that definition was complexity in interaction with modal dialogs and performance. This is why changes have been made to the standard to use a CSS-based approach to define inert nodes.

According to the HTML specification, when a node is inert:

  • Hit-testing must act as if the ‘pointer-events’ CSS property were set to ‘none’.
  • Text selection functionality must act as if the ‘user-select’ CSS property were set to ‘none’.
  • If it is editable, the node behaves as if it were non-editable.

In addition to the above:

  • It is not focusable.
  • It behaves similarly to aria-hidden="true" for assistive technologies

Example Usage: A Carousel

Let’s build a carousel with multiple pages:

You will notice that you can still interact with links/inputs/etc. from inactive pages. This is undesirable behavior that can be prevented with the inert attribute. In the switchToIndex method which changes the active page, we can add 2 lines of code that fix this.

this.items being an array of HTML elements representing each slide, the first line makes every slide inert, and the second line makes the active one non-inert.

  switchToIndex(index) {
    this.items.forEach(item => item.inert = true);
    this.items[index].inert = false;

Notice that we have used the inert DOM property. When set to a value, it is equivalent to element.toggleAttribute("inert", value) .

For support for in older browsers, you may want to use a polyfill until the inert attribute is widely supported.

Finally it is recommended to add a visual cue that a certain element is inert. Let’s make inactive slides less opaque:

.carousel-item[inert] {
  opacity: 0.6;

Here is the final result in action:

As you can see above, inactive slides are no longer interactive but they are still visible.

Browser support

Additional resources

In this post, we gave an overview of the new inert attribute. Here are some interesting additional resources you might want to check:

Feel free to reach out to @therealntim on Twitter for any questions. To report any issues, please file a bug blocking bug 165279.

April 26, 2022 05:21 PM

April 21, 2022

WPE WebKit Blog: Happy birthday WPE!

Igalia WebKit

Welcome to the new Blog section on wpewebkit.org!

Today is a special day for Igalia, especially for those colleagues that work on WebKit: Five years ago, on the 21st of April 2017, the WPE port was announced by our colleague Žan Doberšek on the WebKit mailing list.

Let’s take some time to celebrate and recap how WPE evolved from the early prototyping days to the product empowering hundreds of millions of devices worldwide today.

Celebrating WPEs 5th birthday with a cake

WPE is … what exactly?

To get everyone on the same page, let’s start by reiterating what WPE is: a WebKit port optimized for embedded devices. It allows you to embed a full-fledged Web browser engine that supports a large set of modern Web technologies into your product. WPE itself is not a Web browser such as Safari, Chrome or Firefox but contains the underlying building blocks to load, parse and render websites. To learn more about the distinction between a Web browser and a Web browser engine read our explainer.

You might ask yourself, what does “optimized for embedded devices” mean in practice? Unlike most other WebKit ports, WPE does not rely on a specific user-interface toolkit, such as Qt, GTK, Cocoa, etc., nor does it offer any integration with these kinds of toolkits. WPE WebKit is light-weight, integrates well with a variety of hardware configurations, and only requires a minimum set of APIs on your side: EGL and OpenGL ES 2.

The early days 2014 - 2017

The idea for a new WebKit port was born in 2014, as part of a collaboration between Metrological and Igalia. The goal of this collaboration was to have a WebKit port running efficiently on their set-top boxes, utilizing a modern Wayland based Linux graphics architecture. Back then, QtWebKit was popular among embedders; however, it was unmaintained and its future was unclear since Qt wanted to transition from using WebKit to Blink.

In September 2014 a group of Igalians forked the WebKitGtk port, removed all GTK toolkit dependencies, and prototyped what was necessary to achieve the goal: rendering websites without involving any of the traditional toolkits and instead utilizing a Wayland-based rendering approach.

During development it became apparent that this WebKit port is generally useful for all our customers and the community as a whole. Therefore Igalia decided to aim for an even more flexible design, where Wayland is only one of the possible backends. Our fellow Igalian Miguel Gomez reported in his late 2016 blog post about this change, and the renaming of the port: WPE appears for the first time in public.

The project’s removal of the Wayland dependency and the subsequent reorganization lead to the architecture we have today, consisting of not only the WPE port itself but a whole ecosystem of projects such as libwpe, WPEBackend-fdo, WPEBackend-rdk, etc., that together form the WPE project.

2017 - today

After months of focused engineering efforts, the downstream work was finished and Igalia was ready to announce WPE to the public on the 17th of April 2017, with the promise that Igalia will maintain the port alongside the existing WebKitGtk port. That is not a cheap bill: maintaining an upstream port is a recurring multi-million dollar investment. Just in order to keep the port itself healthy, as updates are made all around it, requires infrastructure, bots and a team of fully dedicated engineers to deal with maintenance, testing, triaging, tickets, etc. To implement new Web standards, fix related bugs or design and contribute features requires an even more considerable amount of resources.

Since then, Igalia ramped up the WPE investments and steadily advanced the port while helping customers to integrate WPE into their environments. Today WPE is healthy, runs on many platforms, and offers the most flexible browser architecture at present. Also, thanks in great part to this work, Igalia was responsible for nearly 16.5% of all commits in WebKit itself last year, helping make the larger project and ecosystem around it healthier too.

However, none of this would be possible without the commitment of many Igalians pushing the project forward every day for the past 8 years. A new People Behind WPE series will be launched soon: over the following months, the Igalians involved with WPE will introduce themselves, their area of expertise, and talk about a specific WPE related technical topic. You’ll get to know the people behind the product and a first-class technical overview of individual parts of the WPE architecture! We plan to release a new article every 3-4 weeks, so be sure to visit wpewebkit.org/blog again soon and enjoy the upcoming People Behind WPE series.

Feel free to spread the word and make noise about WPE. Stay healthy, stay tuned!

April 21, 2022 12:00 AM

April 19, 2022

Manuel Rego: Web Engines Hackfest 2022

Igalia WebKit

Once again Igalia is organizing the Web Engines Hackfest. This year the event is going to be hybrid. Though most things will happen on-site, online participation in some part of the event is going to be possible too.

Regarding dates, the hackfest will take place on June 13 & 14 in A Coruña. If you’re interested in participating, you can find more the information and the registration form at the event website: https://webengineshackfest.org/2022/.

What’s the Web Engines Hackfest?

This event started a long way back. The first edition happened in 2009 when 12 folks visited the Igalia offices in A Coruña and spent there a whole week working on WebKitGTK port. At that time, it was kind of early stages on the project and lots of work was needed, so those joint weeks were very productive to move things forward, discuss plans and implement features.

As the event grew and more people got interested, in 2014 it was renamed to Web Engines Hackfest and started to welcome people working on different web engines. This brought the opportunity for engineers of the different browsers to come together for a few days and discuss different features.

The hackfest has continued to grow and these days we welcome anyone that is somehow involved on the web platform. In this year’s event there will be people from different parts of the web platform community, from implementors and spec editors, to people interested in some particular feature.

This event has an unconference format. People attending are the ones defining the topics, and work together in breakout sessions to discuss them. They could be issues on a particular browser, generic purpose features, new ideas, even sometimes tooling demos. In addition, we always arrange a few talks as part of the hackfest. But the most important part of the event is being together with very different folks and having the chance to discuss a variety of topics with them. There are not lots of places where people from different companies and browsers join together to discuss topics. The idea of the hackfest is to provide a venue for that to happen.

2022 edition

This year we’re hosting the event in a new place, as Igalia’s office is no longer big enough to host all the people that will be attending the event. The venue is called Palexco and it’s close to the city center and just by the seaside (with views of the port). It’s a great place with lots of spaces and big rooms, so we’ll be very comfortable there. Note that we’ll have childcare service for the ones that might need it.

New venue: Palexco (picture by Jose Luis Cernadas Iglesias) New venue: Palexco (picture by Jose Luis Cernadas Iglesias)

The event is going to be 2 days this time, 13th and 14 June. Hopefully the weather will be great at that time of the year, and the folks visiting A Coruña should be able to really enjoy the trip. There are going to be lots of light hours too, sunrise is going to be around 7am and sunset past 10pm.

The registration form is still open. So far we’ve got a good amount of people registered from different companies like: Arm, Deno Land, Fission, Google, Igalia, KaiOS, Mozilla, Protocol Labs, Red Hat and Salesforce.

Arm, Google and Igalia will be sponsoring 2022 edition, and we’re really thankful for your support! If your company is also interested in sponsoring the hackfest, please contact us at hackfest@webengineshackfest.org.

Apart from that there are going to be some talks that will be live streamed during the event. We have a Call For Papers with a deadline by the end of this month. Talks can be on-site or remote, so if you’re interested on giving one, please fill the form.

We know we’re in complex times and not everyone can attend onsite this year. We’re sorry about that, and we hope you all can make it in future editions.

Looking forward to the Web Engines Hackfest 2022!

April 19, 2022 10:00 PM

April 11, 2022

Private Click Measurement: Conversion Fraud Prevention and Replacement For Tracking Pixels

Surfin’ Safari

Welcome to the fourth feature update on Private Click Measurement, our proposed web standard for measuring advertising in a privacy-preserving way. More precisely three major and two minor updates to PCM, all available in iOS/iPadOS 15.4 and macOS Monterey 12.3.

Major updates:

  • Conversion fraud prevention. This enables merchant websites to sign unlinkable tokens and get proof in the attribution report that it was triggered by a trustworthy conversion event.
  • Replacement for third-party tracking pixels. Merchant websites can now trigger a conversion event through a same-site pixel which removes the need to call any third-parties in PCM.
  • Measurement of clicks in cross-site iframes. Many publishers want to isolate ads on their site in cross-site iframes. Now clicks in such iframes can be measured too.

What is Private Click Measurement?

Private Click Measurement, or PCM, is a proposed web standard for measuring the effectiveness of click-through advertising in a privacy-preserving way. It allows for 8 bits of data on the click source site to be combined with 4 bits of data on the click destination site to measure which clicks are driving conversions. The combined 8+4 bits of data is sent to both the click source and destination in an attribution report that doesn’t carry any user or device identifiers. The net result is a report that says “Someone who clicked ad X on website A later converted with value Y on website B.”

PCM was made available as a beta in May 2019, and then shipped 2021 in iOS/iPadOS 14.5 and in Safari 14.1 on macOS. Its privacy-preserving nature means it can be used without getting the user’s permission to track according to AppTrackingTransparency.

Conversion Fraud Prevention

In July 2021 we presented our beta feature for click fraud prevention in PCM. It allows the click source website to sign an unlinkable token at the time of the click navigation, which results in a signed token being included in the resulting attribution report. Today we present the same capability for the click destination website.

PCM’s triggering event is a redirect to the well-known path .well-known/private-click-measurement/trigger-attribution/. Now that redirect supports a query string parameter called attributionDestinationNonce. If a nonce is included in the redirect, it triggers WebKit to ask the click destination server to sign an unlinkable token.

Step 1: Generate an RSA Key Pair

Unlinkable tokens require a public key for token generation and validation, and a corresponding private key for signing. PCM supports three different RSA key sizes: 2048, 3072 and 4096 bits. The expected encoding of the public key is a Base64URL encoded (using RFC4648 section 5) SPKI with the RSA-PSS OID and the parameters corresponding to the RSABSSA IETF draft. Examples of such key encodings are included in an earlier blog post.

Step 2: Add the Query Parameter attributionDestinationNonce

The triggering event should look like this to opt in to conversion fraud prevention:

… redirects to …

The attributionDestinationNonce is only in place to help the click destination server know the context for which it’s signing an unlinkable token. When the click destination server is asked to sign an unlinkable token, it’ll get the attributionDestinationNonce and can make a decision as to whether the triggering event was trustworthy or not.

The attributionDestinationNonce needs to be a Base64URL encoded 128-bit/16-byte value. Any smaller or larger value will cancel the issuance flow of the fraud-prevention signature. Any non Base64URL encoded value will also cancel the token transaction. Web Inspector will log a warning if the attributionDestinationNonce is malformed.

Step 3: Respond to a Request for Your Public Key

The browser and any validating party needs to be able to fetch your public key at any point in time from this well-known location: https://clicksource.example/.well-known/private-click-measurement/get-token-public-key/.

Replacement For Third-Party Tracking Pixels

Previous versions of PCM required HTTP requests on the click destination site to go to the click source site. This was designed to enable reuse of existing cross-site tracking pixels that no longer carry cookies under tracking prevention.

For new adoption of PCM, for instance onboarding a new publisher site where ads are shown, there’s no need to add such legacy pixels. Longer term, we want to remove support for triggering events through cross-site tracking pixels since even though they don’t carry cookies, they do ping third-party domains that may be categorized as trackers. Many websites want to be completely tracker-free and we’re happy to be able to support that with PCM while still allowing for click measurement across websites.

Click destination sites can now signal a triggering event through a same-site pixel. It looks like below.

Same-site subresource request to:

… redirects to same-site well-known location:

The above redirect tells PCM to schedule an attribution report if there is a pending attribution from clickSource.example.

Why not a JavaScript API to trigger attribution without cross-site pixels, you may ask? There are two reasons for that:

  • The standards conversation in W3C Privacy CG told us that some click destination sites have a policy against placing third-party scripts on their websites because of the risky dependencies they introduce. We think that’s a very valid concern, not in the least for user privacy. However, those same click destination sites do not have the same strict policies against pixels. We can given them the API functionality they need by introducing same-site pixels. They can be triggered through actual image elements or through a JavaScript Fetch.
  • We continue to consider it very important that websites should not be able to tell at page load time whether or not the user has PCM (or other ad measurement) features enabled. This is to protect the user’s right to a choice. Pixel APIs don’t reveal if the triggering event is accepted or not. A JavaScript API could be made to not reveal that info either but pixel APIs just do that.

Measurement of Clicks in Cross-Site Iframes

One of the first PCM change requests from the web community was to allow for measurement of clicks that happen in cross-site iframes. This would allow for measurement of advertising isolated in iframes. We’re happy to announce that we now support that. Note that the resulting attribution report is still sent to the two first-party websites, often referred to as the publisher and the merchant.

WebIDL Attributes Now In Camelcase

JavaScript access to PCM’s anchor tag attributes now requires camel-casing. This is the result of interoperability work in web standards. Here’s how it looks:

<a id="test" href="https://clickDestination.example" attributionsourceid=40 attributiondestination="https://clickDestination.example"></a>
    const anchorTag = document.getElementById("test");
    anchorTag.attributionSourceId …;
    anchorTag.attributionDestination …;

Encoding Update for Token Keys

When sending your public key to the browser, it needs to be a 2048, 3072 or 4096 bit RSA public key wrapped with an RSAPSS OID in ASN1 format. See “Step 1: Generate an RSA Key Pair above.” Those bytes then need to be base64 encoded with the URL and filename safe alphabet. Examples of such key encodings are included in an earlier blog post.

April 11, 2022 04:18 PM

April 07, 2022

Release Notes for Safari Technology Preview 143

Surfin’ Safari

Safari Technology Preview Release 143 is now available for download for macOS Big Sur and of macOS Monterey. If you already have Safari Technology Preview installed, you can update in the Software Update pane of System Preferences on macOS.

This release covers WebKit revisions 290223-291506. This is the last release of Safari Technology Preview that will support versions of macOS Monterey prior to 12.3. Please update to macOS Monterey 12.3 or later to continue using Safari Technology Preview.

Note: Tab Groups do not sync in this release.

Web Inspector

  • Elements Tab
    • Added option in the Layout panel of the Details Sidebar for Flexbox overlays to show each item’s CSS order and/or DOM index in the parent flex container (r290613)
  • Service workers are no longer terminated while they are being inspected. (r291467)

CSS Container Queries

  • Added support for nested container queries (r290257)
  • Added basic support for container units (r291474)
  • Changed to only apply inline-size containment when it is allowed (r291154)
  • Ensured container style changes are propagated to descendants (r291500)
  • Fixed getComputedStyle to update the style for invalid query containers (r290320)
  • Fixed offsetWidth, offsetHeight, and similar to update layout for container queries (r290380)
  • Implemented new container selection algorithm (r291098)

CSS Cascade Layers

  • Added support for revert in @keyframes (r290457)
  • Added support for revert-layer in @keyframes (r290729)
  • Fixed revert on low-priority properties (r291260)
  • Let revert-layer in the lowest layer roll back to user styles (r290864)


  • Fixed computing the correct containing block override size for items that are subgridded in one dimension only (r290577)
  • Converted grid direction to be relative to subgrid when accounting for extra margin (r290576)
  • Handled reverse flow direction when converting iterator coords for a subgrid (r290572)
  • Fixed subgrid items to always be stretched (r291464)
  • Fixed positioning of position: absolute items within nested grids (r290674)


  • Implemented text-decoration as a shorthand (r290756, r291244)
  • Implemented logical properties for CSS overscroll-behavior (r290422)
  • Fixed background-clip: text to work with display: flex (r291303)


  • Added CalendarDateTime parsing (r290248)
  • Fixed ShadowRealm unwinding (r290283)
  • Fixed Temporal.PlainDate to validate input range (r290282)


  • Fixed image alt text bi-directional reordering (r290734)
  • Fixed alt text position in right-to-left context (r290726)
  • Fixed table sizing when colgroup comes after tbody (r290512)
  • Fixed scrollbars disappearing when very long or wide (r290545)
  • Handled perpendicular containing blocks when computing available logical height (r290634)

Web Animations

  • Added support for passing an optional timeline to Element.animate() (r290655)
  • Changed setting the composite property on a keyframe effect to invalidate the target style (r290741)
  • Fixed inherit values should trigger keyframe recomputation if any previous effect has changed that property (r290831)
  • Fixed keyframe values set to inherit to recompute their values when the inherited value changes (r290823)
  • Fixed animating fill and stroke to or from currentColor (r290898)
  • Fixed ::placeholder to not be a valid pseudo-element for a keyframe effect target (r290662)
  • Fixed animations on modal <dialog> elements and ::backdrop to run more than once (r291282)
  • Fixed outline-width with transition to animate correctly (r290735)
  • Fixed text-emphasis shorthand to be animatable (r290895)
  • Fixed text-emphasis-color to support non-discrete animations (r290887)
  • Made changes to font-size recompute keyframes (r290730)
  • Added support for discrete animation to:


  • Fixed clamping animated values to the 0-1 range for:


  • Allowed history swipe in scroller with overscroll-behavior (r291497)
  • Fixed incorrect painting when scrolling a page with fixed backgrounds (r290785)
  • Fixed scroll animation when scroll snap scroller is navigated with the keyboard (r290548, r290625)
  • Fixed element with position: sticky after sticking, starting to move incorrectly when scrolling (r290812)


  • Added support for authenticatorSelection.residentKey (r291176)
  • Added fallback to attestation=none if requested but unavailable for platform authenticator (r290539)
  • Enabled using WebAuthn within cross-origin iframe elements (r291018)
  • Improved virtual authenticator support ( r291423 , r291321)


  • Fixed WebGL rendering incorrect results when using preserveDrawingBuffer (r291218)


  • Enabled the inert attribute by default (r290587)


  • Enabled the Permissions API by default (r291116, r290301)
  • Fixed mousemove events double-firing in Safari (r290743)
  • Fixed rendering when loading a USDZ as the main resource (r290562)
  • Fixed CORS preflight failing due to cache-control header (r290507)
  • Fixed PerformanceNavigationTiming Response Start being unavailable when using Service Worker Cache (r291441)
  • Fixed buffered flag not working in Paint Timing (r290247)
  • Fixed load event never firing after a form is submitted (r290841)
  • Fixed WebSocket.send() to synchronously update bufferedAmount (r290995)
  • Made input element UA shadow tree creation lazy (r290284)
  • Made pointer-events checks for SVG take in account inert subtrees (r290306)
  • Removed the 1ms minimum for setTimeout (r291476)


  • AudioContext will continue playing when minimizing or moving the macOS Safari window to the background (r291267)
  • Fixed scrambled output for some WebM videos with VP8 codec (r291216)
  • Implemented remote-inbound-rtp packetsLost (r290865)


  • Updated WebSpeech API support (r291124)

File System Access

  • Changed to throw an exception if a file or directory cannot be accessed in file system (r291014)
  • Disallowed empty name in FileSystemHandle (r290998)
  • Disallowed names that are not permitted by the underlying file system (r291057)
  • Fixed fetching website data that may get a wrong or missing record after migrating data to general storage directory (r290239, r290233)

Web Extensions

  • Fixed cookie expiration dates so they are not off by 30 years

April 07, 2022 10:19 PM

Manuel Rego: :focus-visible is shipping in Safari/WebKit

Igalia WebKit

This is the final report about the work Igalia has been doing to add support for :focus-visible in WebKit. As you probably already know this work is part of the Open Prioritization campaign by Igalia that has been funded by different people and organizations. Big thanks to all of you! If you’re curious and want to know all the details you can find the previous reports on this blog.

The main highlight for this blog post is that :focus-visible has been enabled by default in WebKit (r286783). 🚀 This change was included in Safari Technology Preview 138, with its own post on the official WebKit blog. And finally reached a stable release in Safari 15.4. It’s also included in WebKitGTK 2.36 and WPE WebKit 2.36.

Open Prioritization

Let’s start from the beginning, my colleague Brian Kardell had an idea to find more diverse ways to sponsor the development of the web platform, after some internal discussion that idea materialized into what we call Open Prioritization. In summer 2020 Igalia announced Open Prioritization that intially had six different features on the list:

  • CSS lab() colors in Firefox
  • :focus-visible in WebKit/Safari
  • HTML inert in WebKit/Safari
  • Selector list arguments for :not() in Chrome
  • CSS Containment support in WebKit/Safari
  • CSS d (SVG path) support in Firefox

By that time I wrote a blog post about this effort and CSS Containment in WebKit proposal and my colleagues did the same for the rest of the contenders:

After some months :focus-visible was the winner. By the end of 2020 we launched the Open Prioritization Collective to collect funds and we started our work on the implementation side.

Last year at TPAC, Eric Meyer gave an awesome talk called Adventures in Collective Implementation, explaining the Open Prioritization effort and the ideas behind it. This presentation also explains why there’s room for external investments (like this one) in the web platform, and that all open source projects (in particular the web browser engines) always have to make decisions regarding priorities. Investing on them will help to influence those priorities and speed up the development of features you’re interested in.

It’s been quite a while since we started all this, but now :focus-visible is supported in WebKit/Safari, so we can consider that the first Open Prioritization experiment has been successful. When :focus-visible was first enabled by default in Safari Technology Preview early this year, there were lots of misunderstandings about how the development of this feature was funded. Happily Eric wrote a great blog post on the matter, explaining all the details and going over some of the ideas from his TPAC talk.

:focus-visble is shipping in in WebKit, how that happened?

In November last year, I gave a talk at CSS Conf Armenia about the status of things regarding :focus-visible implementation in WebKit. In that presentation I explained some of the open issues and why :focus-visible was not enabled by default yet in WebKit.

The main issue was that Apple was not convinced about not showing a focus indicator (focus ring) when clicking on a focusable element (like a <div tabindex="0">). However this is one of the main goals of :focus-visible itself, avoiding to get a focus indicator in such situations. As Chromium and Firefox were already doing it, and aiming to have a better interoperability between the different implementations, Apple finally accepted this behavioral change on WebKit.

Then Antti Koivisto reviewed the implementation, suggesting a few changes and spotting some issues (thanks about that). Those things were fixed and the feature was enabled by default in the codebase last December. As usual once a feature is enabled some more issues appear and they were fixed too. Including even a generic issue regarding accesskey on focusable elements, which required to add support to test accesskey on WebKit Web Platform Tests (WPT).

As part of all this work since my previous blog post we landed 9 more patches on WebKit, making a total of 36 patches for the whole feature, together with a few new WPT tests.

Buttons and :focus-visible on Safari

This topic has been mentioned in my previous posts and also in my talk. Buttons (and other form controls) are not mouse focusable in Safari (both in macOS and iOS), this means that when you click a button on Safari, the button is not focused. This behavior has the goal to match Apple platform conventions, where the focus doesn’t move when you click a button. However Safari implementation differs from the platform one, as the focus gets actually lost when you click on such elements. There are some very old issues in WebKit bugtracker about the topic (see #22261 from 2008 or #112968 from 2013 for example).

There’s a kind of coincidence related to this. Before :focus-visible existed, buttons were never showing a focus indicator in Safari after mouse click, as they are not mouse focusable. This was different in other browsers where a focus ring was showed when clicking on buttons. So while :focus-visible fixed this issue for other browsers, it didn’t change the default behavior for buttons in Safari.

However with :focus-visible implementation we introduced a problem somehow related to this. Imagine a page that has an element and when you click it, the page moves the focus via script (using HTMLElement.focus()) to a different element. Should the new focused element show a focus indicator? Or in other words, should it match :focus-visible?

ol > li::marker { content: counter(list-item) ") "; }

The answer varies depending on whether the element clicked is or not mouse focusable:

  1. If you click on a focusable element and the focus gets moved via script to a different element, the newly focused element does NOT show a focus indicator and thus it does NOT match :focus-visible.
  2. If you click on a NON focusable element and the focus gets moved via script to a different element, the newly focused element shows a focus indicator and thus it matches :focus-visible.

All implementations agree on this, and Chromium and Firefox have been shipping this behavior for more than a year without known issues so far. But a problem appeared on Safari, because unlike the rest of browsers, buttons are not mouse focusable there. So when you click a button in Safari, you go to point 2) above, and end up showing a focus indicator in the newly focused element. Web authors don’t want to show a focus indicator on that situations, and that’s something that :focus-visible is fixing through point 1) in the rest of browsers, but not in Safari (see bug #236782 for details).

We landed a workaround to fix this problem in Safari, that somehow adds an exception for buttons to follow point 1) even if they are not mouse focusable. Anyway this doesn’t look like the solution for the long term, and looking into making buttons mouse focusable on Safari might be the way to go in the future. That will also help to solve other interop issues.

And now what?

The feature is complete and shipped, but as usual there are some other things that could be done as next steps:

  • The :focus-visible specification is kind of vague and has no normative text related to when or not show a focus indicator. This was done on purpose to advance on this area and have flexibility to adapt to user needs. Anyway now that all 3 major web engines agree on the implementation, maybe there could be the chance to define this in some spec. We tried to write a PR for HTML spec when we started the work on this feature, at that time it was closed, probably it was not the right time anyway. But maybe something like that could be retaken at some point in the future.
  • WebKit Web Inspector (Dev Tools) don’t allow you to force :focus-visible yet. We sent a patch for forcing :focus-within first but some UI refactoring is needed, once that’s done adding support for :focus-visible too should be straight forward.
  • Coming back to the topic on buttons not being mouse focusable in Safari. The web platform provides a way to make elements not keyboard focusable via tabindex="-1". Why not providing a way to mark an element as not mouse focusable? Maybe there could be a proposal for a new HTML attribute that allows making elements not mouse focusable, that way websites could mimic Apple platform conventions. There are nice use cases for this, for example when you’re editing an input and then you click on some button to show some contextual information, with something like this you could avoid losing the focus from the input to carry on with your editing.


So yeah after more than a year since Igalia started working on :focus-visible in WebKit, we can now consider that this work has been complete. We can call the first Open Prioritization experiment a success, and we can celebrate together with all the people that have supported us during this achievement. 🎉

Thank you very much to all the people that sponsored this work. And also to all the people that helped reviewing patches, reporting bugs, discussing things, etc. during all this time. Without all your support we won’t be able to have made this happen. 🙏

Last but not least, we’d like to highlight how this work has helped the web platform as a whole. Now the major web browser engines have shipped :focus-visible and are using it in the default UA stylesheet. This makes tweaking the focus indicator on websites easier than ever.

April 07, 2022 10:00 PM

March 24, 2022

Release Notes for Safari Technology Preview 142

Surfin’ Safari

Safari Technology Preview Release 142 is now available for download for macOS Big Sur and macOS Monterey. If you already have Safari Technology Preview installed, you can update in the Software Update pane of System Preferences on macOS.

This release covers WebKit revisions 289213-290223.

Note: Tab Groups do not sync in this release.

Web Inspector

  • Elements Tab
  • Sources Tab
    • Fixed clicking to re-enable a breakpoint clearing automatic continue (r289669)
    • Fixed double-clicking a breakpoint icon to show the edit popover (r289670)

CSS Subgrid

  • Enabled subgrid by default (r290111)
  • Added accounting for subgrid margin, border, and padding when sizing (r290096)
  • Added support for parsing subgrid in grid-template-columns and grid-template-row (r289722)
  • Changed to copy track sizes from the parent grid into subgrid (r290007)
  • Changed to inherit track count from the parent grid for subgridded axes and clamp item placement to that explicit grid (r289986)
  • Included subgrid items in the track sizing algorithm of the outer grid (r290077)
  • Implemented getComputedStyle for subgrids (r289993)
  • Fixed certain scenarios where grid may be empty (r289437)
  • Fixed recalculating styles when updating a grid gap value (r289241)

CSS Container Queries

  • Enabled CSS Container Queries by default (r290025)
  • Added query container tracking so they can be invalidated on size change (r289457)
  • Added support for all size features (r289838)
  • Added support for full range notation in size queries (r290037)
  • Added support for range operators in size queries (r289789)
  • Changed size queries on unsupported axis to evaluate to unknown (r289890)
  • Implemented container name matching (r289617)
  • Implemented full query parser and evaluator (r289742)
  • Implemented inline-size containment (r289466)
  • Implemented container shorthand serialization (r289886)
  • Matched container queries correctly in non-rendered subtrees (r290205


  • Enabled CSS Motion Path by default (r290071)
  • Enabled overscroll-behavior by default (r289683)
  • Changed transform: perspective(0) to not be considered an identity operation (r289903)
  • Changed to return none for the computed style of a mask when there are no mask images (r289377)
  • Fixed :focus-visible with a click on radio or checkbox labels (r289521)
  • Fixed contain: content in fullscreen (r289686)
  • Fixed incorrect absolute position layout when toggling contain (r289527)
  • Updated conversion to a color space with a smaller gamut to perform gamut mapping (r289396)
  • Updated an element with both -webkit-user-select: all and -webkit-user-drag: element to get a snapshot as when using only -webkit-user-drag: element (r289544)

Web Animations

  • Enabled the KeyframeEffect.composite property (r290067)
  • Added composite accumulation support for transform properties (r289599)
  • Added support for logical properties in JS-originated animations (r289216)
  • Aligned animations with different, but compatible, frameRate values (r290121)
  • Allowed setting frameRate as an option passed to Element.animate() (r290123)
  • Allowed setting frameRate as an option passed to document.timeline.animate() (r290125)
  • Changed to properly handle interpolation of non-invertible matrices (r289862)
  • Changed to use the animation frameRate during animation resolution and scheduling (r290003)
  • Changed Animation.commitStyles() to use the non-animated style (r289453)
  • Fixed additive and accumulation interpolation to work correctly with implicit 0% and 100% keyframes (r289454)
  • Fixed animating from scale() to scale() translate() (r289732)
  • Fixed additive animations to prevent other animations from running accelerated (r289605)
  • Fixed recomputing keyframes when changing direction or writing-mode (r289426)
  • Fixed clearing computed keyframes when changing direction or writing-mode (r289226)
  • Fixed animations associated with a custom effect to appear in document.getAnimations() result (r290122)
  • Implemented parsing and animation support for offset shorthand (r289876)


  • Fixed tab characters and ch units to obey synthetic bold width adjustments correctly (r289609)


  • Changed input elements to return an empty string for an invalid floating-point number that ends with “.” (r290124)
  • Fixed selection method return values to match the spec (r289813)
  • Fixed light appearance text fields rendering invisible in Increased Contrast mode (r290054)
  • Fixed clicking an <input type="image"> submitting the form with a null submitter (r289615)
  • Improved applyStep() to match the spec (r289465)


  • Enabled Shadow Realms support by default (r290119)
  • Implemented Temporal.PlainDate behind a flag: __XPC_JSC_useTemporal=1 (r290209)
  • Optimized JSString’s atomization (r289359)

Shared Workers

  • Added support for sharing Shared Workers (including across WebProcesses) (r289247)
  • Changed to fail synchronously when constructing a SharedWorker with a URL that is not same-origin (r289532)
  • Fixed self.location.href in Shared Workers in case of redirects (r289483)


  • Changed worker scripts to always be decoded as UTF-8 (r289489)
  • Fixed WorkerGlobalScope.importScripts() to protect blob URLs that were passed in until the imports are done (r289236)
  • Fixed MIME type check for classic worker script fetches (r289672)
  • Fixed exceptions to be properly reported when initializing a worker as a module (r289479)

Dialog Element

  • Fixed the Dialog element only animating once (r289498)
  • Exposed the correct role, subrole, and role description properties for the <dialog> element (r289713)


  • Added support for both versions of ScreenCaptureKit API (r289547)
  • Changed to use the system window and screen picker when available (r289696, r289701)
  • Fixed settling a fetch promise to be delayed in case the page is entering page cache (r289533)
  • Optimized DOM storage event dispatch (r290223)

Experimental Model Element

  • Improved sizing on macOS (r289495)
  • Made standalone model documents interactive (r289666)

Web Extensions

  • Added support for the browser.action.openPopup() and browser.browserAction.openPopup() API to open the extension popup for a specific window (this is a WECG proposal)
  • Added support for the optional_host_permissions manifest key in manifest_version 3 extensions (this is a WECG proposal)
  • Added support for browser.runtime.getFrameId() so it easier to get frame identifiers from content scripts (this is a WECG proposal)
  • Added support for the frameId option that can be passed to browser.tabs.sendMessage()
  • Fixed the number returned by parentFrameId for webNavigation and webRequest events to be -1 when it is the main frame
  • Fixed devtools.panels.onShown so the window object of the panel is sent to the listeners
  • Fixed devtools.panels.onShown to prevent it from firing multiple times per active panel change
  • Made the devtools API namespace only exposed to the devtools background pages

March 24, 2022 12:18 AM

March 14, 2022

New WebKit Features in Safari 15.4

Surfin’ Safari

With over 70 additions to WebKit, Safari 15.4 is packed with new web technologies, updates, and fixes. We’ve assembled a huge release as part of our commitment to web developers, and the people who use the web. This is the first big WebKit release of 2022, and we’re just getting started.

Safari 15.4 is available for macOS Monterey 12.3, macOS Big Sur, macOS Catalina, iPadOS 15.4, and iOS 15.4. You can update to Safari 15.4 on macOS Big Sur and macOS Catalina by going to System Preferences → Software Update → More info, and choosing to update Safari.


Let’s start with HTML. WebKit added support for lazy-loading images with the loading attribute on the <img> element, providing web developers with an easy way to instruct the browser to defer loading certain images until the user scrolls near them.

After years of standardization debates over accessibility considerations and with a solution finally at hand, WebKit added support for the <dialog> element and ::backdrop pseudo-element. The <dialog> element provides a robust and powerful way to create overlays and modals.

<dialog id="confirmation-dialog">
    <h1>Do you want to delete everything?</h1>
    <p>You will lose all your data.</p>
    <button id="cancel-delete">Cancel</button>
    <button id="confirm-delete">Delete!</button>

The ::backdrop pseudo-element makes it possible to style the background underneath the modal.

This is a pretty dialog

Pretty dialog example styled

You can learn all about using <dialog> and ::backdrop in Introducing the Dialog Element.

WebKit also added support for the global autofocus attribute allowing developers to indicate which element should be the one in focus when the page loads or when a <dialog> is displayed.


Features for CSS Architecture

Several additions to CSS in 2022 offer revolutionary new ways for web developers to architect their code, making it easier to reuse code, create design systems, and integrate with complex applications.

Landing in Safari first, WebKit added support for the :has() pseudo-class. This selector fulfills a long-expressed desire for a “parent selector” — a way to apply CSS rules conditionally based on the contents of an element — and goes even further with the possibilities it enables. It was long thought such a selector was not possible, but our team figured out a way to highly-optimize performance and deliver a flexible solution that does not slow the page.

WebKit added support for Cascade Layers — a powerful way to organize styles into layers where specificity is calculated independently inside each layer.

a diagram of cascade layers, showing how Author layers cascade

A web developer could create a “framework” layer and a “custom” layer — assigning all the CSS from a 3rd-party framework to the “framework” layer, and writing their own code in the “custom” layer. They could designate that everything in the custom layer should beat everything in the framework layer, no matter the specificity of the selectors used in each layer. Cascade Layers is arriving in all major browsers at about the same time and is included in Interop 2022, ensuring this is a tool web developers can begin to seriously consider for the future.

WebKit also added support for CSS Containment — all four types: size, layout, style, and paint — with the contain property.

Solving Pain Points

Several more additions to CSS in WebKit introduce solutions to long-standing pain points.

Web developers often ask for a tool that would work similar to existing viewport units, but work better on mobile devices where the dimensions of the browser’s viewport change as a user scrolls the page. The new Viewport Units are that solution. 100svh refers to 100% of the height of the smallest possible viewport. 100lvh refers to 100% of the height of the largest possible viewport. And 100dvh refers to 100% of the dynamic viewport height — meaning the value will change as the user scrolls.

100svh measures the smallest viewport, top to bottom. 100lvh measures the largest viewport. 100dvh measures the dynamic viewport, changing as the user scrolls.

There are other new viewport units as well — svw, lvw, and dvw serve the same purpose for width. To cover the small, large, and dynamic versions of vmin and vmax, the svmin, svmax, lvmin, lvmax, dvmin, and dvmax units were implemented. To support logical dimensions, the new vi and vb are similar to existing Viewport Units, in the viewport inline and viewport block dimensions. And svi, svb, lvi, lvb, dvi, and dvb provide logical dimension units for the small, large, and dynamic versions of the inline and block dimensions. WebKit is happy to lead the pack, shipping these new units first and encouraging other browsers to do so through Interop 2022.

WebKit added support for the :focus-visible pseudo-class to style the focus indicator only when the browser renders it. Learn more by reading The Focus-Indicated Pseudo-class :focus-visible.

To make native form controls more customizable, the accent-color property provides a way for web developers to alter the color of particular parts of the form control UI. Accent color is supported for <input type="checkbox">, <input type="radio">, <progress>, <select>, and text-input types with a <datalist> on macOS, iPadOS, and iOS. Additionally, on iPadOS and iOS, accent color is supported for <input type="range">, <button>, and <input type="button">.

WebKit fixed a bug with the interpolation between colors with alpha transparency — improving gradient support.

How a gradient looks before & after this fix. Without the fix, the color is muddy.

WebKit added support for calc() math functions including sin, cos, tan, e, pi, exp, log, atan, acos, asin, and atan2.


Several new WebKit features in Safari 15.4 enrich what’s possible in typography on the web.

WebKit added support for the font-palette CSS property and @font-palette-values rule. The font-palette property provides a way for web developers to select one of several different pre-defined 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.

four versions of a drop cap, in orange, purple, yellow, and black.The color font used for the enlarged caps is Bradley Initials DJR Web, shown here with its default palette, a customized palette created by the web developer, an alternative palette that’s included with the font, and with color removed by the user’s preference.

WebKit added support for text-decoration-skip-ink to control how underlines and overlines are rendered when they pass over glyph ascenders and descenders. WebKit previously supported this typography feature through text-decoration-skip, but since no other browsers yet support this short-hand, WebKit’s support of the long-hand will make it easier to turn off ink skipping for underlines and overlines.

WebKit added support the ic unit, useful when typesetting CJK scripts. Much like how the ch unit is equivalent to the width (or height, whichever is the inline direction) of the 0 glyph in a font, the ic unit is equivalent to inline direction length (width or height) of the “水” glyph in the element’s current font.

Retiring WebKit prefixes

In an ongoing effort to reduce dependency on prefixes, WebKit newly supports several CSS properties and values that were only previous available in an earlier form. The prefixed versions will still work, now aliased to the unprefixed versions. Safari 15.4 added support for:

  • appearance, including appearance: auto
  • mask, along with the long-hand forms mask-image, mask-size, mask-repeat-x, mask-repeat-y, mask-origin
  • backface-visibility
  • text-combine-upright
  • print-color-adjust
  • match-parent CSS value for the text-align property

WebKit also removed the non-standard CSS properties -webkit-border-fit, -webkit-margin-collapse, -webkit-margin-top-collapse, -webkit-margin-bottom-collapse, -webkit-margin-before-collapse, -webkit-margin-after-collapse, and -webkit-background-composite.

Web APIs

This release includes many upgrades to Web APIs in WebKit to help web developers deliver better user experiences.

New support for BroadcastChannel allows tabs, windows, iframes, and Workers from an origin to send messages to each other. This enables experiences like syncing login state for a site across multiple tabs.

Another new mechanism supported in WebKit is the Web Locks API to manage access to a resource as an asynchronous locking control from an origin in tabs, windows, iframes, and Workers.

Developers can also control scroll behavior for an element with either the CSS scroll-behavior property or the behavior option in window.scroll(), window.scrollTo(), and window.scrollBy() methods in JavaScript. This new support gives developers the ability to choose between instantly jumping to a position in the viewport or smoothly animating the scroll operation.

The ResizeObserver API has updated support for the ResizeObserverSize interface used by ResizeObserverEntry to help developers observe changes to an element’s box-sizing properties.

The addition of structuredClone(value) provides a utility that uses the structured clone algorithm to synchronously perform a deep copy to clone and transfer objects from the input value.

WebKit support of the File System Access API with Origin Private File System first shipped in Safari 15.2. This release introduces the getFile() method in FileSystemFileHandle making it more convenient to read a file from the file system. Plus, WebKit updated WriteableStream to work with the File System Access API. For more information, read File System Access API with Origin Private File System.


New features and updates to JavaScript bring added convenience for developers. Handy new Array features make it nicer to search starting from the end of an array using the findLast() and findLastIndex() methods. These methods help developers avoid the typical approach requiring mutating the array with reverse() first.

There’s also support for the at() method to access an entry at a specified integer index, which notably includes support for using negative integers to start at the end of the array.

let list = ['banana','cherry','orange','apple','kiwi'];

// Instead of this:

// It's as easy as:

The new language utility Object.hasOwn() simplifies detecting when the object has a property itself, one that is not inherited or doesn’t exist.


As the standards process defines more Internationalization features, WebKit continues to add regular updates to its Intl implementation. This release includes identifying the supported values of local time zones, collations, calendars, numbering systems, and currency with the Intl Enumeration API.

Intl.Locale, updated to V2, exposes new information that includes calendar-week data such as the first day of the week, text information like writing direction, and other region-dependent defaults such as calendars, 12- or 24-hour cycles, and numbering systems.

WebKit also updated Intl.DisplayNames to V2, adding support for the calendar and dateTimeField names, and the languageDisplay option.

The selectRange() method added to Intl.PluralRules provides locale-correct pluralization for ranges (e.g. 0-1 items). The Intl.NumberFormat V3 update adds the formatRange() and formatRangeToParts() methods for formatting a number range using locale-aware conventions along with new useGrouping, roundingPriority, roundingIncrement, trailingZeroDisplay, and signDisplay options.

Finally, Intl.DateTimeFormat includes support for four new timeZoneName options: shortOffset, longOffset, shortGeneric, and longGeneric.

Web Apps

Web App Manifest and ServiceWorker received updates that improve the user experience for both websites in Safari and web apps saved to the home screen on iOS and iPadOS.

Web App Manifest improvements include ensuring the browser always fetches the manifest file during page load instead of when the user chooses to “Add to Home Screen” from the Share menu. This approach improves reliability, and also allows a manifest file to define the characteristics of a webpage in Safari.

In addition, declaring icons in a web app manifest file is now supported. Safari and iOS use manifest-declared icons when there is no apple-touch-icon defined in the HTML head, and when the manifest file code for declaring the icons either omits the "purpose" key or includes "purpose": "any". Defining icons by using apple-touch-icon takes precedence over manifest-declared icons in order to provide consistent behavior for web apps that use this technique to define specific icons for iOS, distinct from other mobile platforms.

Developers can now enable Navigation Preload in ServiceWorker to improve load performance and avoid ServiceWorker startup delays that block network requests. There’s also new support for allowing users to download files generated by a ServiceWorker. WebKit also improved the reliability of using Fetch using FormData with a file going through ServiceWorker.


The WebRTC negotiation API is now fully aligned with the WebRTC 1.0 specification to support WebRTC perfect negotiation. It is an approach that solves potential synchronization issues that can happen during negotiation between two remote peers.

WebKit added support for in-band chapter tracks for audio and video. In-band text tracks provide captions or chapter marker information inside the container for the media itself, instead of being declared in HTML or injected with JavaScript. In-band caption tracks like CEA-608 were already supported. Now, in-band chapter tracks are also supported, where the “cue” represents the start time and title of a chapter.

WebKit added support for requestVideoFrameCallback() on <video>, which allows the caller to be notified when there’s a new video frame available for display, and also provides metadata about that frame.


Continuing our dedication to privacy, and to further our proposed web standard for measuring advertising in a privacy-preserving way, Safari 15.4 provides three updates to Private Click Measurement:

  • Added conversion fraud prevention via unlinkable tokens for triggering events on merchant websites.
  • Added support for same-site conversion pixels on merchant websites, to remove dependency on cross-site pixels.
  • Allowed measurement of links in nested, cross-site iframes on publisher websites.


WebKit in Safari 15.4 improves support for Content Security Policy Level 3, providing enhanced security control over the loading of content, and helping web developers to mitigate risks of cross-site scripting and other vulnerabilities. Blocked resource violation reporting for inline script, inline style and eval execution is updated to match web standards. New support for 'strict-dynamic', 'unsafe-hashes', and 'report-sample' source expressions give developers more flexibility. Developers can also safely include external JavaScript in their pages using new support for hash source expressions.

The release also removes support for the XSS Auditor, which has been superseded by modern cross-origin defenses like CSP and COEP.


Developers that use WKWebView, including third-party browsers on iOS and iPadOS, can make use of new WKPreferences for additional user experience control. Apps on iOS, iPadOS, and macOS can now control allowing or preventing web content from using the Fullscreen API. Another new preference allows enabling or disabling site-specific quirks, a set of site-specific behaviors designed to improve web compatibility.

On iPadOS, web content that uses Media Source Extensions now works in WKWebView.

Safari Web Extensions

In our ongoing commitment to a cross-browser interoperable model for extensions, Safari 15.4 includes additional support for Web Extensions, including support for manifest_version 3 and related API changes. New capabilities include:

  • service_worker background scripts as an alternative to non-persistent background pages.
  • Script and style injection via the browser.scripting APIs.
  • Dynamic and session rules via the browser.declarativeNetRequest APIs.
  • Webpage-to-extension messaging using externally_connectable:matches.

And several issues were resolved, including:

  • Limits are now enforced on the size and number of items in extension sync storage.
  • More directives are now allowed to be included in the content_security_policy of an extension’s manifest, such as the sandbox directive.
  • Special matching characters (*, |, ||, and ^) in urlFilter of declarativeNetRequest rules are now handled, instead of being treated as regex patterns.
  • Promise returns from runtime.onMessage listeners are now allowed for the message reply.

Web Inspector

Updates to Web Inspector provide helpful new tools for working with CSS in the Styles panel, including intuitive support for Cascade Layers and the new @layer rulesets, making it easy to identify in which layer a rule is defined.

There are also new CSS Alignment controls when using align-content, align-items, align-self, justify-content, justify-items, or justify-self for Flexbox and Grid to visually identify and select an ideal value.

While adding new properties or values in the Styles panel, Web Inspector offers convenient auto-completion options. This release upgrades auto-completion to use fuzzy matching, making finding the right option even easier.

When working with CSS custom properties, or CSS variables as they’re more widely known, a common practice is to add them to a selector rule for :root or html. Unfortunately, this leads to a long list of inherited CSS variables for every element on the page. Web Inspector helps you handle this in a few ways. First, it hides unused inherited CSS variables automatically. Then, a button is available to reveal them all when you need to see them. You can also use the filter tools to search for the right CSS variable. Or, you can see all applicable CSS variables grouped by value type in the Computed panel, allowing you to collapse the groups that aren’t relevant to your task.

The list of applicable CSS variables can be grouped by value type into collapsible subsections: colors, dimensions and other types.

Learn more by reading Taming CSS Variables with Web Inspector.


We love hearing from you. Send a tweet to @webkit, @jensimmons or @jonathandavis to share your thoughts on this release. What technology from Safari 15.4 are you most excited about? What features or fixes do you want to see next? If you run into any issues, we welcome your feedback on the Safari UI or your WebKit bug report about web technology. 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.

And More

To see the full list of what’s in WebKit for Safari 15.4, including additional bug fixes, read the Safari 15.4 release notes.

These features were first released in Safari Technology Preview: 130, 131, 132, 133, 134, 135, 136, 137, 138, and 139.

March 14, 2022 05:35 PM

March 04, 2022

Release Notes for Safari Technology Preview 141

Surfin’ Safari

Safari Technology Preview Release 141 is now available for download for macOS Big Sur and of macOS Monterey. If you already have Safari Technology Preview installed, you can update in the Software Update pane of System Preferences on macOS.

This release covers WebKit revisions 288438-289213.

Note: Tab Groups do not sync in this release.

Web Inspector

  • Sources Tab
    • Enabled automatic collapsing of blackboxed call frames (r288580)
  • Network Tab
    • Collapsed resource type filter scope bar into a single button to save space (r288469)
    • Changed the Ignore Caches icon to be a button with a label so it’s more visible and immediately understandable (r288533)
    • Moved the Group Media Requests and Preserve Log checkboxes into a single filter icon that shows a contextmenu with those options when clicked to save space (r288470)
  • Graphics Tab
    • Added the display of more pseudo-elements than ::before and ::after (r288623)
  • Console Tab
    • Moved the Preserve Log checkbox into a single filter icon that shows a contextmenu with those options when clicked to save space (r288702)


  • Enabled support for overflow: clip (r288973)
  • Implemented CSS overscroll-behavior for asynchronous scrolling on macOS (r288777)
  • Fixed removal of not yet loaded CSS @import (r288879)
  • Fixed CSS Grid shorthand expansion of initial values (r288544)
  • Fixed scroll-margin-top on inline elements (r288947)


  • Fixed the value not changing for stepUp() and stepDown() with out-of-range values (r289075)
  • Fixed grouping radio buttons with no form owner (r288734)
  • Used min as the default value when min is greater than max for <input type="range"> (r289209)


  • Added support for the WASM branch hinting proposal (r288758, r288761)
  • Added support for the import assertion syntax behind a flag (r288473)
  • Fixed object literal to properly resolve a name clash between an accessor and a constant property (r289166)

Experimental Model Element

  • Allowed disabling interaction (r288728)
  • Fixed mouse interaction flipped in the y-axis (r288610)
  • Fixed <model> to not be draggable on macOS (r288723)

Payment Request

  • Allowed additional payment method specific data to be passed to complete() (r288698)

Web Animations

  • Fixed accelerated transform animations that start with a 1ms delay (r289211)
  • Fixed de-duplication for @keyframes rules to account for animation-composition (r288571)
  • Fixed the ability to redefine @keyframes (r288882)
  • Fixed using logical properties in the transition syntax (r289161)
  • Resolved logical properties when compiling the list of transition properties (r289167)


  • Changed the HTMLMediaElement to dispatch the resize event asynchronously (r289108)
  • Changed to remove customElements when transitioning documents (r288450)
  • Fixed slow, CPU-bound file.stream() (r288463)
  • Fixed Geolocation API to callback with an error if the document is not fully active (r288707)
  • Fixed ServiceWorkerNavigationPreloader to only be used once (r288949)
  • Implemented AbortSignal.timeout() (r289058)


  • Allowed use of hardware-fixed credentials while using “Syncing Platform Authenticator” (r289059)
  • Added authenticator attachment to PublicKeyCredential (r288622)

Content Security Policy

  • Fixed returned WebAssembly error type when blocked (r288992)
  • Fixed blocking image content in object elements (r288792)
  • Implemented wasm-unsafe-eval (r289022)

March 04, 2022 12:20 AM

March 03, 2022

Working together on Interop 2022

Surfin’ Safari

From the very beginning, the web was always intended to work in any browser, on any computer. This is possible through interoperability — when each underlying web technology is implemented in the same way in every browser. To reach interoperability, it takes a commitment from all browser engineers to implement web technology according to web standards — the incredibly detailed specifications where new technology is defined.

In 2022, Apple, Bocoup, Google, Igalia, Microsoft, and Mozilla have come together to commit to improve interoperability in 15 key areas that will have the most impact on web developer experience, in a project called Interop 2022.

At its root, Interop 2022 is an evolving metric generated from a set of automated tests that aims to evaluate support for certain web standards that are most important for web developers. The Interop 2022 dashboard will constantly update throughout the year, showing progress as browser engineers fix bugs, implement new features, and improve the tests.

a screenshot of the Interop 2022 dashboard, showing starting scores of: Chrome and Edge Dev, 71. Firefox Nightly, 74. And Safari Technology Preview: 73.The current overall score on the Interop 2022 dashboard on March 3, 2022.

The group planning Interop 2022 chose ten new focus areas to add to the five areas from Compat 2021. We also committed to several investigation projects, which will begin this spring.

a screenshot of the Interop 2022 dashboard, showing the data table of the 15 focus areas, with the percentage supported for each browserThe scoring breakdown on the Interop 2022 dashboard on March 3, 2022.

Focus areas

Chosen from a list of proposals, with an eye to what web designers & developers want and need most, the ten new focus areas for 2022 are:

  1. Cascade Layers
  2. Color Spaces and Functions
  3. Containment
  4. Dialog Element
  5. Form Fixes
  6. Scrolling
  7. Subgrid
  8. Typography and Encodings
  9. Viewport Units
  10. Web Compat

Let’s take a quick tour of each.

Cascade Layers

Designed to soothe the frustrations of web developers wrestling with CSS on large projects, Cascade Layers provides a powerful way to organize styles into layers, where specificity is calculated independently inside each layer.

a diagram of cascade layers, showing how Author layers cascade

A website could create a “framework” layer and a “custom” layer — assigning all the CSS from a 3rd-party framework to framework layer, writing their own code in the custom layer. They could designate that everything in the custom layer should beat everything in the framework layer, no matter the specificity of the selectors being used.

Color Spaces and Functions

In the early days of the web, most sites restricted their use of color to a specific palette of 216 colors. Then for a long time, web developers used anything in the sRGB color space, and typically expressed those colors in hexadecimal, rgb(), rgba(), or hsl(). Meanwhile, camera and monitor technology have greatly evolved to capture and display a wider and brighter range of colors. Today’s Apple displays support the Display P3 color space, which is about 50% wider than sRGB.

New color functions and support for new color spaces bring this vibrancy to the web. Interop 2022 includes testing for support of three expanded color spaces (LAB, LCH, P3), and two ways to write color in CSS through functional notation: color-mix and color-contrast.

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.


For several years now, web developers’ number one most requested addition to the web has been Container Queries. It will be a powerful tool in CSS for identifying and measuring the size of a specific container, and then conditionally applying styles based on that size. It’s like media queries, but instead of measuring the size of the viewport, you measure the size of a box holding the content.

Containment is foundational to making Container Queries work. In fact, Container Queries is defined in level 3 of the Containment specification. The group driving Interop 2022 didn’t come to consensus to include Container Queries this year. But we did agree to focus on the interoperability of layout, size, and paint containment through the containment property, setting the stage for prioritizing the interoperability of the rest of Containment and Container Queries in the future.

Dialog Element

Another long-requested feature for the web, the dialog element provides a robust and powerful way to create overlays and modals. The ::backdrop pseudo-element makes it possible to style the background underneath the modal. You can learn more about how to use <dialog> and ::backdrop in Introducing the Dialog Element.

Form Fixes

Forms are another area where web designers and developers find interoperability challenges — ones that the Open UI community group and appropriate standards bodies are working to solve. Interop 2022 is contributing to this work by focusing on improving the pass rates for existing tests of existing specs. This includes the appearance property, <form>, events on disabled form controls, and bugs with input elements, form submission, and form validation.


Today’s websites and web apps care more deeply about how scrolling works than ever before. 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.


CSS Grid shipped five years ago in March 2017, revolutionizing what’s possible in layout design on the web. Subgrid is defined in CSS Grid level 2, and provides an easy way to put grandchildren of a grid container on that grid. It will make it possible to line up items across complex layouts, without any regard for the DOM structure. The vision of a working layout system on the web will be more fully realized with Grid and Subgrid together.

Typography and Encodings

Typography and encodings encompasses a collection of tests that impact typography on the web. Font Features are powerful properties for refining typography, but incomplete support has been making them harder to use then they’re supposed to be. The vast majority of the encoding tests pass in every browser, but a handful do not, so they’ve been included. And the ic unit is included.

Viewport Units

Web developers often ask for a tool that would work similar to viewport units, but work better on mobile devices where the dimensions of the browser’s viewport change as a user scrolls the page. The new Viewport Units are that solution. 100svh refers to 100% of the height of the smallest possible viewport. 100lvh refers to 100% of the height of the largest possible viewport. 100dvh refers to 100% of the dynamic viewport height — meaning the value will change as the user scrolls.

100svh measures the smallest viewport, top to bottom. 100lvh measures the largest viewport. 100dvh measures the dynamic viewport, changing as the user scrolls.

There are other new viewport units as well — svw, lvw, and dvw serve the same purpose, for width. And there are new units to refer to the inline or block dimensions of the viewport.

Web Compatibility

There are many scenarios that could impact web compatibility. For example, specific bugs in browsers could disproportionately cause some websites to not work as intended, or perhaps one browser may vary from the web standard, causing an inconsistent and buggy experience for website or web app users. Interop 2022 aims to capture and address these issues through the web compatibility measurement.

Investigation Projects

There were several other items that the group knows are important to web development, but which cannot yet be easily evaluated by automated testing. We’ve committed to embark on several investigations in these areas — to manually test browsers, to determine if and how automated testing could be more helpful, to improve the infrastructure of WPT itself, to discover where there might still be a lack of interop, and to make suggestions to the appropriate standards groups. The three areas of investigation are:

  • Editing, contenteditable, and execCommand
  • Pointer and Mouse Events
  • Viewport Measurement

Each browser will always have the same result for “2022 Investigation”, based on how much work has been accomplished by the group as a whole.

Our Commitment to Interoperability

All of these technologies are important to Apple and to everyone working on WebKit. We care deeply about the health of the web, and interoperable implementations of web standards. We welcome collaboration with our colleagues in the many web standards organizations, and in Interop 2022 to make the web as interoperable as it can be. Because that’s how websites and web apps will work best for the people who matter most — everyday people using the web to live their lives.

For more

Read more about Interop 2022 in articles from Bocoup, Google, Igalia, Microsoft, and Mozilla.

March 03, 2022 05:00 PM

March 02, 2022

Taming CSS Variables with Web Inspector

Surfin’ Safari

CSS Custom Properties, better known as CSS variables, have been widely adopted by web designers to build reusable and configurable design systems. One common approach is to define most CSS variables in a CSS rule with a selector for a root element such as html or :root.

While this has the benefit of putting them all in one easy to find place, it has a side effect: because CSS variables are inheritable, all descendant elements effectively inherit all variables from ancestors. This behavior is what enables you to use a CSS variable defined at a higher level on the styles of an element that is deeply nested within the document.

Descendant elements inherit all CSS variables from their ancestor elements. This can result in very long lists of inherited properties in the Styles panel.

When an element inherits a large number of CSS variables, inspecting its styles can become overwhelming. Likewise, identifying a particular CSS variable to reuse becomes more difficult because you have to search through a large list of them.

Over the past few releases, Web Inspector in Safari Technology Preview has introduced some features to help you when working on projects that use large numbers of CSS variables.

Hiding Unused CSS Variables

Of all inherited CSS variables, only a few are actually used on the styles of any one element. To reduce visual clutter in the Styles panel, unused inherited CSS variables are automatically hidden. They’re replaced with a button that reveals them on click.

This helps focus your attention on just the styles that took effect on the inspected element.

Unused inherited CSS variables are automatically hidden behind a button that reveals them on click.

Searching for CSS Variables

The Computed panel in Web Inspector has a section that lists all CSS variables applicable to the inspected element. This list of properties can help you when searching for a CSS variable to reuse.

Use the filter input field to narrow down the list if you know roughly what you’re looking for, either part of the CSS variable name or part of the value.

Find all CSS variables applicable to the selected element in the Variables section of the Computed panel. Filter the list using the filter input field at the bottom of the panel.

Grouping CSS Variables

Safari Technology Preview 138 introduced the ability to view this list grouped by value type. This creates separate subsections for CSS variables with values such as colors, numbers, dimensions (numbers followed by CSS units), and so forth. Reduce clutter by collapsing the groups you’re not interested in.

The list of applicable CSS variables can be grouped by value type into collapsible subsections: colors, dimensions and other types.

Grouping this way can help you find a CSS variable when you know the type of value you’re looking for, a particular color, for example. Color swatches shown next to variable values together with the ability to group all variables with color values into one distinct section make it easier to visually scan for the desired value.

Jump to CSS Variable Definition

Here’s a tip: place the mouse cursor over any CSS variable in the Computed panel to reveal a go-to arrow. Click this to highlight the place in the Styles panel where the variable is defined. If the target CSS variable is hidden because it is unused, it will be automatically shown. This allows you to quickly jump in context to the place where a CSS variable is defined and edit it.

Use the go-to arrow next to CSS variables in the Computed panel to highlight where the variable is defined in the Styles panel.

You can also use the filter input field at the bottom of the Styles panel (as described above) and type the name of the variable, but using the go-to arrow to quickly jump to it is much more convenient.

Fuzzy Autocompletion of CSS Variable Names

Since its inception, Web Inspector has provided autocompletion for CSS properties and values in the Styles panel. More recently, it introduced the ability to provide completion suggestions for CSS variable names when typing within var() function values, as in var(--link-color).

Safari Technology Preview 138 made this even better with the introduction of fuzzy matching for CSS autocompletion. This is particularly useful for CSS variables when you might not remember the full name. With fuzzy matching, you can get results that match the query at any position, not just at the beginning.

For example, if you know that the CSS variable name you’re looking for, say --link-color, includes the substring “color”, you can type just var(color|) (the | character represents the position of the typing caret). You don’t even need to type the double dash prefix. If the CSS variable --link-color is defined on or inherited by the inspected element, it will be shown in the list of completion suggestions even if the query match occurs at the end of the variable name.

Enjoy the flexibility of fuzzy matching for CSS autocompletion to quickly find a variable by typing any part of its name.
For example, type just “color” to match --link-color.


CSS variables enable a growing number of uses, such as building configurable design systems, practical theming for light and dark modes, customizable styles for web components, among many others. But the proliferation of variables in large numbers within a project can also become a burden during development and debugging.

Web Inspector has introduced features to help keep you focused and productive. Hiding unused inherited CSS variables in the Styles panel reduces clutter. Collecting and grouping CSS variables in the Computed panel focuses your attention. Fuzzy matching in autocompletion of variable names and filter input fields help you quickly find and reuse variables.

We hope these improvements make your work easier when dealing with CSS variables.
As always, if you encounter any issues, please file a report at webkit.org/new-inspector-bug.
If you want to share feedback or ideas, please send them to us on Twitter: @webkit.

Note: Learn more about Web Inspector from the Web Inspector Reference documentation.

March 02, 2022 05:00 PM

February 14, 2022

The File System Access API with Origin Private File System

Surfin’ Safari

It is very common for an application to interact with local files. For example, a general workflow is opening a file, making some changes, and saving the file. For web apps, this might be hard to implement. It is possible to simulate the file operations using IndexedDB API, an HTML input element with the file type, an HTML anchor element with the download attribute, etc, but that would require a good understanding of these standards and careful design for a good user experience. Also, the performance may not be satisfactory for frequent operations and large files.

The File System Access API makes it possible for web apps to have easy and efficient file access. It provides a way to create, open, read, and write files directly. It also allows apps to create directories and enumerate their contents.

Origin Private File System

WebKit has added support for the File System Access API with the origin private file system — a private storage endpoint to some origin. Conceptually, every origin owns an independent directory, and a page can only access files or directories in its origin’s directory. For example, https://webkit.org cannot read files created by https://apple.com.

Based on the implementation of different browsers, one entry in the origin private file system does not necessarily map to an entry in the user’s local filesystem — it can be an object stored in some database. That means a file or directory created via the File System Access API may not be easily retrieved from outside of the browser.


The API is currently unavailable for Safari windows in Private Browsing mode. For where is it available, its storage lifetime is the same as other persistent storage types like IndexedDB and LocalStorage. The storage policy will conform to the Storage Standard. Safari users can view and delete file system storage for a site via Preferences on macOS or Settings on iOS.

Browser Support

The File System Access API with origin private file system is enabled in WebKit from r284131. It is available in Safari on:

  • macOS 12.2 and above
  • iOS 15.2 and above

In Safari on macOS 12.4 and iOS 15.4, we introduced the getFile() method of FileSystemFileHandle.


WebKit currently supports four interfaces of the File System Access API:

  • FileSystemHandle, which represents an entry in the file system. It is available in Worker and
  • FileSystemFileHandle, which inherits from FileSystemHandle and represents a file entry.
  • FileSystemDirectoryHandle, which inherits from FileSystemHandle and represents a directory entry.
  • FileSystemSyncAccessHandle, which provides an exclusive duplex stream for synchronous read and write on an entry. Unlike the interfaces above, which exist in both Window and Worker contexts, FileSystemSyncAccessHandle is only available in Worker.

With these basic interfaces in mind, let’s look at how to use them by diving into some examples.


Accessing the Origin Private File System

In the origin private file system, a FileSystemHandle represents either the root directory of the origin’s space, or a descendant of the root directory. Therefore, the first step is to get the root FileSystemDirectoryHandle. It is done via StorageManager interface.

const root = await navigator.storage.getDirectory();

Creating a directory or a file

With a FileSystemDirectoryHandle object like root, you can get access to its child with some specific name using getDirectoryHandle() and getFileHandle() methods.

// Create a file named Untiled.txt under root directory.
const untitledFile = await root.getFileHandle("Untitled.txt", { "create" : true });
// Get access to existing Untitled.txt file.
// untitledFile and existingUntitledFile point to the same entry.
const existingUntitledFile = await root.getFileHandle("Untitled.txt");
// Create a directory named Diary Folder.
const diaryDirectory = await root.getDirectoryHandle("Diary Folder", { "create" : true });

Moving or Renaming a Directory or a File

To move around the file or directory a FileSystemHandle represents, you can use the move() method. The first parameter is a FileSystemDirectoryHandle representing the target parent directory, and the second parameter is a USVString representing the target file name. The string must be a valid file name.

// Move Untitled.txt from /root/ to /root/Diary Folder/.
await untitledFile.move(diaryDirectory, untitledFile.name);
// Rename Untitled.txt to Feb_01.txt
await untitledFile.move(diaryDirectory, "Feb_01.txt");
// The two steps above can be combined as:
// await untitledFile.move(diaryDirectory, "Feb_01.txt");

Resolving the Path from a Directory Entry to its Descendant

To find out if a FileSystemHandle is a descendant of an existing FileSystemDirectoryHandle, and to get their relative path, you can use the resolve() method. The result is an array of component names that forms the path.

// Get access to Feb_01.txt in Diary Folder.
const diaryFile = await diaryDirectory.getFileHandle("Feb_01.txt");
// Resolve path between Feb_01.txt and root.
const relativePath = await root.resolve(diaryFile);
// relativePath is ["Diary Folder", "Feb_01.txt"].

Enumerating Contents in a Directory

The methods introduced above require you to know the name of target, but if you don’t know the name, you can still get it by enumerating the contents of an existing directory with async iterators returned by the keys(), values(), and entries() methods.

// Create a directory named Trash under the root directory.
const trashDirectory = await root.getDirectoryHandle("Trash", { "create" : true });
// Find directories under root/ and print their names.
const directoryNames = [];
for await (const handle of root.values()) {
    if (handle.kind == "directory") {
// directoryNames is ["Trash", "Diary Folder"].

Deleting a Directory or a File

With a FileSystemDirectoryHandle object, you can delete its child entries by name with the removeEntry() method.

// Delete Feb_01.txt in Diary Folder.
await diaryDirectory.removeEntry(diaryFile.name);
// Delete Trash and all its descendants.
await root.removeEntry(trashDirectory.name, { "recursive" : true });

Reading a File

Once you have the FileSystemFileHandle representing the target file, you can read its properties and content by converting it to a File object using the getFile() method. You can get file information and content using interfaces of File.

const fileHandle = await root.getFileHandle("Draft.txt", { "create" : true });
const file = await fileHandle.getFile();

Reading and Writing a File in a Worker Thread

Another way to read a file is to use the read() method of the FileSystemSyncAccessHandle interface. You can create a FileSystemSyncAccessHandle from a FileSystemFileHandle object using the createSyncAccessHandle() method. Since FileSystemSyncAccessHandle is only available in Worker contexts, you will need to create a dedicated Worker first.

Unlike getFile() that returns a Promise, read() is synchronous, and thus provides better performance. If you’re aiming for the most efficient file access, FileSystemSyncAccessHandle is the way to go.

To write a file, you can use the synchronous write() method of FileSystemSyncAccessHandle. In the current implementation, this is the only way to write a file in WebKit.

To implement synchronous read and write operations, a FileSystemSyncAccessHandle must have exclusive access to a file entry. Therefore, the attempt to create a second FileSystemSyncAccessHandle on an entry will fail, if the previous FileSystemSyncAccessHandle is not closed properly.

// Get access to the existing Draft.txt file.
const root = await navigator.storage.getDirectory();
const draftFile = await root.getFileHandle("Draft.txt");
// Create FileSystemSyncAccessHandle on the file.
const accessHandle = await draftFile.createSyncAccessHandle();
// Get size of the file.
const fileSize = await accessHandle.getSize();
// Read file content to a buffer.
const readBuffer = new ArrayBuffer(fileSize);
const readSize = accessHandle.read(readBuffer, { "at": 0 });
// Write a sentence to the end of the file.
const encoder = new TextEncoder();
const writeBuffer = encoder.encode("Thank you for reading this.");
const writeSize = accessHandle.write(writeBuffer, { "at" : readSize });
// Truncate file to 1 byte.
await accessHandle.truncate(1);
// Persist changes to disk.
await accessHandle.flush();
// Always close FileSystemSyncAccessHandle if done.
await accessHandle.close();


If your web app needs to interact with files, you should try the new File System Access API. It provides interfaces that are similar to the native file system API, with optimized performance.

As the standard evolves and development goes on, we will keep adding or updating interfaces and methods according to the File System Access API spec. If you encounter any issue when using this API, please file a bug on bugs.webkit.org under the “Website Storage” component. You may also create a new bug report for feature requests, describing your use case and why the feature is important. If you have any question or suggestion about the API itself, you can file a spec issue in the WICG repo. Your feedback is very important to us.

February 14, 2022 05:00 PM

February 10, 2022

Release Notes for Safari Technology Preview 140

Surfin’ Safari

Safari Technology Preview Release 140 is now available for download for macOS Big Sur and of macOS Monterey. If you already have Safari Technology Preview installed, you can update in the Software Update pane of System Preferences on macOS.

This release covers WebKit revisions 287834-288438.

Note: Tab Groups do not sync in this release.

Web Inspector

  • Elements Tab
    • Made CSS Alignment controls in the Styles Detail Sidebar accessible (r288385)
  • Sources Tab
    • Added a contextual menu item to create a URL Breakpoint for resources initiated by script (r288029)
    • Fixed fully blackboxed stack traces to show the right top call frame (r288266)
  • Timelines Tab
    • Added better names for newer CSS Animations, CSS Transitions, and Web Animations events (r287945)

:has() Pseudo-Class

  • Added support for :has(:not(foo)) (r288303)
  • Avoided complex style invalidation with repeated DOM mutations (r288012, r287973)
  • Fixed computing specificity (r288196)
  • Changed to disallow nested :has() (r288111)
  • Changed to ignore :visited inside :has() (r288304)


  • Added support for intrinsic sizes in flex-basis (r288113)
  • Added support for intrinsic sizes to the flex shorthand (r288184)
  • Added support for “missing“/”none” color components (r288143)
  • Added support for interpolating colors with “missing”/“none” components via color-mix() (r288427)
  • Added support for preloading of layered @import rules (r288099)
  • Changed interpolation mode for CSS gradients to default to OKLab if any non-legacy color syntax colors are used in the stops (r288071)
  • Changed to only apply automatic minimum block-size aspect-ratio rules to non-replaced elements (r288003)
  • Fixed the ::backdrop pseudo-element to react to associated element event listeners (r287878)
  • Fixed the CSS color() function to not clamp channels to the 0-1 range (r287838)
  • Fixed the height of flex items with aspect-ratio whenever the cross axis intrinsic size is larger than the viewport (r287976)
  • Fixed rounding of distributed free space to flexible tracks (r287977)
  • Fixed position: fixed layers to not allocate a backing buffer if all the children are offscreen (r288429)
  • Fixed setting content: normal on a ::marker to make the computed style return resolved values (r288054)


  • Added support for FetchEvent.handled API for Service Workers (r287915)
  • Enabled form.requestSubmit() (r288179)
  • Fixed nextHopProtocol exposed regardless of Timing-Allow-Origin (r288219)
  • Fixed input.labels inside shadow DOM (r288162)
  • Fixed canvas functions that take colors as strings to support all the syntax that CSS supports (r288134)
  • Implemented HTMLScriptElement.supports(type) method (r287996)
  • Improved computation of Service Worker FetchEvent.resultingClientId (r288201)

Web Animations

  • Added support for animation-composition CSS property (r288433)
  • Changed getKeyframes() for a CSS Animation to not use computed style for keyframes (r287835)
  • Fixed interpolation during animation of two empty transform lists to always yield “none” (r287917)


  • Fixed Date functions’ argument coercion (r288066)
  • Relaxed Date.parse requirement (r288411)


  • Fixed misc WebAssembly.Table issues (r288064)
  • Fixed misc issues in WebAssembly.Exception (r288065)
  • Fixed WebAssembly.Global‘s typename for “anyfunc” (r288049)

Dialog Element

  • Added visibility: visible to modal dialogs in the user-agent stylesheet (r288233)
  • Fixed some overflow and clipping issues with modal dialogs (r288267, r287845)


  • Fixed support for new lines in HTMLTextArea’s placeholder text (r288005)
  • Fixed keeping the selected state of a select element when inserting a selected <option> (r288174)
  • Prevented contenteditable anchors from being stuck (r288420)


  • Fixed gl.texImage2D upload of getUserMedia streams via <video> element fails (r288025)
  • Fixed MediaStream canvas.captureStream() playback (r288435)
  • Fixed portrait video playback on HTML canvas elements (r288053)
  • Fixed no VP9-SVS video stream from remote peer on some devices (r287928)
  • Fixed “Add to Contact” menu item (r287959)
  • Tightened the focus check for getUserMedia (r288087)


  • Allowed single use of WebAuthn without user gesture for all relying parties (r287957)


  • Exposed toggle buttons using role="button" as form controls (r288100)
  • Improved support for aria-owns in ARIA trees (r288117)

Content Security Policy

  • Improved handling of multiple policies (r288132)


  • Fixed an issue where a website may be able to track sensitive user information (r288078)


  • Fixed calculations of filterRegion and outsets of the referenced SVG filter (r288183)
  • Fixed referenced SVG filter always using sRGB color space for its result (r287982)


  • Fixed sometimes not being able to scroll after using a builtin trackpad (r287997)

Web Extensions

  • Fixed a crash when calling browser.webNavigation.getAllFrames() on an empty tab
  • Fixed Active tab permissions for a tab to get removed if a matching per-site permission changes to “Deny”
  • Fixed service worker background script errors to get reset each time they successfully load

February 10, 2022 09:05 PM

February 07, 2022

Introducing the Dialog Element

Surfin’ Safari

Although the alert, confirm and prompt JavaScript methods are convenient, they aren’t recommended due to their script-blocking behavior. That’s why we worked with other browser vendors to drive improvements to the <dialog> specification over the last few years. The most important conversations involved accessibility.

You can find more complex use-cases, like payment dialogs, on the web. They are currently addressed by custom solutions from frameworks like Bootstrap. Unfortunately, they aren’t convenient to use and aren’t always accessible. We believe the web deserves a simple and bug-free solution for these use-cases. Safari Technology Preview 134 and Safari 15.4 beta introduces the <dialog> element for this reason!

How Do I Use <dialog>?

Let’s create a simple confirmation dialog:

<dialog id="confirmation-dialog">
    <h1>Do you want to delete everything?</h1>
    <p>You will lose all your data.</p>
    <button id="cancel-delete">Cancel</button>
    <button id="confirm-delete">Delete!</button>

Dialogs are hidden by default. We can use the showModal() method to show the dialog. When it’s shown, the dialog can be closed with the close() method.

Here is an example:

<button id="delete">Delete everything</button>
<p id="result"></p>
let dialog = document.getElementById("confirmation-dialog");
let result = document.getElementById("result");

// Show the dialog when clicking "Delete everything"
document.getElementById("delete").addEventListener("click", function() {

document.getElementById("cancel-delete").addEventListener("click", function() {
    result.textContent = "Canceled!";
document.getElementById("confirm-delete").addEventListener("click", function() {
    result.textContent = "Deleted!";

Note that the dialog will get an open attribute once opened, which may be useful for styling purposes. However, it’s not recommended to toggle this attribute manually to show or hide the dialog, since the browser may lose track of the dialog state, and will not perform proper focus adjustments for accessibility.

Example confirmation dialog

Modal and Non-modal Dialogs

In the last example, the showModal() method was used to create a modal dialog. User interaction is locked inside modal dialogs and outside content cannot be clicked, focused, selected, edited, or seen by accessibility tools. Another feature of modal dialogs is their ability to appear on top of everything else in the web page, regardless of the z-index of other elements.

Non-modal dialogs also exist and can be invoked using show() method. Unlike modal dialogs, they still allow interaction with the surrounding content. An example use-case may be a find-in-page dialog for a document editor, where you still want to allow the user to interact with the rest of the document.

Using Forms with <dialog>

Forms within dialogs can be used to request information from the user, such as when a shipping address or payment details are needed.

Unlike a traditional <form>, where method="get" or "post" indicates that the form data is sent to a server, using <form method="dialog"> causes form submission instead to close the dialog and set the returnValue property to the submit button’s value. This can save you from writing custom code, while providing the correct semantics to your web page.

We can simplify the initial example using this new feature:

<dialog id="confirmation-dialog">
    <form method="dialog">
        <h1>Do you want to delete everything?</h1>
        <p>You will lose all your data.</p>
        <button type="submit" value="Canceled!">Cancel</button>
        <button type="submit" value="Deleted!">Delete!</button>

<button id="delete">Delete everything</button>
<p id="result"></p>

let dialog = document.getElementById("confirmation-dialog");

document.getElementById("delete").addEventListener("click", function() {

dialog.addEventListener("close", function() {
    document.getElementById("result").textContent = dialog.returnValue;

Note the use of the close event here, which is special to <dialog>.

Example confirmation dialog with a form


The semi-transparent box behind the dialog that you may have noticed from previous examples is the ::backdrop pseudo-element. By default, it is styled so it covers the whole viewport. Like the dialog itself, you can style the backdrop using CSS. Animations can also be used if you would like to add a fade-in effect for instance.

Note that the backdrop is only shown for modal dialogs.

Here is an example:

    <h1>This is a pretty dialog</h1>
    <p>The backdrop animates!</p>

<button onclick="document.querySelector('dialog').showModal()">Show the dialog</button>

dialog {
    box-shadow: 0 2px 5px rgba(0,0,0,0.3);
    border: none;
    border-radius: 10px;

dialog::backdrop {
    background: linear-gradient(rgba(0,0,0,0.1), rgba(0,0,0,0.4));
    animation: fade-in 1s;

@keyframes fade-in {
    from {
        opacity: 0;
    to {
        opacity: 1;

This is a pretty dialog

The backdrop animates!

Pretty dialog example styled and animated


For accessibility tools, the <dialog> element is equivalent to role="dialog". In addition to that, a modal dialog will behave similarly to an element with aria-modal="true".

Users can dismiss modal dialogs using the “Escape” key on desktop browsers. That will trigger a cancel event which you can intercept. If multiple modal dialogs are opened, the one shown last will be dismissed.

It is also possible to specify an element to initially focus on when opening dialogs by adding the autofocus attribute to the relevant element.

Browser Support

Next Steps

In this post, we’ve covered the basics of <dialog> and the features around it. Here are the next steps around this element:

We are working on getting the element interoperable with other browser vendors as part of the Interop 2022 effort. One of the main discussions is around initial focus behaviour, to agree on which elements should be focused by default when there is no element with the autofocus attribute.

As part of implementing <dialog> we’ve also made advances on the inert attribute to get interoperable behavior across browsers. It is currently disabled by default and not yet standardized, but you can enable the “inert attribute” in the Experimental Features menu from the Develop menu in Safari Technology Preview to test it.

Feel free to reach out to @therealntim on Twitter for any questions. To report any issues, please file a bug blocking bug 84635.

February 07, 2022 07:10 PM

January 31, 2022

The Focus-Indicated Pseudo-class :focus-visible

Surfin’ Safari

The “focus indicator”, as its name suggests, visually indicates (often with a kind of an outline) that an element has focus. That sounds simple enough, and it perfectly describes what the old :focus selector makes possible. However, for decades now, whether a browser will actually display a focus indicator natively has been a considerably more complex affair.

Focus indicator on different elements in SafariFocus indicator on different elements in Safari

Based on lots of feedback and study, browsers have long employed heuristics about both the type of element, and how it came to gain focus, in order to determine whether the focus indicator should be displayed. If the user is navigating the page with the keyboard, it should. In other situations, it depends. A text input, for example, will display an indicator regardless of how it received focus. This is important because all users need to know where their input data will be placed. Interfaces that do not employ those heuristics feel unnatural.

The goal of the old :focus selector was to allow authors to better style the focus indicator to be in tune with their overall design choices. The trouble is that using it meant losing the heuristics. The net result, unfortunately, has been that the most common use of the :focus selector has been to remove indicators altogether. This avoids the “false positive” focus styles that cause complaints from many users. The problem is that removing focus styling breaks website accessibility, causing trouble for people navigating the page using the keyboard.

Fortunately, a new CSS selector comes to the rescue, avoiding this kind of accessibility issue while providing the behavior web developers were looking for. The :focus-visible pseudo-class matches elements based on the browsers heuristics. It allows web authors to style the focus indicator only if it would be drawn natively.

Despite being a new feature that has recently landed on the web platform, it’s already being used by almost 1% of web pages (according to the Web Almanac by HTTP Archive).


As of Safari Technology Preview 138, the :focus-visible selector has been added to WebKit, paying special attention to interoperability with other implementations. As part of the WebKit implementation, the Web Platform Tests test suite has been improved and expanded quite a lot, adding coverage to new cases and ensuring a better interop between the different implementations.

This work led to changes and improvements all around. Thanks to tests and discussions, all browsers now follow a common set of heuristics and have the same behavior in most situations. In WebKit, for example, clicking on a <div tabindex="0"> will no longer show a focus indicator by default (matching other browser engines).

In addition, the default User Agent style sheet in all browsers now uses the :focus-visible pseudo-class. This is a nice thing to have because it avoids the type of issues that happened with :focus in the first place, and circumvents the need of using some weird workarounds, like :focus:not(:focus-visible), to style the default focus indicator painted by the browser.

If you’re curious about the implementation details, you can read a series of blog posts written along the path to development at blogs.igalia.com/mrego, or watch this talk.


The good news after all the changes that have happened around :focus-visible lately, is that now you’d just need to use :focus-visible selector to style the focus indicator drawn by the browser engines.

On top of that, browsers are no longer showing a focus indicator when the user isn’t expecting it, like focusing a regular element via mouse click.

Web authors won’t need any kind of workaround to achieve the goal of styling the focus indicator shown by the web engine.

For example, if you want your focus indicator to have a thick magenta outline with a small offset, you just need to use the following CSS on your website:

:focus-visible {
    outline: solid thick magenta;
    outline-offset: 0.1em;
Customized focus indicator outline using :focus-visible

And you can use other properties, not only the outline related ones, to customize the focus indicator in your website. E.g.:

:focus-visible {
    outline: dotted thick green;
    background: lime;
    box-shadow: 0.3em 0.3em lightgrey;
Customized focus indicator changing outline, background and box-shadow with :focus-visible

Open Prioritization

It’s worth mentioning that this work was collectively chosen from among many, in numerous engines and partially funded by the public, through Igalia’s Open Prioritization campaign. This effort works to democratize the development of web platform features, giving groups of people and smaller organizations the chance to have a direct impact on the web ecosystem. If you want to learn more about this, Eric Meyer gave a talk explaining it at the W3C’s TPAC.

Thanks to many contributions, this experiment yielded not only :focus-visible development in WebKit, but a lot of interoperability work and alignment in other implementations and a sense that there was real demand for the feature. Thank you to everyone involved.


:focus-visible pseudo-class has been enabled by default in Safari Technology Preview 138, please try it out and report any issues you might found on bugs.webkit.org. You can also send a tweet to @regocas or @webkit to share your thoughts about this feature.

January 31, 2022 05:00 PM

January 26, 2022

Release Notes for Safari Technology Preview 139

Surfin’ Safari

Safari Technology Preview Release 139 is now available for download for macOS Big Sur and macOS Monterey. If you already have Safari Technology Preview installed, you can update in the Software Update pane of System Preferences on macOS.

This release covers WebKit revisions 286944-287834.

Note: Tab Groups do not sync in this release.

Web Inspector

  • Elements Tab
    • Added revert-layer to CSS autocompletion (r287636)
    • Supported CSS conic gradients in gradient editor and auto-completion (r287409)
    • Made gradient editor angle input readable in dark mode (r287408)
  • Sources Tab
    • Added icon for collapsed blackboxed section (r287586)
    • Fixed expanding a grouping of blackboxed call frames to be persistent (r287590)


  • Fixed CSS Cascade Layers specified in import rules can not be reordered on media query evaluation (r286972)
  • Fixed revert-layer to revert the style attribute to the regular author style for CSS Cascade Layers (r287018)
  • Fixed absolutely positioned children to be aligned using the margin box inside a flexbox (r287064)
  • Used the correct margins in computeInlinePreferredLogicalWidths in orthogonal flows (r286952)
  • Fixed :focus-visible not matching on accessKey focus after focusing something via mouse (r287563, r287662)
  • Fixed flexbox ignoring margins of absolute positioned children when align-items: flex-end or justify-content: flex-end (r287128)
  • Fixed drop-shadow filter to use the value of the color property when it has no specified color (r287817)
  • Fixed transform property to take into account transform reference box (r287606)
  • Fixed inline blocks that contain text with min-width, box-sizing: border-box to include the border in width calculation (r287779)
  • Fixed text-decoration color not changing back after input blur with outline removed (r287674)
  • Implemented text-combine-upright property (standard version of -webkit-text-combine) (r287487)
    • Made -webkit-text-combine an inherited property (r287451)
  • Unprefixed -webkit-print-color-adjust CSS property (r287712)
  • Removed non-standard -webkit-background-composite property (r287433)
  • Removed non-standard -webkit-margin-*-collapse properties (r287429)


  • Added style invalidation for :disabled, :enabled, :valid, and :invalid (r287445, r287551)
  • Fixed :has() matching wrong elements due to style sharing (r287362)
  • Fixed :has() selector invalidation issue with toggling :checked (r287363)
  • Used a bloom filter to quickly reject :has() selectors (r287091)

Web Animations

  • Added support for the animation shorthand property in the computed style (r287535)
  • Changed reversing factor to be computed before canceling the previous transition (r287548)
  • Changed transitions without an explicit transition-property to not be considered (r287764)
  • Fixed animation shorthand to parse values in the right order (r287509)
  • Fixed animation shorthand to list all longhand values when serializing (r287534)
  • Fixed calling setKeyframes() on a running CSS Transition having no immediate effect (r287549)
  • Fixed changing the effect of a transition to no longer mark it as running (r287550)
  • Fixed getKeyframes() for a CSS Animation to not use computed style for keyframes (r287820)
  • Fixed getKeyframes() to ensure that all properties are present on 0% and 100% keyframes (r287518)
  • Fixed getKeyframes() to return an empty object when there are no animatable properties in @keyframes rule (r287517)
  • Fixed inserting a rule within a @keyframes rule should update animations (r287707)
  • Fixed inserting a new @keyframes rule to start animations that already used this name (r287769)
  • Fixed implicit keyframe for a CSS Animation to always use the underlying style (r287827)
  • Fixed interpolation for the filter property failing with a single keyframe (r287826)
  • Fixed translate() function in the transform property to remove trailing 0 value when parsing (r287822)


  • Changed to pre-layout orthogonal children to compute the preferred logical width inside a flexbox (r287263)
  • Fixed paint order of CSS text decorations (r286955)
  • Fixed incorrect percent-based height inside display: table child elements defined when combined with box-sizing: border-box and padding. (r287063)
  • Fixed aspect-ratio size calculation (r287023)


  • Fixed SVG resource invalidation logic causing incorrect layout state (r287076)


  • Changed to allow get() for a same-site, cross-origin iframe (r286993, r287116)
  • Fixed authenticator to fallback to clientPIN after internal verification fails and is blocked (r287315)


  • Added support for using a user-specified preference before using the system’s preferred color scheme (r287030)
  • Fixed FormData constructed in the form’s submit event listener to not include the submitter (r286988)
  • Fixed TextDecoder to detect invalid UTF-8 sequences early enough (r287024)


  • Aligned Array.prototype.toLocaleString to ECMA402 definition (r287560)
  • Fixed Intl.PluralRules.selectRange input validation (r287546)
  • Fixed length of Intl.NumberFormat.formatRange and Intl.PluralRules.selectRange (r287543)

Content Security Policy

  • Changed to always use UTF-8 encoded content when checking hashes (r287270)
  • Implemented CSP strict-dynamic for module scripts (r287756)


  • Added MediaRecorder support for the bitsPerSecond option (r287613)
  • Changed to prevent packing audio samples with discontinuity together (r287249)

Service Workers

  • Added full support for Service Worker interception of fetch requests with FormData body (r287612)
  • Fixed FetchRequest.clone to not need to be called with the current context (r287532)

Web Extensions

  • Added support for the redirect rule type in declarativeNetRequest, which requires host permissions to be granted for the host of the URL being redirected
  • Added support for declarativeNetRequest.getMatchedRules, which requires host permissions to be granted to view the URLs of blocked resources

January 26, 2022 10:22 PM

January 20, 2022

Release Notes for Safari Technology Preview 138

Surfin’ Safari

Safari Technology Preview Release 138 is now available for download for macOS Big Sur and macOS Monterey. If you already have Safari Technology Preview installed, you can update in the Software Update pane of System Preferences on macOS.

This release covers WebKit revisions 286534-286944.

Note: Tab Groups do not sync in this release.

Web Inspector

  • Elements Tab
    • Added support for Cascade Layers in the Styles sidebar (r286558)
    • Added a swatch for align-items and align-self (r286875)
    • Added a swatch for justify-content, justify-items, and justify-self (r286885)
    • Added CSS variable names to property name completion list (r286890)
    • Added an option to group CSS variables by value type in the Computed sidebar (r286876)
    • Enabled fuzzy matching for CSS completions in the Styles sidebar (r286792, r286611)


  • Enabled :focus-visible pseudo-class by default (r286783, r286776, r286775)
  • Enabled the resolution media query by default (r286874)
  • Enabled the CSS Contain property by default (r286828)
  • Changed to account for captions when flexing tables with specified sizes (r286593)
  • Fixed perspective() less than or equal to 1px to be clamped to 1px (r286591)
  • Fixed gap to work correctly when flex-direction: column-reverse is applied (r286654)
  • Fixed the serialization of CSSImportRule (r286668)
  • Unprefixed -webkit-mask (r286795)
  • Unprefixed CSS value text-align: -webkit-match-parent (r286803)
  • Updated color-mix() to support srgb-linear and alpha premultiplication (r286568)

Experimental Model Element

  • Added load and error events to distinguish resource load from model readiness (r286836)


  • Fixed various issues with complicated rendering of VTT cues (r286743)

Web Animations

  • Added a way to run scripted animations via CustomEffect (r286555)
  • Exposed a frameRate property to Web Animations (r286915)


  • Improved WebAuthn Level 2 standards compliance by supporting the displayName (r286746)


  • Fixed transform-origin on SVG elements to take into account the transform reference box origin (r286942)


  • Changed to group radio buttons with no form owner (r286855)
  • Fixed the range of <input type="time"> to be reversible (r286581)
  • Fixed an <input> that’s been autofilled with obscured content to still be editable (r286814)
  • Implemented AbortSignal.throwIfAborted (r286904)
  • Improved <input type="datetime-local"> value parsing and sanitization (r286869)
  • Restored navigator.hardwareConcurrency (r286550)
  • Fixed setting onselectionchange content attribute to add an event listener (r286898)

Service Workers

  • Enabled NavigationPreloadManager by default (r286540)
  • Added support for ServiceWorker downloads (r286944)
  • Fixed “no-cache” network error (r286655)
  • Fixed same-site lax cookies not sent by fetch event handler after page reload (r286656)


  • Closed WebRTC allocation sequence shared socket in case of sequence network failure (r286539)


  • Added preparation of WebAssembly.Memory imports in Wasm/ESM modules (r286703)

Web Extensions

  • Added support for changed web_accessible_resources declaration with manifest_version 3
  • Fixed runtime.onMessage listeners not supporting Promise returns for the reply message
  • Show error messages for incorrect match patterns in web_accessible_resources
  • Show error message to devtools tabs in Web Inspector when inspecting unsupported targets
  • Show error message when the service worker background script fails to load

Bug Fixes

  • Fixed an issue introduced in Safari Technology Preview 137 where pop-up windows wouldn’t open

January 20, 2022 11:39 PM

December 28, 2021

Manuel Rego: A story on web engines interoperability related to wavy text decorations

Igalia WebKit

Some weeks ago I wrote a twitter thread explaining the process of fixing a Chromium bug related to wavy text decorations. At first it was just a patch in Chromium, but we also fixed the same issue in WebKit, which unveiled a mistake on the initial fix in Chromium (a win-win situation).

This blog post is somehow a story around web platform features implementation, which highlights the importance of interoperability and how investigating and fixing bugs on different web engines usually leads to gains for the whole ecosystem.

Some background

Let’s start from the beginning. Igalia (as part of our collaboration with Bloomberg) is working on adding support for ::spelling-error & ::grammar-error highlight pseudo-elements in Chromium.

My colleague Delan Azabani has been leading this effort. If you want more details about this work you can read her two blog posts. Also don’t miss the chance to enjoy her amazing talk from last BlinkOn 15, this talk gives lots of details about how highlight pseudos work, and includes some cool animations that help to understand this complex topic.

Lately I’ve been also helping with some related tasks here and there. Next I’m going to talk about one of them.

Spelling and grammar error markers

As you probably know spelling and grammar error markers use wavy underlines in some platforms like Linux or Windows, though not in all of them as they use dotted underlines on Mac. In Chromium they’re painted on a separated codepath, totally independent of how CSS text decorations are painted. You can easily spot the difference between a “native” spelling errors (left) and elements with text-decoration: wavy red underline (right) in the next picture.

Spelling errors on the left vs wavy red underlines on the right Spelling errors Chromium Linux (left) vs wavy red underlines (right)

As part of our work around ::spelling|grammar-error highlight pseudos, we plan to merge both codepaths and use the CSS one for painting the default spelling and grammar error markers in the future. This doesn’t mean that they’ll look the same, actually they will still have a different rendering so the user can differentiate between a spelling marker and a wavy text decoration (like it happens now). But they’ll share the same code, so any improvement we do will apply to both of them.

There have been some bugs on each of them in the past, related to invalidation and overflow issues, and they had to be fixed in two places instead of just one. That’s why we’re looking into sharing the code, as its main job is to produce very similar things.

The issue we’re describing in the next section doesn’t happen on native spelling error markers, but as we plan to follow the CSS codepath, we had to fix it as a preliminary task getting things ready to move the spelling markers to use that codepath.

The issue

One problem with wavy text decorations in Chromium was that they sometimes don’t cover the full length of the text. This is because it only paints whole cycles and thus fall short in some situations.

A simple example is a wavy underline (text-decoration: wavy green underline) on a “m” letter using big fonts (see the picture below and how it doesn’t cover the full length of the letter).

  <div style="font-size: 5em; text-decoration: wavy green underline;">m</div>

Green wavy underline doesn't cover the full length of the letter m (Chromium) Green wavy underline doesn’t cover the full length of the letter “m” (Chromium)

Fixing the problem

This section goes into some implementation details about how this works on Chromium and how we fixed it.

To draw wavy text decorations Chromium defines a vector path for a Bezier curve, that path is generated at TextDecorationInfo::PrepareWavyStrokePath(). The comment in that method is quite self explanatory: Comment from TextDecorationInfo::PrepareWavyStrokePath() explaining how the path for the Bezier curve is defined Comment from TextDecorationInfo::PrepareWavyStrokePath() explaining how the Bezier curve is defined

This method generates the path for wavy text decorations using the next loop:

    for (float x = x1; x + 2 * step <= x2;) {
      control_point1.set_x(x + step);
      control_point2.set_x(x + step);
      x += 2 * step;
      path.AddBezierCurveTo(control_point1, control_point2,
                            gfx::PointF(x, y_axis));

As you can see, it only uses whole cycles of the wave (2 * step), and it never splits that in smaller chunks. If we’re going to end up further away than the text size, we don’t add that wave to the path (x + 2 * step <= x2). Which leads to the wrong behavior we saw in the example of the “m” letter above, where the text decoration falls short.

To prevent this problem, the code was using the method AdjustStepToDecorationLength(), that was expected to adjust the length of a whole wave. If that method was working properly, we would always cover the full text width adjusting the size of the waves. However there were two different problems on that method:

  • On one side, that method adjusted the step, but we were always generating whole waves (2 * step), so we might need to adjust the whole length of the wave instead.
  • On the other side, the method had some bug, as it was changing the step when it was not actually needed. For example if you pass a total length of 40px and a step of 10px, this method was adjusting the step to 10.75px, which makes no sense.

Digging a little bit on the repository’s history, we found out that this method has been around since 2013 thus it was present in both Blink and WebKit. As it has a bunch of issues and our proposed fix was cutting the waves at any point, we decided it was not needed to try to adjust their size anymore, so we get rid of this method.

The solution we used to the length issue requires two main changes:

  • First we generate two extra waves before and after the text width:
  // We paint the wave before and after the text line (to cover the whole length
  // of the line) and then we clip it at
  // AppliedDecorationPainter::StrokeWavyTextDecoration().
  // Offset the start point, so the beizer curve starts before the current line,
  // that way we can clip it exactly the same way in both ends.
  FloatPoint p1(start_point + FloatPoint(-2 * step, wave_offset));
  // Increase the width including the previous offset, plus an extra wave to be
  // painted after the line.
  FloatPoint p2(start_point + FloatPoint(width_ + 4 * step, wave_offset));
  • Then clip the path so it’s no longer than the text width. For which GraphicsContextStateSaver was really useful to just clip things related to the line that is currently being painted (for example in cases where you have both underline and overline text decorations).

Video showing the solution described above

The reviewers liked the idea and the patch landed in Chromium 97.0.4692 with some internal tests (not using WPT tests as how wavy lines are painted is not defined per spec and varies between implementations).

To finish this section, below there is a screenshot of the “m” with wavy green underline after this patch.

Green wavy underline covering the full length of the letter m (Chromium) Green wavy underline covering the full length of the letter “m” (Chromium)

WebKit & WPT test

While looking into the history of AdjustStepToDecorationLength() method we ended up looking into some old WebKit patches, we realized that the code for the wavy text decoration in WebKit is still very similar to Chromium, and that this very same issue was also present in WebKit. For that reason we decided to fix this problem also in WebKit too, with the same approach than the patch in Chromium.

Green wavy underline doesn't cover the full length of the letter m (WebKit) Green wavy underline doesn’t cover the full length of the letter “m” (WebKit)

The cool thing is that during the patch review Myles Maxfield suggested to create a mismatch reference test.

Just an aside quick explanation, reference tests (reftests) usually compare a screenshot of the test with a screenshot of the reference file, to see if the rendered output matches exactly or not between both files. But sometimes browsers do a different thing that is called mismatch reftests, which compares a test with a reference and checks that they’re actually different.

The idea here was to do a test that has a wavy text decoration but we hide most of the content with some element on top of that, and just show the bottom right corner of the decoration. We mismatch against a blank page, because there should be something painted there, if the wavy text decoration cover the whole line.

So we wrote WPT tests, that we can share between implementations, to check that this was working as expected. And while working on that test we discovered an issue on the initial Chromium fix, as the wavy underline was kind of misplaced to the left. More about that later.

On top of that there was another issue, WPT mismatch tests were not supported by WebKit tests importer, so we also added support for that in order to be able to use these new tests on the final WebKit patch fixing the wavy text decorations length which is included in Safari Technology Preview 136.

Again let’s finish the section with a screenshot of the “m” with wavy green underline after the WebKit patch.

Green wavy underline covering the full length of the letter m (WebKit) Green wavy underline covering the full length of the letter “m” (WebKit)

Round trip

As mentioned in the previous section, thanks to porting the patch to WebKit and working on a WPT test we found out a mistake on the first Chromium fix.

So we’re back in Chromium where we were clipping the wavy text decoration with the wrong offset, so it looks like it was a little bit shifted to the left (specially when using big fonts). I’m repeating here the image for the initial Chromium fix, adding a grey background so it’s easier to notice the problem and compare with the final fix. There you can see that the wavy underline starts more on the left than expected, and ends earlier than the “m” letter.

Green wavy underline covering the full length of the letter m (Chromium). Initial fix. Green wavy underline covering the full length of the letter “m” (Chromium). Initial fix

The patch to fix that was pretty simple, so we landed it in Chromium 98.0.4697. And this is the final output with the text decoration positioned in the proper place.

Green wavy underline covering the full length of the letter m (Chromium). Final fix. Green wavy underline covering the full length of the letter “m” (Chromium). Final fix

Other issues

In addition to an improved rendering on static wavy text decorations, these fixes have some nice effects when animations are involved. See the following video showing an example with animations (stealing a letter-spacing example from Delan’s latest blog post), on the left you can see Chromium (buggy version on top, fixed one on bottom) and on the right WebKit (again buggy on top and fixed on bottom).

Video showing the fix (top left: Chromium buggy, bottom left: Chromium fixed, top right: WebKit buggy, bottom right: WebKit fixed)

But as usual there’s still something else, in this case very related to this topic. There’s the concept of decorating box in CSS Text Decoration spec, and that hasn’t been implemented in Chromium and WebKit yet (though Firefox seems to be doing that right in most cases, except for dotted text decorations).

This issue is quite noticeable when you have different elements in the same line (like a <strong> element), or different font sizes in the same line. See the next video that shows this problem in Chromium (on the left) and Firefox (on the right, where only dotted text decorations have problems).

element. The video shows the behavior in Chromium (buggy) and Firefox (working fine except for dotted)."> element. The video shows the behavior in Chromium (buggy) and Firefox (working fine except for dotted)." class="center-block" style="width: 100%;" controls="" loop="">

Video showing the problem related to decorating box (left: Chromium, right: Firefox)

This has been a problem in Chromium and WebKit forever, even native spelling and grammar error markers have the same issue (thought it’s less noticeable as they’re painted always in a small size). Though even when this isn’t a strictly a blocker for all this work, this is something we’re looking forward to get fixed too.


The main takeaway from this blog post is how browser interoperability plays a key important role in the implementation of web platform features. Which is something we’re very concerned of at Igalia.

The fact that we fixed this issue in Chromium and WebKit at the same time helped to get more eyes looking into the same code, which is usually very beneficial.

We ended up not just fixing the issue in both implementations (Chromium and WebKit), but also adding new WPT tests that would be useful for any other implementation and to prevent regressions in the future. Even as a positive side effect, WebKit added support for mismatch reference tests as part of this work.

Finally, thanks to all the people that helped to make this happen by providing ideas, feedback and reviewing the patches; particularly Delan Azabani (Igalia), Myles Maxfield (Apple) and Stephen Chenney (Google).

December 28, 2021 11:00 PM

December 20, 2021

Release Notes for Safari Technology Preview 137

Surfin’ Safari

Safari Technology Preview Release 137 is now available for download for macOS Big Sur and macOS Monterey. If you already have Safari Technology Preview installed, you can update in the Software Update pane of System Preferences on macOS.

This release covers WebKit revisions 285788-286534.

Note: Tab Groups do not sync in this release.

Web Inspector

  • Elements Tab
    • Enhanced autocomplete to support mid-line completions (r285851)
    • Styles
      • Added a inline swatch for CSS align-content (r285983)
  • Layers Tab
    • Fixed the position of composited layers with a box-shadow (r285839)
  • Console Prompt
    • Fixed console script evaluation not working or being performed in an unexpected execution context after refresh or navigation (r286412)
  • Web Inspector Interface
    • Enabled left docking when in left-to-right and right docking when in right-to-left mode (r285974)


  • Enabled support for :has() pseudo-class by default (r286495, r286135, r286302, r286180, r286226, r286494, r286433, r286188, r286169, r286365)
  • Added support for new srgb-linear, xyz-d50 and xyz-d65 colorspaces (r286168)
  • Added support for oklab() and oklch() colors (r286191)
  • Added support for replaced elements with intrinsic ratio and no intrinsic size (r286206)
  • Added support for *vi (inline) and *vb (block) viewport units (r286458)
  • Added helper to add CSS property with implicit default (r285837)
  • Changed to not shrink tables bellow their intrinsic sizes (r286207)
  • Changed SVG images used as grid items to use the overriding logical width and height when defined to compute the logical dimensions (r286100)
  • Changed dynamic dv* viewport units to ignore the page scale (r286350)
  • Fixed :hover with descendant selector invalidating correctly in shadow trees (r286063)
  • Fixed rem in media queries to be calculated using font-size: initial, not root element font-size (r286123)
  • Fixed sticky th or td in table to stop at the specified top (r286417)
  • Implemented parsing and animation support for ray() shape accepted by offset-path (r286086)
  • Transferred size for grid item with an aspect-ratio and stretch alignment against the definite row (r285987)
  • Updated color-mix() to the latest spec (r286196)


  • Added Intl.NumberFormat.formatRangeToParts for ICU 69~ platforms (r286255)
  • Implemented Date.prototype.toTemporalInstant() (r286149)
  • Revised JSON.parse atomize policy for performance and compatibility with the other engines (r285955)
  • Accelerated public class field initialization (r286251)


  • Fixed WebAssembly memory.fill out of bounds error message (r286092)

Experimental Model Element

  • Added support for mouse-based manipulation of <model> on macOS (r285986)
  • Added audio support (r286065)
  • Added support for controlling looping animations (r286066)
  • Added support for getting and setting the camera (r286019)
  • Added support for pausing and resuming animations (r286048)
  • Added support for seeking animations (r286068)


  • Added accessibility attributes for <model> (r286406)


  • Added initial implementation for the Web Lock API (r286284)
  • Fixed Cross-Origin-Embedder-Policy: require-corp to not prevent loading of data-URL images (r285823)
  • Fixed empty <input type=file> controls not showing up in the urlencoded and text/plain enctypes (r285808)
  • Fixed empty <input type=file> represented incorrectly in FormData (r285861)
  • Fixed modal dialogs to make the root element unfocusable (r285791)
  • Fixed validity.valueMissing to not rely on the element’s disabled state for inputs of type radio, file, or checkbox (r286413)
  • Fixed file inputs in non-multipart form submissions showing up as string values in the formdata event (r286427)
  • Implemented FileSystemFileHandle.getFile() (r285912)

Content Security Policy

  • Fixed missing lineNumber and columnNumber in inline violation reports (r285800)
  • Implemented submitting samples in violation reports (r286150)
  • Fixed CSP DOM reporting which always used the document as the target (r286136)


  • Added support for more requestVideoFrameCallback metadata (r285984)
  • Fixed audio rate issues in WebRTC audio rendering when switching audio output (r285985)
  • Fixed video encoding and decoding for h.264 (r285928)

Apple Pay

  • Changed PaymentRequest to validate payment method data on construction (r286452)
    • This can (and should) now be used instead of ApplePaySession.supportsVersion.

Web Extensions

  • Added support for special matching characters (*, |, ||, and ^) in urlFilter of declarativeNetRequest rules instead of treating them as regex patterns
  • Added permission prompting inside Web Inspector for devtools extension tabs
  • Added support for CSS injections and removals of more than one file with browser.scripting

December 20, 2021 09:23 PM

December 14, 2021

Wide Gamut 2D Graphics using HTML Canvas

Surfin’ Safari

Most colors used on the Web today are sRGB colors. These are the colors that you specify with the familiar #rrggbb and rgb(r, g, b) CSS syntax, and whose individual color components are given as values in the range [0, 255]. For example, rgb(255, 0, 0) is the most saturated, pure red in the sRGB color space. But the range of colors in sRGB — its color gamut — does not encompass all colors that can be perceived by the human visual system, and there are displays that can produce a broader range of colors.

sRGB is based on the color capabilities of computer monitors that existed at the time of its standardization, in the late 1990s. Since then, other, wider gamut color spaces have been defined for use in digital content, and which cover more of the colors that humans can perceive. One such color space is Display P3, which contains colors with significantly higher saturation than sRGB.

This browser reports that the display does not support Display P3 colors; figures in this post may not appear as intended.
A conic gradient showing a range of sRGB colors A conic gradient showing a range of Display P3 colors
Conic gradients showing fully saturated sRGB (left) and Display P3 (right) colors. Viewed in a browser and on a display supporting Display P3, the colors in the circle on the right will show as more intense than those on the left. (View as standalone page.)
For a more in depth introduction to color spaces, see Dean Jackson’s earlier post, Improving Color on the Web.

Today, there are many computer and mobile devices on the market with displays that can reproduce all the colors of the Display P3 gamut, and the Web platform has been evolving over the last few years to allow authors to make best use of these displays. WebKit has supported wide color images and video since 2016, and last year became the first browser engine to implement the new color syntax defined in CSS Color Module Level 4 where colors can be specified in a given color space (like color(display-p3 1 0 0), a fully saturated Display P3 red).

One notable omission in wide gamut color support, until now, has been in the HTML canvas element. The 2D canvas API was introduced before wide gamut displays were common, and until now has only handled drawing and manipulating sRGB pixel values. Earlier this year, a proposal for creating canvas contexts using other color spaces was added to the HTML standard, and we’ve recently added support for this to WebKit.

Drawing on a wide gamut canvas rendering context

The getContext method on a canvas element, which is used to create a rendering context object with 2D drawing APIs, accepts a new option to set the canvas backing store’s color space.

<canvas id="canvas" width="400" height="300"></canvas>
let canvas = document.getElementById("canvas");
let context = canvas.getContext("2d", { colorSpace: "display-p3" });
// ... draw on context ...

The default color space remains sRGB, rather than having the browser automatically use the wider color space, to avoid the performance overhead of color space conversions with existing content. The two explicit color spaces that can be requested are "srgb" and "display-p3".

Fill and stroke styles can be specified using any supported CSS color syntax.

let position = 0;
for (let green of [1, 0]) {
    for (let blue of [1, 0]) {
        for (let red of [1, 0]) {
            context.fillStyle = `color(display-p3 ${red} ${green} ${blue})`;
            context.fillRect(position, position, 40, 40);
            position += 20;
Colored squares that have been clamped to sRGB Colored squares using Display P3 colors that are outside the sRGB gamut
Display P3 colors used as fill styles on an sRGB (left) and Display P3 (right) canvas. Colors on the left are clamped to remain within the sRGB gamut. (View as standalone page.)

Any drawing that uses a color outside the color space of the canvas will be clamped so that it is in gamut. For example, filling a rectangle with color(display-p3 1 0 0) on an sRGB canvas will end up using a fully saturated sRGB red. Similarly, drawing on a Display P3 canvas with color(rec2020 0.9 0 0.9), an almost full magenta in the Rec.2020 color space, will result in pixels of approximately color(display-p3 1.0 0 0.923) being used, since that is the closest in the Display P3 color gamut.

const COLORS = ["#0f0", "color(display-p3 0 1 0)"];
for (let y = 20; y < 180; y += 20) {
    context.fillStyle = COLORS[(y / 20) % 2];
    context.fillRect(20, y, 160, 20);
A filled square of full sRGB green Stripes of full sRGB green and full Display P3 green
Stripes of interleaved Display P3 and sRGB colors on an sRGB (left) and Display P3 (right) canvas. Because colors are clamped to remain within the gamut of the canvas, the two shades of green are indistinguishable on the sRGB canvas. (View as standalone page.)
On macOS, you can use the ColorSync Utility to convert color values between sRGB, Display P3, Rec.2020, and some other predefined color spaces.

Wide gamut colors are usable in all canvas drawing primitives:

  • as the fill and stroke of rectangles, paths, and text
  • in gradient stops
  • as a shadow color

Pixel manipulation in sRGB and Display P3

getImageData and putImageData can be used to get and set pixel values on a wide gamut canvas. By default, getImageData will return an ImageData object with pixel values in the color space of the canvas, but it is possible to specify an explicit color space that does not match the canvas, and a conversion will be performed.

let context = canvas.getContext("2d", { colorSpace: "display-p3" });
context.fillStyle = "color(display-p3 0.5 0 0)";
context.fillRect(0, 0, 100, 100);

let imageData;

// Get ImageData in the canvas color space (Display P3).
imageData = context.getImageData(0, 0, 1, 1);
console.log(imageData.colorSpace);  // "display-p3"
console.log([...imageData.data]);   // [128, 0, 0, 255]

// Get ImageData in Display P3 explicitly.
imageData = context.getImageData(0, 0, 1, 1, { colorSpace: "display-p3" });
console.log(imageData.colorSpace);  // "display-p3"
console.log([...imageData.data]);   // [128, 0, 0, 255]

// Get ImageData converted to sRGB.
imageData = context.getImageData(0, 0, 1, 1, { colorSpace: "srgb" });
console.log(imageData.colorSpace);  // "srgb"
console.log([...imageData.data]);   // [141, 0, 0, 255]

The ImageData constructor similarly takes an optional options object with a colorSpace key.

let context = canvas.getContext("2d", { colorSpace: "display-p3" });

// Create and fill an ImageData with full Display P3 yellow.
let imageData = new ImageData(10, 10, { colorSpace: "display-p3" });
for (let i = 0; i < 10 * 10 * 4; ++i)
    imageData.data[i] = [255, 255, 0, 255][i % 4];

context.putImageData(imageData, 0, 0);

As when drawing shapes using colors of a different color space, any mismatch between the ImageData and the target canvas color space will cause putImageData to perform a conversion and potentially clamp the resulting pixels.

Serializing canvas content

The toDataURL and toBlob methods on a canvas DOM element produce a raster image with the canvas contents. In WebKit, these methods now embed an appropriate color profile in the generated PNG or JPEG when called on a Display P3 canvas, ensuring that the full range of color is preserved.

Drawing wide gamut images

Like putImageData, the drawImage method will perform any color space conversion needed when drawing an image whose color space differs from that of the canvas. Any color profile used by a raster image referenced by an img, and any color space information in a video referenced by a video (be it a video file or a WebRTC stream), will be honored when drawn to a canvas. This ensures that when drawing into a canvas whose color space matches the display’s (be that Display P3 or sRGB), the source image/video and the canvas pixels will look the same.

Here is an interactive demonstration of using canvas to make a sliding tile puzzle. The tiles are drawn by applying a clip path and calling drawImage pointing to the img element on the left, which references a wide gamut JPEG. Toggling the checkbox shows how the colors are muted when an sRGB canvas is used.

Sliding tile puzzle. Toggling the checkbox will change whether an sRGB or a Display P3 canvas is used. (View as standalone page.)

Web Inspector support

Web Inspector also now shows color space information for canvases to help ensure your canvases’ backing stores are in the expected color space.

In the Graphics tab, the Canvases Overview will display the color space for each canvas next to the context type (e.g. 2D) on each canvas overview tile.

After clicking on a Canvas overview tile to inspect it, the color space is shown in the Details Sidebar in the Attributes section.

Browser support

Wide gamut canvas is supported in the macOS and iOS ports of WebKit as of r283541, and is available in Safari on:

  • macOS Monterey 12.1 and above
  • iOS 15.1 and above

Safari is the first browser to support drawing shapes, text, gradients, and shadows with wide gamut CSS colors on Display P3 canvases. All other features, including getImageData, putImageData, and drawImage on Display P3 canvases, are supported in Safari and in Chrome 94 and above.

Feature detection

There are a few techniques you can use to detect whether wide gamut display and canvas support is available.

Display support: To check whether the display supports Display P3 colors, use the color-gamut media query.

function displaySupportsP3Color() {
    return matchMedia("(color-gamut: p3)").matches;

Canvas color space support: To check whether the browser supports wide gamut canvases, try creating one and checking the resulting color space.

function canvasSupportsDisplayP3() {
    let canvas = document.createElement("canvas");
    try {
        // Safari throws a TypeError if the colorSpace option is supported, but
        // the system requirements (minimum macOS or iOS version) for Display P3
        // support are not met.
        let context = canvas.getContext("2d", { colorSpace: "display-p3" });
        return context.getContextAttributes().colorSpace == "display-p3";
    } catch {
    return false;

CSS Color Module Level 4 syntax support: To check whether the browser supports specifying wide gamut colors on canvas, try setting one and checking it wasn’t ignored.

function canvasSupportsWideGamutCSSColors() {
    let context = document.createElement("canvas").getContext("2d");
    let initialFillStyle = context.fillStyle;
    context.fillStyle = "color(display-p3 0 1 0)";
    return context.fillStyle != initialFillStyle;

Future work

There are a few areas where wide gamut canvas support could be improved.

  • 2D canvas still exposes image data as 8 bit RGBA values through ImageData objects. It may be useful to support other pixel formats for a greater color depth, such as 16 bit integers, or single precision or half precision floating point values, especially when wider color gamuts are used, since increased precision can help avoid banding artifacts. This has been proposed in an HTML Standard issue.
  • The two predefined color spaces that are supported are sRGB and Display P3, but as High Dynamic Range videos and displays that support HDR become more common, it’s worth consdering allowing 2D canvas to use these and other color spaces too. See this presentation at the W3C Workshop on Wide Color Gamut and High Dynamic Range for the Web from earlier this year, which talks about proposed new color space and HDR support.
  • Canvas can be used with context types other than 2D, such as WebGL and WebGPU. A proposal for wide gamut and HDR support in these contexts was presented at that same workshop.

In summary

WebKit now has support for creating 2D canvas contexts using the Display P3 color space, allowing authors to make best use of the displays that are becoming increasingly common. This feature is enabled in Safari on macOS Monterey 12.1 and iOS 15.1.

If you have any comments or questions about the feature, please feel free to send me a message at @heycam, and more general comments can be sent to the @webkit Twitter account.

Further reading

  • W3C Workshop on Wide Color Gamut and High Dynamic Range for the Web (W3C)
  • December 14, 2021 05:00 PM

    December 13, 2021

    New WebKit Features in Safari 15.2

    Surfin’ Safari

    The internet has always been about communication and collaboration. It started with asynchronous messages made of text. As it matured, the internet became real-time. Then the web came along, adding images, and later, video. Websites provided a means to publish, to broadcast, to run stores, to gather communities and create worlds.

    Now, the web is maturing to the point where web apps make rich collaboration experiences possible — including digital creation. Recent updates to WebKit bring a number of improvements to Safari 15.2 that focus on supporting creative applications and leveraging the incredible power of today’s hardware.

    WebAssembly Enhancements

    Web Assembly (Wasm) is a low-level assembly language that allows a multitude of programming languages like C/C++, C#, Objective-C, Swift, Python, Java or even Cobol to be compiled to run on the web at near native speed — without the user needing to install anything special. It’s designed to work alongside of JavaScript, allowing sites to use both together. Wasm provides the tools needed to bring powerful software applications to the web.

    In Safari 15.2, the addressable memory for Wasm has been expanded to 4GB, opening up possibilities for bigger and more powerful applications. The addition of zero-cost exception handling also provides potential performance gains.

    COOP/COEP HTTP Headers

    Shared memory provides powerful functionality for native applications, but on the web, such power must be balanced with strong security protections. SharedArrayBuffer was supported in WebKit for Safari 10.1–11, but was disabled along with other browsers due to the risk of using it for speculative execution attacks like Spectre.

    Safari 15.2 adds support for Cross-Origin-Opener-Policy (COOP) and Cross-Origin-Embedder-Policy (COEP) HTTP response headers. Sites can adopt these headers to opt into process isolation and be better protected. If sites serve both Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: require-corp, they are now able to use SharedArrayBuffer and Wasm threading again.

    Wide gamut support for Canvas

    These days modern creative tools depend on amazing camera and gorgeous displays. Yet, most colors on the Web today are sRGB colors, which match the limited color capabilities of computer monitors from the late 1990s. The human visual system can perceive a much broader range of colors. Today’s modern displays reproduce the colors of the Display P3 gamut, with significantly higher saturation than sRGB.

    Since 2016, WebKit has supported wide color images and video, and last year became the first browser engine to implement the new color syntax defined in CSS Color Module Level 4. One notable omission in wide gamut color support was in the HTML canvas element. Earlier this year, a proposal for support was added to the HTML standard, and now, in Safari 15.2, WebKit adds wide gamut support — including Display P3 — for use in canvas.

    Read more about the details, with demos of stunning results, in Wide Gamut 2D Graphics using HTML Canvas.

    More information

    For more on what’s in Safari 15.2, including bug fixes, see the Safari 15.2 Release Notes.


    Safari 15.2 is available on macOS Monterey, macOS Big Sur and macOS Catalina. To update on macOS, go to Apple menu  > System Preferences, and click Software Update.

    Safari 15.2 is available on iOS and iPadOS 15.2. To update, go to Settings > General, then tap Software Update.


    If you run into issues, we welcome your bug reports for Safari, or WebKit bugs for web content issues. Send us a tweet @webkit to share your thoughts on this release.

    December 13, 2021 07:13 PM

    December 08, 2021

    Release Notes for Safari Technology Preview 136

    Surfin’ Safari

    Safari Technology Preview Release 136 is now available for download for macOS Big Sur and macOS Monterey. If you already have Safari Technology Preview installed, you can update in the Software Update pane of System Preferences on macOS.

    This release covers WebKit revisions 285101-285788.

    Note: Tab Groups do not sync in this release.


    • Added support for contain: paint (r285583)
    • Added support for the revert-layer value (r285624)
    • Added flex-basis: content support (r285709)
    • Fixed ::slotted element style to invalidate correctly in nested case (r285211)
    • Fixed ::slotted to not match an active <slot> (r285209)
    • Fixed :host::part(foo) selector to select elements inside shadow roots (r285262)
    • Fixed a mask or isolation to set transform-style to flat (r285482)
    • Fixed border-radius inline style to serialize with valid syntax (r285235)
    • Fixed font-synthesis inline and computed style to be in canonical order (r285383, r285384)
    • Fixed rendering bug with height: min-content, position: absolute, and box-sizing: border-box (r285495)
    • Fixed the default computed value for content to be none for ::before and ::after (r285621)
    • Implemented parsing and animation support for offset-path (r285343)
    • Implemented Scroll To Text Fragment directive parsing (r285528)
    • Implemented transform: perspective(none) (r285255)
    • Removed non-standard -webkit-border-fit CSS property (r285615)
    • Updated the content-size grid width before laying out a grid item with block constraints and aspect-ratio (r285497)

    GPU Process

    • Fixed enabling “media source inline painting” by default to work when using GPU Process for media (r285410)


    • Implemented IntlNumberFormat v3 (formatRangeToParts is not implemented yet) (r285418)
    • Implemented Temporal.Instant (r285178)

    Web API

    • Implemented custom element definition’s disable shadow flag (r285740)
    • Fixed the cssText property for a computed style to return an empty string (r285604)


    • Fixed showing languages and subtitles tracks button and menu for <audio> (r285216)

    Web Animations

    • Added support for composite operations for software animations (r285397)
    • Fixed accelerated animations with a single keyframe not accounting for prior forward-filling animations (r285728)
    • Fixed discrete animation of content property not working (r285423)
    • Improved additivity support when animating the transform property (r285631)


    • Implemented add_virtual_authenticator and remove_virtual_authenticator for WebDriver (r285267)

    Private Click Measurement

    • Fixed occasionally dropped attribution reports for Private Click Measurement (r285170)

    Web Extensions

    • Added support for manifest_version 3 and service_worker background scripts, while also supporting the option of using non-persistent background pages
    • Added support for script and style injection via the browser.scripting APIs
    • Added support for dynamic and session rules via the browser.declarativeNetRequest APIs
    • Fixed an issue with new tab pages not being remembered when switching from Favorites
    • Fixed an issue with long extension descriptions causing the title to be cut-off in Preferences
    • Enforces limits on the size and number of items in extension sync storage

    Other Bugs

    • Fixed opening local HTML files when the Develop menu was enabled (r285130)
    • Stopped using a timer to dispatch the source element’s error event asynchronously (r285413)

    December 08, 2021 11:03 PM

    November 16, 2021

    PCM for In-App Direct Response Advertising

    Surfin’ Safari

    Private Click Measurement (PCM) can now be used for in-app direct response advertising using SFSafariViewController. Try it out in our iOS 15.2 beta.

    What is PCM?

    PCM is a proposed web standard for measuring the effectiveness of click-through advertising in a privacy-preserving way. It allows for 8 bits of data on the click source site to be combined with 4 bits of data on the click destination site to measure which advertising is driving sales. The combined 8+4 bits of data is sent to both the click source and destination in an attribution report that doesn’t carry any user or device identifiers. The net result is a report that says “Someone who clicked ad X on website A later converted with value Y on website B.”

    PCM shipped in iOS/iPadOS 14.5 and in Safari 14.1 on macOS. Its privacy-preserving nature means it can be used without getting the user’s permission to track according to AppTrackingTransparency.

    What is SFSafariViewController?

    SFSafariViewController is a ready-built in-app web browser on iOS/iPadOS with full-fledged Safari features such as Reader, AutoFill, Fraudulent Website Detection, content blocking, and bookmarks. User activity and interaction with SFSafariViewController are not visible to your app which means users can safely browse the web in it and you do not need to secure data between your app and SFSafariViewController.

    On Direct Response Advertising

    Our introductory blog post on PCM featured two important FAQ entries on app-to-web advertising – on the subject of taking the user to the device’s browser and on the subject of an in-app experience.

    When to Take the User To the Device’s Browser

    PCM app-to-web in iOS 14.5 had to take the user to the device’s browser. This was designed to support re-engagement. Stored clicks in PCM are valid for 7 days and customers who are ready to take action only after a few hours or days, will most likely go find the merchant website in their browser. They’ll either look up the tab where they left off, use a bookmark they might have saved, use their search provider to find the right webpage, or enter the website’s address directly in the URL bar.

    For the stored click data to be readily available when the user re-engages in this fashion, the initial click needs to take the user to their browser. This is still true going forward.

    When to Handle the Tap In-App

    Another form of click-through advertising is called direct response. In such cases, the user is not expected to think about converting for an extended period of time, but rather take action directly on the webpage they land on. It could be a limited offer or a product priced so that the user doesn’t feel like they have to think it over.

    Developers and advertisers have told us they want to be able to provide more of an in-app experience for direct response advertising, rather than take the user to the device’s browser. They want a seamless in-app experience for users who tap on an ad, check out the product page, decide to buy or not, and then want to go back to the hosting app.

    Our intro blog post covered this request in the FAQ section, and we said “We are interested in this but don’t have a solution yet.” Today we have a solution. PCM is now capable of supporting in-app advertising with new API for SFSafariViewController.

    PCM App-to-Web with SFSafariViewController

    SFSafariViewController provides a great in-app browsing experience where the user can store Safari bookmarks that can sync across devices, has access to autofill of credentials and payment card info, and Apple Pay. It is simply a great place to take the user as part of direct response advertising.

    Ephemeral Clicks to Prevent Click Fraud

    PCM will only store click data and schedule an attribution report if the user triggers a conversion in the SFSafariViewController that they opened through the click. A tap which navigates to a website in SFSafariViewController without a matching triggering event will not be stored. As a result, an instance of SFSafariViewController can only hold one non-converted click at a time, whereas all converted clicks will be stored and result in reports.

    This ensures that a hosting app cannot speculatively store clicks in its SFSafariViewController for fraudulent reasons. It also ensures that this use of PCM really is geared toward direct response advertising.

    Attributions are Per Hosting App

    Taps in different apps navigating the user to the same advertised website do not affect each other. Every app gets its own attribution. Again, this feature is for direct response advertising so a customer who buys a product twice based on ad clicks in two different apps will generate two attribution reports.

    Attribution Reports Don’t Require Your App to Run

    One particular challenge for the kind of delayed attribution reporting PCM uses is what to do if the user doesn’t use the hosting app frequently or doesn’t use it around the time when the report is supposed to be sent out. We have made sure that pending attribution reports from PCM app-to-web with SFSafariViewController are sent independent of if the hosting app where the click happened is running or not.

    The API

    As shown in our introductory blog post on PCM, apps can already use Private Click Measurement with Safari by putting a UIEventAttribution on a UISceneOpenExternalURLOptions and using it with UIScene’s openURL:options:completionHandler:.

    In iOS 15.2 beta, a new attribute of type UIEventAttribution is added to the existing class SFSafariViewControllerConfiguration:

    @available(iOS 15.2, *)
      @NSCopying var eventAttribution: UIEventAttribution?

    You can optionally use it when opening a URL in SFSafariViewController, like this:

    func didTapOnAdWithIdentifier(advertisementIdentifier: UInt8, url: URL) {
        let attribution = UIEventAttribution(
            sourceIdentifier: advertisementIdentifier, 
            destinationURL: url, 
            sourceDescription: "Ad for toy XYZ.",
            purchaser: "Toy Example Company")
        let configuration = SFSafariViewController.Configuration()
        configuration.eventAttribution = attribution
        present(SFSafariViewController(url: url, configuration: configuration), animated: false)

    When an UIEventAttribution is part of the configuration, SafariViewService checks that a tap on an UIEventAttributionView preceded the opening of SFSafariViewController to guarantee click-through attribution. Then the information from the UIEventAttribution object is checked before it’s given to WebKit for processing.

    Private Click Measurement works as previously from that point.

    Debugging Your App

    See “Testing and Debugging” in our introductory blog post on PCM for how to turn on PCM Debug Mode.

    Make sure to restart your app after enabling PCM Debug Mode with SFSafariViewController. If you are having trouble getting PCM Debug Mode to turn on or off, try restarting the device.

    Please Provide Feedback

    We really appreciate all the developer and ad tech feedback we’ve received so far on Private Click Measurement. Prioritizing PCM for in-app measurement was the result of such feedback. There are three ways for you to continue to tell us what you think:

    • The standards proposal repository in the W3C Privacy Community Group for anything related to the specified web parts of PCM, i.e. feedback on the proposed standard as it would work in any web engine.
    • https://bugs.webkit.org for anything specific to the WebKit implementation of PCM.
    • Apple Feedback Assistant for anything specific to the UIKit or SFSafariViewController APIs for PCM.

    November 16, 2021 05:06 PM

    November 15, 2021

    Release Notes for Safari Technology Preview 135

    Surfin’ Safari

    Safari Technology Preview Release 135 is now available for download for macOS Big Sur and macOS Monterey. If you already have Safari Technology Preview installed, you can update in the Software Update pane of System Preferences on macOS.

    This release covers WebKit revisions 284370-285101.

    Note: Tab Groups do not sync in this release.

    Web Inspector and Web Driver

    • Fixed “testForLinkLabels” Accessibility audit to ignore anchors if aria-hidden (r284986)
    • Added support for the acceptInsecureCerts capability (r285164)


    • Media queries affect Cascade Layer order (r284859)
    • Enabled accent-color by default (r284634)
    • Added support for small svw/svh/svmin/svmax, large lvw/lvh/lvmin/lvmax, and dynamic dvw/dvh/dvmin/dvmax viewport units (r284628)
    • Added flex-basis: content support (r284440)
    • Added support for contain: style for counters (r284642, r284755)
    • Added support for ::before and ::after pseudo elements after ::slotted (r284973)
    • Added support for more CSS properties for ::marker (r284519)
    • Allowed :is and :where after all pseudo elements (r285054)
    • Made :-webkit-any() a synonym of :is() (r285032)
    • Fixed ::part(foo):hover (r284865)
    • Serialized :part() argument as identifier (r284863)
    • Fixed :host invalidation when combined with pseudo classes in descendant position (r285100)
    • Prevented clamping flex base size with min-height, max-height, min-width, and max-width (r284397)
    • Fixed sizing of orthogonal elements with percentage margins (r284773)
    • Fixed -webkit-background-clip: text to paint correctly for inline box spanning multiple lines (r284380)
    • Fixed box-shadow and text-shadow to yield float values while interpolating (r284437)
    • Fixed CSS serialization affecting grid-auto-flow (r284876)
    • Fixed percentages on orthogonal replaced children (r284548)
    • Fixed the border-radius value from .style to be readable when it includes a var() (r285015)
    • Fixed opacity to flatten when combined with transform-style: preserve-3d (r285021)

    Web API

    • Enabled lazy image loading by default (r284995)
    • Added support for rel="noopener/noreferrer" on <form> elements (r284749)
    • Exposed MediaCapabilities to Workers (r284443)
    • Fixed anchor.relList.supports("opener") to return true (r284745)
    • Fixed changing the src attribute of the <img> element inside an ImageDocument to trigger a load (r284901)
    • Fixed document.open() and friends to use the correct document as a source for reset document’s URL (r284758)
    • Fixed form navigations with target="_blank" to not have an opener (r284821)
    • Fixed form submission to be cancelled if the form gets detached from inside the formdata event handler (r284660)
    • Fixed JavaScript URL result to be treated as UTF-8 bytes (r284934)
    • Fixed Origin of opaque blob: URLs to be null instead of an empty string (r284478)
    • Fixed selection extend() with no ranges to trigger an exception (r285084)
    • Fixed the intrinsic size of a picture image inside a template (r284667)
    • Updated appearance of <datalist> indicator (r284626)


    • Fixed misplaced position: fixed content with async-scrollable iframes when switching tabs (r284738)


    • Ensured CanvasRenderingContext2D.drawImage(video) uses the right color space (r284439)


    • Changed to obtain consent to create a new credential when the platform authenticator is in excludedCredentials. This improves compliance with the WebAuthn spec (Step 3.1 of makeCredential). (r284413)


    • Added support for requestVideoFrameCallback API for MediaStreamTrack-based backends (r284528)
    • Fixed video appearing blank with only audio playing if video element isn’t appended to the DOM tree (r284741)
    • Updated WebM with invalid size to fail to load with error (r284434)


    • Decreased WebRTC latency by pulling data more often (r284860)
    • Changed to fallback to SW decoder in case of VP9-SVC (r284523)
    • Changed to always set the color space for incoming H.264/265 streams (r284433)
    • Ensured synchronized rendering of incoming audio tracks (r285027)
    • Fixed latent audio over peer connections when changing the output (r284674)


    • Fixed an issue where high-performance WebGL wasn’t getting the correct GPU (r284669)

    App Extensions

    • Fixed an issue where App Extension toolbar items would not remember their position or stay removed from the toolbar

    Web Extensions

    • Fixed an issue where browser.storage.sync entries were saved into the browser.storage.local storage area. If unable to locate sync storage entries, check in the local storage area and do a one-time migration to the sync storage area

    November 15, 2021 09:30 PM

    October 27, 2021

    Release Notes for Safari Technology Preview 134

    Surfin’ Safari

    Safari Technology Preview Release 134 is now available for download for macOS Big Sur and macOS Monterey. If you already have Safari Technology Preview installed, you can update in the Software Update pane of System Preferences on macOS.

    This release covers WebKit revisions 282317-284370.

    Note: Tab Groups do not sync in this release.

    Web Inspector

    • Graphics Tab
      • Added showing color space for canvases in the Graphics tab on the overview cards (r283572)
    • Styles Tab
      • Changed to format style declarations after editing (r283723)
    • Other
      • Added context menu support for the tab content view (r283859, r283921)


    • Enabled CSS Cascade Layers by default (r283218)
    • Unprefixed -webkit-appearance and added support for the auto value (r283858, r284098)
    • Added support for the x resolution unit outside of image-set (r282396)
    • Added support for text-decoration-skip-ink (r282397)
    • Changed to consider overflow-wrap: anywhere when calculating min-content intrinsic sizes (r283493)
    • Fixed computed style for transform-origin on SVG boxes (r282379)
    • Fixed overflow to be computed with the actual logical bottom in CSS Grid (r282463)
    • Fixed RTL for an out of flow child in CSS Grid (r282340)
    • Fixed SVG linear gradients getting drawn incorrectly sometimes (r282443)
    • Fixed radial-gradient to accept calc() values that combine length and percent (r283561)
    • Implemented exp, and log functions in calc functions (r282795)
    • Implemented allowing NaN, infinity, and -infinity in calc (r283434)
    • Implemented atan, acos, asin, atan2 in calc functions (r283013)
    • Updated CSS Cascade Layers with recent spec change: unlayered styles are highest priority (r284182)
    • Updated transform-origin to not accept four lengths (r282359)


    • Enabled font palette support:
      • Added parsing support for font-palette-values (r282806)
      • Added parsing support for font-palette (r282851)
      • Added pushing font-palette-values data into CSSFontSelector (r282838)
      • Added support for CSSFontPaletteValuesRule.name (r283140)
      • Added Web Inspector support for font-palette (r282987)
      • Allowed base-palette can accept "light" or "dark" (r283398)
      • Changed CSSFontPaletteValuesRule to not be map-like (r283219)
      • Changed to align with CSS Fonts specification changes (r283130)
      • Fixed shadowing of @font-palette-values rules (r283756)
      • Handle CSSOM style mutation of font-palette and font-palette-values (r283032, r283031)
      • Made negative integers in @font-palette-values invalid (r283197, r283540)
      • Made sure empty font families do the right thing for font palettes (r283075)
      • Prevented parsing unimplemented font palette features (r283752)
      • Removed the "none" value from font-palette (r283536)
      • Renamed override-color to override-colors (r283159)
      • Required font-families inside @font-palette-values to be case insensitive (r283794)
      • Required font palette names to start with two hyphens (r283221)
      • Stopped parsing context-sensitive colors in override-color (r283537)
    • Updated the implementation of the CSS Font Loading API to be closer to the spec and other browsers:
    • Fixed CSSFontFaceSrcValue.cssText to be quoted consistently with other browsers (r282442)


    • Enabled support for ScrollOptions’ ScrollBehavior and CSS scroll-behavior properties (r284029)
    • Moved smooth scroll animations to run on the scrolling thread (r283871)
    • Fixed scrollIntoView to not take into account sticky positioning offsets (r283546)
    • Fixed properly redrawing a sticky element inside another sticky element on scroll (r284084)


    • Enabled 2D canvas color space support on Apple platforms (r283541)
    • Updated converting an SVG image for canvas drawImage to choose an appropriate color space (r283531)

    Dialog Element

    • The <dialog> element is now enabled by default (r284155), also including:
      • support for the CSS ::backdrop pseudo element
      • support for the top layer
      • <form method="dialog"> support
    • The inert attribute is available for testing behind an experimental flag with the same name


    • Allowed WASM to use up to 4GB (r284330)
    • Implemented the WebAssembly exception handling proposal (r283852)


    • Enabled unlinked Baseline JIT for performance (r283139)
    • Fixed Intl.DateTimeFormat#resolvedOptions not to return detailed information of formatting if dateStyle or timeStyle is set (r283460)
    • Fixed Intl.supportedValuesOf to populate emoji and eor for collation (r282897)
    • Fixed syntactic production for #x in expr (r282968)
    • Optimized JSON.parse object creation (r282468)
    • Optimized put-by-val with for-in (r283098)
    • Optimized JSON.stringify property enumeration (r282707)
    • Refined RegExp#compile based on regexp-legacy-features proposal (r283874)

    Web API

    • Enabled BroadcastChannel (r282426)
      • Implemented top-origin and frame-origin partitioning for BroadcastChannel (r282366)
    • Enabled Storage API by default (r284273)
    • Enabled FileSystemAccess and AccessHandle by default (r284131)
      • Implemented FileSystemSyncAccessHandle read() and write() (r284059)
    • Implemented the borderBoxSize and contentBoxSize parts of ResizeObserver (r282441)
    • Implemented CSP script-src-elem, style-src-elem, script-src-attr and style-src-attr directives (r284254)
    • Cached Web Audio PannerNode’s azimuth, elevation, and coneGain for performance (r283740)
    • Changed <model> to be draggable, similar to <img> (r283563)
    • Updated the autofocus attribute behavior to match the latest specification (r283935)
    • Updated to preserve color space when creating ImageBuffers for ImageBitmaps (r282696)


    • Fixed image-rendering: crisp-edges for WebGL canvases (r282335)


    • Fixed the progress bar moving when playback stops (r282374)
    • Fixed createImageBitmap using a HLS video as source always returning a black image (r283585)


    • Added support for WebRTC media capabilities (r284085, r284236)
    • Changed MediaCapabilities to enqueue a task to resolve promises (r284236)


    • Exposed the URL attribute of <video> elements (r283799)
    • Made PDFs loaded via <embed> accessible (r282358)
    • Updated role="math" elements to no longer be considered to have presentational children (r284246)

    Private Click Measurement

    • Allowed measurement of links in nested, cross-site iframes (r283593)

    Web Extensions

    • Allowed more directives to be included in the content_security_policy of an extension’s manifest, such as the sandbox directive

    October 27, 2021 08:59 PM

    October 26, 2021

    New WebKit Features in Safari 15

    Surfin’ Safari

    With the release of Safari 15 for macOS Monterey, iPadOS 15, iOS 15, and watchOS, as well as macOS Big Sur and macOS Catalina, WebKit brings significant advancements in privacy and security, improved interoperability, and a host of new features for web developers. Take a look.

    Web Extensions

    This release brings Safari Web Extensions to iOS and iPadOS. Web Extensions use HTML, CSS, and JavaScript to offer powerful browser customizations. Now developers can create them for every device that supports Safari, using APIs, functionality, and permissions that are increasingly standardized across all browsers. Learn how to build Safari Web Extensions and discover how to convert an existing extension by watching Meet Safari Web Extensions on iOS at WWDC21.

    This year’s release also adds support for the Declarative Net Request WebExtensions API to block content on the web. Learn all about the latest WebExtension APIs by watching Explore Safari Web Extension Improvements at WWDC21.


    WebKit now provides support for theme-color in HTML meta tags, and in Web Manifest. By specifying a theme-color, web developers can change the color of the status bar and overscroll area in Safari on iOS 15. Theme-color also changes the Tab Bar and overscroll area background colors in Compact Tab layout for Safari 15 on macOS Monterey and Big Sur and iPadOS 15.

    In the HTML meta tag, developers can specify separate colors for Dark Mode and light appearance with the media attribute.

    <meta name="theme-color" 
          media="(prefers-color-scheme: light)">
    <meta name="theme-color" 
          media="(prefers-color-scheme: dark)">

    Watch “Design for Safari 15” at WWDC21 to learn more about the Compact Tab bar and how to use theme-color.


    demo of aspect ratio property

    WebKit now supports CSS aspect-ratio. This property can be used to set a preferred aspect ratio on any element, including boxes like divs, iframes for embedded video, or graphic design elements on a page.

    WebKit provides support for the new lab(), lch(), hwb() color syntaxes from Color level 4, providing web developers with ways to express a richer range of colors in Lab, Lch, and Hue-Whiteness-Blackness. WebKit also supports predefined color spaces using the color() function syntax: srgb, display-p3, a98-rgb, prophoto-rgb, rec2020, xyz.

    WebKit supports 12 new values for list-style-type: disclosure-closed, disclosure-open, ethiopic-numeric, japanese-formal, japanese-informal, korean-hangul-formal, korean-hanja-formal, korean-hanja-informal, simp-chinese-formal, simp-chinese-informal, trad-chinese-formal, and trad-chinese-informal.

    1. Apollo
    2. Hubble
    3. Chandra
    4. Cassini-Huygens
    5. Spitzer
    Disclosure closed
    1. Apollo
    2. Hubble
    3. Chandra
    4. Cassini-Huygens
    5. Spitzer
    Ethiopic Numeric
    1. Apollo
    2. Hubble
    3. Chandra
    4. Cassini-Huygens
    5. Spitzer
    Simplified Chinese informal

    There’s also improved implementation of existing values for list-style-type: armenian, cjk-ideographic, hebrew, lower-armenian, lower-roman, upper-armenian, and upper-roman. See a demo of all of these options at MDN. We also updated WebKit’s implementation of list-style-position:inside to match the updated CSS specification, creating interoperability after a 22 year old debate.

    Watch “Design for Safari 15” at WWDC21 to learn more about the latest updates to CSS.

    Web Inspector

    screenshot of Safari 15's CSS Grid Inspector

    Web Inspector in Safari 15 includes a CSS Grid Inspector overlay for inspecting grid containers on your pages. Watch “Discover Web Inspector Improvements” at WWDC21 to learn more.

    JavaScript and WebAssembly

    This release of WebKit adds support for ES6 Modules in Workers and ServiceWorkers. ES6 Modules provides a powerful way for developers to organize large applications using purpose-specific libraries. Workers/Service Workers provides a way to offload work from the main thread, and are often used for complex applications. Now, developers can use them together — moving work off the main thread, improving performance, while retaining the organizational benefits of modules.

    Additional new capabilities to the JavaScript engine, include:

    • support for top-level await
    • Error.cause
    • private class methods and accessors
    • BigInt64Array and BigUint64Array

    Improvements to WebAssembly include streaming compilation, bulk memory operations, reference types, and non-trapping conversions from float to int.

    You can learn more about the latest JavaScript and WebAssembly updates to WebKit and Safari 15 by watching “Develop Advanced Web Content” at WWDC21.

    Web APIs

    gorgeous weird 3D environments created to show off what's possible

    WebKit now supports WebGL2 (demos). In addition, the WebGL implementation now runs on top of Metal for better performance.

    Web Share level 2 enhancements to Web Share enable sharing files from a web page to an app. See Web Share API for more information.

    User gestures now propagate through requestAnimationFrame with a one-second time limit.

    And now, with Safari 15.1, performance.timeOrigin is available in Web Workers.

    You can learn more about the latest Web APIs in WebKit by watching “Develop Advanced Web Content” at WWDC21.


    Safari 15 includes several media improvements for users and developers. For example, built-in media controls now have Playback Speed and Chapters menus. Plus, the language/subtitle tracks menu is now available on iOS and iPadOS.

    There’s also new support for the Opus audio codec in WebM containers. And on on all iPads that support iPadOS 15, VP9 and WebM in Media Source Extensions (MSE) are now hardware-accelerated.

    Safari 15 also adds support for the MediaSession API to enable SharePlay experiences. You can learn more about creating SharePlay experiences by watching “Coordinate media playback in Safari with Group Activities” at WWDC21.

    Security and Privacy

    Continuing our dedication to privacy and security, Safari on iOS 15 and macOS Monterey supports automatic HTTPS upgrades and hides your IP address from known trackers. Automatic HTTPS upgrades are also supported in Safari 15 on older macOS versions.

    Earlier this year, Safari was the first browser to ship a proposed web standard for measuring advertising in a privacy-preserving way – Private Click Measurement, or PCM. Safari 15 provides three major updates to PCM:

    • Attribution reports also sent to click destination.
    • Click fraud prevention with unlinkable tokens.
    • IP address protection for attribution reports.

    To learn more, read PCM: Click Fraud Prevention and Attribution Sent to Advertiser or watch “Meet privacy-preserving ad attribution” at WWDC21.

    Authentication and Passwords

    WebKit now includes support for on-device verification codes in your app or website for a more secure sign-in experience with iCloud Keychain Password Manager. To use verification codes with Safari and Autofill:

    • Use autocomplete=one-time-code to make an <input> eligible for AutoFill.
    • Use a standard otpauth URL and replace the scheme with apple-otpauth to link directly to the password manager for setup.
    • Use a raster image to enable contextual menus on otpauth QR codes that offer to set up a verification code generator.

    Learn how to support the process in your apps and websites by watching “Secure login with iCloud Keychain verification codes” at WWDC21.

    a diagram of how private keys are routed with WebAuthn

    Despite their prevalence, passwords inherently come with challenges that make them poorly suited to securing someone’s online accounts. Passkeys are WebAuth credentials intended to replace passwords for websites and apps with device sync and backup. The technology is now available in WebKit as a preview. To enable in Safari, choose Develop > Enable Syncing Platform Authenticator. Learn more watching “Move beyond passwords” at WWDC21.


    Apple Pay enhancements allow developers using the Payment Request API to indicate an estimated arrival date for shipping methods, support a coupon code, and mark the shipping method as in-store pickup.


    These improvements are available to users running Safari on iPadOS 15, iOS 15, or Safari 15 on macOS Monterey, macOS Big Sur, or macOS Catalina. These features were also available to web developers in Safari Technology Preview releases. Changes in this release of Safari were included in the following Safari Technology Preview releases: 123, 124, 125, 126, 127, 128, 129.

    Download the latest Safari Technology Preview release to stay at the forefront of future web platform and Web Inspector features. You can also use the WebKit Feature Status page to watch for changes to web platform features you’re interested in.


    If you run into any issues, we welcome your bug reports for Safari or WebKit bugs for web content issues. Send us a tweet @webkit to share your thoughts on this release.

    October 26, 2021 09:27 PM

    September 30, 2021

    Release Notes for Safari Technology Preview 133

    Surfin’ Safari

    Safari Technology Preview Release 133 is now available for download for macOS Big Sur and betas of macOS Monterey. If you already have Safari Technology Preview installed, you can update in the Software Update pane of System Preferences on macOS.

    This release covers WebKit revisions 281797-282317. Note: The changes for these release notes were updated after publishing to account for an incorrect end revision number.

    Note: Tab Groups do not sync in this release.


    • Added support for self-start, self-end, start, end, left, and right values in positional alignment (r282267, r282078, r281840)
    • Added support for percentages in the scale() transform functions, and the scale property (r282144)
    • Added support for sin(), cos(), tan(), e, and pi in calc() (r282162)
    • Fixed incorrect stacking order with an absolutely positioned and negative z-index <div> with a canvas child (r281913)
    • Fixed absolute positioning with orthogonal writing modes (r281995)
    • Fixed right-relative and bottom-relative values in background-position-x and background-position-y (r282234)
    • Fixed incorrect vertical position in table layout when the inline level box has 0px height (r282256)
    • Fixed changing the border size on rows with border-collapse not redrawing (r282266)
    • Fixed position: sticky used within table cells (r282201)
    • Fixed incorrectly calculated position: sticky constraints when the scrolling container has padding and borders (r282138)
    • Fixed an interoperability issue in margin collapsing with overflow: hidden elements (r282085)

    CSS Cascade Layers

    • Added initial support for CSS Cascade Layers in Experimental Features:
      • Added support for computing the order correctly for late added sublayers (r281798)
      • Supported layer argument in @import rules (r281928)

    CSS Font Loading API

    • Updated the implementation of the CSS Font Loading API to be closer to the spec and other browsers:
      • Fixed CSSFontFaceSet.clear() to not clear CSS-connected members (r281842)
      • Updated FontFaceSet methods that need to react to style changes (r282016, r282015, r282015, r282261, r282204)
      • Updated FontFaceSet.add() to throw when called on a CSS-connected font (r281951)


    • Fixed blank braille display in contenteditable elements when the field is followed by another element (r281920)
    • Made PDFs loaded via <embed> accessible (r282358)


    • Enabled Object.hasOwn (r281835)
    • Implemented Temporal.PlainTime behind the flag --useTemporal=1 (r282125)
    • Implemented Temporal.TimeZone behind the flag --useTemporal=1 (r282018)
    • Implemented Temporal.Duration behind the flag --useTemporal=1 (r281838)
    • Implemented self.structuredClone() (r281808)
    • Implemented Object.hasOwn() (r281799)
    • Updated Intl.Locale weekendInfo to list all weekend days instead of range to follow to the latest spec change (r282257)

    Web API

    • Added basic support for Storage API (r282130)
    • Added support for ServiceWorkerGlobalScope.serviceWorker (r281854)
    • Added handling for non-fully active documents in navigator.share() / navigator.canShare() (r282282)
    • Enabled Cross-Origin-Opener-Policy / Cross-Origin-EmbedderPolicy headers support (r282105, r282246)
    • Enabled SharedArrayBuffer support when COOP/COEP headers are used (r281832)
    • Fixed scrollbars on pointer-events: none element still intercepting events (r281991)
    • Implemented top-origin and frame-origin partitioning for BroadcastChannel (r282105)
    • Implemented navigation reporting for Cross-Origin-Opener-Policy (r282305)
    • Implemented getClientRects() for SVG elements (r282316)
    • Updated to always fetch the first manifest if provided (r282026)


    • Added support for RTCError and RTCErrorEvent (r282199)
    • Added support for RTCDataChannel closing event (r282198)
    • Added support for RTCSctpTransport (r282197)
    • Updated timing of RTCPeerConnection descriptions update to align with the WebRTC spec (r282217)
    • Updated signaling state check when applying a local or remote description to align with the WebRTC spec (r281985)
    • Updated getDisplayMedia to capture at the constrained size if possible (r281880)


    • Fixed an incorrect number of frames returned if the decoding frame rate doesn’t match the original in WebM (r282196)
    • Removed Web Audio canPlayType() workaround that made it reports false negatives (r282137)

    Web and App Extensions

    • Added the extension’s icon to extension URL tabs for both app and web extensions
    • Added the extension name as the title of tabs when an app extension page and does not specify a title

    September 30, 2021 05:07 PM

    September 16, 2021

    Release Notes for Safari Technology Preview 132

    Surfin’ Safari

    Safari Technology Preview Release 132 is now available for download for macOS Big Sur and betas of macOS Monterey. If you already have Safari Technology Preview installed, you can update in the Software Update pane of System Preferences on macOS.

    This release covers WebKit revisions 281002-281797.

    Note: Tab Groups do not sync in this release.

    Web Inspector

    • Elements Tab
      • Fixed CSS Changes sidebar to update live (r281441)
      • Fixed showing style rules declared after a rule whose selector has over 8192 components (r281354)
      • Changed to not show contextual documentation popup in the Changes panel (r281139)
    • Miscellaneous
      • Adjusted tab bar style to be consistent between docked and undocked layouts (r281182)


    • Fixed CSS keyframe animations to respect edges in four-value background-position (r281683)
    • Fixed sticky position to not use transformed position to compute the offset (r281446)
    • Improved sticky positioning when applied to inline items(r281185)
    • Prevented snapping to offscreen snap areas in unidirectional scrolls (r281189)
    • Unprefixed -webkit-backface-visibility (r281009)


    • Added Intl Enumeration APIs (r281513)
    • Enabled Array#findLast method (r281369)
    • Enabled String#at and TypedArray#at (r281370)
    • Extended Intl TimeZoneName Option (r281371)
    • Fixed Intl.DateTimeFormat incorrectly parsing patterns with ‘h’ literal (r281688)
    • Implemented Temporal.Calendar behind the flag (--useTemporal) (r281788)
    • Implemented Intl Locale Info extension (r281374)
    • Implemented Intl.DisplayNames V2 (r281375)
    • Made polymorphic-keyed put-by-value faster (r281615)

    Web API

    • Added Cross-Origin-Embedder-Policy support for Blob URLs (r281055)
    • Added onsecuritypolicyviolation on GlobalEventHandlers (r281569)
    • Enabled PerformanceNavigationTiming API by default (r281111)
    • Fixed including outer selector when matching ::slotted() (r281692)
    • Fixed document.hasFocus() returning true for unfocused pages (r281228)
    • Fixed Geolocation API to callback with an error if the document is not fully active (r281520)
    • Fixed setting window.location.href to an invalid URL to throw a TypeError (r281472)
    • Fixed SubmitEvent.submitter property to be set for <button type="submit"> (r281770)
    • Fixed Web Share CanShare() to be called after transient activation check (r281126)
    • Implemented Crypto.randomUUID() (r281206, r281284)
    • Implemented self.reportError() (r281756)


    • Added support for RTCDtlsTransport (r281225)
    • Added support for RTCPeerConnection.canTrickleIceCandidates (r281298)


    • Fixed caret to respect text background color (r281685)
    • Fixed incorrect repaint when inline level box style change triggers line height change (r281136)
    • Changed synthetic bold additional advances to be applied after shaping (r281687)


    • Fixed nexttrack and previoustrack MediaSession handlers (r281013)

    Web Extensions

    • Added support for externally_connectable for sending messages to extensions from web pages
    • Added a drop shadow around color extension icons when the tab is using a theme color from the web page
    • Added an error message when declarative net request is used and the declarativeNetRequest permission is not specified in the extension manifest

    September 16, 2021 09:16 PM

    September 01, 2021

    Release Notes for Safari Technology Preview 131

    Surfin’ Safari

    Safari Technology Preview Release 131 is now available for download for macOS Big Sur and betas of macOS Monterey. If you already have Safari Technology Preview installed, you can update in the Software Update pane of System Preferences on macOS.

    This release covers WebKit revisions 280418-281002.

    Note: Tab Groups do not sync in this release.

    Web Inspector

    • Elements
      • Added CSS keyword completions for standard logical properties (r280588)
    • Console
      • Fixed missing execution context dropdown for contexts added after page load (r280989)
    • Network
      • Fixed sorting the Transfer Size column for failed requests changing the ordering of requests continually (r280566)


    • Changed to consider all snap areas at a given snap offset when snapping (r280527)
    • Fixed aspect ratio for replaced elements (r280471)
    • Implemented the clip value for overflow (r280509)

    Web API

    • Added initial support for Cross-Origin-Embedder-Policy (COEP) (r280953)
    • Added initial support for Cross-Origin-Opener-Policy (COOP) (r280504, r280881, r280582)
    • Fixed Blob URLs changing after loading (r280824)
    • Fixed clicking an HTMLLinkElement to not trigger a navigation (r280479)
    • Fixed inaccurate Document.baseURI for iframe srcdoc documents (r280855)
    • Fixed the document’s fallback base URL to be deduced from its creator when the URL is “about:blank” (r280491)
    • Fixed <a rel="opener noopener" target="_blank"> to create a window without opener (r280933)
    • Fixed meta HTTP refresh to not navigate if the document has sandboxed automatic features browsing context flag set (r280870)
    • HTMLElement.innerText setter should convert new lines to <br> (r280482, r280541)
    • HTMLMetaElement http-equiv should not be processed in shadow trees (r280913)
    • HTMLStyleElement should create its style sheet even if its media attribute is invalid (r280910)
    • Implemented support for <dialog> element cancel event (r280703)
    • Stopped changing invalid baseURLs from loadData or loadHTMLString to “about:blank” (r280562)
    • Stopped evaluating <script> elements moved between Documents during fetching (r280924)


    • Renamed Temporal.now to Temporal.Now (r280506)
    • Fixed super-Latin1 white space and line terminator after regular expression literal getting misinterpreted as flags (r280825)
    • Improved RegExp performance by introducing Boyer-Moore search (r280452)
    • Made legacy RegExp constructor properties (e.g. RegExp.$1) accessors (r280460)

    Platform Features

    • Fixed the start drag on image when the first piece of text inside the image is selected with Live Text (r280872)
    • Fixed the translate popover becoming detached from webpage after scrolling (r280690)


    • Fixed enter fullscreen animation interfering with auto-hiding menu bar (r280976)
    • Fixed media element to autoplay when going from background to foreground if it is initially not in viewport (r280920)

    Web Audio

    • Added WebM container support for Vorbis and Opus (r280573, r280416)
    • Fixed audio buffer that may contain more frames than decoded (r280948)


    • Enabled WebRTC relay by default (r280908)
    • Enabled WebRTCPlatformUDPSocketsEnabled feature by default (r280545)
    • Introduced an experimental feature to toggle WebRTC socket proxying (r280523)

    Payment Request

    • Fixed issue where additionalShippingMethods was not used when paymentMethodType was provided (r280459)


    • Added console logging to encourage the use of authenticated encryption (r280790)


    • Added support for aria-selected value changes in table cells (r280633)


    • Fixed dynamically changing HTMLStyleElement.type to change the rendering accordingly (r280909)

    September 01, 2021 05:25 PM

    August 18, 2021

    Release Notes for Safari Technology Preview 130

    Surfin’ Safari

    Safari Technology Preview Release 130 is now available for download for macOS Big Sur and betas of macOS Monterey. If you already have Safari Technology Preview installed, you can update in the Software Update pane of System Preferences on macOS.

    This release covers WebKit revisions 279831-280418.

    Note: Tab Groups do not sync in this release. On macOS Big Sur, this release requires enabling GPU Process: Media option from Experimental Features under the Develop menu to address issues with streaming services.

    Web Inspector

    • Elements
      • Fixed selecting a sibling node using navigation breadcrumbs (r280037)


    • Changed to use the correct block-size to resolve min-content (r280023)
    • Changed to pass the full target point when selecting a snap offset (r280171)
    • Changed images as grid items to use the overridingLogicalWidth when defined to compute the logical height (r280024, r280078)
    • Ignored the aspect-ratio of a replaced element if stretch alignments are applied to both axes (r280022)


    • Implemented Array.prototype.findLast and Array.prototype.findLastIndex behind a runtime flag (--useArrayFindLastMethod) (r279937)


    • Added support for MediaError.message (r279978)
    • Added webm/opus container support for Web Audio (r280416)
    • Fixed hanging when entering PiP from element fullscreen (r280358)
    • Fixed SourceBuffer.abort() doesn’t go back to state WAITING_FOR_SEGMENT properly (r279904)
    • Fixed video pausing after scrubbing with the Touch Bar (r280330)

    Web API

    • Fixed document.referrer value missing a trailing slash (r280342)
    • Fixed FetchResponse.formData() to not reject the promise if the body is null and the MIME type is "application/x-www-form-urlencoded" (r280046, r279969)
    • Fixed getBoundingClientRect() to return the correct rectangle on elements inside a multi-column container (r280017)
    • Fixed HTMLImageElement.decoding to reflect the decoding content attribute, limited to only known values (r280047)
    • Fixed Sync XHR “load” event always having total/loaded=0 (r279967)
    • Implemented SubmitEvent interface (r279979)


    • Fixed IDBFactory.databases to return correct results (r280410)
    • Implemented IDBTransaction.commit() (r280053)
    • Implemented IDBTransaction.durability (r280415)

    August 18, 2021 05:58 PM

    August 05, 2021

    Chris Lord: OffscreenCanvas update

    Igalia WebKit

    Hold up, a blog post before a year’s up? I’d best slow down, don’t want to over-strain myself 🙂 So, a year ago, OffscreenCanvas was starting to become usable but was missing some key features, such as asynchronous updates and text-related functions. I’m pleased to say that, at least for Linux, it’s been complete for quite a while now! It’s still going to be a while, I think, before this is a truly usable feature in every browser. Gecko support is still forthcoming, support for non-Linux WebKit is still off by default and I find it can be a little unstable in Chrome… But the potential is huge, and there are now double the number of independent, mostly-complete implementations that prove it’s a workable concept.

    Something I find I’m guilty of, and I think that a lot of systems programmers tend to be guilty of, is working on a feature but not using that feature. With that in mind, I’ve been spending some time in the last couple of weeks to try and bring together demos and information on the various features that the WebKit team at Igalia has been working on. With that in mind, I’ve written a little OffscreenCanvas demo. It should work in any browser, but is a bit pointless if you don’t have OffscreenCanvas, so maybe spin up Chrome or a canary build of Epiphany.

    OffscreenCanvas fractal renderer demo, running in GNOME Web Canary

    Those of us old-skool computer types probably remember running fractal renderers back on their old home computers, whatever they may have been (PC for me, but I’ve seen similar demos on Amigas, C64s, Amstrad CPCs, etc.) They would take minutes to render a whole screen. Of course, with today’s computing power, they are much faster to render, but they still aren’t cheap by any stretch of the imagination. We’re talking 100s of millions of operations to render a full-HD frame. Running on the CPU on a single thread, this is still something that isn’t really real-time, at least implemented naively in JavaScript. This makes it a nice demonstration of what OffscreenCanvas, and really, Worker threads allow you to do without too much fuss.

    The demo, for which you can look at my awful code, splits that rendering into 64 tiles and gives each tile to the first available Worker in a pool of rendering threads (different parts of the fractal are much more expensive to render than others, so it makes sense to use a work queue, rather than just shoot them all off distributed evenly amongst however many Workers you’re using). Toggle one of the animation options (palette cycling looks nice) and you’ll get a frame-rate counter in the top-right, where you can see the impact on performance that adding Workers can have. In Chrome, I can hit 60fps on this 40-core Xeon machine, rendering at 1080p. Just using a single worker, I barely reach 1fps (my frame-rates aren’t quite as good in WebKit, I expect because of some extra copying – there are some low-hanging fruit around OffscreenCanvas/ImageBitmap and serialisation when it comes to optimisation). If you don’t have an OffscreenCanvas-capable browser (or a monster PC), I’ve recorded a little demonstration too.

    The important thing in this demo is not so much that we can render fractals fast (this is probably much, much faster to do using WebGL and shaders), but how easy it is to massively speed up a naive implementation with relatively little thought. Google Maps is great, but even on this machine I can get it to occasionally chug and hitch – OffscreenCanvas would allow this to be entirely fluid with no hitches. This becomes even more important on less powerful machines. It’s a neat technology and one I’m pleased to have had the opportunity to work on. I look forward to seeing it used in the wild in the future.

    By Chris Lord at August 05, 2021 03:33 PM

    August 04, 2021

    Release Notes for Safari Technology Preview 129

    Surfin’ Safari

    Safari Technology Preview Release 129 is now available for download for macOS Big Sur and betas of macOS Monterey. If you already have Safari Technology Preview installed, you can update in the Software Update pane of System Preferences on macOS.

    This release covers WebKit revisions 279264-279831.

    Note: On macOS Big Sur, this release requires enabling GPU Process: Media option from Experimental Features under the Develop menu to address issues with streaming services.

    Web Inspector

    • Added contextual documentation for CSS properties (r279510)
    • Changed the sidebar panel and navigation bar to layout asynchronously during resize (r279790)
    • Elements Tab
      • Fixed Details sidebar navigation items wrapping to a second line (r279613)
      • Added support for function value completions in the Styles sidebar (r279422)
      • Autocomplete var() and attr() values in the Styles sidebar (r279502)
    • Sources Tab
      • Fixed the Scope Chain sidebar panel to not strip repeating whitespace from strings (r279294)


    • Changed to not clamp flex base size with min-height, max-height, min-width, and max-width (r279271)
    • Changed :link and :visited pseudo-class selectors to not match <link> elements (r279818)
    • Changed to match the CSS specification which prohibits numbers with a trailing decimal point (e.g. “1.px”) (r279429)
    • Fixed the CSS parser “consume declaration” algorithm to handle whitespace correctly (r279358)
    • Fixed CSS style sheets loaded by HTMLLinkElement to fall back correctly when the charset is an invalid encoding name (r279383)
    • Improved computation of intrinsic sizes of flex items with aspect ratio (r279286)
    • Included container’s writing mode to get grid item’s margin (r279278)
    • Unprefixed :autofill pseudo-class (r279457)


    • Changed scroll-snap-align to use the box’s writing-mode when the box is larger than the snap-port (r279714)
    • Fixed CSS scroll snap to allow scrolling to the middle of snap areas that overflow the snap-port (r279364)
    • Fixed layouts during scroll causing jittery scrolling when dragging the scrollbar (r279564)


    • Added support for rendering <model> resources (r279451)
    • Fixed the scrollbar being hidden when the scroller has a negative z-index child (r279748)


    • Added support for (ref null? $t) type constructor (r279265)

    Web API

    • Fixed ReadableStream.getReader to throw a proper exception when the parameter is of the wrong type (r279472)
    • Fixed 'data:application/javascript' URLs for Worker (r279602)
    • Fixed WebGL toDataURL image being upside down if premultipliedAlpha=false (r279424)

    Platform Features

    • Fixed extraneous spaces when copying or translating Chinese and Japanese in Live Text (r279609)
    • Fixed misaligned Live Text selection on some images (r279751)


    • Fixed transaction to be inactive during structured clone (r279686)
    • Fixed IDBIndex.keyPath to keep returning the same object (r279669, r279683)


    • Fixed WebM loads hanging if the server sends only small amount of data (r279375)
    • Fixed SourceBuffer.abort() to go back to state WAITING_FOR_SEGMENT properly (r279542)


    • Fixed WebGL content to be able to use the discrete GPU (r279303)


    • Added support for Elliptic Curve P-521 (r279688)
    • Fixed deriveBits() failing if the length is not a multiple of 8 for ECDH algorithm (r279723)
    • Fixed SubtleCrypto to only be exposed to secure contexts (r279642)

    August 04, 2021 05:35 PM

    August 02, 2021

    Philippe Normand: Introducing the GNOME Web Canary flavor

    Igalia WebKit

    Today I am happy to unveil GNOME Web Canary which aims to provide bleeding edge, most likely very unstable builds of Epiphany, depending on daily builds of the WebKitGTK development version. Read on to know more about this.

    Until recently the GNOME Web browser was available for end-users in two …

    By Philippe Normand at August 02, 2021 12:00 PM

    July 29, 2021

    PCM: Click Fraud Prevention and Attribution Sent to Advertiser

    Surfin’ Safari

    Earlier this year, Safari was the first browser to ship a proposed web standard for measuring advertising in a privacy-preserving way – Private Click Measurement, or PCM. Today we’re happy to announce three major updates to PCM, available in our iOS/iPadOS 15 and macOS Monterey betas:

    • Attribution reports also sent to click destination.
    • Click fraud prevention with unlinkable tokens.
    • IP address protection for attribution reports.

    All of it is covered in Kate’s WWDC session. There are also two minor updates to naming and data types so look out for those below.

    Let’s jump in.

    Quick PCM Refresher

    PCM allows for measurement of clicks which navigate the user from one website to another or from an iOS app to a website. The website or app where the click happens is called the click source, and the website the user is navigated to is called the click destination.

    Attribution Reports Also Sent to Click Destination

    We’ve designed PCM’s attribution reports to ensure they make sense to both the click source and the click destination, i.e. no opaque IDs that can only be understood or decoded by one party. PCM now sends the resulting attribution report to both click source and destination to help advertisers validate data and be in control of their ad measurement. The two reports are sent independently with a 24-48 hour delay (each report gets its own delay within those 24-48 hours). Since PCM reports already contain information about both click source and destination, there is no new privacy risk involved in sending it to both places (they could have already shared this information).

    PCM’s Debug Mode (see “Testing and Debugging” in our previous blog post) sends them independently too but with the shorter 10 second delay, i.e. one after 10 seconds and one after 10+10=20 seconds.

    Click Fraud Prevention With Unlinkable Tokens

    We mentioned in our introductory blog post on PCM that fraud prevention is a top request for the feature and we’re super excited to announce that optional unlinkable tokens for click fraud prevention are now supported. The cryptographic operations required for blinding and unblinding the tokens are only available on iOS/iPadOS 15 and macOS Monterey so no such tokens will be provided by clients on older operating systems. However, PCM will still work and send attribution reports if you opt-in to tokens in a Safari version that doesn’t support them. Also, unlinkable tokens for click fraud prevention are only available in PCM web-to-web for now.

    An unlinkable token provides a privacy-preserving proof, generated by the click-source and the client, of a unique click event on the attributed link. Unlinkable tokens are implemented using RSA blind signatures, a well-studied cryptographic construction that guarantees unlinkability between the moment the token is getting signed and the verification of the resulting signature, through blinding and unblinding operations that are performed on the client side. In contrast with some other cryptographic token constructions, blind signatures provide public verifiability, allowing both the click source and click destination to verify the authenticity of the click event on the click’s source website.

    This is how you as a developer of the click source website opt in to click fraud prevention with unlinkable tokens:

    Step 1: Generate an RSA Key Pair

    Unlinkable tokens require a public key for token generation and validation, and a corresponding private key for signing. PCM supports three different RSA key sizes: 2048, 3072 and 4096 bits. The expected encoding of the public key is a Base64-encoded SPKI with the RSA-PSS OID and the parameters corresponding to the RSABSSA IETF draft.

    Step 2: Add the New Link Attribute attributionsourcenonce

    Add a nonce on the click source side:

    <a href="https://shop.example/productABC.html" attributionsourceid=3 attributiondestination="https://shop.example" attributionsourcenonce="ABCDEFabcdef0123456789"></a>

    The attributionsourcenonce is only in place to help the click source server know the context for which it’s signing an unlinkable token. The click source is intended to uniquely and ephemerally identify a specific click event in the eyes of the server. When the server is asked to sign an unlinkable token it’ll get the attributionsourcenonce and can make a decision as to whether the click event was trustworthy or not.

    The attributionsourcenonce needs to be a Base64URL encoded 128-bit/16-byte value. Any smaller or larger value will cancel the issuance flow of the fraud-prevention signature. Any non Base64URL encoded value will also cancel the token transaction. Web Inspector will log a warning if the attributionsourcenonce is malformed.

    Step 3: Respond to a Request for Your Public Key

    The browser and any validating party needs to be able to fetch your public key at any point in time from this well-known location: https://clicksource.example/.well-known/private-click-measurement/get-token-public-key/.

    Your server’s response should look like this, with its key Base64URL-encoded:

      "token_public_key": "MIICUjA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCAqEaMBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgKiAwIBMAOCAg8AMIICCgKCAgEAoGhU5Mgsbb51ZbJVPHSgf8c93TJdtkxeKfyxQ5fCpwE2Fe9xJ7tByExdGKj4XO+HFi7npmtEPzR4cRXdsAL7YcH5UXNbVhXmVcbFCBXks+Ih+jqLwfNac0wPLG5K1Zzhf1gZ++JBzVjw87zvqpWrzzxviuV//0sn/u7f01E1OdaD83110fhfiXp/Ex62Q2uhcek0hqbqEvyKlLVBOjlJFJc2FLyw+l8+9xd7GcX1ZRyPx4lITvYG7KIbSMrFTfuQNOyJf4DlO97qq08R6Utl249AnBfLe3ZDbWBnl0fDOwkJgBmbaa7EnRlQ3p6Ir2SY1hNTnzW+p2ceytIMYwTMSES7+j21oeTUC+OmcC/5g05AgxROzUJPZdyY33m4Q7lqkHkLAYtdN2TVCP79MuswS+fJJQOD/dDCqq/hk0MySLCbnUGe5lyFBoO5vBMH5k38LjSQuN6jfP7quYA6cOONzmn842eLT61tIjRoX2czeUJrSmx89SfY8WnFE2fhk9G52cXp6L2Vzr5IV7rOws3ZPw+RnjKnZZaejs0bKGOXC1+jl+u4A5ip55ohlUjm7lvDtKFAeJ7gajJBtiNnq3s3m/IMkv7ztCQpv0pBxst6MmvNOO0jOQvYkzQbGooI1/qjeDup0BYY67xxyNRaA9V4CKEJ7j/hznrAmjSiz0LSqTkCAwEAAQ=="

    Step 4: Receive Token Signing Request, Sign, and Respond

    After the browser has requested your public key, it will send your server a signing request with an unlinkable token to this well-known location: https://clicksource.example/.well-known/private-click-measurement/sign-unlinkable-token/.

    The request body looks like this:

      "source_engagement_type": "click",
      "source_nonce": "ABCDEFabcdef0123456789",
      "source_unlinkable_token": "BC16WmucFh4u8pnfKX+3oRLyu2Bkc39UhMDt8ncOHQsd1Joo5ZslNVNdYajMQaNcOdlCpb6weGOE0R9nHtMjzMyUyJWx1T6ADsJsuFwfHvaVGY6v4fOHRc5P0WReOaiBgkGnDwOdG38rQcKk9lAWHCrcSSCsPTuA6L2W81C9/+0fUED+HY8Dqh1q7AkK/dJbsH0oA1nkYPHhPwghdp4QHZzTPSIHtQt/kNUXjT6Z2UPPEUelZNuEYKHUYyKrsKHZhP/2SJmJzJRrV3wb8chKxOpLmQPRkuDBRLIjqe+o7d2IHe4/5Gt1S3m/jrNSggUb8hekHD9C6WLcZ2tVI2A4ALV4clkJAOMtOH819KEd7fQgCT2kRjvz5EkhVto7WHhToCAbLSFCUjucMWqG7o8iRjy6BGvz09GdSNYBSeALwKm+QjOtsuh+sHMh/H0ngqRbT6RgRa8a+4ejsMCeoqZ52H9X6B+yJywT9eLqcKjDnAk2CJR+EOt4Q6FeMqkfUz5SJtGkjGv1PMnXw3PqT3SzuL3B6d3nW7DySkWkR1xMcZnIC0vW7gMgj9O5+Jq3WQh1XlNqkCraPZIbDFGeCIs4LHMRfTA8yzWFEL1CwdrMDjrmpqtzENHGxFHRr/TKozc3v/vGKc2rE9EfhWSAATFSIjeyUUByUCySR3rCzBssaR0=",
      "version": 2

    The source_nonce is the attributionsourcenonce that was provided in the link and the source_unlinkable_token is the Base64URL-encoded token to sign.

    If you deem this is a valid request, your server performs the BlindSign operation of the RSABSSA draft, which is a RSA private key operation on the browser-provided source_unlinkable_token and returns the blind signature as a Base64-encoded output labeled “unlinkable_token" in a response like this:

      "unlinkable_token": "QfvIa2RF16zPcXmsbhrsX7ZcUDAk1rtoOcrqE1XoaK7MUrsLNeolZwzNhkOUSSwJKiXPJpam4q1/teU379uiizDFTLPPaPXqxoEq7L/+QjkGmh5lrmFYSbN475Lm+hb9k1rrPT+ek4PDQ3PZpk35h/cB36iE4cf0/F72Iuf4gnn2S/gGL4oZDb4Yi9njY186TzAZ3E9/1bGKiw6qg1gFD92i7yEm//KdqlcwTrdvaMkqzZtD7KmCzkaub46bVIokLwOuDa2SCj9dDaBVRmcHIAtF174nARQjKkp3do/q8pdZh+syeEUYmnpl+qe+yG9+AlSWQXI+3zW6KZ0PbFAQ/hrmqTU9v3vDOdKFi/gr321A6XeUtL4dQxr/Anw0opLxX/lcwsa6gFiWnpMqBv7x+xnhJBFJI+0USUxq2gXVonhXBg/HVMhrW+eEbqMtrVF23JkXaYX1eaQrV9lfFf6LgHo+7GAVbHF6Y7J4IwfwuvksDfJ1/9axdO5jKQ58gCAlH0zpVgMxNmBcAgCBUv3ebZmrKNzNFSjsodBQ30FmKMPkT1l0eWlaDBz5QIG4y1Pc+ZKW9tCV0rFTg4FMoeN8aayUkTCKGpnRgmfO03uQMeQbuPOkAndjyXQyhevOTespEo9X6Z1KI+w7dVmPL/8oG8Mx+2bic6eszWprP/Kef64="

    Step 5: Respond to Another Request for Your Public Key

    When it’s time for the browser to send the attribution report, it will again fetch the public key from your server and make sure that it’s the same public key. This is how PCM makes sure that the server doesn’t use user-specific keys. Note that this second request for your public key may happen multiple days after the click you are measuring and that the browser will discard the attribution data if it receives a mismatching key.

    There is currently no support for managed key renewal. We intend to support responses with two public keys – one current and one decommissioned. That way, the browser can compare with both and allow attribution with tokens that were signed with the private key matching the decommissioned public key.

    Step 6: Receive and Validate the Attribution Report

    The resulting attribution report will contain a signed secret token (source_secret_token) that your server has never seen before and that your server cannot link to its corresponding unlinkable token (source_unlinkable_token). However, the signature you created with your private key will be valid for the secret token, effectively proving to you that you deemed this a trustworthy click some time back. Make sure to validate the signature.

    Since the click destination receives attribution reports too, they should validate the token as well.

    The report will look like this, with the source_secret_token and source_secret_token_signature Base64URL-encoded:

      "source_engagement_type": "click",
      "source_site": "clicksource.example",
      "source_id": 201,
      "attributed_on_site": "shop.example",
      "trigger_data": 10,
      "version": 2,
      "source_secret_token": "7JgS5aIQPUm9T5DcT2a91NC1lt2xq5bLjuaJi4A/Wbg=",
      "source_secret_token_signature": "ThyNW13Z7DTVSj/U8+5oWyG73bskeB2ZtmyG+tZRbuX216mK2F7wgv8piQEFxjDC49O9fPP7DFovcJbGOx3JR7zS7fDq3pYOKz/LkF8I2DkLz9jDcgXxgddMRfFsG8ud6FyEtmESiFgF23Nfqnn4JrhC4luDb7JceOdFsNWtXTURYeVcnARhKlcQ8h8Gs0zTCTGz2LkhwOHUlRYUTnqy5Ng9DiK4Rb9XSaTTPFPK2VJ7PNDmVFtvj1uc2OSxO8AJu9FYF4pv0wQjXjBKy00BF6Qm3m7vZXIwu7pTHBbXlb7DpJ2/15OblNEZrbS0BbXUzv8gqhz6MqmstltZdDiQZHRNDXabmPX7Rm1NRiy5XBr2oF+YBcSHJ0xV3YEH3XoeGN2McBoZCQ7CLhhMcDQLGVBv0L05Wp5rwausxd6Yerf01ebedk5D7RlQmrQ0lMo6fnqm6/F9gEHil2axA8zB/xThPD4ZQ0ARHkGWQYraQzGq5Xj65CIa1yV174iDcf6ZP18Hvkj1VcQIderLg0oMI6FOFzSYYeWJR0vKSc6C+y6jAX4dPPS+1uKRMBBijdv/4H9GazAQHhXLGKxaRgbLg+mLXKG4I9YoPVgU/gc/ePeTAyXFs+EgTi5ExpTF2Klv10E8HTtYLAO76FQVjnDNB98dq+XIbFHMuVKzAaBFr7s="

    IP Address Protection for Attribution Reports

    Safari 15 already hides the devices IP address from known trackers so if PCM is communicating with a known tracker, that protection is there. On top of that, PCM now protects all of the requests it makes that don’t happen very close in time to a linkable event in a first-party context, i.e. requests that don’t have a high likelihood of being matched based on time with very recent non-protected requests. The device IP address is hidden by sending requests through a two-hop relay which makes sure that Apple doesn’t get to see things like the attribution data. Learn more about this technology in the WWDC session “Get ready for iCloud Private Relay.”

    PCM Debug Mode skips IP address protection so that you can test locally.

    Attribute Name and Data Type Change

    Our introductory blog post on PCM also mentioned that there will likely be changes to naming due to the ongoing efforts to harmonize as much as possible with Google’s alternative proposal Click Through Attribution Reporting API.

    The PCM naming and data type changes in Safari 15 are:

    • The click destination is now stated in the anchor element’s attributiondestination attribute (used to be attributeon).
    • attributionsourceid is now an unsigned long, i.e. a non-negative integer (used to be a string).

    This means that a PCM link now looks like this:

    <a href="…" attributionsourceid=3 attributiondestination="https://shop.example"></a>

    Feature Enabled and Disabled Should Be Indistinguishable

    Our continued work in this space has taught us that it’s important to design ad measurement features so that websites cannot tell if the user has the feature enabled or not, at least not at page render time. The reason why is to offer users a real choice. If a webpage can tell that the user has chosen to disable ad measurement, it may pressure the user to enable it. We encourage other browser vendors in this space to think about this important aspect of user agency, especially in light of the multi year effort to make the web work well without third-party cookies (as a user setting or as the default).


    Q1: My triggering event is not accepted. How should I debug?
    A1: Make sure the HTTP request to https://clickSource.example/.well-known/private-click-measurement/trigger-attribution/ is done as the result of a same-site HTTP redirect, e.g. a clickSource.example to clickSource.example redirect. Otherwise it won’t be accepted as a triggering event. There are two reasons for this requirement:

    • Support for legacy tracking pixels. With a redirect, nothing needs to change on the click destination site.
    • Server-side control. By requiring a server-side redirect, we enable the domain owner to be in control of when a triggering event is fired. If it was just a HTTP request, any JavaScript on the destination site could fire triggering events. The redirect is not a fool proof system but it offers at least one checkpoint of control.

    Q2: I’m not receiving attribution reports in my testing. How should I debug?
    A2: Attribution reports are sent over HTTPS to the registrable domain of the click source and click destination. There needs to be a valid TLS certificate for each of those domains and the server needs to accept a request to the well-known location.

    Q3: Will Apple add support for unlinkable tokens for triggering events on the destination site?
    A3: Yes, that is our intention.

    Q4: Will these enhancements be available in Safari 15 on older versions of macOS?
    A4: Attribution reports also sent to click destination will be available in Safari 15 across the board. However, click fraud prevention with unlinkable tokens relies on cryptographic functionality that is only available starting with iOS/iPadOS 15 and macOS Monterey.

    July 29, 2021 05:00 PM

    July 28, 2021

    Optimizing JavaScript Standard Library Functions in JSC

    Surfin’ Safari

    After three years working on JavaScriptCore (JSC), I recently had the opportunity to work on optimizing one of our standard library functions for the first time. I thought it’d be interesting to share what I learned about how they work in JSC and how we make them faster.

    How are standard library functions implemented in JSC?

    The JavaScript standard library functions include all the prototype functions for Array, Object, etc, and in this post we’ll look at Function.prototype.toString.

    In JSC, standard library functions can either be implemented in native code (C++) or in JavaScript. When using JavaScript, we can use a special syntax for operations that are not allowed for regular JavaScript programs. Standard library functions written in JavaScript can be called like any other JavaScript function, and will also run through the same optimizations in each of our tiers, including inlining. Meanwhile, standard library functions written in C++ require the VM to make calls to native code, which is more expensive, and while the implementation will be optimized by the C++ compiler, its internals are completely opaque to the caller JS function, so there can be no inlining. The reason I mention inlining is that it allows the caller to “see” inside the function body, which unlocks many further optimizations to be done beyond the function boundary, some of which we’ll see in this example.

    Making standard library functions faster

    Let’s start with a reduced test case to see how can we optimize Function.prototype.toString:

    function f() { /* ... some code here ... */ }
    function g() {
      return f.toString();

    When we call g, JSC will start by executing it in the interpreter (called LLInt), and if we continue calling it enough times it will eventually be promoted through the 3 compilers in JSC: the non-optimizing Baseline compiler and our optimizing DFG and FTL compilers. You can read more about our execution tiers on this post from back when the FTL was first introduced, but since then the FTL has gotten a new backend.

    The first step before we run any code in any tier is to convert it from source code to bytecode (again, you can read a lot more about our bytecode here). After that, our DFG and FTL compilers also have their own representation of the code, that we call an Intermediate Representation or IR for short. For this post I’ll take the liberty of using some pseudocode that is somewhere in between our initial bytecode and DFG IR. This way we can see some of the details that are only available in DFG but without exposing too much low level complexity that is not relevant for our example. Here’s what our pretend IR could look like for g:

    function g():
        f = Lookup("f") // look for the variable "f" in the lexical scope
        toString = Get(f, "toString") // access the "toString" property of `f`,
                                      // respecting the semantics of JavaScript property
                                      // lookup, including looking up the prototype, etc.
        result = Call(toString, f) // call the toString function with `f` as `this`
        Return(result) // return our result to the caller


    The first optimization implemented wasn’t specific to standard library functions at all: the result of calling toString on a function never changes, so we can cache it.

    Our implementation of Function.prototype.toString is written in C++ and has to handle a few special cases. One such case is when we are calling toString on a native function implemented in C++, but for the common case where it’s a regular JavaScript function, we have to look at the source code for the function. Since the source can’t be changed while it’s being executed, and the name of the function also cannot be changed, this result can be cached. This is completely transparent to our IR, which means we don’t have to change anything in the compiler and we already get a great speedup.


    When we start trying to optimize any JavaScript program we quickly face several challenges, since pretty much everything in JavaScript can be mutated at runtime, including our standard library functions. One way that modern JavaScript VMs get around these challenges is by speculating that certain facts about the program will not change during its execution, but since we can’t ever be sure of that, we need a way to fall back if our assumptions become invalid. We have an amazing post that goes deep into how we speculate in JSC, but for our current purposes all we need to know is that we can compile a function and say the code we generated is only valid so long as some assumptions are valid. This also isn’t specific to standard library functions, but it’ll be important later to see how all these optimizations interact with each other yielding more than the sum of their parts.

    In this case we can speculate that f will never change, for our example let’s assume that it’s always called with an object allocated at address 0x123456. This is done through a mechanism called watchpoints, which is beyond the scope of this post, but the TL;DR is that this code will immediately become invalid if anyone assigns to f, which would produce a different result. Using other watchpoints we can also speculate that f.toString will always resolve to Function.prototype.toString which already leads to much better code:

    function g():
        f = 0x123456 // speculated value of Lookup("f")
        toString = Function.prototype.toString // speculated value of Get(f, "toString")
        result = Call(toString, f)


    Next, JSC has the concept of intrinsics. Intrinsics in JSC are when the compiler utilizes the knowledge that it’s calling a well known standard library function to emit optimized code inline. This is even more powerful than regular function inlining, since it can emit only the fast path inline and it works even if the standard library function was written in C++. In this case, the intrinsic tells us we are calling Function.prototype.toString and we can emit a new instruction, FunctionToString, instead of the generic function call. Our new pseudo instruction will try to load the cached value we computed in our very first optimization, but for the slow case, where we don’t have cached value yet, it will still call the C++ implementation. Computing the toString for the first time requires some really complex code that we don’t want to emit inline for every call to toString. Our code with our new instruction might look like this:

    function g():
        f = 0x123456
        result = FunctionToString(f)

    And diving a little deeper, the implementation of our new FunctionToString instruction might look like the following:

    function g():
        f = 0x123456
        result = Load(f, "cachedToString") // Load a specific property of the object,
                                           // much faster since it's just a memory
                                           // access, not a JS property access like Get
        if (!result) {
            // For the slow case where we don't have a cached value we just fallback
            // to calling the C++ code
            toString = Function.prototype.toString
            result = Call(toString, f)

    Abstract Interpretation

    The next step in speeding up our example is using our Abstract Interpreter (AI). The idea behind the AI is that it understands what our IR instructions will do to its operands at runtime, and if all of its operands are known (i.e. we proved they will always have the same value), we can try to compute the result of our instruction at compile time. In this case, since we already speculated that f will be 0x123456, when we’re compiling our FunctionToString instruction we can try to load the cachedToString property from the object at 0x123456. If that succeeds our generated code will look more like this:

    function g():
        result = "function f() { /* … some code here .. */ }"

    That’s much better!


    We can speed up the f.toString() call in our example by:

    • Caching the result
    • Speculating f will always be the same object
    • Speculating that f.toString will always resolve to Function.prototype.toString
    • Adding an Intrinsic and a new instruction, FunctionToString, that loads the cached value directly whenever it’s available
    • Teaching our abstract interpreter that if we already know which function we are stringifying, and its toString value has already been computed, we can just use the cached value as a constant.

    If you want to dive deeper into the actual implementation you can find the commit here and if you have any questions feel free to reach out to me on Twitter.

    July 28, 2021 06:13 PM

    July 21, 2021

    Release Notes for Safari Technology Preview 128

    Surfin’ Safari

    Safari Technology Preview Release 128 is now available for download for macOS Big Sur and betas of macOS Monterey. If you already have Safari Technology Preview installed, you can update in the Software Update pane of System Preferences on macOS.

    This release covers WebKit revisions 278571-279264.

    Note: Tab Groups do not sync in this release.

    Web Inspector

    • Elements Tab
      • Unused inherited CSS variables are now hidden by default in the Styles panel (r278607)
      • CSS variable names are no longer converted to all lowercase in the Computed panel (r278848)


    • Added support for 12 CSS list-style-type values along with other list style fixes (r279165)
    • Fixed CSSOM “set a CSS declaration” for logical properties (r279044)
    • Fixed new snap containers always snapping to the first scroll position (r278862)
    • Fixed Scroll snap offsets interpreted as scroll positions in a scrollable area (r278868)
    • Fixed flex items staying invisible after initial layout (r278659)
    • Fixed text-decoration: underline not applied to web component (r278602)
    • Stopped computing the min or max sizes of flex items twice (r278865)


    • Ignored Intl.NumberFormat feature options when linked-ICU is old (r278697)
    • Optimized JSON.parse with small data by changing Identifier pool mechanism (r278971)
    • Optimized valueOf call via ToPrimitive (r279053)
    • Fixed that Window should behave like a legacy platform object without indexed setter (r278585)

    Live Text

    • Added a mechanism to regenerate text in an image element when it changes dimensions (r278747)
    • Changed mouse events to trigger text recognition only if the cursor is moving (r279059)
    • Text selection inside image elements should not be cleared upon resize (r278775)


    • Reworked handling buffer full in SourceBuffer (r278603)

    Performance API

    • Implemented performance.timeOrigin (r278665)

    Web API

    • Adjusted fetch port blocking for ports 990, 989 (r279099)
    • Fixed Document’s execCommand() and queryCommand() to throw an exception on non-HTML or non-XHTML documents ** (r278974)
    • Fixed EventSource.constructor to not throw an exception when the URL parameter is an empty string (r278763)
    • Implemented width and height attributes on source elements of <picture> (r279108)
    • Improved specification compatibility for the outerHTML setter (r278821)

    July 21, 2021 10:00 PM

    July 01, 2021

    Release Notes for Safari Technology Preview 127

    Surfin’ Safari

    Safari Technology Preview Release 127 is now available for download for macOS Big Sur and betas of macOS Monterey. If you already have Safari Technology Preview installed, you can update in the Software Update pane of System Preferences on macOS.

    This release covers WebKit revisions 277448-278571.

    Note: Tab Groups and Theme Colors are not available in this release on macOS Big Sur.


    • Added discrete animation support for grid-template-columns and grid-template-rows (r278173)
    • Added support for calc() on components inside relative color syntax colors (r278261, r278304)
    • Added support for “relative color syntax” for color() (r278364)
    • Added additional target luminance keywords for color-contrast() (r278262)
    • Fixed the height of an empty table inside an orthogonal flex parent (r277777)
    • Fixed will-change: position to only create a containing block for position: absolute elements (r277579)
    • Made will-change: transform-style create a containing block (r277566)
    • Fixed percent calculations for padding-top and padding-bottom when the parent has padding (r278194)


    • Fixed scroll snapping in non-horizontal writing modes (r278350)
    • Fixed layout issue handling changes to scroll-snap properties (r278193)
    • Improved scrolling performance when background-attachment: fixed is used inside a position: fixed layer (r278419)
    • Improved how the current document scroll position is maintained on full page zoom (r277775)


    • Added support for Ergonomic Brand Checks proposal (e.g. #x in object) behind the--usePrivateIn flag (r277926)
    • Fixed private static method in class-scope (r278510)
    • Optimized Function.prototype.toString (r278462)
    • Optimized in with non-identifier via non ad-hoc IC (r278445)


    • Added MediaSession.callActionHandler (r278222)
    • Fixed MediaSession action handlers to be treated as having a user gesture (r277588)
    • Fixed macOS WebM Format Reader returning enabled for tracks that do not have samples (r278155)
    • Added support for H.264 profiles in MediaRecorder (r278158)


    • Changed to tighter bitrate allocation rules for WebRTC H.264 software encoder (r278272)

    Web API

    • Added support for creating, accessing, and setting non-sRGB ImageData via canvas (r277569)
    • Added support for dispatching wheel events with ctrlKey on pinch gestures, which is commonly used for zooming embedded maps (r277772)
    • Fixed the value of a color input to update visually when using setAttribute (r277778)


    • Fixed increased contrast not detected in the browser until an additional setting is applied (r277971)
    • Fixed accessibility caption styles to always reflect the selection (r277874)


    • Enabled <summary> to be a flex container (r278280)
    • Changed grid track size to reject a unit-less length (r277868)
    • Fixed incorrect selection when a tall float element is present (r278379)
    • Fixed incorrect text selection when crossing a flex item boundary (r278411)

    July 01, 2021 11:23 PM

    June 28, 2021

    Miguel A. Gómez: Unresponsive web processes in WPE and WebKitGTK

    Igalia WebKit

    In case you’re not familiar with WebKit‘s multiprocess model, allow me to explain some basics: In WebKitGTK and WPE we currently have three main processes which collaborate in order to ultimately render the web pages (this is subject to change, probably with the addition of new processes):

    1. The UI process: this is the process of the application that instantiates the web view. For example, Cog when using WPE or Epiphany when using WebKitGTK. This process is usually in charge of interacting with the user/application and send events and requests to the other processes.
    2. The network process: the goal of this process is to perform network requests for the different web processes and make the results available to them.
    3. The web process: this is the process that really performs the heavy lifting. It’s in charge of requesting the resources required by the page (through the network process), create the DOM tree, execute the JS code, render the content, respond to user events, etc.

    In a simple case, we would have a UI process, a web process and a network process working together to render a page. There are situations where (due to security reasons, performance, build options, etc.) the same UI process can be using more than a single web process at the same time, while these share the network process. I won’t go into details about all the possibilities here because that’s beyond the goal of this post (but it’s a good idea for a future post!). If you want more information related to this you can search for topics like process prewarm, process swap on navigation or service workers running on a dedicated processes. In any case, at any given moment, one of those web processes is always the main one performing all the tasks mentioned before, and the others are helpers for concrete tasks, so the situation is equivalent to the simpler case of a single UI process, a web process and an network process.

    Developers know that processes have the bad habit of getting hung sometimes, and that can happen here as well to any of the processes. Unfortunately, in many cases that’s probably due to some kind of bug in the code executed by the processes and we can’t do much more about that than fixing the bug. But there’s a special kind of block that affects the web process only, and it’s related to the execution of JS code. Consider this simple JS script for example:

    setTimeout(function() {
        while(true) { }
    }, 1000);

    This will create an infinite loop during the JS execution after one second, blocking the main thread of the web process, and taking 100% of the execution time. The main thread, besides executing the JS code, is also in charge of processing incoming events or messages from the UI process, perform the layout, initiate redraws of the page, etc. But as it’s locked in the JS loop, it won’t be able to perform any of those tasks, causing the web process to become unresponsive to user input or API calls that come through the UI process. There are other situations that could make the process unresponsive, but the execution of faulty JS is probably the most common one.

    WebKit has some internal tools to detect these situations, that mainly consist on timeouts that mark the process as unresponsive when some expected reply is not received in time from the web process. But on WebKitGTK and WPE there wasn’t a way to notify the application that’s using the web view that the web process had become unresponsive, or a way to recover from this situation (other than closing the application or the tab). This is fixed in trunk for both ports by adding two components to the WebKitWebView class:

    1. A new property named is-web-process-responsive: this property will signal responsiveness changes of the web process. The application using the web view can connect to the notifications of the object property as with any other GObject class, and can also get the its value using the new webkit_web_view_get_is_web_process_responsive() API method.
    2. A new API method webkit_web_view_terminate_web_process() that can be used kill the web process when it becomes unresponsive (but will also work with responsive ones). Any load performed after this call will spawn a new and shiny web process. When this method is used to kill a web process, the web view will emit the signal web-process-terminated with WEBKIT_WEB_PROCESS_TERMINATED_BY_API as the termination reason.

    With these changes, the browser can now connect to the is-web-process-responsive signal changes. If the web process becomes unresponsive, the browser can launch a dialog informing the user of the problem, and ask whether to wait or kill the process. If the user chooses to kill the process, the browser can use webkit_web_view_terminate_web_process() to kill the problematic process and then reload (or load a new page) to go back to functional state.

    These changes, among other wonderful features we’re developing at Igalia, will be available on the upcoming 2.34 release of WebKitGTK and WPE. I hope they are useful for you 🙂

    Happy coding!

    By magomez at June 28, 2021 02:15 PM

    June 17, 2021

    Release Notes for Safari Technology Preview 126 with Safari 15 Features

    Surfin’ Safari

    Safari Technology Preview Release 126 is now available for download for macOS Big Sur and betas of macOS Monterey. If you already have Safari Technology Preview installed, you can update in the Software Update pane of System Preferences on macOS.

    Many of the new Safari 15 features are now available in Safari Technology Preview 126:

    Streamlined tab bar. Use Tab Groups to save and organize your tabs. Experience the new design. Test your site. Experiment with theme-color.

    Live Text. Select and interact with text in images on the web in macOS Monterey betas on M1 Macs.

    Improved Safari Web Extensions. Try out the support for declarativeNetRequest, which expanded to 150K content blocking rules and non-persistent background pages for improved performance.

    Quick Notes. Add links and Safari highlights to remember important information or ideas on the web in macOS Monterey betas.

    WebGL 2. Try out the improved 3D graphics performance of WebGL running on top of Metal via ANGLE.

    Web technologies. Experience and test the HTML, CSS, JavaScript, and other web technologies that are available in Safari 15 Beta and included in previous Safari Technology Preview releases.

    If you see bugs or unexpected behavior with the interface of Safari Technology Preview, please file Feedback in Apple’s Feedback Assistant. If you come across an implementation bug in web technology, or have a request, please file a ticket at bugs.webkit.org.

    UPDATE: If you downloaded an earlier version of Safari Technology Preview 126, you may need to reboot.

    June 17, 2021 05:15 PM

    June 08, 2021

    WebKit Features in Safari at WWDC21

    Surfin’ Safari

    There’s a lot of news coming out of WWDC21 about WebKit and the web technology that’s shipping in Safari 15 on Apple’s platforms. Many of the new features were announced on Monday, at this year’s WWDC21 Keynote, and listed in the Safari 15 Beta Release Notes. But that’s not all, and we’re excited to share it with you.

    Ten sessions at WWDC21 will go into greater detail and announce even more. New videos are released each day this week. You can watch them on the WWDC21 website, or in the Apple Developer app for macOS, iOS, iPadOS, and tvOS.

    You can be part of the conversations around WWDC on the Apple Developer Forums, share your thoughts with @WebKit team on Twitter, or use other ways of staying in touch with folks involved in the WebKit project.

    Tuesday, June 8

    iPad and iPhone showing a Safari Web Extension on iOS

    Meet Safari Web Extensions on iOS

    Safari Web Extensions use HTML, CSS, and JavaScript to offer people powerful browser customizations — and you can now create them for every device that supports Safari. Learn how to build a Safari Web Extension that works for all devices, and discover how you can convert an existing extension to Safari through Xcode and the Safari Web Extension Converter.

    Watch Meet Safari Web Extensions on iOS starting on Tuesday.

    Wednesday, June 9

    iPad showing a Safari Web Extension on iOS

    Explore Safari Web Extension Improvements

    Learn how you can extend Safari’s functionality with Safari Web Extensions. We’ll introduce you to the latest WebExtension APIs, explore non-persistent background page support — a particularly relevant topic if you’re developing for iOS — and discover how you can use the Declarative Net Request WebExtensions API to block content on the web. Lastly, we’ll show you how to customize tabs in Safari 15.

    Watch Explore Safari Web Extension Improvements starting on Wednesday.

    JS logo and a browser-like web view

    Explore WKWebView Additions

    Explore the latest updates to WKWebView. We’ll show you how to use APIs to manipulate web content without JavaScript, explore delegates that can help with WebRTC and Downloads, and share how you can easily create a richer web experience within your app.

    Watch Explore WKWebView Additions starting on Wednesday.

    Passkeys in iCloud Keychain technology preview powered by WebAuthn, backed by iCloud Keychain

    Move beyond passwords

    Despite their prevalence, passwords inherently come with challenges that make them poorly suited to securing someone’s online accounts. Learn more about the challenges passwords pose to modern security and how to move beyond them. Explore the next frontier in account security with secure-by-design, public-key-based credentials that use the Web Authentication standard. Discover in this technology preview how Apple is approaching this standard in iOS 15 and macOS Monterey.

    Watch Move beyond passwords starting on Wednesday.

    Icon depicting a key inside a cloud for iCloud Keychain verification codes

    Secure login with iCloud Keychain verification codes

    Learn how you can support on-device verification codes in your app or website for a more secure sign-in experience. We’ll explore the latest updates to the iCloud Keychain password manager and discover how verification codes, AutoFill, iCloud Keychain sync, and two-tap setup simplify the multi-step sign-in process. We’ll show you how to support this process in your apps and websites.

    Watch Secure login with iCloud Keychain verification codes starting on Wednesday.

    Thursday, June 10

    iPhone showing a Stopwatch Records demo using the JavaScript Internationalization API

    Develop Advanced Web Content

    Develop in JavaScript, WebGL, or WebAssembly? Learn how the latest updates to Safari and WebKit — including language changes to class syntax — can help simplify your development process, enhance performance, and improve security. We’ll explore several web APIs that can help provide better interoperability and bring new capabilities to your web content.

    Watch Develop Advanced Web Content starting on Thursday.

    A website in Safari with a grid overlay from Web Inspector

    Discover Web Inspector Improvements

    Web Inspector provides the tools for you to understand and debug your web pages on macOS, iOS, and iPadOS. We’ll take you through the latest features and improvements to Web Inspector, including a new overlay for inspecting CSS Grid containers on your pages, even more configurable breakpoints to make debugging simpler, and the ability to create and edit Audits.

    Watch Discover Web Inspector Improvements starting on Thursday.

    A diagram showing the link tap/click attribution

    Meet Privacy-Preserving Ad Attribution

    Discover how you can measure your ad campaigns in apps and on the web without compromising privacy. We’ll introduce you to Private Click Measurement and explore SKAdNetwork, which provides you with a more secure, private, and useful way to measure your app installs.

    Watch Meet Privacy-Preserving Ad Attribution starting on Thursday.

    Friday, June 11

    A website demo in thew new Safari 15 on an iPad

    Design for Safari 15

    Meet Safari 15: redesigned and ready to help people explore the web. Discover how you can approach designing websites and apps for Safari, and learn how to incorporate the tab bar in your designs. We’ll also take you through features like Live Text and accessibility best practices, explore the latest updates to CSS and Form Controls, and learn how to use the aspect-ratio property in CSS to create incredible websites.

    Watch Design for Safari 15 starting on Friday.

    Synced video playback in Safari on macOS and iOS

    Coordinate media playback in Safari with Group Activities

    Create SharePlay experiences that people can enjoy on the web and in your companion app. Learn how you can use the GroupActivities framework in combination with a companion website to bring SharePlay to Safari, letting people connect with each other for enjoyable group interactions — even if they haven’t yet downloaded your app from the App Store.

    Watch Coordinate media playback in Safari with Group Activities starting on Friday.

    June 08, 2021 01:00 PM

    June 07, 2021

    MotionMark 1.2

    Surfin’ Safari

    MotionMark Version 1.2

    Today we are announcing an update to the MotionMark benchmark. This is a relatively small update, aimed at increasing test reliability and reproducibility. The largest change is the removal of the Focus subtest, which was causing significant variance in test results, and wasn’t measuring what it was intending to measure.

    Benchmark Harness

    Most of the changes in MotionMark 1.2 aim to reduce variance between multiple runs of the benchmark. We increased the warm-up time between each test by 1900ms and required at least 30 frames to be rendered in between tests to reduce interference between adjacent tests. Different tests stress different parts of the graphics pipeline, and their processing can overlap if they aren’t more strongly segmented.

    We also implemented a few different strategies to decrease the benchmark’s sensitivity to individual frame times. The first is to make sure that the benchmark never makes any ramping decisions based on the time of a single frame, but instead requires at least 9 frames before adjusting complexity. In addition, the benchmark now discards outlier frame times.

    Focus Subtest

    Modern browsers use a compositing architecture, where part of the graphics work is responsible for drawing individual elements into layers, and other graphics work is responsible for compositing layers together into a final image. The interface between these two parts behaves differently in different browsers, and may indeed be entirely asynchronous, possibly providing almost no backpressure if the compositor is running more slowly than element painting.

    In browser engines which run the compositor asynchronously (like WebKit), the Focus subtest measured how fast descriptions of work can be delivered to the compositor, rather than how fast the compositor can actually execute that work, which is what the subtest was trying to measure. In addition, the backpressure in the Focus subtest is indirect, passes through the scheduler, and is therefore noisy. It was causing a huge variance in subtest score on machines which have relatively high element painting performance compared to their compositor performance.


    MotionMark 1.2 produces significantly less score variance than previous versions of MotionMark on a wide variety of machines of varying relative performance. Because of the removal of the Focus subtest, MotionMark 1.2 is also more reflective of real-world graphics performance across browsers.


    Here is a list of all the changes that have gone into MotionMark 1.2:

    June 07, 2021 09:21 PM

    June 06, 2021

    Manuel Rego: :focus-visible in WebKit - May 2021

    Igalia WebKit

    And again this is a new report about the work around :focus-visible in WebKit, you can check the previous ones at:

    As you might already know this work is part of the Open Prioriziatation campaign by Igalia that has been funded by a lot of people. Thank you all for your support!

    The high level summary is that the implementation in WebKit can be considered to be complete and all the :focus-visible patches have been included on the last Safari Technology Preview 125 as an experimental feature. Moreover, Igalia has been in conversations with Apple trying to find a way to enable the feature by default at some point.

    Implementation details

    As I’ve just mentioned, the implementation finished by the end of April, and no more patches have landed since then. It passes most of the WPT tests, there are still some minor differences here and there (like some input types matching or not :focus-visible) but those issues have been considered to be fine as they depend on the different browsers specific behavior.

    You can test this feature in Safari Technology Preview (since release 125) by enabling the runtime flag in the menu (Develop > Experimental Features > :focus-visible pseudo-class). Please play with it and report any issue you might find.

    Debate time

    During the last patch reviews more Apple engineers got interested on the feature, and there were a bunch of discussions about whether it would (or should) change the default behavior in WebKit, and how.

    So let’s start from the beginning, what is focus-visible? A broad description of :focus-visible is that it will match based on when the browser would natively show a focus ring. The typical example for this are buttons, in general when people click a button they don’t expect to see a focus ring, for that reason most browsers haven’t been showing it for years. When an element is focused browsers use some internal heuristics to decide when to show or not a focus ring.

    However buttons in Safari are different to other browsers, and that’s because Safari follows the Mac platform conventions. Buttons are not click focusable in Safari (though you can still focus them via keyboard with Option + Tab), as they don’t receive focus on click they don’t even match :focus, so they never show a focus ring on mouse interactions. This behavior tries to mimic what happens on the Mac platform, but there are still some differences. The Mac platform standard, for example, allows that you can be editing an input, click on a button and keep editing the input as the focus is still there. However that’s not exactly what happens in Safari either, when you click the button, even if it doesn’t get the focus, the focus is gone from the input, so you cannot just continue editing it like in the platform. On top of that, an invisible navigation caret moves to that button on click, and further keyboard navigations start from there. So it’s kind of similar to the platform, but with some nuances.

    This is only part of the problem, the web is full of things that are focusable, like <div tabindex="0"> elements. These elements have always matched (and still match) :focus by default, and have usually showed a focus ring when focused via mouse click. Web authors generally want to hide the focus ring when clicking on <div tabindex="0"> elements, and that’s why the current :focus-visible implementations don’t match in this case. Chrome and Firefox are using :focus-visible in the User Agent (UA) style sheet, so they don’t show a focus ring when clicking on such elements. However, Apple has expressed some concerns here that it might change the default focus indicator behavior in a way that might differ from their platform philosophy, and thus needs more review.

    During these conversations an idea showed up as potential solution. What if we show a focus ring when users click on a generic <div tabindex="0">, but we don’t if that element has some specific role, e.g. <div tabindex="0" role="button">. This would give web authors the possibility to get their desired behavior by just adding a role to those elements.

    This would make <div tabindex="0" role="button"> work similar to regular buttons on Mac, but there’s still one difference, those elements will still get the focus so some use cases might get broken. James Craig came out with a scenario in which an user is scrolling the page with the spacebar, then they click on a <div tabindex="0" role="button">, and if they enter spacebar again, that wouldn’t keep scrolling the page anymore. And the user won’t know exactly why, as they haven’t seen any focus ring after click (note that with the current :focus-visible implementation, they user will start to see a focus ring on that <div tabindex="0" role="button"> after entering the spacebar).

    On that discussion James has shared an idea to add a new CSS property (or it could be a HTML attribute) that marks an element so it cannot receive focus via mouse click. That would make possible to make buttons work like in Safari in other browsers, or make a <div tabindex="0"> to work like a Mac button too. However this would be something new that would need to get implemented in all browsers, not just WebKit and that would need to get discussed and agreed with the web community.

    On the same issue Brian Kardell is proposing some alternatives, for example having some special parameter like :focus-visible(platform) (syntax to be defined) that could behave differently in Safari than other browsers, so Safari can use it in the UA style sheet, while :focus-visible alone would work the same in all browsers.

    As you see there’s not a clear solution to all this discussion yet, but we’re following it closely and providing our feedback to try to reach some final proposal that makes everyone happy.

    Some numbers

    Let’s do a final review of the total numbers (as nothing has changed in May):

    • 26 PRs merged in WPT.
    • 27 patches landed in WebKit.
    • 9 patches landed in Chromium.
    • 2 PRs merged in CSS spcs.
    • 1 PR merged in HTML spec.

    Wrapping up

    :focus-visible has been added to WebKit thanks to the support from many individual people and organizations that make it happen through the Open Prioritization experiment by Igalia. Once more big thanks to you all! 🙏

    In addition, the WPT test suite has been improved counting now ~40 tests for this feature. Also in January neither Firefox or Chrome were using :focus-visible on the UA style sheet, however they both use it there nowadays. Thus, doing the implementation on WebKit has helped to move forward this feature on different places.

    There is still the ongoing discussion about when or how this could be enabled by default in WebKit and eventually shipped in Safari. That conversation is moving and we hope there’ll be some kind of positive resolution so this feature can be enjoyed by web authors in all the browser engines. Igalia will keep being on top of the topic and pushing things forward to make it happen.

    Finally, thanks to everyone who has helped in the different conversations, reviews, etc. during these months.

    June 06, 2021 10:00 PM

    May 26, 2021

    Release Notes for Safari Technology Preview 125

    Surfin’ Safari

    Safari Technology Preview Release 125 is now available for download for macOS Big Sur and macOS Catalina. If you already have Safari Technology Preview installed, you can update in the Software Update pane of System Preferences on macOS.

    This release covers WebKit revisions 275811-277448.

    Web Inspector

    • Remote Inspection
      • Fixed an issue that prevented remotely inspecting iOS and iPadOS devices
    • Sources Tab
      • Added support for panning and zooming image resources (r277279)
    • Audit Tab
      • Fixed edits not saving if the text input was still focused when leaving Edit mode (r276616)
      • Fixed default and new test cases showing minified source (r276680, r277212)


    • Added parsing for @counter-style descriptors (r276488)
    • Added support for CSS display 2-value syntax (e.g. display: inline flex ) (r276293)
    • Added support for inline-{start/end} values to float & clear CSS properties (r276216)
    • Changed to not use margins when computing aspect ratio cross sizes (r277371)
    • Changed invalid media query keyword values to not be parsable (r277039)
    • Fixed treating border and padding correctly for box-sizing: border-box with aspect-ratio (r276745)
    • Fixed flex item construction to not affect sibling flex item height computation (r277222, r277435)
    • Fixed percent children to resolve against the flex basis on a fully inflexible item with fixed flex-basis (r276634)
    • Fixed table layout disregarding the overriding width in CSS Flexbox (r276572)
    • Fixed logical shorthands with var() (r276837)
    • Fixed using a modifier key on an element causing it stop matching :focus-visible (r276698)
    • Fixed CSS custom properties on pseudo-elements background gradients that caused infinite layout and high CPU load (r277112)
    • Fixed position for orthogonally positioned element with writing-mode: vertical-rl (r277391)
    • Improved parsing and computed style of the rotate CSS property (r276554)
    • Shared style resolvers between author shadow trees with identical style (r276882)

    Web Animations

    • Added discrete animation support for border-image-repeat (r276465)
    • Fixed interpolation of stroke-dasharray in the discrete case (r276643)
    • Fixed interpolation of page-break- ** properties (r276638). Fixed animation of the visibility CSS property between hidden and collapse (r276639)
    • Fixed interpolation of the clip CSS property (r276552)
    • Fixed interpolation of the rotate CSS property (r276231)
    • Support interpolation of the background-repeat shorthand (r276553)


    • Added call_ref instruction (r276896)


    • Improved local storage size estimation for quota limitation (r276689)

    Web API

    • Fixed picture element to ignore any img descendant that is not a direct child (r276679)
    • Fixed blob contentType being ignored when it contained a charset (r276986)
    • Implemented <form>.requestSubmit() (r277257)
    • Implemented FontFace in Workers for OffscreenCanvas (r276450)
    • Implemented ShadowRoot.prototype.delegatesFocus attribute (r276585)
    • Avoided error for a fetch body stream when its request or response is stopped (r277028)
    • Changed to not compute image aspect ratios from width and height attributes for lazy loaded images (r276521)
    • Fixed Notification.requestPermission() to return a Promise (r277420)


    • Fixed computed style for the translate CSS property to use px for the z value (r276551)
    • Fixed will-change CSS property to create a containing block when the one of the specified properties may create one (r276627)
    • Fixed sizing of CSS backgrounds affected by background-size and EXIF orientation (r276984)


    • Fixed color gamut in WebRTC when using VPx software decoder (r276478)
    • Set audio transceiver nMax to 1 (r276717)

    May 26, 2021 08:30 PM

    May 25, 2021

    Enrique Ocaña: GStreamer WebKit debugging by using external tools (2/2)

    Igalia WebKit

    This is the last post of the series showing interesting debugging tools, I hope you have found it useful. Don’t miss the custom scripts at the bottom to process GStreamer logs, help you highlight the interesting parts and find the root cause of difficult bugs. Here are also the previous posts of the series:

    How to debug pkgconfig

    When pkg-config finds the PKG_CONFIG_DEBUG_SPEW env var, it explains all the steps used to resolve the packages:

    PKG_CONFIG_DEBUG_SPEW=1 /usr/bin/pkg-config --libs x11

    This is useful to know why a particular package isn’t found and what are the default values for PKG_CONFIG_PATH when it’s not defined. For example:

    Adding directory '/usr/local/lib/x86_64-linux-gnu/pkgconfig' from PKG_CONFIG_PATH
    Adding directory '/usr/local/lib/pkgconfig' from PKG_CONFIG_PATH
    Adding directory '/usr/local/share/pkgconfig' from PKG_CONFIG_PATH
    Adding directory '/usr/lib/x86_64-linux-gnu/pkgconfig' from PKG_CONFIG_PATH
    Adding directory '/usr/lib/pkgconfig' from PKG_CONFIG_PATH
    Adding directory '/usr/share/pkgconfig' from PKG_CONFIG_PATH

    If we have tuned PKG_CONFIG_PATH, maybe we also want to add the default paths. For example:

    export PKG_CONFIG_PATH=${SYSROOT}/usr/local/lib/pkgconfig:${SYSROOT}/usr/lib/pkgconfig
    # Add also the standard pkg-config paths to find libraries in the system
    export PKG_CONFIG_PATH=${PKG_CONFIG_PATH}:/usr/local/lib/x86_64-linux-gnu/pkgconfig:\
    # This tells pkg-config where the "system" pkg-config dir is. This is useful when cross-compiling for other
    # architecture, to avoid pkg-config using the system .pc files and mixing host and target libraries
    export PKG_CONFIG_LIBDIR=${SYSROOT}/usr/lib
    # This could have been used for cross compiling:

    Man in the middle proxy for WebKit

    Sometimes it’s useful to use our own modified/unminified files with a 3rd party service we don’t control. Mitmproxy can be used as a man-in-the-middle proxy, but I haven’t tried it personally yet. What I have tried (with WPE) is this:

    1. Add an /etc/hosts entry to point the host serving the files we want to change to an IP address controlled by us.
    2. Configure a web server to provide the files in the expected path.
    3. Modify the ResourceRequestBase constructor to change the HTTPS requests to HTTP when the hostname matches the target:
    ResourceRequestBase(const URL& url, ResourceRequestCachePolicy policy)
        : m_url(url)
        , m_timeoutInterval(s_defaultTimeoutInterval)
        , m_isAppBound(false)
        if (m_url.host().toStringWithoutCopying().containsIgnoringASCIICase(String("out-of-control-service.com"))
            && m_url.protocol().containsIgnoringASCIICase(String("https"))) {
            printf("### %s: URL %s detected, changing from https to http\n",
                __PRETTY_FUNCTION__, m_url.string().utf8().data()); 

    :bulb: Pro tip: If you have to debug minified/obfuscated JavaScript code and don’t have a deobfuscated version to use in a man-in-the-middle fashion, use http://www.jsnice.org/ to deobfuscate it and get meaningful variable names.

    Bandwidth control for a dependent device

    If your computer has a “shared internet connection” enabled in Network Manager and provides access to a dependent device , you can control the bandwidth offered to that device. This is useful to trigger quality changes on adaptive streaming videos from services out of your control.

    This can be done using tc, the Traffic Control tool from the Linux kernel. You can use this script to automate the process (edit it to suit to your needs).

    Useful scripts to process GStreamer logs

    I use these scripts in my daily job to look for strange patterns in GStreamer logs that help me to find the cause of the bugs I’m debugging:

    • h: Highlights each expression in the command line in a different color.
    • mgrep: Greps (only) for the lines with the expressions in the command line and highlights each expression in a different color.
    • filter-time: Gets a subset of the log lines between a start and (optionally) an end GStreamer log timestamp.
    • highlight-threads: Highlights each thread in a GStreamer log with a different color. That way it’s easier to follow a thread with the naked eye.
    • remove-ansi-colors: Removes the color codes from a colored GStreamer log.
    • aha: ANSI-HTML-Adapter converts plain text with color codes to HTML, so you can share your GStreamer logs from a web server (eg: for bug discussion). Available in most distros.
    • gstbuffer-leak-analyzer: Analyzes a GStreamer log and shows unbalances in the creation/destruction of GstBuffer and GstMemory objects.

    By eocanha at May 25, 2021 06:00 AM

    May 18, 2021

    Enrique Ocaña: GStreamer WebKit debugging by using external tools (1/2)

    Igalia WebKit

    In this new post series, I’ll show you how both existing and ad-hoc tools can be helpful to find the root cause of some problems. Here are also the older posts of this series in case you find them useful:

    Use strace to know which config/library files are used by a program

    If you’re becoming crazy supposing that the program should use some config and it seems to ignore it, just use strace to check what config files, libraries or other kind of files is the program actually using. Use the grep rules you need to refine the search:

    $ strace -f -e trace=%file nano 2> >(grep 'nanorc')
    access("/etc/nanorc", R_OK)             = 0
    access("/usr/share/nano/javascript.nanorc", R_OK) = 0
    access("/usr/share/nano/gentoo.nanorc", R_OK) = 0

    Know which process is killing another one

    First, try to strace -e trace=signal -p 1234 the killed process.

    If that doesn’t work (eg: because it’s being killed with the uncatchable SIGKILL signal), then you can resort to modifying the kernel source code (signal.c) to log the calls to kill():

    SYSCALL_DEFINE2(kill, pid_t, pid, int, sig)
        struct task_struct *tsk_p;
        /* Log SIGKILL */
        if (sig & 0x1F == 9) {
            tsk_p = find_task_by_vpid(pid);
            if (tsk_p) {
                printk(KERN_DEBUG "Sig: %d from pid: %d (%s) to pid: %d (%s)\n",
                    sig, current->pid, current->comm, pid, tsk_p->comm);
            } else {
                printk(KERN_DEBUG "Sig: %d from pid: %d (%s) to pid: %d\n",
                    sig, current->pid, current->comm, pid);

    Wrap gcc/ld/make to tweak build parameters

    If you ever find yourself with little time in front of a stubborn build system and, no matter what you try, you can’t get the right flags to the compiler, think about putting something (a wrapper) between the build system and the compiler. Example for g++:

    main() {
        # Build up arg[] array with all options to be passed
        # to subcommand.
        for opt in "$@"; do
            case "$opt" in
            -O2) ;; # Removes this option
                arg[i]="$opt" # Keeps the others
        EXTRA_FLAGS="-O0" # Adds extra option
        echo "g++ ${EXTRA_FLAGS} ${arg[@]}" # >> /tmp/build.log # Logs the command
        /usr/bin/ccache g++ ${EXTRA_FLAGS} "${arg[@]}" # Runs the command
    main "$@"

    Make sure that the wrappers appear earlier than the real commands in your PATH.

    The make wrapper can also call remake instead. Remake is fully compatible with make but has features to help debugging compilation and makefile errors.

    Analyze the structure of MP4 data

    The ISOBMFF Box Structure Viewer online tool allows you to upload an MP4 file and explore its structure.

    By eocanha at May 18, 2021 06:00 AM

    May 11, 2021

    Enrique Ocaña: GStreamer WebKit debugging by instrumenting source code (3/3)

    Igalia WebKit

    This is the last post on the instrumenting source code series. I hope you to find the tricks below as useful as the previous ones.

    In this post I show some more useful debugging tricks. Don’t forget to have a look at the other posts of the series:

    Finding memory leaks in a RefCounted subclass

    The source code shown below must be placed in the .h where the class to be debugged is defined. It’s written in a way that doesn’t need to rebuild RefCounted.h, so it saves a lot of build time. It logs all refs, unrefs and adoptPtrs, so that any anomaly in the refcounting can be traced and investigated later. To use it, just make your class inherit from LoggedRefCounted instead of RefCounted.

    Example output:

    void WTF::adopted(WTF::LoggedRefCounted<T>*) [with T = WebCore::MediaSourceClientGStreamerMSE]: this=0x673c07a4, refCount 1
    void WTF::adopted(WTF::LoggedRefCounted<T>*) [with T = WebCore::MediaSourceClientGStreamerMSE]: this=0x673c07a4, refCount 1
    ^^^ Two adopts, this is not good.
    void WTF::LoggedRefCounted<T>::ref() [with T = WebCore::MediaSourceClientGStreamerMSE]: this=0x673c07a4, refCount 1 --> ...
    void WTF::LoggedRefCounted<T>::ref() [with T = WebCore::MediaSourceClientGStreamerMSE]: this=0x673c07a4, refCount ... --> 2
    void WTF::LoggedRefCounted<T>::deref() [with T = WebCore::MediaSourceClientGStreamerMSE]: this=0x673c07a4, refCount 2 --> ...
    void WTF::LoggedRefCounted<T>::deref() [with T = WebCore::MediaSourceClientGStreamerMSE]: this=0x673c07a4, refCount ... --> 1
    void WTF::adopted(WTF::LoggedRefCounted<T>*) [with T = WebCore::MediaSourceClientGStreamerMSE]: this=0x673c07a4, refCount 1
    void WTF::LoggedRefCounted<T>::deref() [with T = WebCore::MediaSourceClientGStreamerMSE]: this=0x673c07a4, refCount 1 --> ...
    void WTF::LoggedRefCounted<T>::deref() [with T = WebCore::MediaSourceClientGStreamerMSE]: this=0x673c07a4, refCount 1 --> ...
    ^^^ Two recursive derefs, not good either.
    #include "Logging.h"
    namespace WTF {
    template<typename T> class LoggedRefCounted : public WTF::RefCounted<T> {
        void ref() {
            printf("%s: this=%p, refCount %d --> ...\n", __PRETTY_FUNCTION__, this, WTF::RefCounted<T>::refCount()); fflush(stdout);
            printf("%s: this=%p, refCount ... --> %d\n", __PRETTY_FUNCTION__, this, WTF::RefCounted<T>::refCount()); fflush(stdout);
        void deref() {
            printf("%s: this=%p, refCount %d --> ...\n", __PRETTY_FUNCTION__, this, WTF::RefCounted<T>::refCount()); fflush(stdout);
            printf("%s: this=%p, refCount ... --> %d\n", __PRETTY_FUNCTION__, this, WTF::RefCounted<T>::refCount()); fflush(stdout);
        LoggedRefCounted() { }
        ~LoggedRefCounted() { }
    template<typename T> inline void adopted(WTF::LoggedRefCounted<T>* object)
        printf("%s: this=%p, refCount %d\n", __PRETTY_FUNCTION__, object, (object)?object->refCount():0); fflush(stdout);
    } // Namespace WTF

    Pause WebProcess on launch

    WebProcessMainGtk and WebProcessMainWPE will sleep for 30 seconds if a special environment variable is defined:


    It only works #if ENABLE(DEVELOPER_MODE), so you might want to remove those ifdefs if you’re building in Release mode.

    Log tracers

    In big pipelines (e.g. playbin) it can be very hard to find what element is replying to a query or handling an event. Even using gdb can be extremely tedious due to the very high level of recursion. My coworker Alicia commented that using log tracers is more helpful in this case.

    GST_TRACERS=log enables additional GST_TRACE() calls all accross GStreamer. The following example logs entries and exits into the query function.


    The names of the logging categories are somewhat inconsistent:

    • log (the log tracer itself)
    • GST_PADS
    • query
    • bin

    The log tracer code is in subprojects/gstreamer/plugins/tracers/gstlog.c.

    By eocanha at May 11, 2021 06:00 AM

    May 07, 2021

    Release Notes for Safari Technology Preview 124

    Surfin’ Safari

    Safari Technology Preview Release 124 is now available for download for macOS Big Sur and macOS Catalina. If you already have Safari Technology Preview installed, you can update in the Software Update pane of System Preferences on macOS.

    This release covers WebKit revisions 274641-275811.

    Web Inspector

    • Added autocomplete for experimental CSS Color values: hwb, lch, lab, color-mix, color-contrast (r275310)
    • Changed grid overlay track size labels to show implicit auto value and no computed size (r275559)
    • Fixed grid layout labels that were getting drawn outside the viewport (r275128)
    • Fixed CSS Grid overlay track sizes when inline styles are applied to the element (r275293)
    • Fixed a bug with more than two timeline recordings not showing a timescale (r275337)
    • Fixed grid overlay areas appearing offset from their actual areas when the grid container has a border set (r275529)
    • Fixed grid overlay to honor writing modes and RTL layout direction. (r275519)
    • Fixed grid overlay line numbers showing implicit tracks with negative line numbers (r275558)
    • Improved grid overlay label appearance (r275560)
    • Removed the duplicate Box Model section from Layout panel in Elements Tab (r275545)


    • Accounted for cover and contain when interpolating background-size (r275202)
    • Accounted for hanging and each-line when blending text-interpolation (r275224)
    • Added support for animating the vertical-align CSS property (r275160)
    • Animated pseudo element style resolved against wrong parent style (r275277)
    • Fixed interpolation of the caret-color CSS property (r275092)
    • Computed style for a border-radius corner should never be 0px when the provided width isn’t 0px (r275273)
    • Enabled hanging and each-line keywords for the text-indent CSS property (r275199)
    • Fixed align-content issues in Flexbox (r275416)
    • Fixed max-height percentages getting wrongly resolved for replaced grid items in nested percentage flexboxes (r275758)
    • Fixed min and max widths of grid affected by ancestor (r275754)
    • Fixed initial horizontal scrollbar position when vertical scrollbar is on the left (r275811)
    • Fixed max-content on tables with percentage cell widths (r275462)
    • Improved interpolation of the shape-outside CSS property (r275015)
    • Prevented negative heights in CSS Grid (r274933)
    • Supported animation of the tab-size CSS property (r274939)
    • Updated CSS Color 5 color-mix() implementation to match the latest draft spec (r274947)


    • Fixed Intl.Locale to not assume is8Bit (r274784)
    • Fixed Object.freeze(this) at the global scope to not lose a reference to a WatchpointSet (r274882)
    • Fixed RegExp interpreter not to match against non-BMP characters with multiple dots (r274806, r274945)
    • Fixed incorrect Array toString() if join() is not callable (r275544)

    Web API

    • Enabled the ability to prevent scrolling in Element.focus() (r274812)
    • Implemented AbortSignal.abort() (r274773)
    • Propagated user gestures through requestAnimationFrame just like setTimeout (r275187)
    • ServiceWorker should save module scripts (r275751)


    • Fixed aspect-ratio to recompute on hover (r275377)
    • Implemented text rendering on OffscreenCanvas in a Worker (r275420)

    Wheel Events

    • Allowed wheel events to trigger high frequency DisplayLinks (r275440)

    Web Driver

    • Fixed SendKeys on <input type="file"> returning element not found in some cases (r275050)


    • Enabled Metal ANGLE backend for WebGL (r274927)


    • Implemented RTCDataChannel transfer (r274758)


    • Fixed WebCrypto to support AES-GCM 0 byte encryption (r275535)


    • Fixed scrolling momentum with scroll-snap-type: x mandatory when the scroller scrolls vertically (r274853)
    • Fixed scroll-snap-stop: always not respected during momentum scrolling (r274726)

    Web Extensions

    • Allow wss:// URL in content_security_policy to allow extension pages to use WebSocket connections

    May 07, 2021 08:30 PM

    May 04, 2021

    Manuel Rego: :focus-visible in WebKit - April 2021

    Igalia WebKit

    A new report after a new month is gone, you can see the previous ones at:

    Again this is a status report about the work Igalia is doing on the implementation of :focus-visible in WebKit, which is part of the Open Prioriziatation campaign. Thanks everyone supporting this!

    There has been some nice progress in April, though some things are still under ongoing discussion.

    Script focus and :focus-visible

    Finally we decided to reflect the reality in the script focus tests that I created, and merge them on WPT. The ones where the implementations Chromium and Firefox don’t match the agreed expectations (the ones when you click a non-focusable element, and that click moves focus elsewhere), where marked as .tentative.

    So we opened a separated issue to explain the situation and gather more feedback about what to do here.

    Once we had the tests I implemented the same behavior as other browsers, the current one reflected on the tests, in WebKit. The patch got reviewed and merged, so script focus and :focus-visible work the same in all browsers right now.

    :focus-visible and Shadow DOM

    The test that checks that :focus-visible doesn’t match on ShadowRoot was also merged in WPT. That’s the current behavior on WebKit implementation too. More about this in January’s post.

    Implementation details

    There was a crash in WebKit due to my initial implementation of script focus, that problem has been already fixed. Also an extra bug was found and fixed too.

    On the review of those patches, some new discussion started about different things related to :focus-visible feature, like why a keyboard input triggers :focus-visible matching. The discussion with Apple engineers is ongoing on the bug and let’s see how it ends.

    Some numbers

    Let’s take a look to the numbers again:

    • 26 PRs merged in WPT (5 in April).
    • 27 patches landed in WebKit (10 in April).
    • 9 patches landed in Chromium (2 in April).
    • 2 PRs merged in CSS spcs.
    • 1 PR merged in HTML spec.

    Next steps

    Implementation is mostly over, now the goal is to close the discussions with the different parties and check the possibilities of shipping this in WebKit.

    Thanks everyone that has provided input in the different discussions and jumped on the patches review. Your feedback has been really useful to keep moving this forward.

    Stay tuned!

    May 04, 2021 10:00 PM