October 22, 2017

Frédéric Wang: Recent Browser Events

Igalia WebKit


At Igalia, we attend many browser events. This is a quick summary of some recents conferences I participated to… or that gave me the opportunity to meet Igalians in Paris 😉.

Week 31: Paris - CSS WG F2F - W3C

My teammate Sergio attended the CSS WG F2F meeting as an observer. On Tuesday morning, I also made an appearance (but it was so brief that ceux que j’ai rencontrés ne m’ont peut-être pas vu). Together with other browser vendors and WG members, Sergio gave an interview regarding the successful story of CSS Grid Layout. By the way, given our implementation work in WebKit and Blink, Igalia finally decided to join the CSS Working Group 😊. Of course, during that week I had dinner with Sergio and it was nice to chat with my colleague in a French restaurant of Montmartre.

Week 38: Tokyo - BlinkOn 8 - Google

Jacobo, Gyuyoung and I attended BlinkOn 8. I had nice discussions and listened to interesting talks about a wide range of topics (Layout NG, Accessibility, CSS, Fonts, Web Predictability & Standards, etc). It was a pleasure to finally meet in persons some developers I had been in touch with during my projects on Ozone/Wayland and WebKit/iOS. For the lightning talks, we presented our activities on embedded linux platforms and the Web Platform. Incidentally, it was great to see Igalia’s work mentioned during the Next Generation Rendering Engine session. Obviously, I had the opportunity to visit places and taste Japanese food in Asakusa, Ueno and Roppongi 😋.

Week 40: A Coruña - Web Engines Hackfest - Igalia

I attended one of my favorite events, that gathers the whole browser community during three days for technical presentations, breakout sessions, hacking and galician food. This year, we had many sponsors and attendees. It is good to see that the event is becoming more and more popular! It was long overdue, but I was finally able to make Brotli and WOFF2 installable as system libraries on Linux and usable by WebKitGTK+ 😊. I opened similar bugs in Gecko and the same could be done in Chromium. Among the things I enjoyed, I met Jonathan Kew in person and heard more about Antonio and Maksim’s progress on Ozone/Wayland. As usual, it was nice to share time with colleagues, attend the assembly meeting, play football matches, have meals, visit Asturias… and tell one’s story 😉.

Week 41: San Jose - WebKit Contributors Meeting - Apple

In the past months, I have mostly been working on WebKit at Igalia and I would have been happy to see my fellow WebKit developers. However, given the events in Japan and Spain, I was not willing to make another trip to the USA just after. Hence I had to miss the WebKit Contributors Meeting again this year 😞. Fortunately, my colleagues Alex, Michael and Žan were present. Igalia is an important contributor to WebKit and we will continue to send people and propose some talks next year.

Week 42: Paris - Monthly Speaker Series - Mozilla

This Wednesday, I attended a conference on Privacy as a Competitive Advantage in Mozilla’s office. It was nice to hear about the increasing interest on privacy and to see the regulation made by the European Union in that direction. My colleague Philippe was visiting the office to work with some Mozilla developers on one of our project, so I was also able to meet him in the conference room. Actually, Mozilla employees were kind enough to let me stay at the office after the conference… Hence I was able to work on Apple’s Web Engine on a project sponsored by Google at the Mozilla office… probably something you can only do at Igalia 😉. Last but not least, Guillaume was also in holidays in Paris this week, so I let you imagine what happens when three French guys meet (hint: it involves food 😋).

October 22, 2017 10:00 PM

October 20, 2017

Adrián Pérez de Castro: Web Engines Hackfest, 2017 Edition

Igalia WebKit

At the beginning of October I had the wonderful chance of attending the Web Engines Hackfest in A Coruña, hosted by Igalia. This year we were over 50 participants, which was great to associate even more faces to IRC nick names, but more importantly allows hackers working at all the levels of the Web stack to share a common space for a few days, making it possible to discuss complex topics and figure out the future of the projects which allow humanity to see pictures of cute kittens — among many other things.

Mandatory fluff (CC-BY-NC).

During the hackfest I worked mostly on three things:

  • Preparing the code of the WPE WebKit port to start making preview releases.

  • A patch set which adds WPE packages to Buildroot.

  • Enabling support for the CSS generic system font family.

Fun trivia: Most of the WebKit contributors work from the United States, so the week of the Web Engines hackfest is probably the only single moment during the whole year that there is a sizeable peak of activity in European day times.

Watching repository activity during the hackfest.

Towards WPE Releases

At Igalia we are making an important investment in the WPE WebKit port, which is specially targeted towards embedded devices. An important milestone for the project was reached last May when the code was moved to main WebKit repository, and has been receiving the usual stream of improvements and bug fixes. We are now approaching the moment where we feel that is is ready to start making releases, which is another major milestone.

Our plan for the WPE is to synchronize with WebKitGTK+, and produce releases for both in parallel. This is important because both ports share a good amount of their code and base dependencies (GStreamer, GLib, libsoup) and our efforts to stabilize the GTK+ port before each release will benefit the WPE one as well, and vice versa. In the coming weeks we will be publishing the first official tarball starting off the WebKitGTK+ 2.18.x stable branch.

Wild WEBKIT PORT appeared!

Syncing the releases for both ports means that:

  • Both stable and unstable releases are done in sync with the GNOME release schedule. Unstable releases start at version X.Y.1, with Y being an odd number.

  • About one month before the release dates, we create a new release branch and from there on we work on stabilizing the code. At least one testing release with with version X.Y.90 will be made. This is also what GNOME does, and we will mimic this to avoid confusion for downstream packagers.

  • The stable release will have version X.Y+1.0. Further maintenance releases happen from the release branch as needed. At the same time, a new cycle of unstable releases is started based on the code from the tip of the repository.

Believe it or not, preparing a codebase for its first releases involves quite a lot of work, and this is what took most of my coding time during the Web Engines Hackfest and also the following weeks: from small fixes for build failures all the way to making sure that public API headers (only the correct ones!) are installed and usable, that applications can be properly linked, and that release tarballs can actually be created. Exhausting? Well, do not forget that we need to set up a web server to host the tarballs, a small website, and the documentation. The latter has to be generated (there is still pending work in this regard), and the whole process of making a release scripted.

Still with me? Great. Now for a plot twist: we won't be making proper releases just yet.

APIs, ABIs, and Releases

There is one topic which I did not touch yet: API/ABI stability. Having done a release implies that the public API and ABI which are part of it are stable, and they are not subject to change.

Right after upstreaming WPE we switched over from the cross-port WebKit2 C API and added a new, GLib-based API to WPE. It is remarkably similar (if not the same in many cases) to the API exposed by WebKitGTK+, and this makes us confident that the new API is higher-level, more ergonomic, and better overall. At the same time, we would like third party developers to give it a try (which is easier having releases) while retaining the possibility of getting feedback and improving the WPE GLib API before setting it on stone (which is not possible after a release).

It is for this reason that at least during the first WPE release cycle we will make preview releases, meaning that there might be API and ABI changes from one release to the next. As usual we will not be making breaking changes in between releases of the same stable series, i.e. code written for 2.18.0 will continue to build unchanged with any subsequent 2.18.X release.

At any rate, we do not expect the API to receive big changes because —as explained above— it mimics the one for WebKitGTK+, which has already proven itself both powerful enough for complex applications and convenient to use for the simpler ones. Due to this, I encourage developers to try out WPE as soon as we have the first preview release fresh out of the oven.

Packaging for Buildroot

At Igalia we routinely work with embedded devices, and often we make use of Buildroot for cross-compilation. Having actual releases of WPE will allow us to contribute a set of build definitions for the WPE WebKit port and its dependencies — something that I have already started working on.

Lately I have been taking care of keeping the WebKitGTK+ packaging for Buildroot up-to-date and it has been delightful to work with such a welcoming community. I am looking forward to having WPE supported there, and to keep maintaining the build definitions for both. This will allow making use of WPE with relative ease, while ensuring that Buildroot users will pick our updates promptly.

Generic System Font

Some applications like GNOME Web Epiphany use a WebKitWebView to display widget-like controls which try to follow the design of the rest of the desktop. Unfortunately for GNOME applications this means Cantarell gets hardcoded in the style sheet —it is the default font after all— and this results in mismatched fonts when the user has chosen a different font for the interface (e.g. in Tweaks). You can see this in the following screen capture of Epiphany:

Web using hardcoded Cantarell and (on hover) -webkit-system-font.

Here I have configured the beautiful Inter UI font as the default for the desktop user interface. Now, if you roll your mouse over the image, you will see how much better it looks to use a consistent font. This change also affects the list of plugins and applications, error messages, and in general all the about: pages.

If you are running GNOME 3.26, this is already fixed using font: menu (part of the CSS spec since ye olde CSS 2.1) — but we can do better: Safari has had support since 2015, for a generic “system” font family, similar to sans-serif or cursive:

/* Using the new generic font family (nice!). */
body {
    font-family: -webkit-system-font;

/* Using CSS 2.1 font shorthands (not so nice). */
body {
    font: menu;       /* Pick ALL font attributes... */
    font-size: 12pt;  /* ...then reset some of them. */
    font-weight: 400;

During the hackfest I implemented the needed moving parts in WebKitGTK+ by querying the GtkSettings::gtk-font-name property. This can be used in HTML content shown in Epiphany as part of the UI, and to make the Web Inspector use the system font as well.

Web Inspector using Cantarell, the default GNOME 3 font (full size).

I am convinced that users do notice and appreciate attention to detail, even if they do unconsciously, and therefore it is worthwhile to work on this kind of improvements. Plus, as a design enthusiast with a slight case of typographic OCD, I cannot stop myself from noticing inconsistent usage of fonts and my mind is now at ease knowing that opening the Web Inspector won't be such a jarring experience anymore.


But there's one more thing: On occasion we developers have to debug situations in which a process is seemingly stuck. One useful technique involves running the offending process under the control of a debugger (or, in an embedded device, under gdbserver and controlled remotely), interrupting its execution at intervals, and printing stack traces to try and figure out what is going on. Unfortunately, in some circumstances running a debugger can be difficult or impractical. Wouldn't it be grand if it was possible to interrupt the process without needing a debugger and request a stack trace? Enter “Out-Of-Band Stack Traces” (proof of concept):

  1. The process installs a signal handler using sigaction(7), with the SA_SIGINFO flag set.

  2. On reception of the signal, the kernel interrupts the process (even if it's in an infinite loop), and invokes the signal handler passing an extra pointer to an ucontext_t value, which contains a snapshot of the execution status of the thread which was in the CPU before the signal handler was invoked. This is true for many platform including Linux and most BSDs.

  3. The signal handler code can get obtain the instruction and stack pointers from the ucontext_t value, and walk the stack to produce a stack trace of the code that was being executed. Jackpot! This is of course architecture dependent but not difficult to get right (and well tested) for the most common ones like x86 and ARM.

The nice thing about this approach is that the code that obtains the stack trace is built into the program (no rebuilds needed), and it does not even require to relaunch the process in a debugger — which can be crucial for analyzing situations which are hard to reproduce, or which do not happen when running inside a debugger. I am looking forward to have some time to integrate this properly into WebKitGTK+ and specially WPE, because it will be most useful in embedded devices.

By aperez (adrian@perezdecastro.org) at October 20, 2017 11:30 PM

October 18, 2017

Release Notes for Safari Technology Preview 42

Surfin’ Safari

Safari Technology Preview Release 42 is now available for download for macOS Sierra and macOS High Sierra. If you already have Safari Technology Preview installed, you can update from the Mac App Store’s Updates tab. This release covers WebKit revisions 222556-223209.

If you recently updated from macOS Sierra to macOS High Sierra, you may need to install the High Sierra version of Safari Technology Preview manually.

File and Directory Entries API

  • Fixed a failure when calling fileSystemDirectoryEntry.getDirectory() with an empty path (r223118)
  • Fixed recognizing a path starting with 2 slashes as a valid absolute path (r223135)

Payment Request

  • Implemented PaymentRequest.canMakePayment() (r223160)
  • Implemented PaymentRequest.show() and PaymentRequest.hide() (r223076)

Clipboard API

  • Added the support for custom pasteboard MIME types and hid unsafe MIME types (r222595 and r222830)
  • Fixed copying and pasting of image files on TinyMCE and GitHub (r222656)
  • Fixed DataTransfer.items to expose custom pasteboard types (r223034)
  • Prevented revealing the file URL when pasting an image (r222688)
  • Prevented dragenter and dragleave from using the same data transfer object (r223031)
  • Removed “text/html” from DataTransfer.items when performing paste and match style (r222956)
  • Started pasting images in RTF and RTFD contents using blob URLs (r222839)
  • Sanitized the URL in the pasteboard for other applications and cross-origin content (r223195)


  • Added “display” to the FontFace JavaScript object (r222949)
  • Implemented font-display loading behaviors (r222926)
  • Upgraded Brotli to version 1.0.1 and WOFF2 to the latest upstream (r222903)


  • Removed constant() in favor of env() (r222627)


  • Added support for DOM aborting (r222692)
  • Added support for <link rel=preconnect> (r222613)
  • Changed to use the blob URL when pasting RTFD (r222839)
  • Changed XMLHttpRequest.setRequestHeader() to allow Content-Transfer-Encoding header (r222807, r222817)
  • Prevented submitting a form that is disconnected (r223117)
  • Updated Document.createEvent for recent DOM specification changes (r223023)


  • Added support for selecting an <option> element by sending keys to its parent <select> element.
  • Fixed an issue that caused driver.sendKeys("") to unexpectedly fail and throw an exception.


  • Addressed an issue with if (!await get(something)) (r223043)
  • Dropped instantiate hook in ES6 module loader (r223173)
  • Fixed object properties that are undefined in super.call() but not in this.call() (r223175)
  • Implemented polymorphic prototypes (r222827)
  • Implemented RegExp Unicode property escapes (r223081)
  • Introduced import.meta (r222895)


  • Exposed ARIA drag-and-drop attribute values via AtkObject attributes (r222787)
  • Exposed ARIA menu items with ATK*ROLE*MENU_ITEM even when it’s the child of group role (r222822)
  • Fixed redundant layout on tables (r222790)
  • Fixed exposing aria-rowindex set on a row element (r222821)
  • Fixed exposing the value of aria-level on non-heading roles (r222765)


  • Added basic support for getting an ImageBitmapRenderingContext (r222997)
  • Fixed slow WebGL compositing performance (r222961)
  • Fixed seek() command for encrypted content when the <video> element is not in the DOM at decode time (r222995)


  • Fixed incorrect fullscreen animation when the element has a transform (r223051)
  • Fixed an issue where minimum font size may cause elements to have an infinite line-height (r222588)
  • Improved the progressive display of large images (r223091)


  • Changed to allow async to be able to be used as an imported binding name (r223124)
  • Changed the way WebGL is composited into the page significantly, providing much better performance on lower-end hardware with high-resolution displays (r222961)
  • Reduced the maximum samples used in Multi-Sample Anti-Aliasing (MSAA) for improved performance (r222963)

Web Inspector

  • Added a Canvas tab (r223011)
  • Added auto-completion for min() and max() within a CSS calc() (r223038)
  • Added support for keyboard navigation with Tab, Shift-Tab, Enter, and ESC in the redesigned styles sidebar (r222959)
  • Added support for editing rule selectors in the redesigned styles sidebar (r222799)
  • Added support for undo and redo of manual edits in the redesigned styles sidebar (r222678)
  • Added detail views for resources in Network tab (r222868)
  • Added a headers detail view for resources in the Network tab (r223006)
  • Added remote address in the headers detail view of the Network tab (r223078)
  • Added a cookies detail view in the Network tab (r223058)
  • Added support to search in the headers detail view of the Network tab (r223057)
  • Changed Layers tab sidebar DOM highlight to be by row hover, not row selection (r222801)
  • Changed Network tab filter resources to be based on URL and text content (r223065)
  • Changed the Network tab to show initially loaded resources even if network info was not logged (r223170)
  • Fixed jitter in timeline ruler labels (r223171)
  • Fixed an issue where clicking in the Web Inspector web view clears the selection in the inspected page (r223007)
  • Fixed Beacon and Ping grouping issues (r222865)
  • Fixed Layers tab sidebar popover (r222566)
  • Fixed a row wrapping issue causing waterfall graphs to display behind the next row’s name (r223059)
  • Fixed blurry quick open resource dialog icons (r222662)
  • Fixed misaligned popover when selecting child layers using the keyboard (r222759)
  • Fixed the table in the Network tab from appearing blank when scrolling it reduces the number of rows (r222899)
  • Enabled 3D objects to be selectable in the Layers visualization (r223209)
  • Ensured popovers are not malformed on window resize. (r222742)
  • Escaped more characters in the command generated by “Copy as cURL” (r222762)
  • Improved Canvas recording events (r222888)
  • Improved setting the initial default sorting for tables (r222983)
  • Improved reliability of selection in a table in the Network tab (r222988)
  • Improved the quick open dialog to include source mapped files in the search results (r223164)
  • Included Beacon and Ping requests in Network tab (r222739)
  • Set initial column widths to allow the waterfall column to expand more by default in the Network tab (r223147)

Bug Fixes

  • Fixed an issue introduced in Safari Technology Preview 41 where the tab bar could get out of sync with which tab’s content is being displayed when opening links from another app

By Jon Davis at October 18, 2017 05:00 PM

October 17, 2017

Enrique Ocaña: Attending the GStreamer Conference 2017

Igalia WebKit

This weekend I’ll be in Node5 (Prague) presenting our Media Source Extensions platform implementation work in WebKit using GStreamer.

The Media Source Extensions HTML5 specification allows JavaScript to generate media streams for playback and lets the web page have more control on complex use cases such as adaptive streaming.

My plan for the talk is to start with a brief introduction about the motivation and basic usage of MSE. Next I’ll show a design overview of the WebKit implementation of the spec. Then we’ll go through the iterative evolution of the GStreamer platform-specific parts, as well as its implementation quirks and challenges faced during the development. The talk continues with a demo, some clues about the future work and a final round of questions.

Our recent MSE work has been on desktop WebKitGTK+ (the WebKit version powering the Epiphany, aka: GNOME Web), but we also have MSE working on WPE and optimized for a Raspberry Pi 2. We will be showing it in the Igalia booth, in case you want to see it working live.

I’ll be also attending the GStreamer Hackfest the days before. There I plan to work on webm support in MSE, focusing on any issue in the Matroska demuxer or the vp9/opus/vorbis decoders breaking our use cases.

See you there!

UPDATE 2017-10-22:

The talk slides are available at https://eocanha.org/talks/gstconf2017/gstconf-2017-mse.pdf and the video is available at https://gstconf.ubicast.tv/videos/media-source-extension-on-webkit (the rest of the talks here).

By eocanha at October 17, 2017 10:48 AM

October 16, 2017

Who knew we still had low-hanging fruits?

Gustavo Noronha

Earlier this month I had the pleasure of attending the Web Engines Hackfest, hosted by Igalia at their offices in A Coruña, and also sponsored by my employer, Collabora, Google and Mozilla. It has grown a lot and we had many new people this year.

Fun fact: I am one of the 3 or 4 people who have attended all of the editions of the hackfest since its inception in 2009, when it was called WebKitGTK+ hackfest \o/


It was a great get together where I met many friends and made some new ones. Had plenty of discussions, mainly with Antonio Gomes and Google’s Robert Kroeger, about the way forward for Chromium on Wayland.

We had the opportunity of explaining how we at Collabora cooperated with igalians to implemented and optimise a Wayland nested compositor for WebKit2 to share buffers between processes in an efficient way even on broken drivers. Most of the discussions and some of the work that led to this was done in previous hackfests, by the way!


The idea seems to have been mostly welcomed, the only concern being that Wayland’s interfaces would need to be tested for security (fuzzed). So we may end up going that same route with Chromium for allowing process separation between the UI and GPU (being renamed Viz, currently) processes.

On another note, and going back to the title of the post, at Collabora we have recently adopted Mattermost to replace our internal IRC server. Many Collaborans have decided to use Mattermost through an Epiphany Web Application or through a simple Python application that just shows a GTK+ window wrapping a WebKitGTK+ WebView.


Some people noticed that when the connection was lost Mattermost would take a very long time to notice and reconnect – its web sockets were taking a long, long time to timeout, according to our colleague Andrew Shadura.

I did some quick searching on the codebase and noticed WebCore has a NetworkStateNotifier interface that it uses to get notified when connection changes. That was not implemented for WebKitGTK+, so it was likely what caused stuff to linger when a connection hiccup happened. Given we have GNetworkMonitor, implementation of the missing interfaces required only 3 lines of actual code (plus the necessary boilerplate)!


I was surprised to still find such as low hanging fruit in WebKitGTK+, so I decided to look for more. Turns out WebCore also has a notifier for low power situations, which was implemented only by the iOS port, and causes the engine to throttle some timers and avoid some expensive checks it would do in normal situations. This required a few more lines to implement using upower-glib, but not that many either!

That was the fun I had during the hackfest in terms of coding. Mostly I had fun just lurking in break out sessions discussing the past, present and future of tech such as WebRTC, Servo, Rust, WebKit, Chromium, WebVR, and more. I also beat a few challengers in Street Fighter 2, as usual.

I’d like to say thanks to Collabora, Igalia, Google, and Mozilla for sponsoring and attending the hackfest. Thanks to Igalia for hosting and to Collabora for sponsoring my attendance along with two other Collaborans. It was a great hackfest and I’m looking forward to the next one! See you in 2018 =)

By kov at October 16, 2017 06:23 PM

October 04, 2017

Release Notes for Safari Technology Preview 41

Surfin’ Safari

Safari Technology Preview Release 41 is now available for download for macOS Sierra and macOS High Sierra. If you already have Safari Technology Preview installed, you can update from the Mac App Store’s Updates tab. This release covers WebKit revisions 221968-222556.

File and Directory Entries API

  • Enabled File and Directory Entries API (r222412)


  • Added support for min() and max() in calc() (r222190)
  • Added env() as an alias of constant() to match the evolving specification (r222402)
  • Made more of the CSS animation system internals element based (r221980)
  • Prevented fit-content() tracks from stretching (r222440)
  • Removed CSS Regions support (r222435, r222259, r222423, r222356)

Bug Fixes

  • Fixed an issue introduced in Safari Technology Preview 40 where websites would log users out immediately after logging in


  • Fixed RTCDataChannel connectivity issues (r222045)

Drag and Drop

  • Enabled DataTransfer.prototype.items by default (r222376)
  • Expose text/html and text/uri-list in DataTransfer.prototype.items (r222363)
  • Fixed DataTransfer to stop exposing local file paths when dropping files (r222257)


  • Changed history.pushState() and history.replaceState() to align more closely to the HTML standard (r221978)
  • Changed to use a high resolution timestamp for event time (r222392)


  • Added a small optimization for async generators (r222425)


  • Added support for Elliptic Curve P-521 (r222316)


  • Added bindings for optional arguments to some WebGL2 methods (r222258)
  • Enabled passing sequences to various WebGL2 methods (r222026)
  • Fixed accelerated texImage2D for video to respect flipY in WebGL (r222197)
  • Fixed VideoTextureCopierCV to correctly restore vertex attribute state (r222198)
  • Updated some WebGL2 return types to match the specification (r222096)


  • Aligned Media Source Extension IDL with spec (r222443)


  • Changed to avoid style recomputation when forwarding a focus event to a text field’s input type (r222114)
  • Changed to avoid style resolution when clearing focused element (r222164, r222167)
  • Fixed computing animated style to not require renderers (r222129)
  • Fixed partial frame rendering that can occur even after loading all of the encoded data (r222427)
  • Fixed the width of a child’s margin box to always be equal to that of its containing block in regular block layout (r222321)
  • Fixed the spelling, grammar, and correction dots that were being painted upside down (r222065)


  • Fixed ARIA grids that claim to be multiselectable even with aria-multiselectable is set to false (r222527)


  • Added Cache API support of records persistency (r222073)
  • Changed IDBRequest and IDBTransaction error properties to be DOMExceptions (r222250)

Web Driver

  • Fixed an issue that prevented clicking on overflow: hidden elements without children (r222536)
  • Fixed an issue that prevented clicking on <option> elements
  • Fixed an issue that prevented the top-level frame from being re-focused automatically when the main frame navigates

Web Inspector

  • Added auto-completion suggestions for CSS attr based on the selected element’s attributes (r222483)
  • Added auto-completion suggestions for CSS functions such as constant(), env(), linear-gradient(), etc. (r222359)
  • Changed pressing the Escape key in the global search field to clear the field (r221990)
  • Changed the keyboard shortcut for “Reload page from origin” to match Safari (r222338)
  • Fixed updating the Event Listeners section when listeners are added or removed (r222002)
  • Fixed “Sort by size” issues with Cookies and ApplicationCache DataGrids (r222001)
  • Updated user agent strings and iPhone 8 / iPhone 8 Plus models in Responsive Design Mode

By Jon Davis at October 04, 2017 05:00 PM

October 02, 2017

Introducing WebKit Build Archives

Surfin’ Safari

WebKit contributors have long relied on the WebKit Nightly builds. The WebKit project has been posting these builds since r11994, January 11, 2006. Since their introduction, the nightlies have served a meaningful purpose: “Use the newest untested code in WebKit to find bugs, verify fixes and try the latest features.”

Today we’re excited to roll out some improvements to how we deliver WebKit builds. Building upon the continuous integration infrastructure from https://build.webkit.org, we are now making every successful build of WebKit available! This is a significant improvement from the existing nightly infrastructure, as it should effectively allow bisection down to a single commit.

With these enhancements, WebKit Build Archives will replace WebKit Nightly builds. The new build archives are intended for engineers that contribute to WebKit development to test and diagnose issues. These builds do not have a signed app launcher nor an auto-update system, making them ill-suited as a daily web browsing application. To regularly try out recent WebKit builds on macOS, we recommend downloading and installing Safari Technology Preview, a quality-checked release that automatically updates every two weeks.


Starting with r219240, built products are being stored at a publicly accessible location. These builds can be accessed via the OpenSource/Tools/Scripts/bisect-builds tool. This script will allow anyone to perform a simple bisection over the range of available WebKit builds.

For those without WebKit source checkouts, minified release archives can be downloaded directly from the WebKit Build Archives page. These archives contain a README file with usage instructions.

Platform Support

Currently, archives for the following platforms are available: macOS El Capitan, macOS Sierra, and macOS High Sierra.

Archive Types

Two types of archives are stored: full product, and minified product. Full product archives are exactly what comes out of the build pipeline. These builds are currently used by our CI infrastructure for testing WebKit. Because these builds contain dSYM files (on macOS) they are quite large, and would be undesirable for bisecting. To mitigate the size issue, minified archives are also produced. These minified archives contain only what is necessary to function, and are roughly 10x smaller than the full product archives. This makes them quick to download and extract, ideal for fast bisection and testing.

Archive Retention

Full product archives will be retained for 14 days, while minified archives will expire after 2.5 years.


The development of the bisect-builds script is just beginning, and we welcome any help to improve it. Please file bugs at bugs.webkit.org if you run into any issues or have enhancement requests. Or better yet, feel free to contribute a patch to help improve the experience!

By Lucas Forschler at October 02, 2017 09:15 PM

September 22, 2017

New WebKit Features in Safari 11

Surfin’ Safari

With the release of iOS 11 and macOS High Sierra, the new Safari brings impressive performance improvements and great new WebKit features to the web. This release takes bold steps to curb all too common annoyances that have become pervasive across the web. It’s important for developers to be aware of how they might impact their sites. WebKit includes a JavaScript engine that is faster than ever and adds transformative features like WebAssembly and WebRTC. We can’t wait to see what developers will build with them.

Here are the highlights of the features that make Safari 11 such a significant release.

WebRTC and Media Capture

WebKit support for WebRTC and the Media Capture and Streams API brings real-time communication between browsers to Safari. The combination of support for both technology standards enables developers to bring video conferencing experiences to the web without the use of plug-ins. WebKit uses libWebRTC under the hood for interoperability and a solid foundation of features for efficient video conferencing.

Read more in the WebKit blog post about WebRTC.


WebKit added support for WebAssembly as a complement to JavaScript programs. It is a low-level binary format designed to be a compilation target for existing languages like C++. It can’t do everything that JavaScript can, but it works together with JavaScript to accelerate computationally-intense operations. The implementation in WebKit supports both x86-64 and ARM64 platforms.

Learn more about WebAssembly in WebKit.

Variable Fonts

Developers can improve the loading performance on their site and provide designers with more control over typography using Variable Fonts. It is a specially formatted font file that contains values describing font variations across different axes of features like font weight, size, or oblique angles. The implementation in WebKit also adds CSS property support that can be animated, allowing web authors to incorporate fluid motion into typography changes.

Read more about Variable Fonts on the Web to learn more.

Timing APIs

Support for Resource Timing, Performance Timeline, and User Timing APIs in WebKit enables developers to measure performance characteristics of their web applications. The Resource Timing API can gather detailed network timing data, such as the time taken to fetch a specific resource. Performance Observers allow you to gather timing metrics asynchronously without blocking the application. While the User Timing API allows developers to set application-specific timestamps that are tied in to the browser’s performance timeline.

Read the Resource Timing, Performance Timeline, and User Timing specifications for more details.

WebCrypto API Updates

WebCrypto API support was updated in WebKit to include a standards-compliant SubtleCrypto implementation. This includes DER encoding support for importing and exporting asymmetric keys. Time-consuming cryptography methods now execute asynchronously and can even run in a Web Worker. Support for a number of new cryptographic algorithms adds new functionality, better efficiency, and improved security.

Learn more about the WebCrypto updates in WebKit.

Web Inspector Improvements

Web Inspector sports several useful new features for developers. When the system is set to a right-to-left language, Web Inspector will display a right-to-left user interface layout. It also added a new Settings tab for Web Inspector preferences. In the Network tab, Web Socket connections can now be inspected to show data being communicated across the connection. Finally, in the Elements tab developers can set debugging breakpoints on elements when the subtree or attribute is modified, or when the node is removed.

Intelligent Tracking Prevention

WebKit identifies cross-site tracking on websites you visit with machine learning, and shuts it down. This prevents ads that follow users around the web, but it also helps them have more control and awareness of the sites and services using their data. It’s a feature that protects users and enforces better user privacy practices across the web.

Find our more about Intelligent Tracking Prevention in WebKit.

Video Auto-Play Blocking on macOS

The auto-play blocking policy introduced on iOS last year inspired a new video auto-play blocking feature in Safari on macOS. Simply put, auto-play video with sound will be paused. Video elements without audio tracks, or muted audio can still auto-play. This release also includes support for the play method of the video element to return a promise to easily handle successful and unsuccessful video playback.

Read more about Auto-Play Blocking on macOS with a helpful example on using a Promise to handle auto-play success or prevention.

More Web Platform Features

Support for history.scrollRestoration was added to give developers control over when to maintain scroll position when a user navigates back through browser history.

New CSS Fill and Stroke Module support gives developers more tools to control how text and SVG artwork is painted with new fill- and stroke- properties.

An improved Flexbox implementation brings it up to match current specifications and better layout performance.

CSS Scroll Snapping was updated to add scroll snapping to the main document frame, overflow scrolling containers, and adds support for scroll-snap-proximity.

User Experience Enhancements

There are also several user focused changes to enhance the user-experience that can impact web development. Text rendered on transparent layers match regular text for consistently beautiful text. Decoding large images happens asynchronously to keep animations smooth dropped frames in animations. Scrolling speed is now consistent between the top level document, iframes, and across web views in apps. Lastly, when sharing a link to an article on iOS, the canonical link of the article will be used.


All of these improvements are available to users running iOS 11 and macOS High Sierra, as well as macOS Sierra and OS X El Capitan. These features were also available to web developers with Safari Technology Preview releases. Changes in this release of Safari were included in the following Safari Technology Preview releases: 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36. Download the latest Safari Technology Preview release to stay on the forefront of future web features. You can also use the WebKit Feature Status page to watch for changes to your favorite web platform features.

We love hearing from you. Send a tweet to @webkit or @jonathandavis to share your thoughts on this release, and any features you were hoping for that didn’t make it. If you run into any issues, we welcome your bug reports for Safari, or WebKit bugs for web content issues.

By Jon Davis at September 22, 2017 11:00 PM

Designing Websites for iPhone X

Surfin’ Safari

Out of the box, Safari displays your existing websites beautifully on the edge-to-edge display of the new iPhone X. Content is automatically inset within the display’s safe area so it is not obscured by the rounded corners, or the device’s sensor housing.

The inset area is filled with the page’s background-color (as specified on the <body> or <html> elements) to blend in with the rest of the page. For many websites, this is enough. If your page has only text and images above a solid background color, the default insets will look great.

Other pages — especially those designed with full-width horizontal navigation bars, like the page below — can optionally go a little further to take full advantage of the features of the new display. The iPhone X Human Interface Guidelines detail a few of the general design principles to keep in mind, and the UIKit documentation discusses specific mechanisms native apps can adopt to ensure that they look good. Your website can make use of a few similar new pieces of WebKit API introduced in iOS 11 to take full advantage of the edge-to-edge nature of the display.

While reading this post you can tap on any of the images to visit a corresponding live demo page and take a peek at the source code.

Safari's default insetting behaviorSafari’s default insetting behavior.

Using the Whole Screen

The first new feature is an extension to the existing viewport meta tag called viewport-fit, which provides control over the insetting behavior. viewport-fit is available in iOS 11.

The default value of viewport-fit is auto, which results in the automatic insetting behavior seen above. In order to disable that behavior and cause the page to lay out to the full size of the screen, you can set viewport-fit to cover. After doing so, our viewport meta tag now looks like this:

<meta name='viewport' content='initial-scale=1, viewport-fit=cover'>

After reloading, the navigation bar looks much better, running from edge to edge. However, it is immediately clear why it is important to respect the system’s safe area insets: some of the page’s content is obscured by the device’s sensor housing, and the bottom navigation bar is very hard to use.

viewport-fit=coverUse `viewport-fit=cover` to fill the whole screen.

Respecting the Safe Areas

The next step towards making our page usable again after adopting viewport-fit=cover is to selectively apply padding to elements that contain important content, in order to ensure that they are not obscured by the shape of the screen. This will result in a page that takes full advantage of the increased screen real estate on iPhone X while adjusting dynamically to avoid the corners, sensor housing, and indicator for accessing the Home screen.

Safe and Unsafe AreasThe safe and unsafe areas on iPhone X in the landscape orientation, with inset constants indicated.

To achieve this, WebKit in iOS 11 includes a new CSS function, constant(), and a set of four pre-defined constants, safe-area-inset-left, safe-area-inset-right, safe-area-inset-top, and safe-area-inset-bottom. When combined, these allow style declarations to reference the current size of the safe area insets on each side.

The CSS Working Group recently resolved to add this feature, but with a different name. Please keep this in mind while adopting.

constant() works anywhere var() does — for example, inside the padding properties:

.post {
    padding: 12px;
    padding-left: constant(safe-area-inset-left);
    padding-right: constant(safe-area-inset-right);

For browsers that do not support constant(), the style rule that includes it will be ignored; for this reason, it is important to continue to separately specify fallback rules for any declarations using constant().

Safe area constantsRespect safe area insets so that important content is visible.

Bringing It All Together, With min() and max()

This section covers features that are not currently included in iOS 11.

If you adopt safe area inset constants in your website design, you might notice that it is somewhat difficult to specify that you want a minimum padding in addition to the safe area inset. In the page above, where we replaced our 12px left padding with constant(safe-area-inset-left), when we rotate back to portrait, the left safe area inset becomes 0px, and the text sits immediately adjacent to the screen edge.

No marginsSafe area insets are not a replacement for margins.

To solve this, we want to specify that our padding should be the default padding or the safe area inset, whichever is greater. This can be achieved with the brand-new CSS functions min() and max() which will be available in a future Safari Technology Preview release. Both functions take an arbitrary number of arguments and return the minimum or maximum. They can be used inside of calc(), or nested inside each other, and both functions allow calc()-like math inside of them.

For this case, we want to use max():

@supports(padding: max(0px)) {
    .post {
        padding-left: max(12px, constant(safe-area-inset-left));
        padding-right: max(12px, constant(safe-area-inset-right));
It is important to use @supports to feature-detect min and max, because they are not supported everywhere, and due to CSS’s treatment of invalid variables, to not specify a variable inside your @supports query.

In our example page, in portrait orientation, constant(safe-area-inset-left) resolves to 0px, so the max() function resolves to 12px. In landscape, when constant(safe-area-inset-left) is larger due to the sensor housing, the max() function will resolve to that size instead, ensuring that the important content within is always visible.

max() with safe area insetsUse max() to combine safe area insets with traditional margins.

Experienced web developers might have previously encountered the “CSS locks” mechanism, commonly used to clamp CSS properties to a particular range of values. Using min() and max() together makes this much easier, and will be very helpful in implementing effective responsive designs in the future.

Feedback and Questions

You can start adopting viewport-fit and safe area insets today, by using Safari in the iPhone X Simulator included with Xcode 9. We’d love to hear how your adoption of all of these features goes, so please feel free to send feedback and questions to web-evangelist@apple.com or @webkit on Twitter, and to file any bugs that you run into on WebKit’s bug tracker.

By Timothy Horton at September 22, 2017 05:00 PM

September 20, 2017

Release Notes for Safari Technology Preview 40

Surfin’ Safari

Safari Technology Preview Release 40 is now available for download for macOS Sierra and betas of macOS High Sierra. If you already have Safari Technology Preview installed, you can update from the Mac App Store’s Updates tab. This release covers WebKit revisions 221334-221968.


  • Added support for regular expression named capture groups (r221769)
  • Fixed semicolon tokens becoming interpreted as an = assignment operator (r221400)
  • Implemented async iteration statement for-await-of (r221358)
  • Optimized Object.keys using careful array allocation (r221853)

FileSystem Entry API

  • Added support for input.webkitEntries (r221645)
  • Implemented FileSystemDirectoryEntry.getDirectory() (r221540)
  • Implemented FileSystemEntry.getParent() (r221481)
  • Implemented FileSystemFileEntry.file() (r221544)
  • Fixed the FileSystemEntry API to ignore hidden files (r221639)
  • Finished the DOMFormData implementation (r221839, r221914)

Fetch API

  • Added support for FetchRequest.body (r221395)
  • Added support for Request body stream cloning (r221437)
  • Added support for consuming a Request ReadableStream body (r221504)
  • Added support for caching Response with a ReadableStream body (r221704)
  • Aligned FetchResponse and FetchRequest body handling (r221772)
  • Fixed Response.statusText unexpectedly using the full HTTP status line for HTTP/2 responses (r221804)
  • Fixed Request ReadableStream body to throw an exception when keep alive is true (r221342)


  • Distinguished between title attribute tooltips and aria-label attribute labels (r221918)


  • Fixed validation for DOMMatrix and DOMMatrixReadOnly NaN values (r221545)
  • Implemented DOMMatrix2DInit for setTransform() and addPath() (r221462)


  • Removed support for >> descendant combinator syntax (r221788)
  • Fixed wrong getComputedStyle result for pseudo-elements in display:none subtrees. (r221542)
  • Updated the font selection algorithm to match latest CSS specifications (r221630)

CSS Grid

  • Fixed grid shorthand to not reset the gutter properties (r221668)
  • Changed stretching auto tracks to be done as part of the track sizing algorithm (r221931)
  • Changed to use transferred size over content size for automatic minimum size (r221910)

Web Inspector

  • Fixed an issue that caused toolbar buttons to be hidden at narrow widths (r221338)
  • Prevented the split console in the Settings tab (r221882)
  • Use the same Timeline icon in the dashboard and Timeline tab (r221861)
  • Increased the maximum width allowed for sidebars (r221713)
  • Fixed an issue that prevented ⌘E and ⌘G from working in the main content area when quick console drawer is open (r221691)


  • Prevented increasing the reported totalFrameDelay for non-displayed frames, or frames coming in while paused (r221937)
  • Fixed MSE-to-Canvas painting that can become “stuck” during heavy workloads (r221430)


  • Implemented the HTMLImageElement.async attribute (r221803)
  • Implemented HTMLImageElement.decode() method (r221805)
  • Fixed respecting the SVG fragment identifier if it is a part of an HTTP URL (r221377)
  • Enabled previous elements with lang= to affect fonts selected for subsequent elements (r221408)


  • Implemented getActiveUniforms() for WebGL 2 (r221667)
  • Accelerated texImage2D for video doesn’t respect flipY (r221932)
  • Fixed VideoTextureCopierCV to correctly restore vertex attribute state (r221933)

By Jon Davis at September 20, 2017 05:00 PM

September 09, 2017

Carlos García Campos: WebDriver support in WebKitGTK+ 2.18

Igalia WebKit

WebDriver is an automation API to control a web browser. It allows to create automated tests for web applications independently of the browser and platform. WebKitGTK+ 2.18, that will be released next week, includes an initial implementation of the WebDriver specification.

WebDriver in WebKitGTK+

There’s a new process (WebKitWebDriver) that works as the server, processing the clients requests to spawn and control the web browser. The WebKitGTK+ driver is not tied to any specific browser, it can be used with any WebKitGTK+ based browser, but it uses MiniBrowser as the default. The driver uses the same remote controlling protocol used by the remote inspector to communicate and control the web browser instance. The implementation is not complete yet, but it’s enough for what many users need.

The clients

The web application tests are the clients of the WebDriver server. The Selenium project provides APIs for different languages (Java, Python, Ruby, etc.) to write the tests. Python is the only language supported by WebKitGTK+ for now. It’s not yet upstream, but we hope it will be integrated soon. In the meantime you can use our fork in github. Let’s see an example to understand how it works and what we can do.

from selenium import webdriver

# Create a WebKitGTK driver instance. It spawns WebKitWebDriver 
# process automatically that will launch MiniBrowser.
wkgtk = webdriver.WebKitGTK()

# Let's load the WebKitGTK+ website.

# Find the GNOME link.
gnome = wkgtk.find_element_by_partial_link_text("GNOME")

# Click on the link. 

# Find the search form. 
search = wkgtk.find_element_by_id("searchform")

# Find the first input element in the search form.
text_field = search.find_element_by_tag_name("input")

# Type epiphany in the search field and submit.

# Let's count the links in the contents div to check we got results.
contents = wkgtk.find_element_by_class_name("content")
links = contents.find_elements_by_tag_name("a")
assert len(links) > 0

# Quit the driver. The session is closed so MiniBrowser 
# will be closed and then WebKitWebDriver process finishes.

Note that this is just an example to show how to write a test and what kind of things you can do, there are better ways to achieve the same results, and it depends on the current source of public websites, so it might not work in the future.

Web browsers / applications

As I said before, WebKitWebDriver process supports any WebKitGTK+ based browser, but that doesn’t mean all browsers can automatically be controlled by automation (that would be scary). WebKitGTK+ 2.18 also provides new API for applications to support automation.

  • First of all the application has to explicitly enable automation using webkit_web_context_set_automation_allowed(). It’s important to know that the WebKitGTK+ API doesn’t allow to enable automation in several WebKitWebContexts at the same time. The driver will spawn the application when a new session is requested, so the application should enable automation at startup. It’s recommended that applications add a new command line option to enable automation, and only enable it when provided.
  • After launching the application the driver will request the browser to create a new automation session. The signal “automation-started” will be emitted in the context to notify the application that a new session has been created. If automation is not allowed in the context, the session won’t be created and the signal won’t be emitted either.
  • A WebKitAutomationSession object is passed as parameter to the “automation-started” signal. This can be used to provide information about the application (name and version) to the driver that will match them with what the client requires accepting or rejecting the session request.
  • The WebKitAutomationSession will emit the signal “create-web-view” every time the driver needs to create a new web view. The application can then create a new window or tab containing the new web view that should be returned by the signal. This signal will always be emitted even if the browser has already an initial web view open, in that case it’s recommened to return the existing empty web view.
  • Web views are also automation aware, similar to ephemeral web views, web views that allow automation should be created with the constructor property “is-controlled-by-automation” enabled.

This is the new API that applications need to implement to support WebDriver, it’s designed to be as safe as possible, but there are many things that can’t be controlled by WebKitGTK+, so we have several recommendations for applications that want to support automation:

  • Add a way to enable automation in your application at startup, like a command line option, that is disabled by default. Never allow automation in a normal application instance.
  • Enabling automation is not the only thing the application should do, so add an automation mode to your application.
  • Add visual feedback when in automation mode, like changing the theme, the window title or whatever that makes clear that a window or instance of the application is controllable by automation.
  • Add a message to explain that the window is being controlled by automation and the user is not expected to use it.
  • Use ephemeral web views in automation mode.
  • Use a temporal user profile in application mode, do not allow automation to change the history, bookmarks, etc. of an existing user.
  • Do not load any homepage in automation mode, just keep an empty web view (about:blank) that can be used when a new web view is requested by automation.

The WebKitGTK client driver

Applications need to implement the new automation API to support WebDriver, but the WebKitWebDriver process doesn’t know how to launch the browsers. That information should be provided by the client using the WebKitGTKOptions object. The driver constructor can receive an instance of a WebKitGTKOptions object, with the browser information and other options. Let’s see how it works with an example to launch epiphany:

from selenium import webdriver
from selenium.webdriver import WebKitGTKOptions

options = WebKitGTKOptions()
options.browser_executable_path = "/usr/bin/epiphany"
epiphany = webdriver.WebKitGTK(browser_options=options)

Again, this is just an example, Epiphany doesn’t even support WebDriver yet. Browsers or applications could create their own drivers on top of the WebKitGTK one to make it more convenient to use.

from selenium import webdriver
epiphany = webdriver.Epiphany()


During the next release cycle, we plan to do the following tasks:

  • Complete the implementation: add support for all commands in the spec and complete the ones that are partially supported now.
  • Add support for running the WPT WebDriver tests in the WebKit bots.
  • Add a WebKitGTK driver implementation for other languages in Selenium.
  • Add support for automation in Epiphany.
  • Add WebDriver support to WPE/dyz.

By carlos garcia campos at September 09, 2017 05:33 PM

September 06, 2017

Frédéric Wang: Review of Igalia's Web Platform activities (H1 2017)

Igalia WebKit


For many years Igalia has been committed to and dedicated efforts to the improvement of Web Platform in all open-source Web Engines (Chromium, WebKit, Servo, Gecko) and JavaScript implementations (V8, SpiderMonkey, ChakraCore, JSC). We have been working in the implementation and standardization of some important technologies (CSS Grid/Flexbox, ECMAScript, WebRTC, WebVR, ARIA, MathML, etc). This blog post contains a review of these activities performed during the first half (and a bit more) of 2017.



A few years ago Bloomberg and Igalia started a collaboration to implement a new layout model for the Web Platform. Bloomberg had complex layout requirements and what the Web provided was not enough and caused performance issues. CSS Grid Layout seemed to be the right choice, a feature that would provide such complex designs with more flexibility than the currently available methods.

We’ve been implementing CSS Grid Layout in Blink and WebKit, initially behind some flags as an experimental feature. This year, after some coordination effort to ensure interoperability (talking to the different parties involved like browser vendors, the CSS Working Group and the web authors community), it has been shipped by default in Chrome 58 and Safari 10.1. This is a huge step for the layout on the web, and modern websites will benefit from this new model and enjoy all the features provided by CSS Grid Layout spec.

Since the CSS Grid Layout shared the same alignment properties as the CSS Flexible Box feature, a new spec has been defined to generalize alignment for all the layout models. We started implementing this new spec as part of our work on Grid, being Grid the first layout model supporting it.

Finally, we worked on other minor CSS features in Blink such as caret-color or :focus-within and also several interoperability issues related to Editing and Selection.


MathML is a W3C recommendation to represent mathematical formulae that has been included in many other standards such as ISO/IEC, HTML5, ebook and office formats. There are many tools available to handle it, including various assistive technologies as well as generators from the popular LaTeX typesetting system.

After the improvements we performed in WebKit’s MathML implementation, we have regularly been in contact with Google to see how we can implement MathML in Chromium. Early this year, we had several meetings with Google’s layout team to discuss this in further details. We agreed that MathML is an important feature to consider for users and that the right approach would be to rely on the new LayoutNG model currently being implemented. We created a prototype for a small LayoutNG-based MathML implementation as a proof-of-concept and as a basis for future technical discussions. We are going to follow-up on this after the end of Q3, once Chromium’s layout team has made more progress on LayoutNG.


Servo is Mozilla’s next-generation web content engine based on Rust, a language that guarantees memory safety. Servo relies on a Rust project called WebRender which replaces the typical rasterizer and compositor duo in the web browser stack. WebRender makes extensive use of GPU batching to achieve very exciting performance improvements in common web pages. Mozilla has decided to make WebRender part of the Quantum Render project.

We’ve had the opportunity to collaborate with Mozilla for a few years now, focusing on the graphics stack. Our work has focused on bringing full support for CSS stacking and clipping to WebRender, so that it will be available in both Servo and Gecko. This has involved creating a data structure similar to what WebKit calls the “scroll tree” in WebRender. The scroll tree divides the scene into independently scrolled elements, clipped elements, and various transformation spaces defined by CSS transforms. The tree allows WebRender to handle page interaction independently of page layout, allowing maximum performance and responsiveness.


WebRTC is a collection of communications protocols and APIs that enable real-time communication over peer-to-peer connections. Typical use cases include video conferencing, file transfer, chat, or desktop sharing. Igalia has been working on the WebRTC implementation in WebKit and this development is currently sponsored by Metrological.

This year we have continued the implementation effort in WebKit for the WebKitGTK and WebKit WPE ports, as well as the maintenance of two test servers for WebRTC: Ericsson’s p2p and Google’s apprtc. Finally, a lot of progress has been done to add support for Jitsi using the existing OpenWebRTC backend.

Since OpenWebRTC development is not an active project anymore and given libwebrtc is gaining traction in both Blink and the WebRTC implementation of WebKit for Apple software, we are taking the first steps to replace the original WebRTC implementation in WebKitGTK based on OpenWebRTC, with a new one based on libwebrtc. Hopefully, this way we will share more code between platforms and get more robust support of WebRTC for the end users. GStreamer integration in this new implementation is an issue we will have to study, as it’s not built in libwebrtc. libwebrtc offers many services, but not every WebRTC implementation uses all of them. This seems to be the case for the Apple WebRTC implementation, and it may become our case too if we need tighter integration with GStreamer or hardware decoding.


WebVR is an API that provides support for virtual reality devices in Web engines. Implementation and devices are currently actively developed by browser vendors and it looks like it is going to be a huge thing. Igalia has started to investigate on that topic to see how we can join that effort. This year, we have been in discussions with Mozilla, Google and Apple to see how we could help in the implementation of WebVR on Linux. We decided to start experimenting an implementation within WebKitGTK. We announced our intention on the webkit-dev mailing list and got encouraging feedback from Apple and the WebKit community.


ARIA defines a way to make Web content and Web applications more accessible to people with disabilities. Igalia strengthened its ongoing committment to the W3C: Joanmarie Diggs joined Richard Schwerdtfeger as a co-Chair of the W3C’s ARIA working group, and became editor of the Core Accessibility API Mappings, [Digital Publishing Accessibility API Mappings] (https://w3c.github.io/aria/dpub-aam/dpub-aam.html), and Accessible Name and Description: Computation and API Mappings specifications. Her main focus over the past six months has been to get ARIA 1.1 transitioned to Proposed Recommendation through a combination of implementation and bugfixing in WebKit and Gecko, creation of automated testing tools to verify platform accessibility API exposure in GNU/Linux and macOS, and working with fellow Working Group members to ensure the platform mappings stated in the various “AAM” specs are complete and accurate. We will provide more information about these activities after ARIA 1.1 and the related AAM specs are further along on their respective REC tracks.

Web Platform Predictability for WebKit

The AMP Project has recently sponsored Igalia to improve WebKit’s implementation of the Web platform. We have worked on many issues, the main ones being:

  • Frame sandboxing: Implementing sandbox values to allow trusted third-party resources to open unsandboxed popups or restrict unsafe operations of malicious ones.
  • Frame scrolling on iOS: Addressing issues with scrollable nodes; trying to move to a more standard and interoperable approach with scrollable iframes.
  • Root scroller: Finding a solution to the old interoperability issue about how to scroll the main frame; considering a new rootScroller API.

This project aligns with Web Platform Predictability which aims at making the Web more predictable for developers by improving interoperability, ensuring version compatibility and reducing footguns. It has been a good opportunity to collaborate with Google and Apple on improving the Web. You can find further details in this blog post.


Igalia has been involved in design, standardization and implementation of several JavaScript features in collaboration with Bloomberg and Mozilla.

In implementation, Bloomberg has been sponsoring implementation of modern JavaScript features in V8, SpiderMonkey, JSC and ChakraCore, in collaboration with the open source community:

  • Implementation of many ES6 features in V8, such as generators, destructuring binding and arrow functions
  • Async/await and async iterators and generators in V8 and some work in JSC
  • Optimizing SpiderMonkey generators
  • Ongoing implementation of BigInt in SpiderMonkey and class field declarations in JSC

On the design/standardization side, Igalia is active in TC39 and with Bloomberg’s support

In partnership with Mozilla, Igalia has been involved in the specification of various JavaScript standard library features for internationalization, in specification, implementation in V8, code reviews in other JavaScript engines, as well as working with the underlying ICU library.

Other activities

Preparation of Web Engines Hackfest 2017

Igalia has been organizing and hosting the Web Engines Hackfest since 2009. This event under an unconference format has been a great opportunity for Web Engines developers to meet, discuss and work together on the web platform and on web engines in general. We announced the 2017 edition and many developers already confirmed their attendance. We would like to thank our sponsors for supporting this event and we are looking forward to seeing you in October!

Coding Experience

Emilio Cobos has completed his coding experience program on implementation of web standards. He has been working in the implementation of “display: contents” in Blink but some work is pending due to unresolved CSS WG issues. He also started the corresponding work in WebKit but implementation is still very partial. It has been a pleasure to mentor a skilled hacker like Emilio and we wish him the best for his future projects!

New Igalians

During this semester we have been glad to welcome new igalians who will help us to pursue Web platform developments:

  • Daniel Ehrenberg joined Igalia in January. He is an active contributor to the V8 JavaScript engine and has been representing Igalia at the ECMAScript TC39 meetings.
  • Alicia Boya joined Igalia in March. She has experience in many areas of computing, including web development, computer graphics, networks, security, and software design with performance which we believe will be valuable for our Web platform activities.
  • Ms2ger joined Igalia in July. He is a well-known hacker of the Mozilla community and has wide experience in both Gecko and Servo. He has noticeably worked in DOM implementation and web platform test automation.


Igalia has been involved in a wide range of Web Platform technologies going from Javascript and layout engines to accessibility or multimedia features. Efforts have been made in all parts of the process:

  • Participation to standardization bodies (W3C, TC39).
  • Elaboration of conformance tests (web-platform-tests test262).
  • Implementation and bug fixes in all open source web engines.
  • Discussion with users, browser vendors and other companies.

Although, some of this work has been sponsored by Google or Mozilla, it is important to highlight how external companies (other than browser vendors) can make good contributions to the Web Platform, playing an important role on its evolution. Alan Stearns already pointed out the responsibility of the Web Plaform users on the evolution of CSS while Rachel Andrew emphasized how any company or web author can effectively contribute to the W3C in many ways.

As mentioned in this blog post, Bloomberg is an important contributor of several open source projects and they’ve been a key player in the development of CSS Grid Layout or Javascript. Similarly, Metrological’s support has been instrumental for the implementation of WebRTC in WebKit. We believe others could follow their examples and we are looking forward to seeing more companies sponsoring Web Platform developments!

September 06, 2017 10:00 PM

Release Notes for Safari Technology Preview 39

Surfin’ Safari

Safari Technology Preview Release 39 is now available for download for macOS Sierra and betas of macOS High Sierra. If you already have Safari Technology Preview installed, you can update from the Mac App Store’s Updates tab. This release covers WebKit revisions 220795-221334.

Beacon API

  • Added support for quota limitation (r220922)
  • Enabled content extensions to be able to intercept Beacon and Ping redirects (r220996)
  • Improved error reporting (r220946)
  • Prevented cross origin Beacon requests with an ArrayBuffer or ArrayBufferView payload from doing a CORS preflight (r220817)

Directory Upload

  • Added basic support for input.webkitdirectory behind an experimental feature flag (r221177)
  • Added stub File and Directory Entries API interfaces (r221209)

Fetch API

  • Added support for FetchRequest.body (r221329)
  • Added support for a callback-based fetch (r220927)

Input Events

  • Renamed inputType “formatForeColor” to “formatFontColor” (r220901)
  • Fixed an issue where picking an emoji via the emoji dialog using Control-Command-Space (⌃⌘Space) fires inconsistent beforeinput events. (r221234)
  • Fixed an issue where using align left or align justify on the Touchbar both send a beforeinput event with the “formatJustifyLeft” inputType. (r221199)


  • Implemented async generator runtime for async iteration (r221080)
  • Optimized map iteration for faster performance (r221110)
  • Added support for the “dotAll” flag for regular expressions (r221160)


  • Fixed const in unreachable code getting decoded incorrectly, erroneously rejecting the binary as invalid (r220894)


  • Fixed a MediaStream created without tracks to correctly update the active state after tracks are added (r221277)

Web Inspector

  • Fixed copying text from the “View variable value” popover in the Styles sidebar (r220973)
  • Added async stack trace capture when workers or the main context posts a message (r220815)
  • Replaced “Enter Class Name” input label with “Add New Class” for clarity (r220875)


  • Implemented HTMLMediaElement dispatch of the onencrypted event (r221131)
  • Fixed autoplay muted videos not playing when outside the viewport (r221016)
  • Fixed HTMLTrackElement behavior to match standards (r221155)

By Jon Davis at September 06, 2017 05:00 PM

August 31, 2017

Xabier Rodríguez Calvar: Some rough numbers on WebKit code

Igalia WebKit

My wife asked me for some rough LOC numbers on the WebKit project and I think I could share them with you here as well. They come from r221232. As I’ll take into account some generated code it is relevant to mention that I built WebKitGTK+ with the default CMake options.

First thing I did was running sloccount Source and got the following numbers:

cpp: 2526061 (70.57%)
ansic: 396906 (11.09%)
asm: 207284 (5.79%)
javascript: 175059 (4.89%)
java: 74458 (2.08%)
perl: 73331 (2.05%)
objc: 44422 (1.24%)
python: 38862 (1.09%)
cs: 13011 (0.36%)
ruby: 11605 (0.32%)
xml: 11396 (0.32%)
sh: 3747 (0.10%)
yacc: 2167 (0.06%)
lex: 1007 (0.03%)
lisp: 89 (0.00%)
php: 10 (0.00%)

This number do not include IDL code so I did some grepping to get the number myself that gave me 19632 IDL lines:

$ find Source/ -name ".idl" | xargs cat | grep -ve "^[[:space:]]\/*" -ve "^[[:space:]]*" -ve "^[[:space:]]$" -ve "^[[:space:]][$" -ve "^[[:space:]]};$" | wc -l

The interesting part of the IDL files is that they are used to generate code so those 19632 IDL lines expand to:

ansic: 699140 (65.25%)
cpp: 368720 (34.41%)
python: 1492 (0.14%)
xml: 1040 (0.10%)
javascript: 883 (0.08%)
asm: 169 (0.02%)
perl: 11 (0.00%)

Let’s have a look now at the LayoutTests (they test the functionality of WebCore + the platform). Tests are composed mainly by HTML files so if you run sloccount LayoutTests you get:

javascript: 401159 (76.74%)
python: 87231 (16.69%)
xml: 22978 (4.40%)
php: 4784 (0.92%)
ansic: 3661 (0.70%)
perl: 2726 (0.52%)
sh: 199 (0.04%)

It’s quite interesting to see that sloccount does not consider HTML which is quite relevant when you’re testing a web engine so again, we have to count them manually (thanks to Carlos López who helped me to properly grep here as some binary lines were giving me a headache to get the numbers):

find LayoutTests/ -name ".html" -print0 | xargs -0 cat | strings | grep -Pv "^[[:space:]]$" | wc -l

You can see 2205690 of “meaningful lines” that combine HTML + other languages that you can see above. I can’t substract here to just get the HTML lines because the number above take into account files with a different extension than HTML, though many of them do include other languages, specially JavaScript.

But the LayoutTests do not include only pure WebKit tests. There are some imported ones so it might be interesting to run the same procedure under LayoutTests/imported to see which ones are imported and not written directly into the WebKit project. I emphasize that because they can be written by WebKit developers in other repositories and actually I can present myself and Youenn Fablet as an example as we wrote tests some tests that were finally moved into the specification and included back later when imported. So again, sloccount LayoutTests/imported:

python: 84803 (59.99%)
javascript: 51794 (36.64%)
ansic: 3661 (2.59%)
php: 575 (0.41%)
xml: 250 (0.18%)
sh: 199 (0.14%)
perl: 86 (0.06%)

The same procedure to count HTML + other stuff lines inside that directory gives a number of 295490:

$ find LayoutTests/imported/ -name ".html" -print0 | xargs -0 cat | strings | grep -Pv "^[[:space:]]$" | wc -l

There are also some other tests that we can talk about, for example the JSTests. I’ll mention already the numbers summed up regarding languages and the manual HTML code (if you made it here, you know the drill already):

javascript: 1713200 (98.64%)
xml: 20665 (1.19%)
perl: 2449 (0.14%)
python: 421 (0.02%)
ruby: 56 (0.00%)
sh: 38 (0.00%)
HTML+stuff: 997


javascript: 297 (41.02%)
ansic: 187 (25.83%)
java: 118 (16.30%)
xml: 103 (14.23%)
php: 10 (1.38%)
perl: 9 (1.24%)
HTML+stuff: 16026


javascript: 950916 (83.12%)
cpp: 147194 (12.87%)
ansic: 38540 (3.37%)
asm: 5466 (0.48%)
sh: 872 (0.08%)
ruby: 419 (0.04%)
perl: 348 (0.03%)
python: 325 (0.03%)
xml: 5 (0.00%)
HTML+stuff: 238002


cpp: 44753 (99.45%)
ansic: 163 (0.36%)
objc: 76 (0.17%)
xml: 7 (0.02%)
javascript: 1 (0.00%)
HTML+stuff: 3887

And this is all. Remember that these are just some rough statistics, not a “scientific” paper.


In her expert opinion, in the WebKit project we are devoting around 50% of the total LOC to testing, which makes it a software engineering “textbook” project regarding testing and I think we can be proud of it!

By calvaris at August 31, 2017 09:03 AM

August 30, 2017

Concurrent JavaScript: It can work!

Surfin’ Safari

With the recent addition of SharedArrayBuffer, concurrency is finding its way into the JavaScript language. This addition allows JavaScript programs to perform concurrent access to SharedArrayBuffer objects. WebKit supports SharedArrayBuffer and it has full optimization support in our compiler pipeline. Unfortunately, JavaScript does not allow any objects other than SharedArrayBuffer to be shared.

This post considers a wild thought experiment: what would it take to extend concurrency to the entire JavaScript heap? In this world, any object can be shared with other threads. This would be no small change. Existing JavaScript VM optimizations exploit the fact that there is only one thread of execution, so concurrency is sure to introduce some performance problems. This post is concerned with whether this is even technically feasible, and if it is, what the cost might be.

We offer a basic strawman API to illustrate what we mean by concurrency. Most of the post is concerned with how WebKit’s JavaScript VM (called JavaScriptCore, or JSC for short) can implement the strawman. Implementing this strawman will be a big effort. We think that our proposed implementation ought to be able to meet the following goals:

  • No performance regressions for code that does not use concurrency.
  • Linear scalability when a program is run in parallel with itself without deliberately sharing any objects. We don’t expect two threads to be fully twice as fast as one, since we expect some concurrency overhead — but if you have two CPUs then two threads should be faster than one, and hopefully close to twice as fast as one.
  • Linear scalability — including speed-ups versus the best serial baselines — on some corpus of parallel code that does share objects.
  • Sensible semantics, including a memory model that isn’t any weaker than what modern hardware provides.
  • Compatibility. For example, concurrent JavaScript programs should have a story for how to use the DOM without requiring the DOM implementation to be rewritten.

Our proposed implementation scheme relies on 64-bit systems, but that is largely because our engine is already 64-bit-centric.

It’s not yet possible to evaluate the performance of this scheme empirically, but our implementation sketch does make it possible to intuit what performance might look like. Specifically, our scheme ensures that most property accesses will experience at most one arithmetic instruction worth of overhead (which is almost free), with a few particularly tricky (and rare) ones experiencing up to about 7x overhead. This post ends with a section that compares our scheme to other techniques for implementing concurrency.

Strawman Concurrent JS

Our strawman proposal for concurrent JS is to simply add threads. Threads gets separate stacks but share everything else. Threads are great for our experiment because they are so general. We can imagine implementing many other kinds of concurrent programming models on top of threads. Thus, if we can get our VM to support threads, then we can probably get it to support lots of other concurrent and parallel programming models. This post is about removing technical feasibility as a gating factor for adding any concurrent programming model to JavaScript.

This section makes the strawman somewhat concrete, mostly to provide context on the aspects of it that are easy or hard to implement. It’s useful to know what the API looks like in order to understand what constraints it creates.

Each program will start out with one thread. Threads can start other threads. Threads live in the same heap and can share objects with each other. This section shows the API, describes the memory model, and shows how concurrency interacts with the DOM.

Possible API

We propose:

  • a simple API for creating threads,
  • a change to the Atomics object to support building lock objects,
  • a lock and condition variable API that can be built on top of Atomics,
  • a way to create thread-local variables, and
  • some helpers to allow for incremental adoption.

This post will use this strawman to understand exactly what it would take to implement threads in JavaScriptCore.

We want it to be easy to create threads:

new Thread(function() { console.log("Hello, threads!"); });

This will start a new thread, which will eventually print “Hello, threads!”. Note that even this simple example shares lots of stuff with the thread. For example, the function object captures the lexical scope in the thread in which it was created, so that when the thread accesses the console variable, this is an access to a shared object.

Threads can be joined to wait for them to finish and to get their result:

let result = new Thread(() => 42).join(); // returns 42

In web browsers, the main thread cannot block, so join() will throw an exception if the above code was on the main thread. We can support asynchronous versions of blocking operations:

new Thread(() => 42).asyncJoin().then((result) => /* result is 42 */)

You can always get the Thread object for the current thread:

let myThread = Thread.current;

Threads may need to wait on each other to prevent races. This can be accomplished using locks. Rather than simply introduce a locking API, we propose to extend the Atomics API to allow users to build any locks they like. We provide a good lock implementation in our proposed API, but we want to encourage the creation of other kinds of synchronization primitives. The existing SharedArrayBuffer specification allows developers to create custom locks using the Atomics API. This API allows you to say things like:

Atomics.wait(array, index, expectedValue);


Atomics.wake(array, index, numThreadsToWake);

Currently, the array must be an integer typed array backed by a SharedArrayBuffer. We propose extending all Atomics methods that take an array/index to take an object and a property name instead. Since an index is a property name, this does not change behavior of code that already uses this API for SharedArrayBuffer. This also implies that Atomics methods that currently take integer values (for storing or comparing to elements in typed arrays) will now be able to take any JavaScript value when used with normal JavaScript properties. Atomics.wake, Atomics.wait, and Atomics.compareExchange are sufficient for implementing any a lock using just one JavaScript property.

Additionally, we propose adding a Lock API:

let lock = new Lock();
lock.hold(function() { /* ...perform work with lock held... */ });

Locking on the main thread is possible with promises:

lock.asyncHold().then(function() { /* ...perform work with lock held... */ });

This works because each thread gets its own runloop. We can also add a Condition API:

let cond = new Condition();
cond.wait(lock); // Wait for a notification while the lock is temporarily released.
// ...
cond.asyncWait(lock).then(function() { /* ...perform work with lock reacquired... */ });
// ...
cond.notify(); // Notify one thread or promise.
// ...
cond.notifyAll(); // Notify all threads and promises.

Condition.prototype.wait will release the lock you pass it before waiting, and reacquire it before returning. The async variant associates the resulting promise with the condition variable such that if the condition is notified, the promise will be fulfilled on the current thread.

Using Thread.current and WeakMap, anyone can implement thread-local variables. Nonetheless, it’s sometimes possible for the underlying runtime to do something more clever. We don’t want to require all JavaScript programmers to know how to implement thread-local variables with WeakMap. Hence, we propose a simple API:

let threadLocal = new ThreadLocal();
function foo()
    return threadLocal.value;
new Thread(function() {
    threadLocal.value = 43;
    print("Thread sees " + foo()); // Will always print 43.
threadLocal.value = 42;
print("Main thread sees " + foo()); // Will always print 42.

Finally, we want to make it easy for users to assert that objects stay on one thread:

var o = {f: "hello"}; // Could be any object.
new Thread(function() {
    console.log(o.f); // Throws ConcurrentAccessError

Any object that is Thread.restricted should throw ConcurrencyAccessError in response to any proxyable operation performed by a thread other than the one that called Thread.restrict.

Memory Model

Processors and compilers like to reorder memory accesses. Both processors and compilers love to hoist loads from memory. This happens because the following code:

let x = o.f
o.g = 42
let y = o.f

May get transformed by the compiler or processor to:

let x = o.f
o.g = 42
let y = x

Effectively, this means that the “load” into y got moved above the store to o.g. Processors will do the same optimization dynamically, by caching the load of o.f and reusing the cached result for the second load.

Processors and compilers like to sink stores to memory. This happens because the following code:

o.f = 42
let tmp = o.g
o.f = 43

May get transformed by the compiler or processor to:

let tmp = o.g
o.f = 43

This is “as if” the o.f = 42 statement got moved to just before o.f = 43. Even if the compiler does not perform this transformation, the processor may buffer stores and execute them when it is convenient. This can also mean that o.f = 42 may execute after let tmp = o.g.

It makes most sense for our strawman to follow the existing SharedArrayBuffer memory model. It’s already possible to write multithreaded code that has boundedly nondeterministic behavior using SharedArrayBuffer, and we aren’t going to protect completely from such code. But JavaScript’s objects are much more complicated than a buffer, so guaranteeing that basic invariants of the JS object model hold in the face of races is nontrivial. We propose that operations that modify JavaScript object storage execute atomically. Atomicity means that if many threads execute these operations concurrently, then each one will behave as if they had all executed in some sequence with no concurrency. Each of the underlying operations that JS can do to objects should be atomic:

  • Add a property.
  • Delete a property.
  • Get a property’s value.
  • Set a property’s value.
  • Change a property’s configuration.
  • Snapshot the set of property names.

This doesn’t always mean that the expression o.f is atomic, since this expression may do much more than loading a property’s value. In particular:

  • If o.f is a plain property directly on o, then it is atomic.
  • If o.f is a prototype access, then loading the prototype is separate from loading f from the prototype.
  • If o.f is a getter, then loading the getter is one step (which would be atomic if the getter is directly on o) but calling the getter is not atomic, since the getter may execute arbitrary code.

We propose that the low-level object operations are atomic. Some operations, like getting and setting a property’s value, may be implemented using hardware primitives that allow reordering. We propose to allow reorderings of get/set accesses around each other subject to the same memory model for get/set accesses to SharedArrayBuffer. While our strawman does allow for races and some memory model strangeness, it does not allow for JavaScript’s object model invariants to be invalidated. For any heap created by a concurrent JS program, it should be possible to write a sequential JS program that creates an indistinguishable heap.

Finally, we propose that memory management of the concurrent JS heap happens just as it does in other garbage-collected multi-threaded languages. Quite simply, garbage collection must appear to happen atomically and only at well defined safepoints, like loop back edges, allocation sites, and during calls to native code that doesn’t touch the heap. This requirement is satisfied by popular garbage collection algorithms like those in HotSpot or MMTk. It’s also satisfied by classic algorithms like mark-sweep and semi-space, and even in garbage collectors with no global stop-the-world phase, including ones that are so lock-free that they don’t even stop threads to scan their stacks. WebKit’s Riptide GC already mostly supports multiple threads because our JIT threads can access the heap.

Interaction With The DOM

Extending concurrency to all of JavaScript will be hard; extending it to all of the DOM will be even harder. We extend enough reasoning about threads to the DOM to make this strawman useful.

We propose that by default, DOM objects throw ConcurrentAccessError in response to any proxyable operation from threads other than the main one, just as if Thread.restrict had been called on them from the main thread.

However, a few objects will have to allow for concurrent accesses just to make the language behave sanely. Something obvious like:

new Thread(function() { console.log("Hello, threads!"); });

requires a concurrent access to a DOM object. In WebKit, DOM global objects are in charge of storing the variable state of a window. Ordinary JS properties of the global object (including console, Object, etc) have to be accessible to concurrent threads, because those properties are the scripts’s global variables. Accesses from other threads to exotic properties of the global object, or properties of the global object’s prototype, can throw. Attempts to add new properties to the global object or delete properties from it from non-main threads can throw as well. These restrictions mean that in WebKit, handling the DOM global object’s limited kind of concurrent property accesses is not much harder than handling those same accesses for ordinary JS objects.

Additionally, namespace objects like console can be accessed by concurrent threads because they can just use the JS object model. There is no reason to restrict them to the main thread, and it’s important that console is accessible due to its utility for debugging.

Strawman Summary

This section has proposed a strawman API for threading in JavaScript. This API is powerful enough to implement custom synchronization primitives. It’s also powerful enough to allow for the execution of racy programs, but it does not allow races to break the language. Threads are general enough to allow for many other kinds of programming models to be implemented on top of them.

Implementing Concurrent JS in WebKit

This section shows that we can implement our threads-based strawman without having to disable any of JavaScriptCore’s fundamental performance optimizations. Our scheme aims to achieve close to zero overhead even in the case of programs that read and write to the same objects from multiple threads.

JavaScript shares a lot in common with languages like Java and .NET, which already support threads. Here are some of the things these languages have in common with JavaScript:

  • Like JavaScript, those languages use tracing-based garbage collectors. Our GC mostly supports multiple threads, since JIT threads are already allowed to read the heap. The biggest missing piece is thread local allocation, which enables concurrent allocation. For our GC this just means a separate FreeList per thread for each allocator. Our GC has a fixed number of allocators and we already have fast thread-local storage, so this will be a mechanical change.
  • Like JavaScript, those languages are implemented using multiple tiers of JITs and possibly an interpreter. Our WebAssembly VM already supports multi-threaded tier-up from BBQ (build bytecode quickly) to OMG (optimized machinecode generation). We’re not worried about getting this right for JavaScript.
  • Like implementations of JavaScript, implementations of those languages use inline caching to accelerate dynamic operations. We will have to make some changes to our inline caches to support concurrency, and we describe those changes in a later section in this post. It’s not the hardest part about adding concurrency, since it’s not new territory — it’s been done before.

These similarities suggest that many of the techniques that are already used to make Java virtual machines support concurrency can be reused to make JavaScript concurrent.

Where things get hard is JavaScript’s ability to dynamically reconfigure objects. While Java and .NET have fixed-size objects (once allocated, an object does not change size), JavaScript objects tend to be variable-size. Concurrency in those statically-typed languages relies on the fact that concurrent accesses to fixed-size objects are atomic by default up to the machine’s pointer width (so, 64-bit systems do 64-bit property accesses atomically by default). Pointer values in Java and .NET are addresses to the contiguous slab of memory holding the object’s data, and it only takes some address arithmetic (like adding an offset) and a single memory access instruction to read/write any field. Even if the memory model allows surprising reorderings, it’s never the case that a racing access instruction to the same field (or different fields of the same object) corrupts the entire object or causes a crash. JavaScript’s variable-size objects, on the other hand, mean that object accesses require multiple memory access instructions in some cases. A sequence of operations involving multiple accesses to memory is not atomic by default. In the worst case, the VM might crash because the internal object state gets corrupted. Even if this doesn’t happen, races might cause writes to be lost or for time-travel to occur (writing A and then B to a field may lead to reads of that field to first see A, then B, and then A again).

In our strawman proposal, concurrent JavaScript implies that fundamental operations such as adding a new property to an object, changing the value of a property, reading a property, and removing a property all proceed atomically. No race should ever lead to a VM crash, lost writes, or the value of a property experiencing time travel.

We propose an algorithm that allows most JavaScript object accesses to be wait-free and require minimal overhead compared to our existing serial JS implementation. Wait-free operations execute without ever blocking and complete in a bounded number of steps regardless of contention. This algorithm borrows ideas from real-time garbage collection, locking algorithms, and type inference. We plan to use a tiered defense against the overheads of concurrency:

  1. We propose using our existing polymorphic-inline-cache-based type inference system to infer relaxed notions of thread-locality of objects (and their types) that we call transition-thread-locality (TTL). TTL objects will use the same object model as they do today and accesses to those objects will enjoy close to zero overhead. TTL does not imply true thread-locality; for example even objects that are read and written by many threads may be inferred TTL.
  2. We propose using a segmented object model for objects that fail TTL inference. This will introduce an extra load instruction, and some arithmetic, to the property access fast path. We fear that by itself, this technique would not be fast enough to meet our performance goals — but since the segmented object model will only be used surgically for those objects (or types of objects) that fail TTL inference, we suspect that the net cost will be small enough to be practical.
  3. Operations on non-TTL objects that don’t benefit from the segmented object model will use locks. During our development of the Riptide concurrent GC, we added an internal lock to each object. This lock occupies just 2 bits and allows the lock/unlock fast path to require just an atomic compare-and-swap (CAS) and a branch.

Before diving into the details, we first set up some expectations for the hardware that this proposed system would run on. Then we describe this proposal in reverse. We consider the cost of just using per-object locking. Then we review the existing JSC object model and describe what kinds of operations happen to already be atomic within this model. Next we introduce segmented butterflies, which are the key to allow dynamically reconfiguring objects. Then we show how our TTL inference will allow us to use our existing object model for hopefully most of the JavaScript heap. This section then considers some loose ends, like how to do inline caching concurrently, how resizable arrays fit into TTL and segmented butterflies, how to handle large thread counts using the local optimizer lock (LOL), and finally how to handle native state that isn’t thread-safe.

Hardware Expectations

This post describes how to convert JavaScriptCore to support concurrent JavaScript. JSC is currently optimized for 64-bit systems, and most of our existing concurrency support (concurrent JIT, concurrent GC) only works on 64-bit systems. This section briefly summarizes what we expect from a 64-bit system to be able to use our scheme.

JSC is optimized for x86-64 and ARM64. This scheme assumes the weaker of the two memory models (ARM64) and assumes that the following atomic instructions are inexpensive enough that it’s practical to use them as an optimization over locking:

  • 64-bit loads and stores are atomic by default. We expect that these accesses may be reordered around other accesses. But we also expect that if memory access instruction B has a dataflow dependency on memory access instruction A, then A will always come before B. For example, in a dependent load chain like a->f->g, a->f will always execute before _->g.
  • 64-bit CAS (compare-and-swap). JSC uses 64-bit words for JavaScript properties and two important meta-data fields in the object header: the type header and the butterfly pointer. We want to be able to atomically CAS any JS property and either of the meta-data properties in the object header.
  • 128-bit DCAS (double-word compare-and-swap). Sometimes, we will want to CAS all of the meta-data inside JS objects, which means CASing both the 64-bit type header and the adjacent 64-bit butterfly pointer.

Per-Object Locking

Each object in JSC already has a lock, which we use to synchronize certain fundamental JavaScript operations with the garbage collector. We can use this lock to protect any operations that need to be synchronized between JavaScript threads. The rest of this post deals with optimizations that allow us to avoid this lock. But let’s consider exactly what the cost of the lock is. Our internal object lock algorithm requires an atomic compare-and-swap (CAS) and a branch for locking, and another CAS and branch for unlocking. In the best case, CAS is like executing at least 10 cycles. This is the amortized cost assuming the CAS succeeds. On some hardware, the cost is much higher. Assuming a branch is one cycle, this means at least 22 extra cycles for each object operation that requires the lock. Some rare operations are already expensive enough that 22 cycles is not bad, but many fast path operations would not be able to handle such overhead. Below we consider some operations and how much they would be affected if they had to use locking.

  • Adding a new property currently requires only one load, a branch, and two stores on the optimized fast path. Each of those operations is a single cycle, leading to about 4 cycles total in the fastest case. Adding locking bloats this to 26 cycles – a ~7x slow-down. In some cases, adding a new property can be optimized down to just a single store. In those cases, adding locking creates a 23x regression.
  • Changing the value of an existing property requires a load, a branch, and a store. That’s 3 cycles in the fastest case. Adding two CASes and two branches bloats this to 25 cycles – a 8x slow-down. In some cases, we can optimize a property store to just one store instruction. Putting locking around it is a 23x regression.
  • Loading an existing property’s value requires a load, a branch, and another load. Adding locking is a 8x slow-down, or 23x in the case where we optimized the load to just a single load instruction.
  • Deleting a property is already slow. We are fine with putting locks around it. Deleting properties is relatively rare, but we have to support it.
  • Dictionary lookups — JSC-speak for property accesses that we execute dynamically without any inline cache or compiler smarts — will see a small overhead from locking. Those code paths are already expensive enough that adding locking to them is unlikely to be a problem.
  • Snapshotting the set of properties does not change. It’s already possible for concurrent threads to snapshot the set of properties of any object in JSC because of locking that we implemented for concurrent garbage collection.

While some operations like deletion are already expensive enough that locking is not a problem, we don’t believe it’s practical to add such extreme costs to the fast cases of JavaScript object access. The resulting programming language would be too slow.

Designing a fast concurrent JS implementation requires introducing new algorithms for property accesses that can run concurrently to each other without requiring any locking except in rare cases. In the sections that follow, we describe such an algorithm. First we review JavaScriptCore’s object model. Then we show cases where JavaScriptCore’s object model already behaves as if it had fixed-size objects; those cases never require locking. Next we show a technique called segmented butterflies, which allows for mostly wait-free concurrent object access. By itself, this technique is still too expensive for our tastes. So, we show how to infer which object types are transition-thread-local (TTL) to avoid synchronization when transitioning objects. This allows us to use flat butterflies (our existing object model) for the majority of objects. Then we describe how to handle deletion, dictionary lookups, inline caches, arrays, and thread-unsafe objects.

JavaScriptCore Object Model

The JavaScriptCore Object Model. JavaScript values and object pointers are implemented as pointers to the cell. The cell never moves and never changes size, but contains a pointer to the butterfly, which can grow either left (for named properties) or right (for array elements).

JavaScriptCore’s object model allows for four kinds of state, each of which is optional:

  • Native state represented using ordinary C++ objects.
  • Data for named object properties (like o.f) that we statically guessed the object would have.
  • Data for named object properties that were added dynamically, forcing us to change the size of the object.
  • Data for indexed object properties. These can change the size of the object in many ways.

The first two kinds of state does not involve resizing the object. The last two kinds of state require resizing. In JSC, fixed-sized state is stored directly in the object’s cell. The cell is what a pointer to an object points to. Within the cell, there is a butterfly pointer that can be used to store dynamically-allocated and resizable state in a butterfly. Butterflies store named properties to the left of where the butterfly pointer points inside out-of-line slots, and indexed properties to the right as array elements. Each of those locations may store a tagged JavaScript value, which may be a number, pointer to another cell (representing a string, symbol, or object), or a special value (true, false, null, or undefined).

Every object has a structure, which contains the hashtable used for mapping property names to slots in the object. Objects typically share a structure with other objects that look like it (that have the same properties in the same order, among other requirements). The structure is referenced using a 32-bit index into a structure table. We do this to save space. The indexing and cell state bytes have some spare bits. We used two spare bits in the indexing byte to support per-object locking. We also have spare bits in the butterfly pointer, since pointers don’t need all 64 bits on a 64-bit system.

Butterflies are optional. Many objects don’t have a butterfly. When a butterfly is allocated, each of the two sides are optional. The left side of the butterfly holds the out-of-line slots. It’s possible just to allocate that; in this case the butterfly pointer will point 8 bytes to the right of the end of the butterfly’s memory. The right side of the butterfly holds the array elements and the array header. The public length is the length as it is reported by array.length, while the vector length is the number of array element slots that were allocated.


Within this object model, accesses to anything in the cell itself are atomic by default, just like accesses to objects in Java are atomic by default. This is a big deal, since our optimizer is generally successful at putting the most important object fields inline in the cell. Concurrent JS programs that mostly rely on data that ends up inside the cell will experience almost no overhead versus their serial equivalents.

Additionally, if we know that the butterfly won’t be reallocated ever again (i.e. the butterfly pointer is immutable), then we can access it directly without any problems. Those accesses will be atomic by default.

Alternatively, if we know that only the current thread will ever resize the butterfly and all other threads will only read it, then accesses to the butterfly will be atomic by default.

Problems happen when one thread attempts to transition the object (i.e. add a property and/or reconfigure the butterfly) while some other thread is writing to it (or also transitioning it). If we used our current implementation of object accesses in a concurrent setting, a transition on one thread could cause races that lead to behavior that does not conform to our proposed specification.

  • Writes made by another thread could disappear or experience time travel. This race happens because the transitioning thread might first complete a copy of the butterfly and then transition the object, while another thread does some more writes to the object in between those two steps. If a third thread is observing what is going on by repeatedly reading the state of the fields being written, then it will first see the state before any writes, then it will see the writes, and then once the transition completes it will see the original state again.
  • Two transitions performed concurrently could cause the butterfly pointer and the object’s type to be mismatched. The butterfly’s format is determined by fields in the object’s header that are not inside the same 64-bit word as the butterfly pointer. We cannot allow the butterfly and the header to get out of sync, as this would lead to memory corruption.
  • Two transitions performed concurrently can cause some minor heap corruption even if the butterfly is not involved. If a transitions involving an inline property proceeds as two steps — first, change the object’s type, and then, store the new property — then two racing transitions adding two different properties may result in one property being added, where its value ends up being the intended value of the other property. For example, a race between o.f = 1 and o.g = 2 could result in o.f == 2 and "g" in o == false.

In the next section we show how to create an object model that has no such races, but comes with some cost. After that, we show how to use TTL inference to use our existing object model most of the time even in programs that share objects between threads.

Segmented Butterflies

Transitioning an object means allocating a new butterfly, and copying the contents of the old butterfly into the new one while other threads may be reading or writing the old butterfly. We want the copy to seem as if it had happened in one atomic step. Lots of research has gone into supporting concurrent copying of objects in the context of real-time garbage collectors. The approach that we propose to use is based on the Schism real-time garbage collector‘s arraylet object model. This section reviews the Schism arraylet object model and then shows how it can be used for butterfly transitions.

Schism was trying to solve the problem of implementing a copying garbage collector whose copying phase was completely concurrent to the application. It was based on the observation that copying an object concurrently to other threads accessing the object is easy if the object is immutable. It’s only hard if the object can be written to by the other threads. Schism solves the problem of copying mutable objects concurrently by boxing the mutable state in small fixed-size fragments (32 bytes in the paper). The object that gets copied is the spine that serves as an index for finding fragments. All object accesses use an extra indirection to find the fragment that contains the data being accessed. Spines are immutable objects because the fragments they point to never move.

WebKit already uses something like arraylets as well, in the WTF::SegmentedVector class template. We use it to prevent having to move C++ objects when the vector resizes. We also use it for implementing the JSGlobalObject‘s variable storage (for var statements in global scope). The term arraylets is due to Bacon, Cheng, and Rajan, who used them to control fragmentation in the Metronome garbage collector. Lots of arraylet research shows that the extra indirection has a high cost (often 10% or more). That is, if you double the cost of each array access by adding an extra indirection, then you will increase the total run time of the program by 10%.

Segmented Butterflies. A segmented butterfly comprises a spine (which resizes but contains only immutable state) and zero or more fragments (which don’t resize but are mutable). Splitting resizable state from mutable state to enable concurrent layout changes is a proven technique in concurrent garbage collection. The shape of the fragments matches the shape of an unsegmented butterfly, which we will use for some additional optimizations.

We can use this trick for butterflies. A segmented butterfly has a spine that contains pointers to fragments that contain mutable data. If we need to add new properties and those properties won’t fit in an existing fragment, we can grow the spine and allocate more fragments. Growing the spine implies reallocating it. We can safely allocate a new spine and memcpy the contents of the old one into it, since the spine’s contents never changes. In this world, no writes ever get lost or experience time travel when a butterfly is being transitioned. An access that races with the transition either gets to a fragment using the old spine, or the new spine; since both spines will contain the same fragment addresses for properties that existed before the transition, every possible interleaving results in threads reading and writing the same fragments.

The most natural way to implement segmented butterflies is probably to have 32-byte fragments like in Schism, since this is also a sweet-spot for our GC. The vector length is be inside the butterfly spine, since this is an immutable property of that spine. The vector length allows the spine to self-identify how big its right side is. The public length is mutable, so we want to put it into one of the fragments. Note that the first fragment also contains the old vector length. This property is unused when we are using segmented butterflies. It allows us to convert a flat butterfly into a segmented butterfly by having the spine point at slices of the flat butterfly; we discuss this optimization more in a later section.

This still leaves the problem of concurrent transitions. Transitions have to reallocate the spine, change some data in the type header, and store a property’s value. Reallocating the spine is optional since usually some fragment will already have a spare slot. Changing the type is optional, for example in case of array resizing. The type header and butterfly can be set atomically using a DCAS (double-world compare-and-swap; 64-bit systems typically support 128-bit CAS). But this isn’t enough, since no matter if we set the property’s value before or after the DCAS, we will have a race. The property’s slot can be anywhere in memory, so there’s no way to use CAS to simultaneously do the whole transition.

If we set the newly-added value slot before changing everything else, we risk a race in which one thread tries to use some object slot for adding field f while another thread tries to use the same slot for field g. If we’re not careful, the second thread might win the race for the type (so everyone thinks we added property g) while the first thread wins the race for the property (so we get thread 1’s intended value for property f appearing as if it was stored by thread 2 into g).

If we set the newly-added value slot after changing everything else, then all loads have to contend with the possibility that slots can have “holes”. In other words, at any time, an object may claim a type that includes a property f even though the object does not have a value for f yet. We could change the language to allow this: putting a new property into an object would first involve defining it to undefined and then storing the real value.

We choose to put a lock around transitions. This lock isn’t for guarding races between transitions and other accesses, since those are atomic by default thanks to segmented butterflies — it’s for protecting transitions from each other. To ensure that objects don’t have holes, transitions store the new property’s value before changing the type. Transitions can use this algorithm:

  1. Allocate whatever memory needs to be allocated.
  2. Acquire the lock.
  3. Determine if we allocated the right amount of memory; if not, release the lock and go back to step 1.
  4. Store the new property’s value.
  5. Change the type and butterfly.
  6. Release the lock.

This results in the following cost model:

  • Transitions are about 7x costlier, since they now require locking.
  • Reading or writing existing property slots requires an extra load.
  • Deleting and dictionary lookups still work (we show details in a later section).

Recall that the arraylet research shows 10% or higher costs if arrays use a segmented object model. We’re proposing to use it for ordinary properties as well, if those properties were added in a sufficiently subtle way that we weren’t able to inline them into the cell. It’s probably safe to assume that if we implemented literally this, we incur at least a 10% slow-down. We would like to have close to zero overhead. The next section shows how we think we can get there.

Transition Thread Locality and Flat Butterflies

Segmented butterflies are only necessary when:

  • Some thread other than the thread that allocated an object tries to transition the object.
  • The thread that allocated the object tries to transition it, and other threads may be writing to it.

We can use flat butterflies — our existing object model — when we know that these things haven’t happened yet. This section describes a hybrid object model that uses either flat or segmented butterflies, depending on whether or not we have detected a possible write-transition race. This object model also allows us to avoid locking while doing many transitions.

On a 64-bit system, butterfly pointers have 48 bits of pointer information and have zeroes in their high 16 bits. 16 bits is enough to store:

  • The ID of the thread that allocated the object. We call this the butterfly TID.
  • A bit to indicate if any thread other than the allocating thread has attempted to write to the butterfly. We call this the butterfly shared-write (SW) bit.

Some systems have more than 48 pointer bits. In a later section, we show how to make this scheme useful even if we had to use fewer bits. Also, we could restrict butterfly allocations to the lower 248 addresses if we really wanted 16 spare bits.

Let’s say that these bits are encoded as follows:

static const uint16_t mainThreadTID = 0; // Occassionally, we can optimize a bit more for the main thread.
static const uint16_t notTTLTID = 0x7fff; // For when the thread is no longer transition-thread-local.

static inline uint64_t encodeButterflyHeader(uint16_t tid, bool sharedWrite)
    ASSERT(tid <= notTTLTID); // Only support 2^15 tids.
    return (static_cast<uint64_t>(tid) << 48)
         | (static_cast<uint64_t>(sharedWrite) << 63);

static inline uint64_t encodeButterfly(Butterfly* butterfly, uint16_t tid, bool sharedWrite)
    return static_cast<uint64_t>(bitwise_cast<uintptr_t>(butterfly))
         | encodeButterflyHeader(tid, sharedWrite);

We can use flat butterflies — our existing object model — whenever the TID matches the current thread. We set the SW bit and use a magic TID value (all bits set) to indicate that the butterfly is segmented. This section shows how to use these bits to allow the use of flat butterflies anytime we know that no transition race can occur. We call this transition thread locality inference.

Anytime a thread attempts to write to a butterfly and the TID matches the current thread, it can simply write to the butterfly without doing anything special.

Anytime a thread attempts to write to a butterfly, the TID does not match, but the SW bit is set, it can simply write to the butterfly as well.

Anytime a thread attempts to read a butterfly, it just needs to check that the TID to determine if the read should be segmented (extra indirection) or not.

Anytime a read or write encounters TID = notTTLTID and SW = true, it knows to use the segmented object model.

The following cases need special handling:

  • A thread other than the one identified by the TID attempts to write to the butterfly and the SW bit is not yet set. In this case, it needs to set the SW bit. This does not mean that the butterfly needs to become segmented. It only means that the SW bit must be set, so that any future attempts to transition the butterfly from the owning thread triggers a transition to the segmented butterfly object model.
  • A thread other than the one identified by the TID attempts to transition the butterfly. In this case, it needs to set the SW bit and all TID bits and perform a segmented butterfly transition. We describe this process in detail below.
  • A thread attempts to transition a butterfly that has the SW bit set. This also necessitates a segmented butterfly transition.
  • Even transitions with TID = current and SW = false need locking, to make sure that those assumptions aren’t violated during the transition.

The sections that follow show further refinements that reduce overhead even more. First we consider how to avoid checking TID and SW bits on every operation. Next we show how to use structure watchpointing to avoid locking on the most common transitions. Then we show how to handle array resizing. Finally we explain in more detail how flat butterflies can be transitioned to segmented ones.

Quickly Checking TID And SW Bits

This section will show how to make concurrent JS as fast as serial JS in many of the most important cases by simply extending optimizations that JavaScriptCore already uses.

JSC optimizes the code for heap accesses using inline caching. We use inline caches for accesses to named properties (like o.f) and for array accesses (like a[i]).

Objects that have the same properties at the same offsets will usually share the same structure, which is identified by 32 bits in the object’s type header. If a property access tends to see the same structure, then we will generate new machine code for this property access, which checks that the object has the expected structure and then accesses the property directly. Failed speculation causes recompilation of the inline cache. If the inline cache remains stable (doesn’t recompile much) for a long time and the function that contains it becomes eligible for optimized JIT compilation, then the optimizing JIT compiler might express the inline cache’s code directly in its IR, which has two outcomes: the structure check branches to OSR exit if it fails (causing abrupt termination of the optimized code’s execution), and all of the code for the inline cache (the structure check, the memory access, and any other steps) become eligible for low-level optimization by our DFG and B3 JIT compiler pipelines. Our compilers are good at making type-stable JavaScript property accesses perform great.

Array accesses use similar techniques to detect if an object has array elements, and if so, how they are formatted. We support multiple kinds of storage for array elements depending on how they are being used. Inline caches detect what kind of array each array access is accessing, and we then emit code that speculates for that kind of array access.

Another technique we already use is virtual memory. For example, our WebAssembly implementation uses virtual memory tricks to check the bounds of linear memory accesses for free. We can catch page faults using POSIX signal handlers or Mach exceptions. The handler will know the exact machine state at the point of the fault, and has the power to transfer execution to any state it likes. WebAssembly uses this to throw an exception, but we can use it to transfer control flow to slow paths that handle the generic case of a memory access. Essentially, this means that we can save cycles on safety checks if we can express the condition being checked as something that causes the virtual memory system to issue a page fault. Concurrent JS will require a combination of inline caching and virtual memory tricks to make TID and SW checking cheap.

Inline caching means emitting different code for each property access, and then recompiling each property access potentially many times as we learn new information about what this property access may do. Inline caches are able to get incredibly precise information about the behavior of each property access because we always emit a fast path access that can only handle exactly those cases that we have seen so far. We learn new information by recording everything we know about those accesses that failed the fast path. The complete log of failed accesses is then LUBed (least-upper-bounded) together to create a minimal set of AccessCases. We can implement optimizations for new kinds of property accesses — such as the ones that have to check TID and SW bits — by considering in what ways a particular access site might be special and so specially optimizable. Below is a list of conditions we may encounter along with the strategy for how inline caches can test this condition and handle it.

  • Probably many object accesses will always see TID = current and SW = false. These accesses can simply subtract encodeButterflyHeader(currentTID, 0) from the butterfly before accessing it. If the speculation was wrong, the virtual memory subsystem will issue a page fault because of non-zero high bits. We can catch this as a Mach exception or POSIX signal, and divert execution to the slow path. The subtraction of this constant can often be encoded directly into the subsequent butterfly access instruction. As a result, these kinds of accesses will not experience any overhead in concurrent JS versus what they have currently. Note that this optimization does not apply to transitions, which must install a new butterfly while atomically asserting that nothing bad has happened — we consider those further below. Note that this optimization slightly favors the main thread (and so all single-threaded programs) because if currentTID = 0 then we don’t have to add anything.
  • Probably many object accesses will always see TID = current and SW = true. These can be optimized identically to the previous case. This state is for objects that we already know can be written to from many threads, but that only happened after the last time that the current thread transitioned the object.
  • Probably many object reads will see TID != notTTLTID and SW = anything. These just need to check that the butterfly’s high bits are not notTTLTID. This can be done with a single compare/branch. Other than this, they can proceed exactly how they do in our current engine.
  • Probably many object writes will see TID != notTTLTID and SW = true. This means that the object is being written to by many threads. We are also writing to it, but we don’t need to set the SW bit because it is already set. This check can also be performed in a single compare/branch. Together with the read optimization above, this means that concurrent JS programs that share objects will typically only experience one extra cycle (for fused compare/branch) for butterfly accesses.
  • Sometimes, an object write will see TID != notTTLTID and SW = false. This means having to set the SW bit using a DCAS, which sets the SW bit while asserting that the type header did not change. These accesses will be more expensive than their friends, but this only has to happen the first time that any thread writes to a shared object. Our inline caching infrastructure will probably make it so that writes that sometimes see SW = false and sometimes see SW = true (and don’t necessarily see TID = current but never notTTLTID) will be branchy: they will have a fast path for SW = true and a slightly slower but still inline path for SW = false. In the next section, we will describe optimizations that require invoking functions on the structure when the SW bit of any objects of that structure gets set for the first time. Since this inline cache knows about the structure at the time of generation, it can ensure that the structure is already informed that objects of its type may have the SW bit set.
  • Probably some object accesses will see TID = notTTLTID and SW = true. By convention, we’ll say that it’s not possible to have TID = notTTLTID and SW = false (internally in our VM, it’s technically possible to transition an object without “writing” to it, but we’ll pretend that those are writes anyway). These accesses can subtract encodeButterflyHeader(notTTLTID, true) from the butterfly before accessing it, and then they must perform an additional load when reading from the butterfly. The extra load is necessary because of the segmented object model: the butterfly pointer points at a spine that we can use to find the fragment that contains the value we’re interested in. This is somewhat more than one extra cycle of overhead, since it introduces a load-load dependency.

These optimizations leave an unresolved issue: transitions. Transitions now require acquiring and releasing a lock. We have to do this anytime we add any property. In the next section, we show how to solve this problem using watchpoints. Then we describe how to implement transitions that need to create a segmented butterfly out of a flat one.

Watchpoint Optimizations

Transitions are difficult to optimize. Every transition, including those that see TID = current, need to acquire the object’s internal lock to ensure that they set the butterfly, adjust the object’s type header, and store the new value of the property all in one atomic step. Luckily, we can dramatically improve the performance of transitions by using our engine’s structure watchpointing infrastructure.

Each object has a structure. Many objects will share the same structure. Most inline cache optimizations begin with a check to see if the object’s structure matches the inline cache’s expectations. This means that when an inline cache is compiled, it has a pointer to the Structure object in hand. Each structure can have any number of watchpoint sets in it. A watchpoint set is simply a boolean field (starts valid, becomes invalid) and a set of watchpoints. When the set is fired (the field goes from valid to invalid), all watchpoints are invoked. We can add two watchpoint sets to Structure:

  • transitionThreadLocal. This remains valid so long as all objects that have this structure have TID != notTTLTID.
  • writeThreadLocal. This remains valid so long as all objects that have this structure have SW = false.

This enables the following optimizations on top of the inline cache optimizations described above:

  • Transitions with TID = current and SW = false can proceed as they do in our existing engine so long as the structure’s transitionThreadLocal and writeThreadLocal watchpoint sets are both still valid. This means not doing any extra locking or even CAS when transitioning the object. This works even if other threads are concurrently reading from the object. This works even when building up an object that eventually gets read and written to from other threads, since in that case the writeThreadLocal watchpoint set only fires on the structure that is the target of the final transition used to build the object. The last transition can proceed without locking because the watchpoint sets of the source of the transition are still valid.
  • Any checks for TID != notTTLTID can be elided if the structure’s transitionThreadLocal watchpoint set is still valid and a watchpoint is installed.
  • Any checks for SW == false can be elided if the structure’s writeThreadLocal watchpoint set is still valid and a watchpoint is installed.

The fact that we can elide TID != notTTLTID and SW == false checks means that reads and writes to those objects don’t actually have to check anything; they just need to mask off the high bits of the butterfly.

Most importantly, this means that transitions that happen on the same thread that allocated the object don’t need any locking so long as the structures involved have valid transitionThreadLocal and writeThreadLocal watchpoint sets. Structures are dynamically inferred by our engine so as to have a close relationship to the code that creates those objects. Hence, if you write a constructor that adds a bunch of fields to this but does not escape this, then the structures corresponding to the chain of transitions that occurred in the constructor will all have a valid transitionThreadLocal and writeThreadLocal watchpoint sets. To make sure that the object continues to have a flat butterfly, you need to either never dyamically add properties to the object, or never write to the object on any thread other than the one that constructed it. Objects that play by these rules will experience almost no concurrency overhead, since property accesses will have at most one extra instruction (a mask) on the fast path.

Watchpoints, and the operations that cause them to fire, will execute under safepoint: if we ever perform some operation that finds that it has to invalidate a watchpoint, it will do the operation while all other threads are stopped as if for a garbage collection. This means that if some optimized code is performing non-atomic transitions involving some structures, and some other thread attempts to write or transition an object that uses any of those structures, then it will not actually perform the write until that optimized code reaches a safepoint and gets invalidated. Most of the time, the watchpoint sets will tell us that they have been invalidated even before the optimizing JIT compilers try to install any watchpoints. We expect few watchpoint invalidations in steady state.

To summarize, if our optimizer is able to guess which object properties you will add to an object at the time of allocation, then the cost model of your object accesses does not change at all, since inline properties get concurrency for free. If you do have out-of-line properties, then they will perform almost exactly as they do now (occasionally, an extra arithmetic instruction will be involved in computing the butterfly access) so long as either the object is only written to by the thread that created it (and read by anyone), or no new properties are added to the object after creation (in which case it can be read and written by anyone). If you break this pattern, then transitions will become about 7x more expensive and all other object accesses will become 2x more expensive. This slow-down will be extremely surgical: only those property accesses that touch segmented butterflies will experience the slow-down. This system is designed to let you dynamically and concurrently add stuff to your objects, and the hope is that if you do so in moderation, you won’t see much of a change in performance.


Array element accesses will benefit from TTL similarly to the way that named property accesses do:

  • Accesses to TTL arrays will be about as fast as they are now.
  • Accesses to non-TTL arrays will require one extra indirection.

We handle array transitions a bit specially. Many array transitions in JavaScriptCore already use locking because of their need to avoid races with the garbage collector. Adding locking to the remaining array transitions may cause performance issues, so this section considers an alternative.

Resizing an array in response to an out-of-bounds store or something like array.push is the most common kind of array transition. Fortunately, this transition does not change anything in the type header of the object — it only changes the butterfly pointer. Whether or not the butterfly has array elements is reflected in the structure. Therefore, we can just use CAS on the butterfly pointer, and then have a rule that any changes to butterfly pointers of objects that have array elements requires CAS even if the object lock is already held. Because array structures’ transitionThreadLocal and writeThreadLocal watchpoints are unlikely to be intact (any shared array use will invalidate them, since arrays share structures), we expect that even transitions on TTL arrays will have to use CAS in the common case. This butterfly pointer CAS is sufficient to ensure that a simultaneous attempt to make the array not TTL won’t get confused by our resize operation.

One CAS for array resizing is probably cheap enough to be practical. The CAS is likely cheap relative to the current costs of resizing, which involves allocation, copying data, and initializing the newly allocated memory.

Objects that have both named properties and array elements will now have to use both locking and CAS on some of the transitions involving named properties. Fortunately, objects that have both array elements and named properties are sufficiently uncommon that we can probably get away with increasing their named property transition cost a bit.

Quickly Transitioning From Flat To Segmented

Turning flat butterflies into segmented ones requires a special kind of transition. Fortunartely, this transition is cheap. Butterfly fragments contain only data. They look just like fragments (fixed-size slices) of the payload of a flat butterfly. Therefore, we can transition a flat butterfly to a segmented one by allocating a spine and pointing its fragment pointers at the original flat butterfly.

Any read or write to the flat butterfly while the butterfly is being transitioned to segmented will seem to users of the segmented butterfly to have happened to the fragments. In other words, although some threads may mistakenly think that the butterfly is still flat, their accesses to that butterfly will still be sound even after the butterfly is already segmented.

Making this work right requires making sure that the segmented butterfly’s fragments share the same memory layout as the flat butterfly that they were converted from. For this reason, the first array fragment contains the public length and the old vector length; it will remember the vector length that the flat butterfly used forever, and the real vector length will be in the segmented butterfly’s spine. This ensures that if there is a race between a flat butterfly array access and a flat-to-segmented transition, then the flat butterfly access will correctly know the flat butterfly’s size because its vector length will not change. To line up the object models, we also store out-of-line properties in reverse order in the out-of-line fragments, to match what flat butterflies do.

This works so long as the flat butterfly accesses loaded their butterfly pointer before the transition occured. If they load it later, then their TID check will fail, probably in the form of a page fault on an access to the butterfly.

Deletion and Dictionary Lookups

JavaScriptCore tries to make objects share structures whenever possible. This relies on two properties of structures:

  • Structures are immutable.
  • When a new structure is needed, we generally hash cons it.

This is a great optimization if it indeed causes objects to reuse structures. But some objects will have a unique structure no matter what the VM tries to do about it. JavaScriptCore tries to detect when this happens, and puts the object in dictionary mode. In dictionary mode, the structure has a 1:1 mapping to the object. Also, the structure becomes mutable. Adding and removing properties means editing the structure and the object in tandem.

Deletion is closely related to dictionary mode, since deletion will immediately put the object in dictionary mode.

It’s already the case that mutations to a dictionary require holding the structure’s lock. This is necessary to support concurrent JIT and concurrent GC.

To support concurrent JS, we only need to make these changes:

  1. Reading from a dictionary requires holding the structure’s lock, in case some other thread is changing the dictionary.
  2. Properties added before the object entered dictionary mode must be treated specially by deletion.

We are not worried about the performance hit of grabbing a lock for all reads of a dictionary. It’s already relatively expensive to read a dictionary.

The existing facilities for safely transitioning objects will naturally support transitioning to dictionary mode. Usually, dictionary transitions don’t involve deleting properties. They happen when we detect that the program is adding so many properties to the object that it’s probably going to perform better as a dictionary. In that case, the fact that some other thread may be in the middle of accessing this object without holding any locks does not matter. For non-dictionary objects we require that only transitions take the lock. Reads and writes involve separate steps for checking the object’s type, loading the butterfly, and then accessing the butterfly. But if none of the properties that were added before the dictionary transition get deleted, then it’s fine for some other thread to race when accessing those old properties. We will call this the phenomenon of tardy accesses. Even though those tardy accesses don’t do any locking, they are correct for the same reasons that they are correct before the object becomes a dictionary. That problem is up to the butterfly object model, which will be either flat or segmented depending on whether the object is still TTL. Dictionary mode operates orthogonally to TTL inference and butterflies.

But if any of the properties added before the dictionary transition get deleted, then we have to handle this deletion specially. Normally, deletions cause the deleted slots to become reusable. We cannot do this here, because then a tardy read to some deleted property f might end up reading the value of some newly added property g. Or, a tardy write to some deleted property f might end up overwriting the value of some newly added property g. We can prevent either of these bad outcomes by simply not reusing the space freed up by deleted properties, if those properties had been added before the dictionary transition.

This does not lead to unbounded memory usage. When the GC does its safepoint, it already knows that all memory accesses have completed. Therefore, the simplest implementation is to have GC change the state of those deleted properties when it visits the object. Once the GC flags those property slots during a safepoint, future property additions can reuse those slots.

Inline Caches

Once we enable concurrency, recompiling an inline cache becomes harder because you need to be careful when changing code that may be currently executing on another CPU. We plan to have a tiered defense against this problem: we will infer the thread-locality of code to use the same inline caches as we do now as much as possible, we will buffer inline cache changes whenever it’s safe to do so, and finally we will rely on safepoints if an inline cache needs to be reset eagerly.

We expect that in many programs, inline caches will reach steady state before the code ever executes on more than one thread. Hence, we plan to have each block of code track its thread-locality. So long as it has only ever executed on one thread, it will remember this and check for it on entry. So long as this is true, any inline caches within that code can be modified without any extra synchronization. We can track thread-locality on as fine-grain a level as we like; for example it can even be per-basic-block. It’s probably most natural if we use JavaScriptCore’s notion of CodeBlock as the granularity; this roughly corresponds to functions in the source code.

Once the thread-locality of code is broken, we can switch to buffering inline cache changes. Our PolymorphicAccess inline cache infrastructure already buffers changes because that’s most efficient even if we don’t have to do expensive synchronization. For inline caches that may be executing globally, we can globally buffer all changes. For example, the VM can perform once-per-millisecond safepoints to flush changes to all global inline caches.

Sometimes, we need to make an immediate change to an inline cache. When this happens, we will rely on our ability to safepoint the system — i.e. to stop all threads at a point where we can account for each thread’s state. This is not a fast operation when there are many threads. Java virtual machines already have to do something like this for class hierarchy invalidation and biased locking. By design, these eager invalidations are unlikely. We only perform optimizations that can lead to eager invalidations if we have profiling data that suggests that it would be unlikely.

Local Optimizer Lock

So far, this algorithm relies on being able to sneak 16 bits of information into the high bits of the butterfly pointer. Some hardware will not allow us to do this. For example, fewer than 16 high pointer bits may be used for the all-zero check in virtual memory. If the system only allows for 8 checked high bits, then we will only be able to support 127 threads. Concurrent JavaScript would probably still be useful even if it had a hard 127 thread limit, but this would be an unusually low limit to impose at the language level. This section shows how to overcome this limit.

If the object model can only handle thread-locality inference for 127 threads, then we can either choose to have the 127th thread get no thread-locality inference or we can try to map more than one logical thread onto the same thread identifier. Threads mapped to the same TID won’t be able to execute concurrently to each other. To do this, we can borrow the idea of the GIL (global interpreter lock) from Python. The CPython implementation only allows 1 native thread to interpreting Python code at a time. It achieves this by having a lock (the so-called GIL) that protects the interpreter. The lock is released and reacquired periodically, which gives the appearance of concurrency. Since we can also release the lock around any potentially-blocking operations, we can even avoid deadlocks that arise from insufficient concurrency. We can apply this technique here: if we are limited to 127 threads, then we can have 127 locks protecting JS execution. So long as there are 127 or fewer threads, this lock will not do anything; anytime we try to release it, we will do nothing because the lock will tell us that nobody is waiting to acquire it. “Releasing and reacquiring” the lock will really be a cheap load and branch to verify that there is no need to release it.

This lock will be local to a thread pool rather than global to the whole engine, and it will protect all of our optimized paths rather than just protecting the interpreter. Hence the name: local optimizer lock, or LOL for short.

Thread-Unsafe Objects

DOM objects behave like JavaScript objects, but are actually a proxy for complicated logic implemented in C++. That logic is usually not thread-safe. The native code that supports the DOM transitively uses many native APIs that are meant to only be used from the main thread. It would take a lot of work to make the DOM completely thread-safe. Our strawman proposal only requires making the DOM global object capable of handling lookups to self properties, which we need to allow threads to access global JavaScript properties like Object and Thread.

In WebKit, variable resolution and self property resolution on the JSDOMWindow largely follows a pattern of relying on existing JS property lookup mechanisms. It uses exotic behavior when the window has a null frame. We already support installing a watchpoint on the non-nullness of frame. Hence, we can support fast concurrent accesses to properties of JSDOMWindow while honoring the frame special case by having threads use the existing watchpoint set. This implies that some of the JSDOMWindow slow paths will need locking, but that’s probably acceptable since the majority of global object accesses are inline cached.

Native apps that want to dip their toes into concurrent JS may also want to restrict sharing for some of their classes. The thread-affinity check on accesses to objects will need to be implemented in the VM itself to give our compilers the ability to optimize it away. This means that it’s possible to expose the functionality to C/Objective-C API clients.


We think that we can make it possible to execute JavaScript concurrently in WebKit while providing good enough performance that developers would enjoy using this feature. At the heart of this technique is the combination of segmented butterflies, transition thread locality inference, and lots of cheap per-object locks. So long as programs obey certain behaviors, they should experience minuscule overheads: property accesses will cost about as much as they do today and objects will not require any extra memory. If some objects decide that they don’t want to play by our rules, they will get slightly higher overheads.

Related Work

Segmented butterflies are a straightforward combination of the array object model in the Schism garbage collector and the butterfly object model that we have used for a long time in JavaScriptCore.

Transition-thread-locality inference is inspired by work on biased locking. As in the HotSpot biased locking scheme, we use types to reason about whether we have a guarantee of thread locality. Unlike that scheme, we don’t rely on deoptimization to break a thread-object relationship. Our primary mechanism of informing other threads that an object is no longer transition-thread-local is to have different tag bits in the butterfly pointer.

The combination of segmented butterflies, transition-thread-locality inference, and the ability of both schemes to fall back on per-object locking when things get weird is not something that we have seen before. Most object-oriented systems that allow concurrency do it either by having an object model that naturally avoids expensive-to-resolve races, like in Java, or using some mechanisms to restrict the amount of concurrency in the language.

For example, CPython uses a global interpreter lock (GIL) to ensure that the interpreter never races with itself. This is a powerful technique that captures some of what concurrency is about: once I/O or other kinds of blocking happen, you want your other threads to be able to do some useful work in the meantime. The GIL allows this, so it makes threads useful to a large class of applications. Unfortunately, it doesn’t allow programs to exploit parallelism. The best feature of the GIL is that it is easy to implement. For example, it could be used to implement our proposed thread semantics in any JS engine. The scheme in this post is all about full concurrency optimized for 64-bit platforms.

An effort called the Gilectomy is underway to remove CPython’s GIL and replace it with fine-grained locking and clever atomic algorithms. The Gilectomy is not yet as fast as stock CPython; both single-thread and multi-thread programs run significantly slower in the Gilectomy. The performance problems appear to be related to locking in the allocator (we plan to use thread-local allocation buffers) and in the reference counter (we don’t have reference counting). The Gilectomy does not remove locking from accesses to objects. Like JavaScript’s objects, Python’s objects are dictionaries that can resize dynamically. Most of our scheme is about how to make accesses to those objects fast even when multiple threads are reading and writing to the same object.

PyPy also has a GIL removal effort underway, but they haven’t said much about how they plan to handle synchronizing object accesses aside from using locks. We will also have locks, but we also came up with optimizations to avoid locking in most cases.

Another approach was the title locking scheme in SpiderMonkey. It has since been removed. That scheme also involved per-object locks, but did not have our optimizations for avoiding locking in most cases.

Daloze, Marr, Bonetta, and Mossenbock propose a scheme for concurrency in Truffle, a runtime that supports many dynamic languages including JavaScript. That scheme requires objects that are shared to use synchronization for all writes. Sharing is detected by a write barrier. When a thread-local object is stored into a shared object, the runtime will traverse objects transitively reachable from the escaping object. All of those objects are marked shared so that future writes to those objects use synchronization. Our scheme does not require synchronization on shared writes, except when those writes are transitions. Our scheme does not require traversing object graphs; transition thread locality inference is on a per-object basis. A TTL object may point to a non-TTL object or vice-versa.

Cohen, Tal, and Petrank recently introduced the layout lock, which allows fast reads and writes to objects that may have their layout changed. Readers need an extra load (which has to be fenced or dependent), writers have to acquire a read lock (which can be as cheap as a pair of fenced loads and a branch), and transitions have to acquire a write lock and do some extra book-keeping. We suspect that this has a similar cost model to segmented butterflies, except for writes. Segmented butterflies only require an extra dependent load for writes, which is a bit cheaper than acquiring a read lock, which requires two loads fenced around a store. Fencing loads around a store is inconvenient; for example forcing a store to happen before a load on x86 requires an xchg instruction for the store, which is more expensive than just doing a mov. On ARM it requires using acq/rel variants for the loads and stores. On the other hand, the extra dependent load for writing to a segmented butterfly requires no extra fencing on either x86 or ARM. Transitions and reads are probably equally fast with segmented butterflies and layout locks, but writes matter a lot to us. Writes happen often enough that segmented butterflies are likely to be noticeably faster than layout locks for the JavaScript object model. On the other hand, the method of segmentation is not easy to reproduce in many different kinds of data structures. Since it is more general, the layout lock could be useful for more complex data JSC data structures like SparseArrayValueMap and Map/WeakMap/Set. Those data structures may be too complicated for segmentation, but not too complicated for the layout lock. Like segmented butterflies, layout lock can be combined with transition thread locality inference to avoid doing any of the locking until it’s needed to protect racy transitions.


This post shows how WebKit’s JavaScript implementation can be modified to support threads. Our scheme allows for all JavaScript objects to be shared. Our scheme avoids locking on fast paths, like the fast paths for property accesses. We expect it to be possible to implement this scheme with low overheads. Serial code will experience no overhead, and concurrent code will only experience big overheads if it adds properties to an object that is being written to by multiple threads.

The next step for this wild thought experiment is to attempt to implement it and see if it works. We will be tracking progress under bug 174276.

Update: The original version of this post did not cite Daloze et al’s OOPSLA ’16 paper on concurrency support in Truffle. We have updated the post to include a comparison between our scheme and theirs.

By Filip Pizlo at August 30, 2017 05:00 PM

August 29, 2017

Frédéric Wang: The AMP Project and Igalia working together to improve WebKit and the Web Platform

Igalia WebKit


The AMP Project and Igalia have recently been collaborating to improve WebKit’s implementation of the Web platform. Both teams are committed to make the Web better and we expect that all developers and users will benefit from this effort. In this blog post, we review some of the bug fixes and features currently being considered:

  • Frame sandboxing: Implementing sandbox values to allow trusted third-party resources to open unsandboxed popups or restrict unsafe operations of malicious ones.

  • Frame scrolling on iOS: Trying to move to a more standard and interoperable approach via iframe elements; addressing miscellaneous issues with scrollable nodes (e.g. visual artifacts while scrolling, view not scrolled when using “Find Text”…).

  • Root scroller: Finding a solution to the old interoperability issue about how to scroll the main frame; considering a new rootScroller API.

Some demo pages for frame sandboxing and scrolling are also available if you wish to test features discussed in this blog post.


AMP is an open-source project to enable websites and ads that are consistently fast, beautiful and high-performing across devices and distribution platforms. Several interoperability bugs and missing features in WebKit have caused problems to AMP users and to Web developers in general. Although it is possible to add platform-specific workarounds to AMP, the best way to help the Web Platform community is to directly fix these issues in WebKit, so that everybody can benefit from these improvements.

Igalia is a consulting company with a team dedicated to Web Platform developments in all open-source Web Engines (Chromium, WebKit, Servo, Gecko) working in the implementation and standardization of miscellaneous technologies (CSS Grid/flexbox, ECMAScript, WebRTC, WebVR, ARIA, MathML, etc). Given this expertise, the AMP Project sponsored Igalia so that they can lead these developments in WebKit. It is worth noting that this project aligns with the Web Predictability effort supported by both Google and Igalia, which aims at making the Web more predictable for developers. In particular, the following aspects are considered:

  • Interoperability: Effort is made to write Web Platform Tests (WPT), to follow Web standards and ensure consistent behaviors between web engines or operating systems.
  • Compatibility: Changes are carefully analyzed using telemetry techniques or user feedback in order to avoid breaking compatibility with previous versions of WebKit.
  • Reducing footguns: Removals of non-standard features (e.g. CSS vendor prefixes) are attempted while new features are carefully introduced.

Below we provide further description of the WebKit improvements, showing concretely how the above principles are followed.

Frame sandboxing

A sandbox attribute can be specified on the iframe element in order to enable a set of restrictions on any content it hosts. These conditions can be relaxed by specifying a list of values such as allow-scripts (to allow javascript execution in the frame) or allow-popups (to allow the frame to open popups). By default, the same restrictions apply to a popup opened by a sandboxed frame.

iframe sandboxing
Figure 1: Example of sandboxed frames (Can they navigate their top frame or open popups? Are such popups also sandboxed?)

However, sometimes this behavior is not wanted. Consider for example the case of an advertisement inside a sandboxed frame. If a popup is opened from this frame then it is likely that a non-sandboxed context is desired on the landing page. In order to handle this use case, a new allow-popups-to-escape-sandbox value has been introduced. The value is now supported in Safari Technology Preview 34.

While performing that work, it was noticed that some WPT tests for the sandbox attribute were still failing. It turns out that WebKit does not really follow the rules to allow navigation. More specifically, navigating a top context is never allowed when such context corresponds to an opened popup. We have made some changes to WebKit so that it behaves more closely to the specification. This is integrated into Safari Technology Preview 35 and you can for example try this W3C test. Note that this test requires to change preferences to allow popups.

It is worth noting that web engines may slightly depart from the specification regarding the previously mentioned rules. In particular, WebKit checks a same-origin condition to be sure that one frame is allowed to navigate another one. WebKit always has contained a special case to ignore this condition when a sandboxed frame with the allow-top-navigation flag tries and navigate its top frame. This feature, sometimes known as “frame busting,” has been used by third-party resources to perform malicious auto-redirecting. As a consequence, Chromium developers proposed to restrict frame busting to the case where the navigation is triggered by a user gesture.

According to Chromium’s telemetry frame busting without a user gesture is very rare. But when experimenting with the behavior change of allow-top-navigation several regressions were reported. Hence it was instead decided to introduce the allow-top-navigation-by-user-activation flag in order to provide this improved safety context while still preserving backward compatibility. We implemented this feature in WebKit and it is now available in Safari Technology Preview 37.

Finally, another proposed security improvement is to use an allow-modals flag to explicitly allow sandboxed frames to display modal dialogs (with alert, prompt, etc). That is, the default behavior for sandboxed frames will be to forbid such modal dialogs. Again, such a change of behavior must be done with care. Experiments in Chromium showed that the usage of modal dialogs in sandboxed frames is very low and no users complained. Hence we implemented that behavior in WebKit and the feature should arrive in Safari Technology Preview soon.

Check out the frame sandboxing demos if if you want to test the new allow-popup-to-escape-sandbox, allow-top-navigation-without-user-activation and allow-modals flags.

Frame scrolling on iOS

Apple’s UI choice was to (almost) always “flatten” (expand) frames so that users do not require to scroll them. The rationale for this is that it avoids to be trapped into hierarchy of nested frames. Changing that behavior is likely to cause a big backward compatibility issue on iOS so for now we proposed a less radical solution: Add a heuristic to support the case of “fullscreen” iframes used by the AMP Project. Note that such exceptions already exist in WebKit, e.g. to avoid making offscreen content visible.

We thus added the following heuristic into WebKit Nightly: do not flatten out-of-flow iframes (e.g. position: absolute) that have viewport units (e.g. vw and vh). This includes the case of the “fullscreen” iframe previously mentioned. For now it is still under a developer flag so that WebKit developers can control when they want to enable it. Of course, if this is successful we might consider more advanced heuristics.

The fact that frames are never scrollable in iOS is an obvious interoperability issue. As a workaround, it is possible to emulate such “scrollable nodes” behavior using overflow: scroll nodes with the -webkit-overflow-scrolling: touch property set. This is not really ideal for our Web Predictability goal as we would like to get rid of browser vendor prefixes. Also, in practice such workarounds lead to even more problems in AMP as explained in these blog posts. That’s why implementing scrolling of frames is one of the main goals of this project and significant steps have already been made in that direction.

Class Hierarchy
Figure 2: C++ classes involved in frame scrolling

The (relatively complex) class hierarchy involved in frame scrolling is summarized in Figure 2. The frame flattening heuristic mentioned above is handled in the WebCore::RenderIFrame class (in purple). The WebCore::ScrollingTreeFrameScrollingNodeIOS and WebCore::ScrollingTreeOverflowScrollingNodeIOS classes from the scrolling tree (in blue) are used to scroll, respectively, the main frame and overflow nodes on iOS. Scrolling of non-main frames will obviously have some code to share with the former, but it will also have some parts in common with the latter. For example, passing an extra UIScrollView layer is needed instead of relying on the one contained in the WKWebView of the main frame. An important step is thus to introduce a special class for scrolling inner frames that would share some logic from the two other classes and some refactoring to ensure optimal code reuse. Similar refactoring has been done for scrolling node states (in red) to move the scrolling layer parameter into WebCore::ScrollingStateNode instead of having separate members for WebCore::ScrollingStateOverflowScrollingNode and WebCore::ScrollingStateFrameScrollingNode.

The scrolling coordinator classes (in green) are also important, for example to handle hit testing. At the moment, this is not really implemented for overflow nodes but it might be important to have it for scrollable frames. Again, one sees that some logic is shared for asynchronous scrolling on macOS (WebCore::ScrollingCoordinatorMac) and iOS (WebCore::ScrollingCoordinatorIOS) in ancestor classes. Indeed, our effort to make frames scrollable on iOS is also opening the possibility of asynchronous scrolling of frames on macOS, something that is currently not implemented.

Class Hierarchy
Figure 4: Video of this demo page on WebKit iOS with experimental patches to make frame scrollables (2017/07/10)

Finally, some more work is necessary in the render classes (purple) to ensure that the layer hierarchies are correctly built. Patches have been uploaded and you can view the result on the video of Figure 4. Notice that this work has not been reviewed yet and there are known bugs, for example with overlapping elements (hit testing not implemented) or position: fixed elements.

Various other scrolling bugs were reported, analyzed and sometimes fixed by Apple. The switch from overflow nodes to scrollable iframes is unlikely to address them. For example, the “Find Text” operation in iOS has advanced features done by the UI process (highlight, smart magnification) but the scrolling operation needed only works for the main frame. It looks like this could be fixed by unifying a bit the scrolling code path with macOS. There are also several jump and flickering bugs with position: fixed nodes. Finally, Apple fixed inconsistent scrolling inertia used for the main frame and the one used for inner scrollable nodes by making the former the same as the latter.

Root Scroller

The CSSOM View specification extends the DOM element with some scrolling properties. That specification indicates that the element to consider to scroll the main view is document.body in quirks mode while it is document.documentElement in no-quirks mode. This is the behavior that has always been followed by browsers like Firefox or Interner Explorer. However, WebKit-based browsers always treat document.body as the root scroller. This interoperability issue has been a big problem for web developers. One convenient workaround was to introduce the document.scrollingElement which returns the element to use for scrolling the main view (document.body or document.documentElement) and was recently implemented in WebKit. Use this test page to verify whether your browser supports the document.scrollingElement property and which DOM element is used to scroll the main view in no-quirks mode.

Nevertheless, this does not solve the issue with existing web pages. Chromium’s Web Platform Predictability team has made a huge communication effort with Web authors and developers which has drastically reduced the use of document.body in no-quirks mode. For instance, Chromium’s telemetry on Figure 3 indicates that the percentage of document.body.scrollTop in no-quirks pages has gone from 18% down to 0.0003% during the past three years. Hence the Chromium team is now considering shipping the standard behavior.

UseCounter for ScrollTopBodyNotQuirksMode
Figure 3: Use of document.body.scrollTop in no-quirks mode over time (Chromium's UseCounter)

In WebKit, the issue has been known for a long time and an old attempt to fix it was reverted for causing regressions. For now, we imported the CSSOM View tests and just marked the one related to the scrolling element as failing. An analysis of the situation has been left on WebKit’s bug; Depending on how things evolve on Chromium’s side we could consider the discussion and implementation work in WebKit.

Related to that work, a new API is being proposed to set the root scroller to an arbitrary scrolling element, giving more flexibility to authors of Web applications. Today, this is unfortunately not possible without losing some of the special features of the main view (e.g. on iOS, Safari’s URL bar is hidden when scrolling the main view to maximize the screen space). Such API is currently being experimented in Chromium and we plan to investigate whether this can be implemented in WebKit too.


In the past months, The AMP Project and Igalia have worked on analyzing some interoperability issue and fixing them in WebKit. Many improvements for frame sandboxing are going to be available soon. Significant progress has also been made for frame scrolling on iOS and collaboration continues with Apple reviewers to ensure that the work will be integrated in future versions of WebKit. Improvements to “root scrolling” are also being considered although they are pending on the evolution of the issues on Chromium’s side. All these efforts are expected to be useful for WebKit users and the Web platform in general.

Igalia Logo
AMP Logo

Last but not least, I would like to thank Apple engineers Simon Fraser, Chris Dumez, and Youenn Fablet for their reviews and help, as well as Google and the AMP team for supporting that project.

August 29, 2017 10:00 PM

August 23, 2017

Release Notes for Safari Technology Preview 38

Surfin’ Safari

Safari Technology Preview Release 38 is now available for download for macOS Sierra and betas of macOS High Sierra. If you already have Safari Technology Preview installed, you can update from the Mac App Store’s Updates tab. This release covers WebKit revisions 220128-220795.

Beacon API

  • Enabled the Beacon API by default as an experimental feature (r220553)
  • Added support for CORS-preflighting (r220442)
  • Added support for CORS-preflighting on redirects (r220497)
  • Added support for connect-src CSP checks on redirects (r220549)
  • Updated sendBeacon() to rely on FetchBody instead of the whole FetchRequest (r220366)
  • Changed to use “application/octet-stream” content-type for payloads of ArrayBuffer and ArrayBufferView types (r220779)

Fetch API

  • Added support for Request keepalive getter (r220244)
  • Changed Response to keep all ResourceResponse information (r220320)
  • Implemented quota limitation for keepalive Fetch requests (r220751)

Web Payments

  • Enabled Payment Requests as an experimental feature (r220787)


  • Added support for parsing of the font-display property (r220725)
  • Implement caret-color support (r220706, r220714)
  • Added a fast path for rotate() and rotateZ() transform parsing (r220382)
  • Fixed parsing of <meta http-equiv=refresh> to allow time starting with a ‘.’ without a leading 0 (r220252)
  • Fixed a hit testing issue occurring when an SVG rect element with a non-default stroke style applied (r220717)


  • Added support for considering file extensions in the accept attribute of HTML file input elements (r220135)
  • Improved support for referrer policies (r220208)
  • Fixed the Promise resolve and reject function to have a length of 1 (r220324)
  • Fixed an early error on an ANY operator before new.target (r220481)
  • Fixed removing an empty <li> element when inside a table cell (r220398)
  • Fixed XHR to only fire an abort event if the cancellation was requested by the client (r220731)


  • Fixed deleting the old subtitle track on src attribute change event (r220472)

Apple Pay

  • Added support for phonetic contact names (r220718)

Web Inspector

  • Added Canvas path preview when viewing a recording (r220370)
  • Changed clicking on an autocomplete suggestion to apply it, not dismiss it (r220614)
  • Removed text-shadow and gradient backgrounds (r220710)
  • Updated the filter icon in the styles sidebar (r220609)


  • Added support for interacting with <option> and <select> elements using the element click command (r220740)
  • Added support for uploading files via <input type=file> (r219874, r220115, r220135, r220147, r220222)
  • Fixed a timeout when a JavaScript alert is shown in onload handler (r220741)
  • Implemented “normal” and “eager” page load strategies from the W3C specification (r220317)
  • Updated code to use in-view center points for clicks and other automation logic (r220314)

By Jon Davis at August 23, 2017 06:00 PM

August 09, 2017

Michael Catanzaro: On Firefox Sync

Igalia WebKit

Epiphany 3.26 is, unfortunately, not going to be packed with cool new features like 3.24 was. We’ve just been too busy working on improving WebKit this cycle. But there is one cool new thing: Firefox Sync support. You can sync bookmarks, history, passwords, and open tabs with other Epiphany instances and as well as both desktop and mobile Firefox. This is already enabled in 3.25.90. Just go to the Sync tab in Preferences and sign in or create your Firefox account there. Please test it out and report bugs now, so we can quash problems you find before 3.26.0 rather than after.

Some thank yous are in order:

  • Thanks to Gabriel Ivascu, for writing all the code.
  • Thanks to Google and Igalia for sponsoring Gabriel’s work.
  • Thanks to Mozilla. This project would never have been possible if Mozilla had not carefully written its terms of service to allow such use.

Go forth and sync!

By Michael Catanzaro at August 09, 2017 07:57 PM

Release Notes for Safari Technology Preview 37

Surfin’ Safari

Safari Technology Preview Release 37 is now available for download for macOS Sierra and betas of macOS High Sierra. If you already have Safari Technology Preview installed, you can update from the Mac App Store’s Updates tab. This release covers WebKit revisions 219567-220128.


  • Added initial support for navigator.sendBeacon behind an experimental feature flag (r220121)
  • Implemented document.elementsFromPoint (r219961)
  • Made cross-origin properties enumerable (r219659)
  • Fixed dispatching the click event to the parent when the child target stops hit testing after mouseDown (r219568)
  • Moved DOMException properties to the prototype and changed to use Error.prototype.toString() (r219607, r219663)


  • Added finally method support to Promise (r219989)
  • Added support for optional catch binding (r220068)


  • Reduced the size of generated binaries (r219899)

Apple Pay

  • Added "carteBancaire" as a supported payment network (r219896)


  • Aligned quirky number parsing with other browsers (r219642)

Web Inspector

  • Added a context menu item to the Elements tab for taking a screenshot of a node (r219870)
  • The debugger now captures async stack traces when web content calls addEventListener (r220036)
  • Prevented outputting “No message” for multi-value logs like console.log(x, y) (r219900)
  • Fixed warnings about console.assert lines without semicolons (r219894)
  • Inlined multiple console log values if they are simple (r219893)
  • Fixed inspect(aFunction) to jump to the function definition (r219749)
  • Fixed the page overlay highlight to fade out when a page is constantly updating (r219596)
  • Fixed some controls overlaying the header in the Settings tab (r219851)


  • Fixed an issue where implicit navigations didn’t cause a browsing context switch (r219723)
  • Fixed link and partial link queries if the text link contains trailing or leading whitespaces (r219604)
  • Fixed an issue that caused some script evaluations to be attributed to the wrong frame (r219649)


  • Changed to disable async image decoding for large images after the first time a tile is painted (r219876)
  • Fixed the minimum font size preference to affect absolute line-height values and prevent text lines from overlapping (r219665)
  • Fixed getting round-trip stroke-width styles causing text to gain a stroke (r219755)
  • Fixed Reeder’s default font to correctly use San Francisco (r220009)


  • Fixed zoom to follow the keyboard insertion point (r219987)
  • Added a background color for the focus state of the icon buttons in the media controls (r220041)
  • Fixed the incorrect range from index and length on <p> tags with contenteditable (r219949)
  • Changed to dispatch accessibilityPerformPressAction asynchronously on macOS (r219906)
  • Fixed silent VoiceOver or skipping over time values on the media player (r219983)
  • Fixed the web page getting reloaded when a node is labelling multiple child nodes (r219661)


  • Fixed media controls missing content in fullscreen when the document has a scroll offset (r219645)
  • Fixed the mouse pointer not hiding during fullscreen playback (r219625)
  • Fixed pressing the Escape key to not be a valid user gesture to enter fullscreen (r219950)

By Jon Davis at August 09, 2017 05:00 PM

August 06, 2017

Michael Catanzaro: Endgame for WebKit Woes

Igalia WebKit

In my original blog post On WebKit Security Updates, I identified three separate problems affecting WebKit users on Linux:

  • Distributions were not providing updates for WebKitGTK+. This was the main focus of that post.
  • Distributions were shipping a insecure compatibility package for old, unmaintained WebKitGTK+ 2.4 (“WebKit1”).
  • Distributions were shipping QtWebKit, which was also unmaintained and insecure.

Let’s review these problems one at a time.

Distributions Are Updating WebKitGTK+

Nowadays, most major community distributions are providing regular WebKitGTK+ updates, so this is no longer a problem for the vast majority of Linux users. If you’re using a supported version of Ubuntu (except Ubuntu 14.04), Fedora, or most other mainstream distributions, then you are good to go.

My main concern here is still Debian, but there are reasons to be optimistic. It’s too soon to say what Debian’s policy will be going forward, but I am encouraged that it broke freeze just before the Stretch release to update from WebKitGTK+ 2.14 to 2.16.3. Debian is slow and conservative and so has not yet updated to 2.16.6, which is sad because 2.16.3 is affected by a bug that causes crashes on a huge number of websites, but my understanding is it is likely to be updated in the near future. I’m not sure if Debian will update to 2.18 or not. We’ll have to wait and see.

openSUSE is another holdout. The latest stable version of openSUSE Leap, 42.3, is currently shipping WebKitGTK+ 2.12.5. That is disappointing.

Most other major distributions seem to be current.

Distributions Are Removing WebKitGTK+ 2.4

WebKitGTK+ 2.4 (often informally referred to as “WebKit1”) was the next problem. Tons of desktop applications depended on this old, insecure version of WebKitGTK+, and due to large API changes, upgrading applications was not going to be easy. But this transition is going much smoother and much faster than I expected. Several distributions, including Debian, Fedora, and Arch, have recently removed their compatibility packages. There will be no WebKitGTK+ 2.4 in Debian 10 (Buster) or Fedora 27 (scheduled for release this October). Most noteworthy applications have either ported to modern WebKitGTK+, or have configure flags to disable use of WebKitGTK+. In some cases, such as GnuCash in Fedora, WebKitGTK+ 2.4 is being bundled as part of the application build process. But more often, applications that have not yet ported simply no longer work or have been removed from these distributions.

Soon, users will no longer need to worry that a huge amount of WebKitGTK+ applications are not receiving security updates. That leaves one more problem….

QtWebKit is Back

Upstream QtWebKit has not been receiving security updates for the past four years or thereabouts, since it was abandoned by the Qt project. That is still the status quo for most distributions, but Arch and Fedora have recently switched to Konstantin Tokarev’s fork of QtWebKit, which is based on WebKitGTK+ 2.12. (Thank you Konstantin!) If you are using any supported version of Fedora, you should already have been switched to this fork. I am hopeful that the fork will be rebased on WebKitGTK+ 2.16 or 2.18 in the near future, to bring it current on security updates, but in the meantime, being a year and a half behind is an awful lot better than being four years behind. Now that Arch and Fedora have led the way, other distributions should find little trouble in making the switch to Konstantin’s QtWebKit. It would be a disservice to users to continue shipping the upstream version.

So That’s Cool

Things are better. Some distributions, notably Arch and Fedora, have resolved all of the above problems (or will in the very near future). Yay!

By Michael Catanzaro at August 06, 2017 09:47 PM

July 26, 2017

Release Notes for Safari Technology Preview 36

Surfin’ Safari

Safari Technology Preview Release 36 is now available for download for macOS Sierra and betas of macOS High Sierra. If you already have Safari Technology Preview installed, you can update from the Mac App Store’s Updates tab. This release covers WebKit revisions 219131-219567.


  • Implemented Object Spread (r219443)


  • Changed to not resolve auto values of align-self and justify-self matching specification changes (r219315)
  • Fixed line-height:<number> to not be visually applied twice when text autosizing is in effect (r219543)


  • Fixed incorrect sdpMLineIndex for video to fix interoperability with Firefox (r219393)
  • Fixed sending silence data for a disabled audio track (r219524)
  • Increased the render audio buffer sizes for WebRTC (r219517)

Web Driver

  • Fixed link and partial link queries when the link contains formatting tags (r219555)


  • Disabled asynchronous image decoding for large images by default (r219438)
  • Enabled the Viewport Fit experimental feature by default (r219369)
  • Fixed an element not getting repainted when its background image finishes decoding (r219364)
  • Fixed an issue to avoid unnecessary copying of the frame buffer into a WebGL Layer (r219472)
  • Corrected the radix used in Unicode Escape in invalid character error message (r219396)
  • Fixed the low memory notification to prevent causing style recalculation (r219145)
  • Fixed GIFs with infinite animation often only playing once (r219389)


  • Fixed removing user gesture restrictions when adding the autoplay attribute to a media element during a user gesture (r219509)
  • Fixed reflecting "video" and "audio" when they are not a supported as attribute value (r219234)
  • Fixed bad behavior caused by removing samples when the presentation order does not match decode order (r219519)
  • Fixed media controls drawing behind the captions (r219558)
  • Fixed clicking the edges of media control buttons to execute the action, not just change the visual state of the button (r219549)

Web Inspector

  • Changed to group Inspector Style Sheets as part of the Stylesheets folder (r219185)
  • Improved wording for Potential Custom Element that lacks a Custom definition (r219333)
  • Fixed resources that are sometimes missing from the tree outline right before grouping into folders (r219270)
  • Fixed WebSocket resource tree elements to show the connection status (r219269)


  • Implemented name section’s module name, and skipped unknown sections (r219134)

Bug Fixes

  • Fixed the “Show My Relationship” link in familysearch.org (r219151)
  • Fixed an issue where font loads can cause Chinese characters to draw as .notdef (r219221)
  • Changed AppCache to ignore fallback entries whose namespace is not prefixed with the manifest path (r219272)

By Jon Davis at July 26, 2017 05:00 PM

July 25, 2017

Adobe Announces Flash Distribution and Updates to End

Surfin’ Safari

Adobe has announced it will stop distributing and updating Flash Player at the end of 2020 and is encouraging web developers to migrate any existing Flash content to open standards. Apple is working with Adobe, industry partners, and developers to complete this transition.

Apple users have been experiencing the web without Flash for some time. iPhone, iPad, and iPod touch never supported Flash. For the Mac, the transition from Flash began in 2010 when Flash was no longer pre-installed. Today, if users install Flash, it remains off by default. Safari requires explicit approval on each website before running the Flash plugin.

To display rich interactive content in the browser, WebKit—the engine that powers Safari—supports the latest standards, including the following:

  • HTML Video and Media Source Extensions support a wide range of video experiences, including short clips, longer content, and live streaming.
  • HTML Canvas and WebGL provide fast, dynamic graphics for games and interactive experiences.
  • CSS Transitions and Animations add polished animations to web interfaces.
  • WebRTC enables real-time peer-to-peer video.
  • WebAssembly allows games and other compute-intensive applications to run faster.

The WebKit Project is excited about the future of the open web. We invite you to follow this blog to learn about new technologies as they’re implemented in WebKit.

By Apple's WebKit Team at July 25, 2017 04:00 PM

July 21, 2017

Update on Web Cryptography

Surfin’ Safari

Cryptography is the cornerstone of information security, including various aspects such as data confidentiality, data integrity, authentication, and non-repudiation. These provide support for the fundamental technologies of today’s Internet like HTTPS, DNSSEC, and VPN. The WebCrypto API was created to bring these important high-level cryptography capabilities to the web. This API provides a set of JavaScript functions for manipulating low-level cryptographic operations, such as hashing, signature generation and verification, encryption and decryption, and shared secret derivation. In addition, it supports generation and management of corresponding key materials. Combining the complete support of various cryptographic operations with a wide range of algorithms, the WebCrypto API is able to assist web authors in tackling diverse security requirements.

This blog post first talks about the advantages of implementing web cryptography through native APIs, and then introduces an overview of the WebCrypto API itself. Next, it presents some differences between the updated SubtleCrypto interface and the older webkit- prefixed interface. Some newly-added algorithms are discussed, and finally we demonstrate how to smoothly transition from the webkit- prefixed API to the new, standards-compliant API.

Native or Not Native?

Long before the WebCrypto API was standardized, several JavaScript cryptography libraries were created and have successfully served the open web since. So why bother implementing a web-facing cryptography library built on native APIs? There are several reasons, one of the more important being performance. Numbers tell the truth. We conducted several performance tests to compare our updated WebCrypto API and some famous pure JavaScript implementations.

The latest SJCL (1.0.7), asmcrypto.js, and CryptoJS (3.1) were selected for the comparison. The test suite contains:

  1. AES-GCM: Test encryption/decryption against a 4MB file, repeat certain times and record down the average speed. It uses a 256-bit AES key.
  2. SHA-2: Hash a 512KB file by SHA-512, repeat certain times and record down the average speed.
  3. RSA: Test RSA-PSS signature and verification against a 512KB file, repeat certain times and record down the average speed. It uses a 2048-bit key pair and SHA-512 for hashing.

The content under test was carefully selected to reflect the most frequently used day-to-day cryptography operations and paired with appropriate algorithms. The test platform was a MacBook Pro (MacBookPro11,5) with a 2.8 GHz Intel Core i7 running MacOS 10.13 Beta (17A306f) and Safari Technology Preview 35. Some of the pure JavaScript implementations do not support all of the test content, therefore corresponding results were omitted from those results.

Here are the test results.

AES-GCM Encryption/Decryption SHA-2 RSA

As you can see, the difference in performance is staggering. This was a surprising result, since most modern JavaScript engines are very efficient. Working with our JavaScriptCore team, we learned that the causes of these pure JavaScript implementations not performing well is that most of them are not actively maintained. Few of them take full advantage of our fast JavaScriptCore engine or modern JavaScript coding practices. Otherwise, the gaps may not be that huge.

Besides superior performance, WebCrypto API also benefits better security models. For example, when developing with pure JavaScript crypto libraries, secret or private keys are often stored in the global JavaScript execution context. It is extremely vulnerable as keys are exposed to any JavaScript resources being loaded and therefore allows XSS attackers be able to steal the keys. WebCrypto API instead protects the secret or private keys by storing them completely outside of the JavaScript execution context. This limits the risk of the private key being exfiltrated and reduces the window of compromise if an attacker gets to execute JavaScript in the victim’s browser. What’s more, our WebCrypto implementation on macOS/iOS is based on the CommonCrypto routines, which are highly tuned for our hardware platforms, and are regularly audited and reviewed for security and correctness. WebCrypto API is therefore the best way to ensure users enjoy the highest security protection.

Overview of WebCrypto API

The WebCrypto API starts with crypto global object:

    subtle: SubtleCrypto,
    ArrayBufferView getRandomValues(ArrayBufferView array)

Inside, it owns a subtle object that is a singleton of the SubtleCrypto interface. The interface is named subtle because it warns developers that many of the crypto algorithms have sophisticated usage requirements that must be strictly followed to get the expected algorithmic security guarantees. The subtle object is the main entry point for interacting with underlying crypto primitives. The crypto global object also has the function getRandomValues, which provides a cryptographically strong random number generator (RNG). The WebKit RNG (macOS/iOS) is based on AES-CTR.

The subtle object is composed of multiple methods to serve the needs of low-level cryptographic operations:

    Promise<ArrayBuffer> encrypt(AlgorithmIdentifier algorithm, CryptoKey key, BufferSource data);
    Promise<ArrayBuffer> decrypt(AlgorithmIdentifier algorithm, CryptoKey key, BufferSource data);
    Promise<ArrayBuffer> sign(AlgorithmIdentifier algorithm, CryptoKey key, BufferSource data);
    Promise<boolean> verify(AlgorithmIdentifier algorithm, CryptoKey key, BufferSource signature, BufferSource data);
    Promise<ArrayBuffer> digest(AlgorithmIdentifier algorithm, BufferSource data);
    Promise<CryptoKey or CryptoKeyPair> generateKey(AlgorithmIdentifier algorithm, boolean extractable, sequence<KeyUsage> keyUsages );
    Promise<CryptoKey> deriveKey(AlgorithmIdentifier algorithm, CryptoKey baseKey, AlgorithmIdentifier derivedKeyType, boolean extractable, sequence<KeyUsage> keyUsages );
    Promise<ArrayBuffer> deriveBits(AlgorithmIdentifier algorithm, CryptoKey baseKey, unsigned long length);
    Promise<CryptoKey> importKey(KeyFormat format, (BufferSource or JsonWebKey) keyData, AlgorithmIdentifier algorithm, boolean extractable, sequence<KeyUsage> keyUsages );
    Promise<ArrayBuffer> exportKey(KeyFormat format, CryptoKey key);
    Promise<ArrayBuffer> wrapKey(KeyFormat format, CryptoKey key, CryptoKey wrappingKey, AlgorithmIdentifier wrapAlgorithm);
    Promise<CryptoKey> unwrapKey(KeyFormat format, BufferSource wrappedKey, CryptoKey unwrappingKey, AlgorithmIdentifier unwrapAlgorithm, AlgorithmIdentifier unwrappedKeyAlgorithm, boolean extractable, sequence<KeyUsage> keyUsages );

As the names of these methods imply, the WebCrypto API supports hashing, signature generation and verification, encryption and decryption, shared secret derivation, and corresponding key materials management. Let’s look closer at one of those methods:

Promise<ArrayBuffer> encrypt(AlgorithmIdentifier algorithm,
                             CryptoKey key,
                             BufferSource data)

All of the functions return a Promise, and most of them accept an AlgorithmIdentifier parameter. AlgorithmIdentifier can be either a string that specifies an algorithm, or a dictionary that contains all the inputs to a specific operation. For example, in order to do an AES-CBC encryption, one has to supply the above encrypt method with:

var aesCbcParams = {name: "aes-cbc", iv: asciiToUint8Array("jnOw99oOZFLIEPMr")}

CryptoKey is an abstraction of keying materials in WebCrypto API. Here is an illustration:

    type: "secret",
    extractable: true,
    algorithm: { name: "AES-CBC", length: 128 },
    usages: ["decrypt", "encrypt"]

This code tells us that this key is an extractable (to JavaScript execution context) AES-CBC “secret” (symmetric) key with a length of 128 bits that can be used for both encryption and decryption. The algorithm object is a dictionary that characterizes different keying materials, while all the other slots are generic. Bear in mind that CryptoKey does not expose the underlying key data directly to web pages. This design of WebCrypto keeps the secret and private key data safely within the browser agent, while allowing web authors to still enjoy the flexibility of working with concrete keys.

Changes to WebKitSubtleCrypto

Those of you that have never heard of WebKitSubtleCrypto may skip this section and use SubtleCrypto exclusively. This section is aimed at providing compelling reasons for current WebKitSubtleCrypto users to switch to our new standards-compliant SubtleCrypto.

1. Standards-compliant implementation

SubtleCrypto is a standards-compliant implementation of the current specification, and is completely independent from WebKitSubtleCrypto. Here is an example code snippet that demonstrates the differences between the two APIs for importing a JsonWebKey (JWK) format key:

var jwkKey = {
    "kty": "oct",  
    "alg": "A128CBC",
    "use": "enc",
    "ext": true,
    "k": "YWJjZGVmZ2gxMjM0NTY3OA"

// WebKitSubtleCrypto:
// asciiToUint8Array() takes a string and converts it to an Uint8Array object.
var jwkKeyAsArrayBuffer = asciiToUint8Array(JSON.stringify(jwkKey));
crypto.webkitSubtle.importKey("jwk", jwkKeyAsArrayBuffer, null, false, ["encrypt"]).then(function(key) {
    console.log("An AES-CBC key is imported via JWK format.");

// SubtleCrypto:
crypto.subtle.importKey("jwk", jwkKey, "aes-cbc", false, ["encrypt"]).then(function(key) {
    console.log("An AES-CBC key is imported via JWK format.");

With the new interface, one no longer has to convert the JSON key to UInt8Array. The SubtleCrypto interface is indeed significantly more standards-compliant than our old WebKitSubtleCrypto implementation. Here are the results of running W3C WebCrypto API tests:

W3C WebCrypto TestSuite Result Chart
This test suite is an improved one based on the most updated web-platform-tests GitHub repository. Pull requests are made for all improvements: #6100, #6101, and #6102.

The new implementation’s coverage is around 95% which is 48X higher than our webkit- prefixed one! The concrete numbers for all selected parties are: 999 for prefixed WebKit, 46653 for Safari 11, 45709 for Chrome 59, and 18636 for FireFox 54.

2. DER encoding support for importing and exporting asymmetric keys

The WebCrypto API specification supports DER encoding of public keys as SPKI, and of private key as PKCS8. Prior to this, WebKitSubtleCrypto only supported the JSON-based JWK format for RSA keys. This is convenient when keys are used on the web because of its structure and human readability. However, when public keys are often exchanged between servers and web browsers, they are usually embedded in certificates in a binary format. Even though some JavaScript frameworks have been written to read the binary format of a certificate and to extract its public key, few of them convert a binary public key into its JWK equivalent. This is why support for SPKI and PKCS8 is useful. Here are code snippets that demonstrate what can be done with the SubtleCrypto API:

// Import:
// Generated from OpenSSL
// Base64URL.parse() takes a Base64 encoded string and converts it to an Uint8Array object.
var spkiKey = Base64URL.parse("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwCjRCtFwvSNYMZ07u5SxARxglJl75T7bUZXFsDVxHkMhpNC2RaN4jWE5bwYUDMeD2fVmxhpaUQn/6AbFLh6gHxtwrCfc7rIo/SfDdGd3GkRlXK5xXwGuM6MvP9nuZHaarIyArRFh2U2UZxFlVsKI0pSHo6n58W1fPZ1syOoVEZ/WYE6gLhMMwfpeAm97mro7mekRdMULOV/mR5Ul3CHm9Zt93Dc8GpnPA8bhLiB0VNyGTEMa06nJul4gj1sjxLDoUvZY2EWq7oUUnfLBUYMfiqK0kQcW94wvBrIq2DQUApLyTTbaAOY46TLwX6c8LtubJriYKTC5a9Bb0/7ovTWB0wIDAQAB");
crypto.subtle.importKey("spki", spkiKey, {name: "RSA-OAEP", hash: "sha-256"}, true, ["encrypt"]).then(function(key) {
    console.log("A RSA-OAEP key is imported via SPKI format.");

// Export:
var rsaKeyGenParams = {
    name: "RSA-OAEP",
    modulusLength: 2048,
    publicExponent: new Uint8Array([0x01, 0x00, 0x01]),  // Equivalent to 65537
    hash: "sha-256"
crypto.subtle.generateKey(rsaKeyGenParams, true, ["decrypt", "encrypt"]).then(function(keyPair) {
    crypto.subtle.exportKey("spki", keyPair.publicKey).then(function(binary) {
        console.log("A RSA-OAEP key is exported via SPKI format.");

A live example from a third party to generate public key certificates can be found here.

3. Asynchronously execute time-consuming SubtleCrypto methods

In the previous WebKitSubtleCrypto implementation, only generateKey for RSA executes asynchronously, while all the other operations are synchronous. Even though synchronous operation works well for methods that finish quickly, most crypto methods are time-consuming. Consequently, all time-consuming methods in the new SubtleCrypto implementation execute asynchronously:

Method encrypt decrypt sign verify digest generateKey* deriveKey deriveBits importKey exportKey wrapKey* unwrapKey*

Note that only RSA key pair generation is asynchronous while EC key pair and symmetric key generation are synchronous. Also notice that AES-KW is the only exception where synchronous operations are still done for wrapKey/unwrapKey. Normally key size is a few hundred bytes, and therefore it is less time-consuming to encrypt/decrypt such small amount of data. AES-KW is the only algorithm that directly supports wrapKey/unwrapKey operations while others are bridged to encrypt/decrypt operations. Hence, it becomes the only algorithm that executes wrapKey/unwrapKey synchronously. Web developers may treat every SubtleCrypto function the same as any other function that returns a promise.

4. Web worker support

Besides making most of the APIs asynchronous, we also support web workers to allow another model of asynchronous execution. Developers can choose which one best suit their needs. Combining these two models, developers now could integrate cryptographic primitives inside their websites without blocking any UI activities. The SubtleCrypto object in web workers uses the same semantics as the one in the Window object. Here is some example code that uses a web worker to encrypt text:

// In Window. 
var rawKey = asciiToUint8Array("16 bytes of key!");
crypto.subtle.importKey("raw", rawKey, {name: "aes-cbc", length: 128}, true, ["encrypt", "decrypt"]).then(function(localKey) {
    var worker = new Worker("crypto-worker.js");
    worker.onmessage = function(evt) {
        console.log("Received encrypted data.");

// In crypto-worker.js.
var plainText = asciiToUint8Array("Hello, World!");
var aesCbcParams = {
    name: "aes-cbc",
    iv: asciiToUint8Array("jnOw99oOZFLIEPMr"),
onmessage = function(key)
    crypto.subtle.encrypt(aesCbcParams, key, plainText).then(function(cipherText) {

A live example is here to demonstrate how asynchronous execution could help to make a more responsive website.

In addition to the four major areas of improvement above, some minor changes that are worth mentioning include:

  • CryptoKey interface enhancement includes renaming from Key to CryptoKey, making algorithm and usages slots cacheable, and exposing it to web workers.
  • HmacKeyParams.length is now bits instead of bytes.
  • RSA-OAEP can now import and export keys with SHA-256.
  • CryptoKeyPair is now a dictionary type.

Newly added cryptographic algorithms

Together with the new SubtleCrypto interface, this update also adds support for a number of cryptographic algorithms:

  1. AES-CFB: CFB stands for cipher feedback. Unlike CBC, CFB does not require the plain text be padded to the block size of the cipher.
  2. AES-CTR: CTR stands for counter mode. CTR is best known for its parallelizability on both encryption and decryption.
  3. AES-GCM: GCM stands for Galois/Counter Mode. GCM is an authenticated encryption algorithm designed to provide both data authenticity (integrity) and confidentiality.
  4. ECDH: ECDH stands for Elliptic Curve Diffie–Hellman. Elliptic curve cryptography (ECC) is an approach to public-key cryptography based on the algebraic structure of elliptic curves over finite fields. ECC requires smaller keys compared to RSA to provide equivalent security. ECDH is one among many ECC schemes. It allows two parties each of whom owns an ECC key pair to establish a shared secret over an insecure channel.
  5. ECDSA: ECDSA stands for Elliptic Curve Digital Signature Algorithm. It is another ECC scheme.
  6. HKDF: HKDF stands for HMAC-based Key Derivation Function. It transforms secrets into key, allowing to combine additional non-secret inputs when needed.
  7. PBKDF2:PBKDF2 stands for Password-Based Key Derivation Function 2. It takes a password or a passphrase along with a salt value to derive a cryptographic symmetric key.
  8. RSA-PSS: PSS stands for Probabilistic Signature Scheme. It is an improved digital signature algorithm for RSA.

This set of new algorithms not only adds new functionality, e.g. key derivation functions, but also benefits developers from higher efficiency and better security by replacing existing ones having the same functionalities. To demonstrate the benefits, sample code snippets written with selected new algorithms are presented in the following. Implementations under these examples are not written with the best practices and therefore are for demonstration only.

Example 1: AES-GCM

Prior, AES-CBC is the only available block cipher for encryption/decryption. Even though it does a great job for protecting data confidentiality, yet it doesn’t protect the authenticity (integrity) of the produced ciphers. Hence, it often bundles with HMAC-SHA256 to prevent silent corruptions of the ciphers. Here is the corresponding code snippet:

// Assume aesKey and hmacKey are imported before with the same raw key.
var plainText = asciiToUint8Array("Hello, World!");
var aesCbcParams = {
    name: "aes-cbc",
    iv: asciiToUint8Array("jnOw99oOZFLIEPMr"),

// Encryption:
// First encrypt the plain text with AES-CBC.
crypto.subtle.encrypt(aesCbcParams, aesKey, plainText).then(function(result) {
    console.log("Plain text is encrypted.");
    cipherText = result;

    // Then sign the cipher text with HMAC.
    return crypto.subtle.sign("hmac", hmacKey, cipherText);
}).then(function(result) {
    console.log("Cipher text is signed.");
    signature = result;

    // Finally produce the final result by concatenating cipher text and signature.       
    finalResult = new Uint8Array(cipherText.byteLength + signature.byteLength);
    finalResult.set(new Uint8Array(cipherText));
    finalResult.set(new Uint8Array(signature), cipherText.byteLength);
    console.log("Final result is produced.");

// Decryption:
// First decode the final result from the encryption step.
var position = finalResult.length - 32; // SHA-256 length
signature = finalResult.slice(position);
cipherText = finalResult.slice(0, position);

// Then verify the cipher text.
crypto.subtle.verify("hmac", hmacKey, signature, cipherText).then(function(result) {
    if (result) {
        console.log("Cipher text is verified.");

        // Finally decrypt the cipher text.
        return crypto.subtle.decrypt(aesCbcParams, aesKey, cipherText);
    } else
        return Promise.reject();
}).then(function(result) {
    console.log("Cipher text is decrypted.");
    decryptedText = result;
}, function() {
    // Error handling codes ...

So far, the codes are a bit complex with AES-CBC because the extra overhead of HMAC. However, it is much simpler to achieve the same authenticated encryption effect by using AES-GCM as it bundles authentication and encryption together within one single step. Here is the corresponding code snippet:

// Assume aesKey are imported/generated before, and the same plain text is used.
var aesGcmParams = {
    name: "aes-gcm",
    iv: asciiToUint8Array("jnOw99oOZFLIEPMr"),

// Encryption:
crypto.subtle.encrypt(aesGcmParams, key, plainText).then(function(result) {
    console.log("Plain text is encrypted.");
    cipherText = result; // It contains both the cipherText and the authentication data.

// Decryption:
crypto.subtle.decrypt(aesGcmParams, key, cipherText).then(function(result) {
    console.log("Cipher text is decrypted.");
    decryptedText = result;
}, function(error) {
    // If any violation of the cipher text is detected, the operation will be rejected.
    // Error handling codes ...

It is just that simple to use AES-GCM. This simplicity will definitely improve developers’ efficiency. A live example can also be found here to demonstrate how AES-GCM can prevent silent corruption during decrypting corrupted ciphers.

Example 2: ECDH(E)

Block ciphers alone are not sufficient to protect data confidentiality because secret (symmetric) keys need to be shared securely as well. Before this change, only RSA encryption was available for tackling this task. That is to encrypt the shared secret keys and then exchange the ciphers to prevent MITM attacks. This method is not entirely secure as perfect forward secrecy (PFS) is difficult to guarantee. PFS requires session keys, the RSA key pair in this case, to be destroyed once a session is completed, i.e. after a secret key is successfully shared. So the shared secret key can never be recovered even if the MITM attackers are able to record down the exchanged cipher and access the recipient in the future. RSA key pairs are very hard to generate, and therefore maintaining PFS is really a challenge for RSA secret key exchange.

However, maintaining PFS is a piece of cake for ECDH simply because EC key pairs are easy to generate. In average, it takes about 170 ms to generate a RSA-2048 key pair on the same test environment shown in the first section. On the contrary, it only takes about 2 ms to generate a P-256 EC key pair which can provide comparable security to a RSA-3072 alternative. ECDH works in the way that the involved two parties exchange their public keys first and then compute a point multiplication by using the acquired public keys and their own private keys, of which the result is the shared secret. ECDH with PFS is referred as Ephemeral ECDH (ECDHE). Ephemeral merely means that session keys are transient in this protocol. Since the EC key pairs involved with ECDH are transient, they cannot be used to confirm the identities of the involved two parties. Hence, other permanent asymmetric key pairs are needed for authentication. In general, RSA is used as it is widely supported by common public key infrastructures (PKI). To demonstrate how ECDHE works, the following code snippet is shared:

// Assuming Bob and Alice are the two parties. Here we only show codes for Bob's.
// Alice's should be similar.
// Also assumes that permanent RSA keys are obtained before, i.e. bobRsaPrivateKey and aliceRsaPublicKey.
// Prepare to send the hello message which includes Bob's public EC key and its signature to Alice:
// Step 1: Generate a transient EC key pair.
crypto.subtle.generateKey({ name: "ECDH", namedCurve: "P-256" }, extractable, ["deriveKey"]).then(function(result) {
    console.log("EC key pair is generated.");
    bobEcKeyPair = result;

    // Step 2: Sign the EC public key for authentication.
    return crypto.subtle.exportKey("raw", bobEcKeyPair.publicKey);
}).then(function(result) {
    console.log("EC public key is exported.");
    rawEcPublicKey = result;

    return crypto.subtle.sign({ name: "RSA-PSS", saltLength: 16 }, bobRsaPrivateKey, rawEcPublicKey);
}).then(function(result) {
    console.log("Raw EC public key is signed.");
    signature = result;

    // Step 3: Exchange the EC public key together with the signature. We simplify the final result as
    // a concatenation of the raw format EC public key and its signature.
    finalResult = new Uint8Array(rawEcPublicKey.byteLength + signature.byteLength);
    finalResult.set(new Uint8Array(rawEcPublicKey));
    finalResult.set(new Uint8Array(signature), rawEcPublicKey.byteLength);
    console.log("Final result is produced.");

    // Send the message to Alice.
    // ...

// After receiving Alice's hello message:
// Step 1: Decode the counterpart from Alice.
var position = finalResult.length - 256; // RSA-2048
signature = finalResult.slice(position);
rawEcPublicKey = finalResult.slice(0, position);

// Step 2: Verify Alice's signature and her EC public key.
crypto.subtle.verify({ name: "RSA-PSS", saltLength: 16 }, aliceRsaPublicKey, signature, rawEcPublicKey).then(function(result) {
    if (result) {
        console.log("Alice's public key is verified.");

        return crypto.subtle.importKey("raw", rawEcPublicKey, { name: "ECDH", namedCurve: "P-256" }, extractable, [ ]);
    } else
        return Promise.reject();
}).then(function(result) {
    console.log("Alice's public key is imported.");
    aliceEcPublicKey = result;

    // Step 3: Compute the shared AES-GCM secret key.
    return crypto.subtle.deriveKey({ name: "ECDH", public: aliceEcPublicKey }, bobEcKeyPair.privateKey, { name: "aes-gcm", length: 128 }, extractable, ['decrypt', 'encrypt']);
}).then(function(result) {
    console.log("Shared AES secret key is computed.");
    aesKey = result;


    // Step 4: Delete the transient EC key pair.
    bobEcKeyPair = null;
    console.log("EC key pair is deleted.");

In the above example, we omit the way how information, i.e. public keys and their corresponding parameters, is exchanged to focus on parts that WebCrypto API is involved. The ease to implement ECDHE will definitely improve the security level of secret key exchanges. Also, a live example to tell the differences between RSA secret key exchange and ECDH is included here.

Example 3: PBKDF2

The ability to derive a cryptographically secret key from existing secrets such as password is new. PBKDF2 is one of the newly added algorithms that can serve this purpose. The derived secret key from PBKDF2 not only can be used in the subsequent cryptographically operations, but also itself is a strong password hash given it is salted. The following code snippet demonstrates how to derive a strong password hash from a simple password:

var password = asciiToUint8Array("123456789");
var salt = asciiToUint8Array("jnOw99oOZFLIEPMr");

crypto.subtle.importKey("raw", password, "PBKDF2", false, ["deriveBits"]).then(function(baseKey) {
    return crypto.subtle.deriveBits({name: "PBKDF2", salt: salt, iterations: 100000, hash: "sha-256"}, baseKey, 128);
}).then(function(result) {
    console.log("Hash is derived!")
    derivedHash = result;

A live example can be found here.

The above examples are just a tip of capabilities of WebCrypto API. Here is a table listing all algorithms that WebKit currently supports, and corresponding permitted operations of each algorithm.

Algorithm name encrypt decrypt sign verify digest generateKey deriveKey deriveBits importKey** exportKey** wrapKey unwrapKey
* WebKit doesn’t support P-521 yet, see bug 169231.
** WebKit doesn’t check or produce any hash information from or to DER key data, see bug 165436, and bug 165437.
*** RSAES-PKCS1-v1_5 and SHA-1 should be avoided for security reasons.

Transition to the New SubtleCrypto Interface

This section covers some common mistakes that web developers have made when they have tried to maintain compatibility to both WebKitSubtleCrypto and SubtleCrypto, and then we present recommended fixes to those mistakes. Finally, we summarize those fixes into a de facto rule to maintain compatibility.

Example 1:

// Bad code:
var subtleObject = null;
if ("subtle" in self.crypto)
    subtleObject = self.crypto.subtle;
if ("webkitSubtle" in self.crypto)
    subtleObject = self.crypto.webkitSubtle;

This example wrongly prioritizes window.crypto.webkitSubtle over window.crypto.subtle. Therefore, it will overwrite the subtleObject even that the subtle object actually exists. A quick fix for it is to prioritizes window.crypto.subtle over window.crypto.webkitSubtle.

// Fix:
var subtleObject = null;
if ("webkitSubtle" in self.crypto)
    subtleObject = self.crypto.webkitSubtle;
if ("subtle" in self.crypto)
    subtleObject = self.crypto.subtle;

Example 2:

// Bad code:
(window.agcrypto = window.crypto) && !window.crypto.subtle && window.crypto.webkitSubtle && (console.log("Using crypto.webkitSubtle"), window.agcrypto.subtle = window.crypto.webkitSubtle);
var h = window.crypto.webkitSubtle ? a.utils.json2ab(c.jwkKey) : c.jwkKey;
agcrypto.subtle.importKey("jwk", h, g, !0, ["encrypt"]).then(function(a) {

This example incorrectly pairs window.agcrypto and the latter jwkKey. The first line prioritizes window.crypto.subtle over window.crypto.webkitSubtle, which is correct. However, the second line prioritizes window.crypto.webkitSubtle over window.crypto.subtle again.

// Fix:
(window.agcrypto = window.crypto) && !window.crypto.subtle && window.crypto.webkitSubtle && (console.log("Using crypto.webkitSubtle"), window.agcrypto.subtle = window.crypto.webkitSubtle);
var h = window.crypto.subtle ? c.jwkKey : a.utils.json2ab(c.jwkKey);
agcrypto.subtle.importKey("jwk", h, g, !0, ["encrypt"]).then(function(a) {

A deeper analysis of these examples reveals they both assume window.crypto.subtle and window.crypto.webkitSubtle cannot coexist and therefore wrongly prioritize one over the other. In summary, developers should be aware of the coexistence of these two interfaces and should always prioritize window.crypto.subtle over window.crypto.webkitSubtle.


In this blog post, we reviewed WebKit’s update to the WebCrypto API implementation which is available on macOS, iOS, and GTK+. We hope you enjoy it. You can try out all of these improvements in the latest Safari Technology Preview. Let us know how they work for you by sending feedback on Twitter (@webkit, @alanwaketan, @jonathandavis) or by filing a bug.

By Jiewen Tan at July 21, 2017 06:30 PM

July 12, 2017

Release Notes for Safari Technology Preview 35

Surfin’ Safari

Safari Technology Preview Release 35 is now available for download for macOS Sierra and betas of macOS High Sierra. If you already have Safari Technology Preview installed, you can update from the Mac App Store’s Updates tab. This release covers WebKit revisions 218629-219131.


  • Fixed a 50% regression on MotionMark Suites when extended color support was added (r218717)
  • Fixed the bug that Speedometer’s score worsens by 40% when accessibility features are enabled (r218910)


  • Changed image decoding so that when an image appears more than once on a page, decoding to paint one instance repaints them all (r219045)
  • Fixed a frame rate issue that caused getUserMedia to fail on some machines (r218852)
  • Fixed allowing media element to update its state when Mission Control closes the fullscreen window (r218813)
  • Made a change to hide volume controls when AirPlay is active (r218891)
  • Prevented capturing at unconventional resolutions when using the software encoder (r218699)
  • Prevented clearing capture mute from clearing audio mute (r218632)

Web Inspector

  • Added a small delay before showing the progress spinner when loading resources (r219017)
  • Added a toggle button to the left side of the split console navigation bar (r218839)
  • Fixed initial search sometimes being performed twice, producing duplicate results (r219021)
  • Fixed slowness when pausing with a deep call stack by avoiding eagerly generating object previews (r218718)
  • Flipped all go-to-arrow instances in right-to-left mode (r218777)
  • Fixed script timeline bubbles that sometimes appear to miss large events (r218781)
  • Fixed a hang when using “break on all exceptions” throws a stack overflow (r218652)
  • Improved type token background color in the debugger (r219041)


  • Cleaned up Object.entries implementation (r218790)
  • Implemented Object Rest Destructuring (r218861)
  • Made Object.values faster by writing it in C++ (r218697)
  • Removed Reflect.enumerate (r218784)


  • Fixed calling setValue() on contenteditable for ARIA text controls (r218986)
  • Fixed role="none" or role="presentation" on an <iframe> (r219075)


  • Disabled some WebAssembly APIs under CSP (r218951)


  • Fixed a backward compatibility issue with CryptoKey objects stored in the IndexedDB (r218666)

Web APIs

  • Fixed a TypeError in the Fetch API when called with body === {} (r218677)
  • Fixed an issue causing Safari to leave a popup window opened during the beforeunload event (r219039)
  • Included audio/vnd.wave as a valid mime-type for wav files (r218634)


  • Added support for structured serialization of CSS Geometry types (r218644)
  • Fixed @font-face rules with invalid primary fonts never downloading their secondary fonts (r218733)
  • Fixed applying font features only for the particular type of font they are being applied to (r218919)
  • Fixed CSS text properties affecting <video> shadow root (r218655)

By Jon Davis at July 12, 2017 05:00 PM

July 04, 2017

Charlie Turner: Qt Creator Tips for WebKit GTK

Igalia WebKit


Using an IDE on GNU/Linux for C/C++ development is slightly contentious in many circles. People either seem to not find IDE’s value-add worthwhile compared to their cult text editor + UNIX tools, or have tried them in the past and not had good experiences, so soilder on with the cult text editor approach. I’ve tended to be in the latter camp of people, knowing that in a perfect world an IDE would help me, but they don’t seem to be up-to-snuff in this environment yet.

I’d limped along with taggers like GNU global and etags alongside Emacs. Cortored find+grep commands wired into Emacs’ helm package were my “Find all references” and “Jump to definition”. It worked to an extent, but it does feel a little primitive, and GUD always frustrated me. New semantic taggers such as SourceWeb and rtags looked interesting and hope they continue to mature, but I was struggling getting WebKit through them. The Clang tooling is also rather slow at processing the source files, upon which both these tools are based.

You can make Qt Creator build and install WebKit into a jhbuild for, say, Epiphany. I describe those steps if you’re inclined have that full IDE experience. The instructions below are annotated with [Building?] for steps that are applicable only to that configuration. I don’t personally do this because I prefer to run the build/install commands outside the IDE. With those introductions out of the way, what I’ve ended up with is a decent code navigator (alternative to Eclipse!) and a good debugger frontend. I’m happier with the combination of cult editor + Qt Creator for working on C++ projects. It’s not perfect, but I hope you might find it useful as well.

First get Qt Creator installed. If using your distributions package manager, just check the version is fairly recent. If it isn’t, download if from the Qt Creator site, but during the installation process, I recommend not installing the Qt libraries.

Load the project into Qt Creator

  • Always run Qt Creator from the WebKit jhbuild environment. E.g., ./Tools/jhbuild/jhbuild-wrapper --gtk run /usr/bin/qtcreator. If you don’t, CMake will find all kinds of random junk it calls dependencies on your system, if you’re lucky.
  • Go to File > Open File or Project.
  • Navigate to the top-level CMakeLists.txt in the WebKit checkout.
  • In the Configure Project screen, change the build directory output to taste. If you’re not planning on building from IDE, this doesn’t matter.
  • [Building?] For build directories, you could put it in $WEBKIT_ROOT/WebKitBuild/{Release,Debug} to match WebKit conventions. Don’t bother with the other configurations, especially not RelWithDebInfo, there are problems in WebKit with this configuration. Now click on Manage in the Desktop kit page (it’s one of those buttons that magically appears on the screen when you hover over it…), scroll down to CMake Configuration and click Change. Remove the Qt install prefix definitions, and add CMAKE_INSTALL_PREFIX:INTERNAL=/path/to/jhbuild/install/ and CMAKE_INSTALL_LIBDIR:INTERNAL=lib. Note carefully that shell variables are not expanded here, so don’t use something like $HOME. You can also change the compiler and debugger used by the kit as well. Also make sure Qt version is None.
  • Once you get into the IDE after these steps, CMake will fail because we haven’t specified a port.
  • From the mode selector, click Projects (thing with the wrench icon) and go to the build settings. Set PORT=GTK and also add a boolean property for DEVELOPER_MODE=ON and ENABLE_WAYLAND_TARGET=OFF if you’re working on X11.
  • [Building?] Click Advanced if you’d like to change the default compiler switches for Debug/Release configurations. With GCC I like to use -ggdb -Og in Debug.
  • Configuring should now suceed
  • [Building?] Click Build and it will likely fail. I’ve found Qt Creator needs to be restarted at this point. Restart and the build should now work.
  • [Building?] As a finishing touch, you can configure the run configuration for launching Epiphany. In the Run Settings window under the projects mode, create a custom deploy step to run command jhbuild with arguments run cmake -P cmake_install.cmake. This will install WebKit in the jhbuild environment. Now add a custom executable and specify the executable to be jhbuild and the arguments to be run epiphany. The Run button will now install WebKit for use by Epiphany and launch the browser ready for attachment (see next section).


  • Due to the multi-process nature of WebKit, you can’t just click on “Start Debugging”, since there’s several processes you might want to attach to. Launch WebKit and once it’s running, go to Debug > Start Debugging > Attach to Running Application and select the PID of the process you’d like to attach to.
  • It’s likely Qt Creator will time out the GDB launch and ask if you’d like to give it more time. Say yes, and go to Tools > Options > Debugger > GDB and bump the timeout up to 60 seconds.
  • If you’re getting assembly instructions when you hit a breakpoint, it’s likely your source isn’t getting found with the debugger. This shouldn’t happen to you, but if it does you’ll want to add ../../Source -> $WEBKIT_CHECKOUT/Source source mapping. This can be done in Tools > Options > Debugger > General. The build system doesn’t force
    the compiler to emit absolute paths in debugging info (there are ways around that, but this is easier)
  • GDB commands can be issued by bringing up the poorly named “Debugger Log” in the debugger views menu. Some helpful commands I’ve used on WebKit are handle SIGUSR1 noprint to stop being interrupted by IPC, and set scheduler-locking on to single-step through the current thread (you really don’t want to enable that from the start though 😉 just use it in the middle of debug session when you want to step a thread).
  • Everything else I’ve found convenient to do via the IDE.


  • Header files don’t have their #if parsed properly, I think because the config.h is indirectly available to header files, which is really unfriendly to static analysis tools used by IDEs. This is with the default code model, I’m sure it would be better if you try the Clang code model, but the current support for that in Qt Creator is limited, and the tradeoff is much, much slower indexing. This isn’t really an issue with the IDE but rather the coding style guidelines of WebKit.
  • Switching kits often requires restarting the IDE, otherwise you get build step errors. I’m guessing this has something to do with the CMake caching the IDE uses. When in doubt, restart the IDE.
  • When you do an expensive interaction with the code model, it blocks the UI thread rendering the whole IDE unresponsive. This is much worse with the Clang code model because it’s so much slower than the default. Can be a problem with the Qt Code Model if you ask for things like the type hierachy.

By cturner at July 04, 2017 12:58 PM

July 03, 2017

A Closer Look Into WebRTC

Surfin’ Safari

We recently announced WebRTC support in Safari 11 on High Sierra and iOS 11 in our last WebKit blog post. Today, we would like to dive into more details of our implementation, and provide some tips on bringing WebRTC support to your website.

A website employing WebRTC and media capture can obtain and broadcast very personal information. Users must explicitly grant their trust to the website, and assume that their pictures and voices are used appropriately. WebKit requires websites to meet certain conditions in order to use the technologies and protect the privacy of its users. Additionally, Safari shows users when their capture devices are used, and gives users ways they can control a website’s access to their capture devices. For developers that use WebKit in their apps, RTCPeerConnection and RTCDataChannel are available in any web view, but access to the camera and microphone is currently limited to Safari.

Develop Menu

Safari Technology Preview 34 exposes various flags to make it easier for you to test your WebRTC website or integrate Safari in your continuous integration systems through the Develop > WebRTC sub-menu:

WebRTC Menu

We’ll go through each of these flags and explain how they can help you in your development below.

In addition, WebKit logs WebRTC state to the system log, which includes SDP offers and answers, ICE candidates, WebRTC statistics, and incoming and outgoing video frame counters.

Security Origin Policy for Media Capture

Websites that wish to access capture devices need to meet two constraints.

First, the document requesting the camera and microphone needs to come from a HTTPS domain. Since that can be burdensome when you’re developing and testing locally, you can bypass the HTTPS restriction by checking “Allow Media Capture on Insecure Sites” in the Develop > WebRTC menu.

Second, when a sub-frame requests a media capture device, the chain of frames leading to the main frame needs to come from the same secure origin. The user may not recognize the sub-frame’s third-party origin in relation to the main frame, so this constraint avoids confusing the user about whom the user is granting access to.

Mock Capture Devices

In the Develop > WebRTC menu, you can select “Use Mock Capture Devices” to replace the use of real capture devices with a mock one. The mock loops a bip-bop AV stream, as displayed below. When used as an incoming stream, the mock’s predictable data makes it easy to evaluate aspects of streaming media playback including synchronization, latency, and selection of input device.

Bip-Bop AV Mock Loop

The mock can also be useful for running automated tests in a continuous integration system. If you are using one and want to avoid prompts from getUserMedia, set the camera and microphone policy for the website to Allow through the Safari Preferences… > Websites panel.

ICE Candidate Restrictions

ICE candidates are exchanged at an early stage of a WebRTC connection to identify all possible network paths between two peers. To do this, WebKit must expose ICE candidates of each peer to websites so that they can be shared. ICE candidates expose IP addresses, and notably those that are host IP addresses can be used for tracking.

In many network topologies, however, host ICE candidates are not necessary to make the connection. Server Reflexive and TURN ICE candidates usually suffice for ensuring the connection, regardless of whether it is used for exchanging video or arbitrary data. Without access to capture devices, WebKit only exposes Server Reflexive and TURN ICE candidates, which expose IPs that could already be gathered by websites. When access is granted, WebKit will expose host ICE candidates, which maximizes the chance the connection succeeds and is efficient. We make this exception since we believe that the user is expressing a high level of trust to the website by granting access to his or her capture streams.

Some test pages may assume the availability of host ICE candidates. To test this, turn on “Disable ICE Candidate Restrictions” from the Develop > WebRTC menu, and reload the page.

Legacy WebRTC and Media Streams API

Through the WebRTC standardization process, the RTCPeerConnection API progressively improved in various ways. Initially callback-based, the API changed to being fully promise-based. API initially focused on MediaStream moved to MediaStreamTrack. Thanks to the upstream effort by the WebRTC in WebKit team, the RTCPeerConnection API was aligned with these two major changes.

We have turned the legacy WebRTC APIs off by default on Safari Technology Preview 34, and plan to ship Safari 11 on macOS High Sierra and iOS 11 without these APIs. Keeping the legacy API around limits our ability to move forward faster on WebRTC. Any website looking to bring support to Safari may need to make other adjustments, so this is as good a time as ever to move away from these legacy APIs. Existing websites may still rely on these legacy APIs, which you can check by turning on “Enable Legacy WebRTC API” in the Develop > WebRTC menu.

More precisely, the following APIs are only available with the legacy API switch turned on, with suggestions for how to update:

partial interface Navigator {
    // Switch to navigator.mediaDevices.getUserMedia
    void getUserMedia(MediaStreamConstraints constraints, NavigatorUserMediaSuccessCallback successCallback, NavigatorUserMediaErrorCallback errorCallback);

partial interface RTCPeerConnection {
    // Switch to getSenders, and look at RTCRtpSender.track
    sequence<MediaStream> getLocalStreams();
    // Switch to getReceivers, and look at RTCRtpReceiver.track
    sequence<MediaStream> getRemoteStreams();

    // Switch to getSenders/getReceivers
    MediaStream getStreamById(DOMString streamId);
    // Switch to addTrack
    void addStream(MediaStream stream);
    // Switch to removeTrack
    void removeStream(MediaStream stream);

    // Listen to ontrack event
    attribute EventHandler onaddstream;

    // Update to promise-only version of createOffer
    Promise<void> createOffer(RTCSessionDescriptionCallback successCallback, RTCPeerConnectionErrorCallback failureCallback, optional RTCOfferOptions options);
    // Update to promise-only version of setLocalDescription
    Promise<void> setLocalDescription(RTCSessionDescriptionInit description, VoidFunction successCallback, RTCPeerConnectionErrorCallback failureCallback);
    // Update to promise-only version of createAnswer
    Promise<void> createAnswer(RTCSessionDescriptionCallback successCallback, RTCPeerConnectionErrorCallback failureCallback);
    // Update to promise-only version of setRemoteDescription
    Promise<void> setRemoteDescription(RTCSessionDescriptionInit description, VoidFunction successCallback, RTCPeerConnectionErrorCallback failureCallback);
    // Update to promise-only version of addIceCandidate
    Promise<void> addIceCandidate((RTCIceCandidateInit or RTCIceCandidate) candidate, VoidFunction successCallback, RTCPeerConnectionErrorCallback failureCallback);

Many sites polyfill API support through the open source adapter.js project. Updating to the latest release is one way to cover for the API gap, but we recommend switching to the APIs listed in the specification.

Here are a couple examples of how to use the latest APIs. A typical receive-only/webinar-like WebRTC call could be done like this:

var pc = new RTCPeerConnection();
var offer = await pc.createOffer();
await pc.setLocalDescription(offer);
// send offer to the other party

And a typical audio-video WebRTC call could be done like this:

var stream = await navigator.mediaDevices.getUserMedia({audio: true, video: true});
var pc = new RTCPeerConnection();
var audioSender = pc.addTrack(stream.getAudioTracks()[0], stream);
var videoSender = pc.addTrack(stream.getVideoTracks()[0], stream);
var offer = await pc.createOffer();
await pc.setLocalDescription(offer);
// send offer to the other party

MediaStreamTrack-based APIs make sense as most of the handling is done at this level. Let’s say the 640×480 default resolution of the capture video track is not good enough. Continuing with the previous example, changing it dynamically can be done as follows:

videoSender.track.applyConstraints({width: 1280, height: 720});

Or we might want to mute the video but keep the audio flowing:

videoSender.track.enabled = false;

Oh but wait, let’s say that we actually want to apply some cool filter effects to the current video track, like in this example. All that is needed is a few function calls that will not require any SDP renegotiation:

videoSender.track.enabled = true;
renderWithEffects(video, canvas);

Access to Capture Streams

Safari allows users to have complete control over a website’s access to their capture devices.

First, the user is prompted to grant website access to capture devices when getUserMedia is first called. Unlike other browsers, however, Safari does not require the user to choose specific devices; instead the prompt requests access for all devices of a specific type, like all cameras or microphones. This reduces fatigue from being prompted multiple times, and potentially avoids training the user to always tap “Allow”. One common case where this could happen is switching between the front and back cameras of iOS devices. The resolved promise in getUserMedia returns a device that fulfills the constraints, and subsequent calls to getUserMedia for the same device type will avoid presenting additional prompts to the user. If you want to allow the user to switch to a different device, be sure to provide UI to do so.

Second, the user can decide to always allow or deny access to the camera and microphone through Safari preferences. The user may do this on a per-origin basis and can even set a general policy for all websites.

Third, once a website creates a MediaStream for a device, icons appear in the Safari UI and the system menu bar indicating that capture devices are being used. The user may click or tap that icon to pause the camera and microphone mid-stream. Here WebKit will send silent audio and black video frames, and your website can present appropriate UI by listening for the mute and unmute events on MediaStreamTrack.

Active Capture Devices Icons

Finally, to avoid unexpected capture, WebKit only allows one tab to capture video or audio at a time. Tabs already using capture devices will see their MediaStreamTracks silenced and receive the mute event when a new tab gains access.


navigator.mediaDevices.enumerateDevices exposes the list of capture devices available, and can be queried by websites even when access to those devices is not granted. For users that have custom camera and microphone setups, this can add to a user’s fingerprinting surface. When access hasn’t yet been requested or is explicitly denied, WebKit avoids exposing this additional information by returning a default list of devices that may not correspond to the actual set of devices available. In addition, the devices have missing labels as per the specification. Once access is granted, the full list of devices and their labels are available.

Media Capture and Autoplay Video

In previous posts we’ve discussed changes in autoplay policies for video on macOS and iOS. We’ve adjusted the policies on both platforms to accommodate WebRTC applications, where it is common to want to autoplay incoming media streams that include audio. To address these scenarios while retaining the benefits of the current autoplay rules, the following changes have been made:

  • MediaStream-backed media will autoplay if the web page is already capturing.
  • MediaStream-backed media will autoplay if the web page is already playing audio. A user gesture will still be required to initiate audio playback.


WebRTC is a very powerful feature that can have numerous applications. We all know that with great power comes great responsibility. Designing WebRTC applications require to have efficiency in mind from the start. CPU, memory and network have limits that can seriously affect user experience. This problem should be tackled by both the web engine and the web application. On the web application side, various mechanisms are already available: choosing the right video resolution and frame rate, selecting the right video codec profile, using CVO, muting tracks at the source, and performing client-side monitoring of WebRTC statistics.


That concludes our deep dive into WebRTC and media capture. Our door is always open to hear feedback from you. File a bug, email web-evangelist@apple.com, or tweet to @webkit.

By Youenn Fablet, Jon Lee at July 03, 2017 05:00 PM

June 28, 2017

Release Notes for Safari Technology Preview 34

Surfin’ Safari

Safari Technology Preview Release 34 is now available for download for macOS Sierra and betas of macOS High Sierra. If you already have Safari Technology Preview installed, you can update from the Mac App Store’s Updates tab. This release covers WebKit revisions 217978-218629.


  • Added WebRTC options to the Developer menu
  • Disabled Legacy WebRTC API in the Experimental Features menu by default (r218169)
  • Changed behavior to close NetworkProcess WebRTC sockets as soon as the Web Process no longer needs them (r218432)
  • Added support for receive-only SDP offers through addTransceiver (r218431)
  • Changed handling capture status based on MediaStreamTrack (r218399)
  • Changed RTCPeerConnection to return RTCSessionDescriptionInit instead of RTCSessionDescription (r218335)
  • Fixed a cloned MediaStreamTrack to not mute the other tracks using the same source (r218497)
  • Fixed RTCPeerConnection getReceivers() to return transceivers that have an active receiver but no active sender (r218182)
  • Fixed the screen going into sleep mode during WebRTC video (r218151)


  • Fixed high CPU usage when entering fullscreen or seeking during MSE video playback (r218463)
  • Fixed seeking during MSE video playback where audio would begin playing long before rendering the video (r218150)
  • Fixed video flashing black when switching back to a tab (r218291)
  • Improved media controls rendering for long-loading media files (r218600)
  • Prevented media elements continuing to load media data after navigation (r218016)


  • Made Object.assign faster by rewriting it in C++ (r218348)
  • Reduced Structure size (r218070)
  • Updated RegExp.prototype.[@@search]] implementation according to the latest specifications (r218051)
  • Fixed PreTypedArray constructor with a string to not throw an exception (r218082)


  • Applied img-src CSP directive to favicon loads (r218015, r218026)
  • Implemented W3C Secure Contexts Draft Specification (r218027, r218028, r218155, r218196)
  • Restricted filtered painting across cross-origin boundaries with transforms (r218300)
  • Added allow-popups-to-escape-sandbox attribute support for <iframe> elements (r218000)
  • Added Subresource Integrity as an experimental feature (r217996)

Web Inspector

  • Added grid to image previews to clarify transparency and image size (r218159)
  • Fixed console message icons that overlap the source location (r218243)
  • Fixed pretty print, type info, and code coverage buttons disappearing after switching tabs (r218305)
  • Fixed SVG files and favicon files that don’t display properly (r218298)
  • Fixed the search highlight not showing up in resources when paused (r218359)
  • Fixed showing non-shadow children of an element with a shadow root (e.g. <video>) (r218020)


  • Fixed the meter element not respecting the writing direction (r218468)
  • Fixed WebGPU contexts to have a back reference to the canvas element (r218624)
  • Fixed CSS transitions added while page is not visible so they start animating when the page becomes visible (r217997)
  • Fixed IndexedDB.getAll() use inside a Web Worker (r218041)


  • Moved SubtleCrypto from the experiemental features menu (r218129)
  • Removed unsupported AES_CMAC, DH, and CONCAT (r218030)


  • Fixed several miscellaneous bugs found from web platform tests (r218216)


  • Added an experimental feature setting for asynchronous frame scrolling (r218534)


  • Exposed the inline property as an accessibility attribute (r218226)

Bug Fixes

  • Fixed mint.com header rendering incorrectly when initially loaded (r218257)
  • Fixed scrubbing backward on a YouTube video

By Jon Davis at June 28, 2017 05:00 PM

June 15, 2017

Michael Catanzaro: Debian Stretch ships latest WebKitGTK+

Igalia WebKit

I’ll keep this update short. Debian has decided to ship the latest version of WebKitGTK+, 2.16.3, in its upcoming Stretch release. Since Debian was the last major distribution holding out on providing WebKit security updates, this is a big deal. Huge thanks to Jeremy Bicha for making this possible.

The bad news is that Debian is still considering whether or not to provide periodic security updates after the release, so there might not be any. But maybe there will be. We will have to wait and see. At least releasing with the latest version is a big step in the right direction.

By Michael Catanzaro at June 15, 2017 04:34 PM

June 14, 2017

Release Notes for Safari Technology Preview 33

Surfin’ Safari

Safari Technology Preview Release 33 is now available for download for macOS Sierra and betas of macOS High Sierra. If you already have Safari Technology Preview installed, you can update from the Mac App Store’s Updates tab. This release covers WebKit revisions 217407-217978.


  • Fixed an issue that could lead to large memory use in the Safari Technology Preview and web content processes when certain Safari Extensions are installed


  • Fixed for-in optimization static analysis in the bytecode generator (r217438)
  • Improved performance of String.prototype.concat (r217648)
  • Improved the bytecode and type information provided for toLength (r217530)
  • Optimized Map and Set constructors (r217525)


Media Streams and Capture

  • Fixed getUserMedia prompting too often (r217910)
  • Prevented getUserMedia requests from background tabs unless the tab is already capturing (r217930)
  • Prevented getUserMedia from prompting again if the user denied access (r217945)


  • Enabled clients to specify a list of codecs that should require hardware decode support (r217799)
  • Exempted exclusively wall-powered devices from client-required hardware codec support (r217906)
  • Aligned Web Audio implementation to specifications when clients pass a value of 0 for bufferSize to the createScriptProcessor() method (r217919)

CSS Grid

  • Added support for orthogonally positioned grid items (r217486)
  • Fixed the behavior of positioned items without specific dimensions (r217411)
  • Fixed the logical margin applied in the tracks sizing algorithm of auto tracks (r217709)
  • Fixed margin applied when stretching an orthogonal item in a fixed size track (r217705)


  • Aligned <col span> and <colgroup span> limits with the latest HTML specification (r217907)
  • Fixed null content-type and content-length when fetching Blob URLs with XHR (r217901)
  • Fixed getComputedStyle() to return pixel values for left, right, top, and bottom, matching the specifications (r217522)
  • Implemented fromFloat32Array, fromFloat64Array, toFloat32Array, and toFloat64Array for DOMMatrix (r217764)
  • Implemented DOMPointReadOnly.matrixTransform() (r217763)
  • Enabled script modules to be imported via data URLs (r217760)
  • Updated to slightly stricter rules for custom element names from the recent draft standards (r217864)
  • Used the parent box style to adjust RenderStyle for alignment (r217536)
  • Added conditional support for media preloading and aligned media as values (r217863)
  • Aligned preload implementation to specifications with mandatory as value and other alignments (r217962)


  • Changed behavior to remove backing store for layers that are outside the viewport (r217696)
  • Fixed an issue where a frame’s composited content is visible when the frame has visibility:hidden (r217472)
  • Changed behavior to destroy the associated renderer subtree when display:contents node is deleted (r217794)

Web Inspector

  • Added contextual menu item to log a WebSocket object to the console (r217912)
  • Added Debug view to the Settings tab for debug settings and experimental features (r217625)
  • Added the ability for the user to choose stylesheet when creating new rules (r217911)
  • Changed the Node Details Sidebar to allow editable key and values in the Attributes table (r217744)
  • Prevented unnecessary layout triggered when a Sidebar is resized while collapsed (r217452)
  • Fixed performing search on reload for an existing query in the Search tab (r217733)
  • Fixed images dragged from Web Inspector to Desktop being named “Unknown.png” (r217584)
  • Fixed an issue where reloading the page after switching from the Resource tab switches back (r217505)
  • Fixed the CodeMirror instance in the ConsolePrompt getting refreshed each time it is shown (r217746)
  • Fixed showing active Web Sockets when opening Web Inspector (r217721)
  • Fixed an issue preventing the go-to arrow to inspect Web Sockets that receive >50 messages per second (r217690)
  • Improved the reliability of automatically pausing in auto-attach when inspecting a JSContext (r217509)

Bug Fixes

  • Enabled AirPods to work with Netflix (r217858)
  • Fixed stuttering audio in YouTube when the page changes visibility (r217936)

By Jon Davis at June 14, 2017 08:05 PM

June 08, 2017

Auto-Play Policy Changes for macOS

Surfin’ Safari

This is a guest post from the Safari team about changes to how Safari handles HTML5 video and audio auto-play. These changes may affect compatibility with your websites.

As follow up to Safari’s updated video policies for iOS last year, this week we announced we are making important changes to auto-play policies on the Mac. These changes provide users the ability to browse the web with fewer distractions, particularly in the form of relief from websites that auto-play with sound.

New Behaviors

The WebKit engine provides rich flexibility for user agents to configure and manage media auto-play policies. Safari in macOS High Sierra uses an automatic inference engine to block media elements with sound from auto-playing by default on most websites. Safari 11 also gives users control over which websites are allowed to auto-play video and audio by opening Safari’s new “Websites” preferences pane, or through the “Settings for This Website…” option in the Safari menu. Further, a new power-saving feature prevents silent videos from auto-playing when either hidden in a background tab or otherwise off-screen.

Best Practices for Web Developers

Websites should assume any use of <video> or <audio> requires a user gesture click to play. It’s important to detect if auto-play was denied, since users now have the ability to turn off all forms of auto-play, including silent videos. The code snippet below shows just how easy this is to check. It’s worth pointing out that the new auto-play policies apply both to video used as a tool for making something visual happen (like background video or video-as-animated-gif) and also to video that serves as consumable content. We recommend web developers test their site with these new behaviors, ensuring any custom media controls behave correctly when auto-play is disabled, either automatically by Safari or by users.

  • Websites using WebKit’s built-in media controls automatically work great with the new policies.
  • Don’t assume a media element will play, and don’t show the pause button from the start. Look at the Promise returned by the play function on HTMLMediaElement to see if it was rejected:
var promise = document.querySelector('video').play();

if (promise !== undefined) {
    promise.catch(error => {
        // Auto-play was prevented
        // Show a UI element to let the user manually start playback
    }).then(() => {
        // Auto-play started
  • Auto-play restrictions are granted on a per-element basis. Change the source of the media element instead of creating multiple media elements if you want to play multiple videos back to back (or play a pre-roll ad with sound, followed by the main video).
  • Don’t play ads without showing media controls because they may not auto-play and users will have no way of starting playback.
  • Remember that audio tracks that render silence are still audio tracks, and their existence affects whether a video will auto-play at all. In these cases, a video with silent audio tracks won’t play. The audio track should be removed or, alternatively, the muted attribute can be set on the media element.


We’d love to hear from developers on these new auto-play policies. Please reach out to our Web Technologies Evangelist, Jon Davis on Twitter to share your thoughts with our team.

By Kevin Decker at June 08, 2017 05:00 PM

June 07, 2017

Announcing WebRTC and Media Capture

Surfin’ Safari

Today we are thrilled to announce WebKit support for WebRTC, available on Safari on macOS High Sierra, iOS 11, and Safari Technology Preview 32. In this post, we will go through an overview of our implementation. We will have future posts that cover more best practices for developers.

When talking about WebRTC, we immediately think about making a video conference call. There are two steps to start a call. First, WebKit needs access to the user’s camera and microphone. HTTPS websites use the Media Capture and Streams API on Safari for that purpose. Once the user grants permission through a prompt, capture streams start to flow. These streams can be tailored to websites’ needs through the use of constraints.

Second, the user joins the conversation, once he checks to make sure his hair looks good on-screen. Websites send these capture streams to the other participants. The user obviously wants to see the other participants’ coifs as well, so this is where the WebRTC API kicks in. WebKit finds and creates the optimal network channel to connect those streams.

To handle the networking layer, WebKit chose the LibWebRTC open source framework. LibWebRTC provides both a high level of interoperability and a rich set of streaming features for efficient video conferencing. Safari supports modern audio codecs such as Opus, and with the H.264 video codec takes full advantage of power-efficient hardware.

Currently, Safari supports legacy WebRTC APIs. Web developers can check whether their websites conform to the latest specifications by toggling the STP Experimental Features menu item “Remove Legacy WebRTC API”. Legacy WebRTC APIs will be disabled by default on future releases. Websites that need to accommodate older implementations of the WebRTC and Media Capture specifications can take advantage of polyfill libraries like adapter.js.

There are a lot of ingredients that go into a good WebRTC recipe. To make sure we had what we needed to make video conferencing possible, a few partners joined the party to bring Safari support to their products. Kudos to TokBox and BlueJeans for getting betas available today.

The next generation of communication technologies is here, and we’re really excited to see them in WebKit and on Apple platforms. We want to hear your feedback! File a bug, email web-evangelist@apple.com, or tweet to @webkit.

By Youenn Fablet at June 07, 2017 05:00 PM

Safari Technology Preview 32, with WebRTC, is Now Available

Surfin’ Safari

Safari Technology Preview Release 32 is now available for download for macOS Sierra. With this release, Safari Technology Preview is now available for betas of macOS High Sierra. If you already have Safari Technology Preview installed, you can update from the Mac App Store’s Updates tab.

This release covers the same revisions of WebKit from Safari Technology Preview 31 , but includes new Safari and WebKit features that will be present in Safari 11. The following web-facing Safari 11 features are new to Safari Technology Preview 32:

WebRTC and Media Capture
Safari now supports peer-to-peer video conferencing through webRTC. For more information, take a look at “Announcing WebRTC and Media Capture”.

WebAssembly is a low-level binary format for executable code on the web. It is a standards-based supplement to JavaScript. It is secure, portable, and designed to be fast and efficient. To learn more about what WebAssembly is, and what it isn’t, see “Assembling WebAssembly”.

Auto-Play Improvements
Safari prevents auto-play of media with sound on most websites. Users can control which websites are allowed to auto-play video and audio by opening the new “Websites” preferences pane, or through the “Settings for This Website…” option in the Safari Technology Preview menu. We recommended that web developers test their websites with these new behaviors, ensuring any custom media controls behave correctly when auto-play is disabled, either automatically or by the user.

Many more WebKit features in Safari 11 are present in this release of Safari Technology Preview and have been in past releases. You can learn more about what’s new in Safari 11 from the Apple Developer website.

By Ricky Mondello at June 07, 2017 05:00 PM

June 06, 2017

Assembling WebAssembly

Surfin’ Safari

We’re pleased to announce that WebKit has a full WebAssembly implementation.

Dynamic Duo

WebAssembly is a no-nonsense sidekick to JavaScript. It isn’t meant to be hand-written; rather, it’s a low-level binary format designed to be a suitable compilation target for existing languages such as C++. The WebAssembly code that the browser sees will already have undergone high-level, language-specific optimizations. This is great because it means implementations don’t have to know about how C++ or other languages are optimized. Running expensive language-specific optimization on the developers’ machines allows WebKit to focus on target-specific optimizations. It also means that we can focus WebAssembly compiler optimizations on fast code delivery and predictable performance.

WebAssembly cannot do everything that JavaScript does. For example, WebAssembly cannot access the DOM except by calling into JavaScript. WebAssembly is meant to be used in conjunction with JavaScript. The JavaScript / WebAssembly dynamic duo work in partnership, allowing JavaScript to stay focused on taking over the world, while WebAssembly accelerates computation-intensive tasks.

JavaScript and its sidekick, cosplaying as 1966 Batman

The web wouldn’t be itself without security and portability. WebAssembly delivers on both fronts. It executes C++ code at near native speed with the same joker-less security guarantees that JavaScript offers. Our implementation supports WebAssembly on x86-64 as well as ARM64 platforms. Portable performance is really where WebAssembly shines: the WebAssembly virtual Instruction Set Architecture was designed to be an ideal compilation target for today’s modern processors.


WebAssembly fits in with the rest of the web platform, as a good sidekick would. It re-uses existing web APIs and exposes a new JavaScript API. WebAssembly has four core concepts: WebAssembly.Module, WebAssembly.Instance, WebAssembly.Memory, and WebAssembly.Table. A module represents code and is similar to a program on disk, whereas an instance is an execution of that program. There can be multiple concurrently executing instances of the same module. Finally, a memory represents an instance’s heap. It is contiguous, bounds-checked, and can be exposed to JavaScript as an ArrayBuffer. All WebAssembly memory operations operate on the instance’s memory. Finally, a table holds handles to WebAssembly functions, allowing indirect calls within an instance to target different functions with the same signature (in C++-speak: virtual functions and function pointers). Interestingly, instances can share the same memory, and tables can call directly across instances which enables dynamic linking.

Because WebAssembly exposes itself as a regular JavaScript object, we were able to reuse some machinery that already existed within WebKit. An interesting example is our reuse of our ECMAScript Module implementation to implement WebAssembly.Instance‘s API. For now it’s an implementation detail—invisible to web developers—but integration with ECMAScript Modules is being discussed. For developers who use modules, interacting between JavaScript and WebAssembly would then be totally seamless. Behind the mask of modules, our heroes’ secret identities wouldn’t be revealed.

To allow sharing of modules between Web Workers and to prepare ourselves for future features like threads, we’ve made our internal representation of WebAssembly code thread-safe. This lets developers postMessage a compiled WebAssembly.Module across workers without requiring re-compilation, copying, or any other redundant work. Our implementation of postMessage for modules is simpler than a riddle: sharing a module between workers involves passing a reference to our internal module representation to the other worker. That worker will run the same machine code as the agent that originally produced the module.

Utility Belt

WebAssembly directly exposes 32- and 64-bit integers as well as 32- and 64-bit floating point numbers. Its instruction set is equally simple:

i32.add i64.add f32.add f64.add i32.wrap/i64 i32.load8_s i32.store8
i32.sub i64.sub f32.sub f64.sub i32.trunc_s/f32 i32.load8_u i32.store16
i32.mul i64.mul f32.mul f64.mul i32.trunc_s/f64 i32.load16_s i32.store
i32.div_s i64.div_s f32.div f64.div i32.trunc_u/f32 i32.load16_u i64.store8
i32.div_u i64.div_u f32.abs f64.abs i32.trunc_u/f64 i32.load i64.store16
i32.rem_s i64.rem_s f32.neg f64.neg i32.reinterpret/f32 i64.load8_s i64.store32
i32.rem_u i64.rem_u f32.copysign f64.copysign i64.extend_s/i32 i64.load8_u i64.store
i32.and i64.and f32.ceil f64.ceil i64.extend_u/i32 i64.load16_s f32.store
i32.or i64.or f32.floor f64.floor i64.trunc_s/f32 i64.load16_u f64.store
i32.xor i64.xor f32.trunc f64.trunc i64.trunc_s/f64 i64.load32_s
i32.shl i64.shl f32.nearest f64.nearest i64.trunc_u/f32 i64.load32_u
i32.shr_u i64.shr_u i64.trunc_u/f64 i64.load call
i32.shr_s i64.shr_s f32.sqrt f64.sqrt i64.reinterpret/f64 f32.load call_indirect
i32.rotl i64.rotl f32.min f64.min f64.load
i32.rotr i64.rotr f32.max f64.max
i32.clz i64.clz nop grow_memory
i32.ctz i64.ctz block current_memory
i32.popcnt i64.popcnt f32.demote/f64 loop
i32.eqz i64.eqz f32.convert_s/i32 if get_local
i32.eq i64.eq f32.convert_s/i64 else set_local
i32.ne i64.ne f32.convert_u/i32 br tee_local
i32.lt_s i64.lt_s f32.convert_u/i64 br_if
i32.le_s i64.le_s f32.reinterpret/i32 br_table get_global
i32.lt_u i64.lt_u f32.eq f64.eq f64.promote/f32 return set_global
i32.le_u i64.le_u f32.ne f64.ne f64.convert_s/i32 end
i32.gt_s i64.gt_s f32.lt f64.lt f64.convert_s/i64 i32.const
i32.ge_s i64.ge_s f32.le f64.le f64.convert_u/i32 drop i64.const
i32.gt_u i64.gt_u f32.gt f64.gt f64.convert_u/i64 select f32.const
i32.ge_u i64.ge_u f32.ge f64.ge f64.reinterpret/i64 unreachable f64.const

The instructions are low-level by design, and it is this low-level quality that gives WebAssembly its power. WebAssembly was born as a compilation target, molded by compiler engineers.


WebKit’s WebAssembly implementation, like our JavaScript implementation, uses a tiering system to balance startup costs with throughput. Currently, there are two tiers to the engine: the Build Bytecode Quickly (BBQ) tier and the Optimized Machine-code Generator (OMG) tier. Both rely on the B3 JIT as their low-level optimizer.

WebAssembly modules can easily contain tons of code, some of which isn’t executed more than once or very frequently. This is why we opted to use two tiers: one that generates decent code quickly, and one that generates optimized code only when the engine thinks the code is hot enough to warrant it. BBQ compiles code about 4× as fast as OMG, but produces code that executes roughly 2× as slow as OMG. We use a background thread when compiling functions using the OMG. When OMG compilation finishes, we pause the executing WebAssembly threads and hot-patch the OMG compilation into the module.

WebAssembly being a low-level format—compared to JavaScript being a dynamic language—means that things aren’t as fickle when compiling WebAssembly. For example, WebAssembly statically tells us the types of all values within a function and gives us the signatures of all functions ahead of time.


In order to produce executable code as soon as possible, the BBQ tier omits many of the optimizations possible in the B3 compiler. Additionally, the BBQ tier also uses a linear scan combined register / stack allocation algorithm. This allocates registers about 11× faster than the graph coloring algorithm that B3 usually uses. Avoiding expensive optimization allows WebKit to produce BBQ fast, so that BBQ may be consumed as soon as possible.


When a function has been executed enough times, our WebAssembly runtime decides to optimize that function. Since WebAssembly does not require any type speculations, we only use tiering to conserve compile time. BBQ code contains only the profiling needed to detect when code has executed many times.

We share modules, along with all of their runtime state (like tiering-up from BBQ to OMG) between workers. Since we hot-patch the BBQ code, which might be executing on any number of threads, we need to be sure that each call-site can be concurrently updated to point to the OMG code. In order to avoid checking for new code on each call to a function, like JavaScript does, we track each call-site to every function, both in assembly and indirectly. Whenever the OMG version of a function is finished compiling, it replaces each call-site with a pointer to the code.


One of the most important optimizations in WebAssembly is reducing the overhead on memory accesses while preserving security guarantees. WebAssembly specifies that all memory accesses are performed on a single 32-bit linear memory. We do this by reserving slightly more than 4GiB of virtual address space. This virtual reservation doesn’t occupy physical memory unless accessed. We use the hardware’s page protection mechanism to mark all but the lower pages as non-readable and non-writable. All loads and stores from this 32-bit address space can be performed normally, without explicit bounds checking instructions. If a load or store would be out of bounds, it will trigger a hardware fault that will ultimately result in a POSIX SIGSEGV or a Mach EXC_BAD_ACCESS exception. Our custom signal / Mach exception handlers then ensure the fault originated from a WebAssembly memory operation. If so, we set the instruction pointer to a special code stub that performs a WebAssembly trap and materializes a WebAssembly.RuntimeError in JavaScript. This optimization means that a WebAssembly memory operation typically results in a single load or store instruction. Overall, we measured a 15-20% speedup from this optimization on various WebAssembly benchmarks.

WebAssembly memory signal

💥 KAPOW! 💥

Get in touch with us by filing a bug, or contacting JF, Keith, and Saam on Twitter.

By JF Bastien, Keith Miller, Saam Barati at June 06, 2017 07:30 PM

June 05, 2017

Intelligent Tracking Prevention

Surfin’ Safari

The success of the web as a platform relies on user trust. Many users feel that trust is broken when they are being tracked and privacy-sensitive data about their web activity is acquired for purposes that they never agreed to.

WebKit has long included features to reduce tracking. From the very beginning, we’ve defaulted to blocking third-party cookies. Now, we’re building on that. Intelligent Tracking Prevention is a new WebKit feature that reduces cross-site tracking by further limiting cookies and other website data.

What Is Cross-Site Tracking and Third-Party Cookies?

Websites can fetch resources such as images and scripts from domains other than their own. This is referred to as cross-origin or cross-site loading, and is a powerful feature of the web. However, such loading also enables cross-site tracking of users.

Imagine a user who first browses example-products.com for a new gadget and later browses example-recipies.com for dinner ideas. If both these sites load resources from example-tracker.com and example-tracker.com has a cookie stored in the user’s browser, the owner of example-tracker.com has the ability to know that the user visited both the product website and the recipe website, what they did on those sites, what kind of web browser was used, et cetera. This is what’s called cross-site tracking and the cookie used by example-tracker.com is called a third-party cookie. In our testing we found popular websites with over 70 such trackers, all silently collecting data on users.

How Does Intelligent Tracking Prevention Work?

Intelligent Tracking Prevention collects statistics on resource loads as well as user interactions such as taps, clicks, and text entries. The statistics are put into buckets per top privately-controlled domain or TLD+1.

Machine Learning Classifier

A machine learning model is used to classify which top privately-controlled domains have the ability to track the user cross-site, based on the collected statistics. Out of the various statistics collected, three vectors turned out to have strong signal for classification based on current tracking practices: subresource under number of unique domains, sub frame under number of unique domains, and number of unique domains redirected to. All data collection and classification happens on-device.

Actions Taken After Classification

Let’s say Intelligent Tracking Prevention classifies example.com as having the ability to track the user cross-site. What happens from that point?

If the user has not interacted with example.com in the last 30 days, example.com website data and cookies are immediately purged and continue to be purged if new data is added.

However, if the user interacts with example.com as the top domain, often referred to as a first-party domain, Intelligent Tracking Prevention considers it a signal that the user is interested in the website and temporarily adjusts its behavior as depicted in this timeline:

Intelligent Tracking Prevention Timeline

If the user interacted with example.com the last 24 hours, its cookies will be available when example.com is a third-party. This allows for “Sign in with my X account on Y” login scenarios.

This means users only have long-term persistent cookies and website data from the sites they actually interact with and tracking data is removed proactively as they browse the web.

Partitioned Cookies

If the user interacted with example.com the last 30 days but not the last 24 hours, example.com gets to keep its cookies but they will be partitioned. Partitioned means third-parties get unique, isolated storage per top privately-controlled domain or TLD+1, e.g. account.example.com and www.example.com share the partition example.com.

This makes sure users stay logged in even if they only visit a site occasionally while restricting the use of cookies for cross-site tracking. Note that WebKit already partitions caches and HTML5 storage for all third-party domains.

What Does This Mean For Web Developers?

With Intelligent Tracking Prevention, WebKit strikes a balance between user privacy and websites’ need for on-device storage. That said, we are aware that this feature may create challenges for legitimate website storage, i.e. storage not intended for cross-site tracking. Please let us know of such cases and we will try to help (contact info at the end of this blog post).

To get you started, here are some some guidelines.

Storage Requires User Interaction

Check to make sure that you aren’t relying on cookies and other storage to persist if the user does not interact directly with your website on a regular basis. Requiring user interaction covers most legitimate uses of client-side storage. It also provides better transparency and gives users more control over who gets to store data on their devices.

Web Analytics

Make sure to configure your web analytics to not rely on third-party cookies from domains that don’t get user interaction. A popular way to do cross-site analytics for a family of sites is to use link decoration, i.e. pad links with information that needs to be carried across origins and navigations.

Ad Attribution

We recommend server-side storage for attribution of ad impressions on your website. Link decoration can be used to pass on attribution information in navigations.

Managing Single Sign-On

If you run a single sign-on system with a centralized session, the user needs to interact with the domain that controls the session. Otherwise you run the risk of Intelligent Tracking Prevention treating your session controller domain as a tracker.

Intelligent Tracking Prevention and Single Sign-On

Imagine a scenario as depicted above; a central session at account.com used for the three sites SiteA.com, SiteB.com, and SiteC.com. Session information can be propagated from account.com to the dependents during account.com’s 24-hour exemption from cookie partitioning. From that point on the sites must maintain sessions without account.com cookies, or they must re-authenticate daily with a brief stop at account.com to acquire new user interaction. You can grant the sites the ability to propagate session information between themselves through navigations and new cookies set in HTTP responses. Single sign-out needs to invalidate the account.com session on the server.

Feedback and Bug Reports

Please report bugs through bugs.webkit.org and send feedback to our evangelist Jon Davis if you are a web developer or a web user and Intelligent Tracking Prevention isn’t working as intended for your website. If you have technical questions on how the feature works you can find me on Twitter @johnwilander.

By John Wilander at June 05, 2017 09:00 PM


Surfin’ Safari

Update: The previous version of this post showed performance data from ARES-6 version 1.0. Version 1.0 had a bug where the score for the Worst 4 Iterations was actually using the first 4 iterations. We have fixed the bug and updated the benchmark to version 1.0.1. The performance results shown in this post now use ARES-6 version 1.0.1, which contains the fix.

ES2015 (also known as ES6), the version of the JavaScript specification ratified in 2015, is a huge improvement to the language’s expressive power thanks to features like classes, for-of, destructuring, spread, tail calls, and much more. But powerful language features come at a high cost for language implementers. Prior to ES6, WebKit had spent years optimizing the idioms that arise in ES3 and ES5 code. ES6 requires completely new compiler and runtime features in order to get the same level of performance that we have with ES5.

Overall Performance Results

WebKit’s JavaScript implementation, called JSC (JavaScriptCore), implements all of ES6. ES6 features were implemented to be fast from the start, though we only had microbenchmarks to measure the performance of those features at the time. While it was initially helpful to optimize for our own microbenchmarks and microbenchmark suites like six-speed, to truly tune our engine for ES6, we needed a more comprehensive benchmark suite. It’s hard to optimize new language features without knowing how those features will be used. Since we love programming, and ES6 has many fun new language features to program with, we developed our own ES6 benchmark suite. This post describes the development of our first ES6 benchmark, which we call ARES-6. We used ARES–6 to drive significant optimization efforts in JSC, and this post describes three of them: high throughput generators, a new Map/Set implementation, and phantom spread. The post concludes with an analysis of performance data to show how JSC’s performance compares to other ES6 implementations.

ARES-6 Benchmark

The suite consists of two subtests we wrote in ES6 ourselves, and two subtests that we imported that use ES6. The first subtest, named Air, is an ES6 port of the WebKit B3 JIT‘s Air::allocateStack phase. The second subtest, named Basic, is an ES6 implementation of the ECMA-55 BASIC standard using generators. The third subtest, named Babylon, is an import of Babel’s JavaScript parser. The fourth subtest, named ML, is an import of the feedforward neural network library from the mljs machine learning framework. ARES-6 runs the Air, Basic, Babylon, and ML benchmarks multiple times to gather lots of data about how the browser starts up, warms up, and janks up. This section describes the four benchmarks and ARES-6’s benchmark running methodology.


Air is an ES6 reimplementation of JSC’s allocateStack compiler phase, along with all of Assembly Intermediate Representation needed to run that phase. Air tries to faithfully use new features like arrow functions, classes, for-of, and Map/Set, among others. Air doesn’t avoid any features out of fear that they might be slow, in the hope that we might learn how to make those features fast by looking at how Air and other benchmarks use them.

The next section documents the motivation and design of Air. You can browse the source here.


At the time that Air was written, most JavaScript benchmarks used ES5 or older versions of the language. ES6 testing mostly relied on microbenchmarks or conversions of existing tests to ES6. We use larger benchmarks to avoid over-optimizing for small pieces of code. We also avoid changing existing benchmarks because that approach has no limiting principle: if it’s OK to change a benchmark to use a feature, does that mean we can also change it to remove the use of a feature we don’t like? We feel that one of the best ways to avoid falling into the trap of creating benchmarks that only reinforce what some JS engine is already good at is to create a new benchmark from first principles.

We only recently completed our new JavaScript compiler, named B3. B3’s backend, named Air, is very CPU-intensive and uses a combination of object-oriented and functional idioms in C++. Additionally, it relies heavily on high speed maps and sets. It goes so far as to use customized map/set implementations – even more so than the rest of WebKit. This makes Air a great candidate for ES6 benchmarking. The Air benchmark in ARES-6 is a faithful ES6 implementation of JSC’s Air. It pulls no punches: just as the original C++ Air was written with expressiveness as a top priority, ES6 Air is liberal in its use of modern ES6 idioms whenever this helps make the code more readable. Unlike the original C++ Air, ES6 Air doesn’t exploit a deep understanding of compilers to make the code easy to compile.


Air runs one of the more computationally expensive C++ Air phases, Air::allocateStack(). It turns abstract stack references into concrete stack references, by selecting how to lay out stack slots in the stack frame. This requires liveness analysis and an interference graph.

Air relies on three major ES6 features more so than most of the others:

  • Arrow functions. Like the C++ version with lambdas, Air uses a functional style of iterating most non-trivial data-structures. This is because the functional style allows the callbacks to mutate the data being iterated: if the callback returns a non-null value, forEachArg() will replace the argument with that value. This would not have been possible with for-of. Air’s use of forEachArg() and arrow functions usually looks like this:
   inst.forEachArg((arg, role, type, width) => ...)
  • For-of. Many Air data structures are amenable to for-of iteration. While the innermost loops tend to use functional iteration, pretty much all of the outer logic uses for-of heavily. For example:
   for (let block of code) // Iterate over the basic blocks in a program
       for (let inst of block) // Iterate over the instructions in a block
  • Map/Set. The liveness analysis in Air::allocateStack() relies on maps and sets. For example, we use a liveAtHead map that is keyed by basic block. Its values are sets of live stack slots. This is a relatively crude way of doing liveness, but it is exactly how the original Air::LivenessAnalysis worked. So we view it as being quite faithful to how a sensible programmer might use Map and Set.

Air also uses some other ES6 features. For example, it makes light use of a Proxy. It makes extensive use of classes, let/const, and Symbols. Symbols are used as enumeration elements, and so, they frequently show up as cases in switch statements.

The workflow of an Air run is pretty simple: we do 200 runs of allocateStack on four IR payloads.

Each IR payload is a large piece of ES6 code that constructs an Air Code object, complete with basic blocks, temporaries, stack slots, and instructions. These payloads are generated by running the Air::dumpAsJS() phase. This is a phase we wrote in the C++ version of Air that will generate JS code that builds an IR payload. Just prior to running the C++ allocateStack phase, we perform Air::dumpAsJS() to capture the payload. The four payloads we generate are for the hottest functions in four other major JS benchmarks:

  • Octane/GBEmu, the executeIteration function.
  • Kraken/imaging-gaussian-blur, the gaussianBlur function.
  • Octane/Typescript, the scanIdentifier function.
  • Air (yes, it’s self referential), an anonymous closure identified by our profiler as ACLj8C.

These payloads allow Air to precisely replay allocateStack on those actual functions.

Air validates its results. We added a Code hashing capability to both the C++ Air and ES6 Air, and we assert each payload looks identical after allocateStack to what it would have looked like after the original C++ allocateStack. We also validate that the payloads hash properly before allcoateStack, to help catch bugs during payload initialization. We have not measured how long hashing takes, but it’s an O(N) operation, while allocateStack is closer to O(N^2). We suspect that barring some engine pathologies, hashing should be much faster than allocateStack, and allocateStack should be where the bulk of time is spent.


At the time that Air was written, we weren’t happy with the ES6 benchmarks that were available to us. Air makes extensive use of ES6 features in the hope that we can learn about possible optimization strategies by looking at this and other benchmarks.

Air does not use generators at all. We almost used them for forEachArg iteration, but it would have been a very unusual use of generators because Air’s forEach functions are more like map than for-of. The whole point is to allow the caller to mutate entries. We thought that functional iteration was more natural for this case than for-of and generators. But this led us to wonder: how would we use generators?


Web programming requires reasoning about asynchrony. But back when some of us first learned to program with the BASIC programming language, we didn’t have to worry about that: if you wanted input from the user, you said INPUT and the program would block until the user typed things. In a sense, this is what generators are about: when you say yield, your code blocks until some other stuff happens.

Basic is an ES6 implementation of ECMA-55 BASIC. It implements the interpreter as a recursive abstract syntax tree (AST) walk, where the recursive functions are generators so that they can yield when they encounter BASIC’s INPUT command. The lexer is also written as a generator. Basic tests multiple styles of generators, including functions with multiple yield points and recursive yield* calls.

The next section describes how Basic uses generators in the lexer and in the AST walk. You can browse the source here.


Lexers are usually written as a lex function that maintains some state and returns the next token whenever you call it. Basic uses a generator to implement lex, so that it can use local variables for all of its state.

Basic’s lexer is a generator function with multiple nested functions inside it. It contains eight uses of yield, none of which are recursive.

AST Walk

Walking the AST is an easy way to implement an interpreter and this was a natural choice for Basic. In such a scheme, the program is represented as a tree, and each node has code associated with it that may recursively invoke sub-nodes in the tree. Basic uses plain object literals to create nodes. For example:

    {evaluate: Basic.NumberPow, left: primary, right: parsePrimary()}

This code in the parser creates an AST node whose evaluation function is Basic.NumberPow. Were it not for INPUT, Basic could use ordinary functions for all of the AST. But INPUT requires blocking; so, we implement that with yield. This means that all of the statement-level AST nodes use generators. Those generators may call each other recursively using yield*.

The AST walk interpreter contains 18 generator functions with two calls to yield (in INPUT and PRINT) and one call to yield* (in Basic.Program).


Each Basic benchmark iteration runs five simple Basic programs:

  • Hello world!
  • Print numbers 1..10.
  • Print a random number.
  • Print random numbers until 100 is printed.
  • Find all prime numbers from 2 to 1999.

The interpreter uses a fixed seed, so the random parts always behave the same way. The Basic benchmark runs 200 iterations.


We wrote Basic because we wanted to see what an aggressive attempt at using generators looks like. Prior to Basic, all we had were microbenchmarks, which we feared would focus our optimization efforts only on the easy cases. Basic uses generators in some non-obvious ways, like having multiple generator functions, many yield points, and recursive generator calls. Basic also uses for-of, classes, Map, and WeakMap.

Babylon and ML

It is important to us that ARES-6 consists both of tests we wrote, and tests we imported. Babylon and ML are two tests we imported with minor modifications to make them run in the browser without Node.js style modules or ES6 modules. (The reason for not including tests with ES6 modules is that at the time of writing this, <script type="module"> is not on by default in all major browsers.) Writing new tests for ARES-6 is important because it allows us to use ES6 in interesting and sophisticated ways. Importing programs we didn’t write is also imperative for performance analysis because it ensures that we measure the performance of interesting programs already using ES6 out in the wild.

Babylon is an interesting test for ARES-6 because it makes light use of classes. We think that many people will dip their toes into ES6 by adopting classes since many ES5 programs are written in ways that lead to an easy translation to classes. We’ve seen this firsthand in the WebKit project when Web Inspector moved all their ES5 pseudo-classes to use ES6 class syntax. You can browse the Babylon source in ARES-6 here. The Babylon benchmark runs 200 iterations where each iteration consists of parsing four JS programs.

The feedforward neural network library, that the ML benchmark is imported from, depends heavily on ES6 classes. It uses the ml-matrix library which implements matrix manipulations in a decidedly object oriented style using ES6 classes almost exclusively. You can browse the ML source in ARES-6 here. The ML benchmark runs 60 iterations where each iteration consists of performing analysis over different sample data sets using various activation functions.

Benchmarking Methodology

Air, Basic and Babylon each run for 200 iterations, and ML runs for 60 iterations. Each iteration does the same kind of work. We simulate page reload before the first of those iterations, to minimize the chances that the code will benefit from JIT optimizations at the beginning of the first iteration. ARES-6 analyzes these four benchmarks in three different ways:

  • Start-up performance. We want ES6 code to run fast right from the start, even if our JITs haven’t had a chance to perform optimizations yet. ARES-6 reports a First Iteration score that is just the execution time of the first of the 60 or 200 iterations.
  • Worst-case performance. JavaScript engines have a lot of different kinds of jank. The GC, JIT, and various adaptive optimizations all run the risk of causing programs to sometimes run for much longer than the norm. We don’t want our ES6 optimizations to introduce new kinds of jank. ARES-6 reports a Worst 4 Iterations score that is the average of the execution times of the worst 4 of the 60 or 200 iterations, excluding the first iteration which was used for measuring start-up performance.
  • Throughput. If you write some ES6 code and it runs for long enough, then it should eventually benefit from all of our optimizations. ARES-6 reports an Average score that is the average execution time of all iterations excluding the first.

Each repetition of ARES-6 yields 3 scores (measured in milliseconds): First Iteration, Worst 4 Iterations, and Average, for each of the 4 subtests: Air, Basic, Babylon, and ML, for a total of 12 scores. The geometric mean of all 12 scores is the Overall score for the repetition. ARES-6 runs 6 repetitions, and reports the averages of each of these 13 scores along with their 95% confidence intervals. Since these scores are measures of execution time, lower scores are better because they mean that the benchmark completed in less time.


We built ARES-6 so that we could have benchmarks with which to tune our ES6 implementation. ARES-6 was built specifically to allow us to study the impact of new language features on our engine. This section describes three areas where we made significant changes to JavaScriptCore in order to improve our score on ARES-6. We revamped our generator implementation to give generator functions full access to our optimizing JITs. We rewrote our Map/Set implementation so that our JIT compiler can inline Map/Set lookups. Finally, we added significant new escape analysis functionality to eliminate the object allocation of the rest parameter when used with the spread operator.

High-Throughput Generators

The performance of ES6 generators is critical to the overall performance of JavaScript engines. We expect generators to be frequently used as ES6 adoption increases. Generators are a language-supported way to suspend and resume an execution context. They can be used to implement value streams and custom iterators, and are the basis of ES2017’s async and await, which streamlines the notoriously tricky asynchronous Promise programming model into the direct style programming model. To be performant, it was an a priori goal that our redesigned generator implementation had a sound and simple compilation strategy in all of our JIT tiers.

A generator must suspend and resume the execution context at the point of a yield expression. To do this, JSC needs to save and restore its execution state: the instruction pointer and the current stack frame. While we need to save the logical JavaScript instruction pointer to resume execution at the appropriate point in the program, the machine’s instruction pointer may change. If the function is compiled in upper JIT tiers (like baseline, DFG, and FTL), we must select the code compiled in the best tier when resuming. In addition, the instruction pointer may be invalidated if the compiled code is deoptimized.

JSC’s bytecode is a 3AC-style (three-address code) IR (intermediate representation) that operates over virtual registers. The bytecode is allowed an effectively “infinite” number of registers, and the stack frame comprises slots to store each register. In practice, the number of virtual registers used is small. The key insight into our generator implementation is that it is a transformation over JSC’s bytecode. This completely hides the complexity of generators from the rest of the engine. The phases prior to bytecode generatorification (parsing, bytecode generation from the AST) are allowed to view yield as if it were a function call — about the easiest kind of thing for those phases to do. Best of all, the phases after generatorification do not have to know anything about generators. That’s a fantastic outcome, since we already have a massive interpreter and JIT compiler infrastructure that consumes this bytecode.

When generating the original bytecode, JSC’s bytecode compiler treats a generator mostly as if it were a program with normal control flow, where each “yield” point is simply an expression that takes arguments, and results in a value. However, this is not how yield is implemented at a machine level. To transform this initial form of bytecode into a version that does proper state restoration, we rewrite the generator’s bytecode to turn the function into a state machine.

To properly restore the instruction pointer at yield points, our bytecode transformation inserts a switch statement at the top of each generator function. It performs a switch over an integer that represents where in the program the generator should resume when called. Secondly, we must have a way to restore each virtual register at each yield point. It turns out that JSC already has a mechanism for doing exactly this. We turned this problem into a problem of converting each bytecode virtual register in the original bytecode into a closure variable in JSC’s environment record data structure. Each transformed generator allocates a closure to store all generator state. Every yield point saves each live virtual register into the closure, and every resume point restores each live virtual register from the closure.

Because this bytecode transformation changes the program only by adding closures and a switch statement, this approach trivially meets our goal of being compilable in our optimizing compiler tiers. JSC’s optimizing compilers already do a good job at optimizing switch statements and closure variables. The generator’s dispatch gets all of JSC’s switch lowering optimizations just by virtue of using the switch bytecode. This includes our B3 JIT’s excellent switch lowering optimization, and less aggressive versions of that same optimization in lower JIT tiers and in the interpreter. The DFG also has numerous optimizations for closures. This includes inferring types of closure variables, optimizing loads and stores to closures down to a single instruction in most cases, and properly modeling the aliasing effects of closure accesses. We get these benefits without introducing new constructs into the optimizing compiler.


Let’s walk through an example of the bytecode transformation for an example JavaScript generator function:

function *generator()
    var temp = 20;
    var result = yield 42;
    return result + temp;

JSC generates the bytecode sequence shown in the following figure, which represents the control flow graph.

Pre-Generatorification bytecode

When the AST-to-bytecode compiler sees a yield expression, it just emits the special op_yield bytecode operation. This opcode is a macro. It’s not recognized by any of our execution engines. But it has well-understood semantics, which allows us to treat it as bytecode syntactic sugar for closures and switches.


Desugaring is performed by the generatorification bytecode phase. The figure above explains how generatorification works. Generatorification rewrites the bytecode so that there are no more op_yield statements and the resulting function selects which code to execute using a switch statement. Closure-style property access bytecodes are used to save/restore state around where the op_yield statements used to be.

Previously, JSC bytecode was immutable. It was used to carry information from the bytecode generator, which wrote bytecode as a byproduct of walking the AST, to the compilers, which would consume it to create some other byproduct (either machine code or some other compiler IR). Generatorification changes that. To facilitate this phase, we created a general-purpose bytecode rewriting facility for JSC. It allows us to insert and remove any kind of bytecode instruction, including jumps. It permits us to perform sophisticated control-flow edits on the bytecode stream. We use this to make generatorification easier, and we look forward to using it to implement other crazy future language features.

To allow suspension and resumption of the execution context at op_yield, the rewriter inserts the op_switch_imm opcode just after the op_enter opcode. At the point of op_yield, the transformed function saves the integer that represents the virtual instruction pointer and then returns from the function with op_ret. Then, when resuming, we use the inserted op_switch_imm with the saved integer, jumping to the point just after the op_yield which suspended the context.

To save and restore live registers, this pass performs liveness analysis to find live registers at op_yield and then inserts op_put_to_scope and op_get_from_scope operations to save their state and restore it (respectively). These opcodes are part of our closure object model, which happens to be appropriate here because JSC’s closures are just objects that statically know what their fields are and how they will be laid out. This allows fast allocation and fast access, which we already spent a great deal of time optimizing for actual JS closures. In this figure, generatorification performs liveness analysis and finds that the variable temp is live over the op_yield point. Because of this, the rewriter emits op_put_to_scope and op_get_from_scope to save and restore temp. This does not disrupt our optimizing compiler’s ability to reason about temp‘s value, since we had already previously solved that same problem for variables saved to closures.


The generatorification rewrite used bytecode desugaring to encapsulate the whole idea of generators into a bytecode phase that emits idiomatic JSC bytecode. This allows our entire optimization infrastructure to join the generator party. Programs that use generators can now run in all of our JIT tiers. At the time this change landed, it sped up Basic’s Average score by 41%. It also improved Basic overall: even the First Iteration score got 3% faster, since our low-latency DFG optimizing JIT is designed to provide a boost even for start-up code.

Generator: Safari-to-WebKit Nightly comparison

The data in the above graph was taken on a Mid 2014, 2.8 GHz Core i7, 16GB RAM, 15″ MacBook Pro, running macOS Sierra version 10.12.0. Safari 10.0.2 is the first version of Safari to ship with JavaScriptCore’s complete ES6 implementation. Safari 10.0.2 does not include any of the optimizations described in this post. The above graph shows that since implementing ES6, we’ve made significant improvements to JSC’s performance running Basic. We’ve made a 1.2x improvement in the First Iteration score, a 1.4x improvement in the Worst 4 Iterations score, and a 2.8x improvement in the Average score.

Desugaring is a classic technique. Crazy compiler algorithms are easiest to think about when they are confined to their own phase, so we turned our bytecode into a full-fledged compiler IR and implemented generatorification as a compiler phase over that IR. Our new bytecode rewriter is powerful enough to support many kinds of phases. It can insert and remove any kind of bytecode instruction including jumps, allowing for complex control flow edits. While it’s only used for generators presently, this rewriting facility can be used to implement complex ECMAScript features in the future.

Fast Map and Set

Map and Set are two new APIs in ES6 that make it a more expressive language to program in. Prior to ES6, there was no official hashtable API for JavaScript. It’s always been possible to use a JavaScript object as a hashtable if only Strings and Symbols are used as keys, but this isn’t nearly as useful as a hashtable that can take any value as a key. ES6 fixes this ancient language deficiency by adding new Map and Set types that accept any JavaScript value as a key.

Both Air and Basic use Map and Set. Profiling showed that iteration and lookup were by far the most common operations, which is fairly consistent with our experience elsewhere in the language. For example, we have always found it more important to optimize property loads than property stores, because loads are so much more common. In this section we present our new Map/Set implementation, which we optimized for the iteration and lookup patterns of ARES-6.

Fast Lookup

To make lookup fast, we needed to teach our JIT compilers about the internal workings of our hashtable. The main performance benefit of doing this comes from inlining the hashtable lookup into the IR for a function. This obviates the need to call out to C++ code. It also allows us to implement the lookup more efficiently by leveraging the compiler’s smarts. To understand why, let’s analyze a hashtable lookup in more detail. JSC’s hashtable implementation is based off the linear probing algorithm. When you perform map.has(key) inside a JS program, we’re really performing a few abstract operations under the hood. Let’s break those operations down into pseudo code:

let h = hash(key);
let bucket = map.findBucket(h);
let has = !isEmptyBucket(bucket);
return has;

You can think of the findBucket(h) operation as:

let bucket = startBucket(h);
while (true) {
    if (isEmptyBucket(bucket))
        return emptyBucketSentinel;

    // Note that the actual key comparison for ES6 Map and Set is not triple equals.
    // But it's close. We can assume it's triple equals for the sake of this explanation.
    if (bucket.key === key)
        return bucket;

    h = nextIndex(h);

There are many things that can be optimized here based on information we have about key. The compiler will often know the type of key, allowing it to emit a more efficient hash function, and a more efficient triple equals comparison inside the findBucket loop. The C code must handle JavaScript key values of all possible types. However, inside the compiler, if we know the type of key, we may be able to emit a triple equals comparison that is only a single machine compare instruction. The hash function over key also benefits from knowing the type of key. The C++ implementation of the hash function must handle keys of all types. This means that it’ll have to do a series of type checks on key to determine how it should be hashed. The reason for this is we hash numbers differently than strings, and differently than objects. The JIT compiler will often be able to prove the type of key, thereby allowing us to avoid multiple branches to learn key‘s type.

These changes alone already make Map and Set much faster. However, because the compiler now knows about the inner workings of a hashtable, it can further optimize code in a few neat ways. Let’s consider a common use of the Map API:

if (map.has(key))
    return map.get(key);

To understand how our compiler optimizations come into play, let’s look at how our DFG (Data Flow Graph) IR represents this program. DFG IR is used by JSC for performing high-level JavaScript-specific optimizations, including optimizations based on speculation and self-modifying code. This hashtable program will be transformed into roughly the following DFG IR (actual DFG IR dumps have a lot more information):

    BasicBlock #0:
        k: GetArgument("key")
        m: GetArgument("map")
        h: Hash(@k)
        b: GetBucket(@m, @h, @k)
        c: IsNonEmptyBucket(@b)
        Branch(@c, True:#1, False:#2)

    BasicBlock #1:
        h2: Hash(@k)
        b2: GetBucket(@m, @h2, @k)
        r: LoadFromBucket(@b2)

    BasicBlock #2:

DFG IR allows for precise modeling of effects of each operation as part of the clobberize analysis. We taught clobberize how to handle all of our new hashtable operations, like GetBucket, IsNonEmptyBucket, Hash, and LoadFromBucket. The DFG CSE (common subexpression elimination) phase uses this data and runs with it: it can see that the same Hash and GetBucket operations are performed twice without any operations that could change the state of the map in between them. Lots of other DFG phases use clobberize to understand the aliasing and effects of operations. This unlocks loop-invariant code motion and lots of other optimizations.

In this example, the optimized program will look like:

    BasicBlock #0:
        k: GetArgument("key")
        m: GetArgument("map")
        h: Hash(@k)
        b: GetBucket(@m, @h, @k)
        c: IsNonEmptyBucket(@b)
        Branch(@c, True:#1, False:#2)

    BasicBlock #1:
        r: LoadFromBucket(@b)

    BasicBlock #2:

Our compiler was able to optimize the redundant hashtable lookups in has and get down to a single lookup. In C++, hashtable APIs go to great lengths to provide ways of avoiding redundant lookups like the one here. Since ES6 provides only very simple Map/Set APIs, it’s difficult to avoid redundant lookups. Luckily, our compiler will often get rid of them for you.

Fast Iteration

As we wrote Basic and Air, we often found ourselves iterating over Maps and Sets because writing such code is natural and convenient. Because of this, we wanted to make Map and Set iteration fast. However, it’s not immediately obvious how to do this because ES6’s Map and Set iterate over keys in insertion order. Also, if a Map or Set is modified during iteration, the iterator must reflect the modifications.

We needed to use a data structure that is fast to iterate over. An obvious choice is to use a linked list. Iterating a linked list is fast. However, testing for the existence of something inside a linked list is O(n), where n is the number of elements in the list. To accommodate the fast lookup of a hashtable, and the fast iteration of a linked list, we chose a hybrid approach of a combo linked-list hashtable. Every time something is added to a Map or Set, it goes onto the end of the linked list. Every element in the linked list is a bucket. Each entry in the hashtable’s internal lookup buffer points to a bucket inside the linked list.

This is best understood through a picture. Consider the following program:

let map = new Map;
map.set(1, "one");
map.set(2, "two");
map.set(3, "three");

A traditional linear probing hashtable would look like this:

Traditional linear probing hashtable

However, in our scheme, we need to know the order in which we need to iterate the hashtable. So, our combo linked-list hashtable will look like this:

Combo linked-list hashtable

As mentioned earlier, when iterating over a Map or Set while changing it, the iterator must iterate over newly added values, and must not iterate over deleted values. Using a linked list data structure for iteration allows for a natural implementation of this requirement. Inside JSC, Map and Set iterators are just wrappers over hashtable buckets. Buckets are garbage collected, so an iterator can hang onto a bucket even after it has been removed from the hashtable. As an item is deleted from the hashtable, the bucket is removed from the linked list by updating the deleted bucket’s neighbors to now point to each other instead of the deleted bucket. Crucially, the deleted bucket will still point to its neighbors. This allows iterator objects to still point to the deleted bucket and then find their way back to non-deleted buckets. Asking such an iterator for its value will lead the iterator to traverse its neighbor pointer until it finds the next non-deleted bucket. The key insight here is that deleted buckets can always find the next non-deleted bucket by doing a succession of pointer chasing through their neighbor pointer. Note that this pointer chasing might lead the iterator to the end of the list, in which case, the iterator is closed.

For example, consider the previous program, now with the key 2 deleted:

let map = new Map;
map.set(1, "one");
map.set(2, "two");
map.set(3, "three");

Now, the hashtable will look like this:

Combo linear probing with entry 2 deleted

Let’s consider what happens when there is an iterator that’s pointing to the bucket for 2. When next() is called on that iterator, it’ll first check if the bucket it’s pointing to is deleted, and if so, it will traverse the linked list until it finds the first non-deleted entry. In this example, the iterator will notice the bucket for 2 is deleted, and it will traverse to the bucket for 3. It will see that 3 is not deleted, and it will yield its value.


We found ourselves using Map/Set a lot in the ES6 code that we wrote, so we decided to optimize these data structures to further encourage their use. Our Map/Set rewrite represents the hashtable’s underlying data structures in a way that is most natural for our garbage collector and DFG compiler to reason about. At the time this rewrite was committed, it contributed to an 8% overall performance improvement on ARES-6.

Phantom Spread

Another ES6 feature we found ourselves using is the combination of the rest parameter and the spread operator. It’s an intuitive programming pattern to gather some arguments into an array using the rest parameter, and then forward them to another function call using spread. For example, here is one way we use this in the Air benchmark:

visitArg(index, func, ...args)
    let replacement = func(this._args[index], ...args);
    if (replacement)
        this._args[index] = replacement;

A naive implementation of spread over the rest parameter will cause this code to run slower than needed because a spread operator requires performing the iterator protocol on its argument. Because the function visitArg is creating the args array, the DFG compiler knows exactly what data will be stored into it. Specifically, it’ll be filled with all but the first two arguments to visitArg. We chose to implement an optimization for this programming pattern because we think that the spread of a rest parameter will become a common ES6 programming idiom. In JSC, we also implement an optimization for the ES5 variant of this programming idiom:

    bar.apply(null, arguments);

The ideal code the DFG could emit to set up the stack frame for the call to func inside visitArg is a memcpy from the arguments on its own stack frame to that of func‘s stack frame. To be able to emit such code, the DFG compiler must prove that such an optimization is sound. To do this, the DFG must prove a few things. It must first ensure that the array iterator protocol is not observable. It proves it is not observable by ensuring that:

By performing such a proof, the DFG knows exactly what the protocol will do and it can model its behavior internally. Secondly, the DFG must prove that the args array hasn’t changed since being populated with the values from the stack. It does this by performing an escape analysis. The escape analysis will give a conservative answer to the question: has the args array changed since its creation on entry to the function? If the answer to the question is “no”, then the DFG does not need to allocate the args array. It can simply perform a memcpy when setting up func‘s stack frame. This is a huge speed improvement for a few reasons. The primary speed gain is from avoiding performing the high-overhead iterator protocol. The secondary improvement is avoiding a heap object allocation for the args array. When the DFG succeeds at performing this optimization, we say it has converted a Spread into a PhantomSpread. This optimization leverages the DFG’s ability to not only optimize away object allocations, but to rematerialize them if speculative execution fails and we fall back to executing the bytecode without optimizations.

Air: Safari-to-WebKit Nightly comparison

The data in the above graph was taken on a Mid 2014, 2.8 GHz Core i7, 16GB RAM, 15″ MacBook Pro, running macOS Sierra version 10.12.0. PhantomSpread was a significant new addition to our DFG JIT compiler. The Phantom Spread optimization, the rewrite of Map/Set, along with other overall JSC improvements, shows that we’ve sped up Air’s Average score by nearly 2x since Safari 10.0.2. Crucially, we did not introduce such a speed up at the expense of the First Iteration and Worst 4 Iterations scores. Both of those scores have also progressed.

Performance Results

We believe that a great way to keep ourselves honest about JavaScriptCore’s performance is to compare to the best performance baselines available. Therefore, we routinely compare our performance both to past versions of JavaScriptCore and to other JavaScript engines. This section shows how JavaScriptCore compares to Firefox and Chrome’s JavaScript engines.

The graphs in this section use data taken on a Late 2016, 2.9 GHz Core i5, 8GB RAM, 13″ MacBook Pro, running macOS High Sierra Beta 1.

Overall Performance Results

The figure above shows the overall ARES-6 scores in three different browsers: Safari 11 (13604., Firefox 53.0.3, and Chrome 58.0.3029.110. Our data shows that we’re nearly to 1.8x faster than Chrome, and close to 5x faster than Firefox.

Detailed Performance Results

The graph above shows detailed results for all four benchmarks and their three scores. It shows that JavaScriptCore is the fastest engine at running ARES-6 not only in aggregate score, but also in all three scores for each individual subtest.


ES6 is a major improvement to the JavaScript language, and we had fun giving it a test drive when creating ARES-6. Writing Air and Basic, and importing Babylon and ML, gave us a better grasp of how ES6 features are likely to be used. Adding new benchmarks to our repertoire always teaches us new lessons. Long term, this only works to our benefit if we keep adding new benchmarks and don’t over optimize for the same set of stale benchmarks. Going forward, we plan to add more subtests to ARES-6. We think adding more tests will keep us honest in not over-tuning for specific ES6 code patterns. If you have exciting ES6 (or ES7 or beyond) code that you think is worth including in ARES-6, we’d love to hear about it. You can get in touch either by filing a bug or contacting Filip, Saam, or Yusuke, on Twitter.

By Saam Barati, Yusuke Suzuki & Filip Pizlo at June 05, 2017 05:45 PM

May 31, 2017

Release Notes for Safari Technology Preview 31

Surfin’ Safari

Safari Technology Preview Release 31 is now available for download for macOS Sierra. If you already have Safari Technology Preview installed, you can update from the Mac App Store’s Updates tab. This release covers WebKit revisions 216643-217407.


  • Added media and type attribute support for <link rel="preload"> (r217247)
  • Added support for DOMMatrix and DOMMatrixReadOnly (r216959)
  • Fixed getElementById to return the correct element when a matching element is removed during beforeload event (r216978)
  • Fixed skipping <slot> children when collecting content for innerText (r216966)


  • Fixed a syntax error thrown when declaring a top level for-loop iteration variable the same as a function parameter (r217200)

Layout & Rendering

  • Added support for transform-box to switch sizing box in SVG (r217236)
  • Fixed clientX and clientY on mouse events to be relative to the layout viewport (r216824)
  • Fixed large animated images getting decoded as a large static image before receiving all of the data (r217262)
  • Fixed screen flickering caused by asynchronous image decoding for large images when interacting with the page (r216901)
  • Fixed element position when dragging jQuery Draggable elements with position:fixed after pinch zoom (r216803)
  • Fixed a timing issue causing a hardware-accelerated transform animation to misplace an element 50% of the time (r217075)


  • Implemented the place-self shorthand (r216829)
  • Fixed static position of positioned grid items (r216916)
  • Ignored collapsed tracks on content-distribution alignment (r217345)

Font Variations

  • Added support for calc() in font-variation-settings and font-feature-settings (r217267)
  • Enabled the woff2-variations format identifier for @font-face (r217241)
  • Updated the font-style implementation in the font selection algorithm (r217272)

Web Inspector

  • Added a new icon for Web Socket resources (r217067)
  • Changed adding new CSS rules so that the added rules go into a new Inspector Style Sheet resource that can be viewed, edited, and saved (r217258)
  • Fixed an issue where changes are not applied in Styles sidebar when switching tabs without blurring editor (r217266)
  • Fixed content views not getting restored on reload if its tree element is filtered out (r217317)
  • Fixed an error when trying to delete DOM breakpoints from the Debugger tab (r216681)
  • Fixed deleting a disabled XHR breakpoint (r217306)
  • Fixed miscellaneous RTL and localization issues (r216692, r217232, r217229)
  • Prevented loading the active recording until a Timeline view needs to be shown (r217379)


  • Added support for painting MSE video-element to canvas (r217185)
  • Fixed captions and subtitles not showing up in picture-in-picture for MSE content (r216951)
  • Fixed media element reporting hidden when in picture-in-picture mode and tab is backgrounded (r217223)

Web Driver

  • Fixed characters produced with the shift modifier on a QWERTY keyboard to be delivered as shift-down, char-down, char-up, and shift-up events (r217244)
  • Fixed navigator.webdriver to return false if the page is not controlled by automation (r217391)


  • Replaced CryptoOperationData with BufferSource (r216992)


  • Improved error message for Access-Control-Allow-Origin violations due to a misconfigured server (r217069)

By Jon Davis at May 31, 2017 05:00 PM

May 17, 2017

Release Notes for Safari Technology Preview 30

Surfin’ Safari

Safari Technology Preview Release 30 is now available for download for macOS Sierra. If you already have Safari Technology Preview installed, you can update from the Mac App Store’s Updates tab. This release covers WebKit revisions 215859-216643.


  • Implemented Subresource Integrity (SRI) (r216347)
  • Implemented X-Content-Type-Options:nosniff (r215753, r216195)
  • Added support for Unhandled Promise Rejection events (r215916)
  • Updated document.cookie to only return cookies if the document URL has a network scheme or is a file URL (r216341)
  • Removed the non-standard document.implementation.createCSSStyleSheet() API (r216458)
  • Removed the non-standard Element.scrollByLines() and scrollByPages() (r216456)
  • Changed to allow a null comparator in Array.prototype.sort (r216169)
  • Changed to set the Response.blob() type based on the content-type header value (r216353)
  • Changed Element.slot to be marked as [Unscopable] (r216228)
  • Implemented HTMLPreloadScanner support for <link preload> (r216143)
  • Fixed setting Response.blob() type correctly when the body is a ReadableStream (r216073)
  • Moved offsetParent, offsetLeft, offsetTop, offsetWidth, offsetHeight properties from Element to HTMLElement (r216466)
  • Moved the style property from Element to HTMLElement and SVGElement, then made it settable (r216426)


  • Fixed Arrow function access to this after eval('super()') within a constructor (r216329)
  • Added support for dashed values in unicode locale extensions (r216122)
  • Fixed the behaviour of the .sort(callback) method to match Firefox and Chrome (r216137)


  • Fixed space-evenly behavior with Flexbox (r216536)
  • Fixed font-stretch:normal to select condensed fonts (r216517)
  • Fixed custom properties used in rgb() with calc() (r216188)


  • Fixed the behavior of aria-orientation="horizontal" on a list (r216452)
  • Prevented exposing empty roledescription (r216457)
  • Propagated aria-readonly to grid descendants (r216425)
  • Changed to ignore aria-rowspan value if a rowspan value is provided for a <td> or <th> (r216167)
  • Fixed an issue causing VoiceOver to skip cells after a cell with aria-colspan (r216134)
  • Changed to treat cells with ARIA table cell properties as cells (r216123)
  • Updated implementation of aria-orientation to match specifications (r216089)

Web Inspector

  • Added resource load error reason text in the details sidebar (r216564)
  • Fixed toggling the Request and Response resource views in certain cases (r216461)
  • Fixed miscellaneous RTL and localization issues (r216465, r216629)
  • Fixed Option-Click on URL behavior in Styles sidebar (r216166)
  • Changed 404 Image Loads to appear as a failures in Web Inspector (r216138)


  • Fixed several issues that prevented cookie-related endpoints from working correctly (r216258, r216261, r216292)


  • Removed black background from video layer while in fullscreen (r216472)


  • Fixed problem with the CSS Font Loading API’s load() function erroneously resolving promises when used with preinstalled fonts (r216079)
  • Fixed flickering on asynchronous image decoding and ensured the image is incrementally displayed as new data is received (r216471)

By Jon Davis at May 17, 2017 05:00 PM

May 15, 2017

Responsive Design for Motion

Surfin’ Safari

WebKit now supports the prefers-reduced-motion media feature, part of CSS Media Queries Level 5, User Preferences. The feature can be used in a CSS @media block or through the window.matchMedia() interface in JavaScript. Web designers and developers can use this feature to serve alternate animations that avoid motion sickness triggers experienced by some site visitors.

To explain who this media feature is for, and how it’s intended to work, we’ll cover some background. Skip directly to the code samples or prefers-reduced-motion demo if you wish.

Motion as a Usability Tool

CSS transforms and animations were proposed by WebKit engineers nearly a decade ago as an abstraction of Core Animation concepts wrapped in a familiar CSS syntax. The standardization of CSS Transforms/CSS Animations and adoption by other browsers helped pave the way for web developers of all skill levels. Richly creative animations were finally within reach, without incurring the security risk and battery cost associated with plug-ins.

The perceptual utility of appropriate, functional motion can increase the understandability and —yes— accessibility of a user interface. There are numerous articles on the benefits of animation to increase user engagement:

In 2013, Apple released iOS 7, which included heavy use of animated parallax, dimensionality, motion offsets, and zoom effects. Animation was used as tool to minimize visual user interface elements while reinforcing a user’s understanding of their immediate and responsive interactions with the device. New capabilities in web and native platforms like iOS acted as a catalyst, leading the larger design community to a greater awareness of the benefits of user interface animation.

Since 2013, use of animation in web and native apps has increased by an order of magnitude.

Motion is Wonderful, Except When it’s Not

Included in the iOS accessibility settings is a switch titled “Reduce Motion.” It was added in iOS 7 to allow users the ability to disable parallax and app launching animations. In 2014, iOS included public API for native app developers to detect Reduce Motion (iOS, tvOS) and be notified when the iOS setting changed. In 2016, macOS added a similar user feature and API so developers could both detect Reduce Motion (macOS) and be notified when the macOS pref changed. The prefers-reduced-motion media feature was first proposed to the CSS Working Group in 2014, alongside the release of the iOS API.

Wait a minute! If we’ve established that animation can be a useful tool for increasing usability and attention, why should it ever be disabled or reduced?

The simplest answer is, “We’re not all the same.” Preference is subjective, and many power users like to reduce UI overhead even further once they’ve learned how the interface works.

The more important, objective answer is, “It’s a medical necessity for some.” In particular, this change is required for a portion of the population with conditions commonly referred to as vestibular disorders.

Vestibular Spectrum Disorder

Vestibular disorders are caused by problems affecting the inner ear and parts of the brain that control balance and spatial orientation. Symptoms can include loss of balance, nausea, and other physical discomfort. Vestibular disorders are more common than you might guess: affecting as many as 69 million people in the United States alone.

Most people experience motion sickness at some point in their lives, usually while traveling in a vehicle. Consider the last time you were car-sick, sea-sick, or air-sick. Nausea can be a symptom of situations where balance input from your inner ear seems to conflict with the visual orientation from your eyes. If your senses are sending conflicting signals to your brain, it doesn’t know which one to trust. Conflicting sensory input can also be caused by neurotoxins in spoiled food, hallucinogens, or other ingested poisons, so a common hypothesis is that these conflicting sensory inputs due to motion or vestibular responses lead your brain to infer its being poisoned, and seek to expel the poison through vomiting.

Whatever the underlying cause, people with vestibular disorders have an acute sensitivity to certain motion triggers. In extreme cases, the symptoms can be debilitating.

Vestibular Triggers

The following sections include examples of common vestibular motion triggers, and variants. If your site or web application includes similar animations, consider disabling or using variants when the prefers-reduced-motion media feature matches.

Trigger: Scaling and Zooming

Visual scaling or zooming animations give the illusion that the viewer is moving forward or backward in physical space. Some animated blurring effects give a similar illusion.

Note: It’s okay to keep many real-time, user-controlled direct manipulation effects such as pinch-to-zoom. As long as the interaction is predictable and understandable, a user can choose to manipulate the interface in a style or speed that works for their needs.

Example 1: Mouse-Triggered Scaling

How to Shoot on iPhone incorporates a number of video and motion effects, including a slowly scaling poster when the user’s mouse hovers over the video playback buttons.

The Apple.com team implemented prefers-reduced-motion to disable the scaling effect and background video motion.

Example 2: 3D Zoom + Blur

The macOS web site simulates flying away from Lone Pine Peak in the Sierra Nevada mountain range. A three-dimensional dolly zoom and animated blur give the viewer a sense that physical position and focal depth-of-field is changing.

In mobile devices, or in browsers that can’t support the more complicated animation, the effect is reduced to a simpler scroll view. By incorporating similar visual treatment, the simpler variant retains the original design intention while removing the effect. The same variant could be used with prefers-reduced-motion to avoid vestibular triggers.

Update May 25, 2017: The macOS web site has been modified to support reduced motion when preferred.

Trigger: Spinning and Vortex Effects

Effects that use spiraling or spinning movements can cause some people with vestibular disorders to lose their balance or vertical orientation.

Example 3: Spinning Parallax Starfield

Viljami Salminen Design features a spinning, background star field by default.

It has incorporated prefers-reduced-motion to stop the spinning effect for users with vestibular needs. (Note: The following video is entirely motionless.)

Trigger: Multi-Speed or Multi-Directional Movement

Parallax effects are widely known, but other variants of multi-speed or multi-directional movement can also trigger vestibular responses.

Example 4: iOS 10 Site Scrolling

The iOS 10 site features images moving vertically at varying speeds.

A similar variant without the scroll-triggered image offsets could be used with prefers-reduced-motion to avoid vestibular triggers.

Update May 25, 2017: The iOS 10 site has been modified to support reduced motion when preferred.

Trigger: Dimensionality or Plane Shifting

These animations give the illusion of moving two-dimensional (2D) planes in three-dimensional (3D) space. The technique is sometimes referred to as two-and-a-half-dimensional (2.5D).

Example 5: Plane-Shifted Scrolling

Apple’s Environment site features a animated solar array that tilts as the page scrolls.

The site supports a reduced motion variant where the 2.5D effect remains a still image.

Trigger: Peripheral Motion

Horizontal movement in the peripheral field of vision can cause disorientation or queasiness. Think back to the last time you read a book while in a moving vehicle. The center of your vision was focused on the text, but there was constant movement in the periphery. This type of motion is fine for some, and too much to stomach for others.

Example 6: Subtle, Constant Animation Near a Block of Text

After scrolling to the second section on Apple’s Environment site, a group of 10-12 leaves slowly floats near a paragraph about renewable energy.

In the reduced motion variant, these leaves are stationary to prevent peripheral movement while the viewer focuses on the nearby text content.

Take note that only the animations known to be problematic have be modified or removed from the site. More on that later.

Using Reduce Motion on the Web

Now that we’ve covered the types of animation that can trigger adverse vestibular symptoms, let’s cover how to implement the new media feature into your projects.

CSS @Media Block

An @media block is the easiest way to incorporate motion reductions into your site. Use it to disable or change animation and transition values, or serve a different background-image.

@media (prefers-reduced-motion) {
  /* adjust motion of 'transition' or 'animation' properties */

Review the prefers-reduced-motion demo source for example uses.

MediaQueryList Interface

Animations and DOM changes are sometimes controlled with JavaScript, so you can leverage the prefers-reduced-motion media feature with window.matchMedia and register for an event listener whenever the user setting changes.

var motionQuery = matchMedia('(prefers-reduced-motion)');
function handleReduceMotionChanged() {
  if (motionQuery.matches) {
    /* adjust motion of 'transition' or 'animation' properties */
  } else { 
    /* standard motion */
handleReduceMotionChanged(); // trigger once on load if needed

Review the prefers-reduced-motion demo source for example uses.

Using the Accessibility Inspector

When refining your animations, you could toggle the iOS Setting or macOS Preference before returning to your app to view the result, but this indirect feedback loop is slow and tedious. Fortunately, there’s a better way.

The Xcode Accessibility Inspector makes it easier to debug your animations by quickly changing any visual accessibility setting on the host Mac or a tethered device such as an iPhone.

  1. Attach your iOS device via USB.
  2. Select the iOS device in Accessibility Inspector.
  3. Select the Settings Tab.

Alternate closed-captioned version of the Accessibility Inspector demo below.

Don’t Reduce Too Much

In some cases, usability can suffer when reducing motion. If your site uses a vestibular trigger animation to convey some essential meaning to the user, removing the animation entirely may make the interface confusing or unusable.

Even if your site uses motion in a purely decorative sense, only remove the animations you know to be vestibular triggers. Unless a specific animation is likely to cause a problem, removing it prematurely only succeeds in making your site unnecessarily boring.

Consider each animation in its context. If you determine a specific animation is likely to be a vestibular trigger, consider serving an alternate, simpler animation, or display another visual indicator to convey the intended meaning.


  1. Motion can be a great tool for increasing usability and engagement, but certain visual effects trigger physical discomfort in some viewers.
  2. Avoid vestibular trigger animations where possible, and use alternate animations when a user enables the “Reduce Motion” setting. Try out these settings, and use the new media feature when necessary. Review the prefers-reduced-motion demo source for example uses.
  3. Remember that the Web belongs to the user, not the author. Always adapt your site to fit their needs.

More Information

By James Craig at May 15, 2017 07:00 PM

May 03, 2017

Javier Fernández: Can I use CSS Box Alignment ?

Igalia WebKit

As a member of the Igalia’s team implementing the CSS Grid Layout feature for Blink and WebKit rendering engines, I’m very proud of what we’ve achieved from our collaboration with Bloomberg. I think Grid is a very interesting feature for the Web Platform and we still can’t see all its potential.

One of my main assignments on this project is to implement the CSS Box Alignment spec for Grid. It’s obvious that alignment is an important feature for many cases in web development, but I consider it a key for a layout model like the one Grid provides.

We recently announced that the patch implementing the self-baseline alignment landed in Blink. This was the last alignment functionality pending to implement, so now we can consider that the spec is complete for Grid. However, implementing a feature like CSS Box Alignment has an additional complexity in the form of interoperability issues.

Interoperability is always a challenge when implementing any new specification, but I think it’s specially problematic for a feature like this for several reasons:

  • The feature applies to several layout models.
  • The CSS Flexible Box specification already defined some of the CSS properties and values.
  • Once a new layout model implements the new specification, Flexbox is forced to follow it as well.

I admit that the editors of this new specification document made a huge effort to keep backward compatibility with the Flexbox spec (which caused not so few implementation challenges). However, the current Flexbox implementation of the CSS properties and values that both specs have in common would become a Partial Implementation regarding the new spec.

Recently Florian Rivoal found out that this partial implementation of the CSS Box Alignment feature prevents the use of cascade or @support for providing customized fallbacks for the unimplemented Alignment properties.

What does Partial Implementation actually mean ?

As anybody can imagine, implementing a fancy web feature takes a considerable amount of time. During this period, the feature passes through several phases with different exposure to the end users. It’s precisely due to the importance of end user’s feedback that these new web features are shipped under experimental flags. This workflow is specially useful no only for browser devs but for the spec editors as well.

For this reason, the W3C CSS Working Group defines a general policy to manage Partial Implementations, which can be summarized as follows:

So that authors can exploit the forward-compatible parsing rules to assign fallback values, CSS renderers must treat as invalid (and ignore as appropriate) any at-rules, properties, property values, keywords, and other syntactic constructs for which they have no usable level of support. In particular, user agents must not selectively ignore unsupported property values and honor supported values in a single multi-value property declaration: if any value is considered invalid (as unsupported values must be), CSS requires that the entire declaration be ignored.

This policy is added to every spec as part of its Conformance appendix, so it is in the case of the CSS Box Alignment specification document. However, the interpretation of the Partial Implementation policy is far from trivial, specially for a feature like CSS Box Alignment. The most restrictive interpretation would imply the following facts:

  • Any new CSS property of the new spec should be declared invalid until is supported by all the layout models it applies to.
  • Any of the already existent CSS properties with new values defined in the new spec should be declared invalid until all these new values are implemented in all the layout models such property applies to.
  • Browsers shouldn’t ship (without experimental flags) any CSS property or value until it’s implemented in all the layout model it applies to.

When we discussed about this at Igalia we applied a less restrictive interpretation, based on the assumption that the spec actually defined several features which could be implemented and shipped independently, obviously avoiding any browsers interoperability issues. As it’s been always in the nature of the specification, keeping backward compatibility with Flexbox implementations has been a must, since its spec already defines some of the CSS properties now present in the new spec.

The issue filed by Florian was discussed during the Tokyo F2F Apr 19-21 2017 meeting, where it was agreed to add a new section in the CSS Box Alignment spec to clarify how implementors of this feature should manage Partial Implementations:

Since it is expected that support for the features in this module will be deployed in stages corresponding to the various layout models affected, it is hereby clarified that the rules for partial implementations that require treating as invalid any unsupported feature apply to any alignment keyword which is not supported across all layout modules to which it applies for layout models in which the implementation supports the property in general.

The new text added makes the Partial Implementation policy less restrictive and, even it contradicts our interpretation of independent alignment features per layout model, it affects only to models which already implement any of the CSS properties defined in the new spec. In this case, only Flexbox has to be updated to implement the new values defined for its alignment related CSS properties: align-content, justify-content and align-self.

Analysis of the implementation and shipment status

Before thinking on how to address the Partial Implementation issues, I decided to analyze what’s the status of the CSS Box Alignment feature in the different browsers. If you are interested in the full analysis, it’s available here. The following table shows the implementation status of the new spec in the Safary, Chrome and Firefox browsers, using a color code like unimplemented, only grid or both (flex and grid):

If you can try out some examples of these Partial Implementation issues, just try flexbox vs grid cases with some of these alignment values: align-items: center, align-self: left; align-content: start or justify-content: end.

The 3 major browsers analyzed have shipped most, if not all, the CSS Box Alignment spec implemented for CSS Grid Layout (since Chrome 57, Safari 10.1, Firefox 52). Firefox is the browser which implemented and shipped a wider support for CSS Flexible Box.

We can extract the following conclusions:

  • The 3 browsers analyzed have shipped Partial Implementations of the CSS Box Alignment specification, although Firefox is almost complete.
  • The 3 browsers have shipped a Grid feature that supports completely the new CSS Box Alignment spec, although Safari still misses the self-baseline values.
  • The 3 implementations of the new CSS Box Alignment specification are backward compatible with the CSS Flexible Box specification, even though it implements for some properties a lower level of the spec (e.g. self-baseline keywords)

Work in progress

Although we are still evaluating the problem together with the Blink and WebKit communities, at Igalia we are already working on improving the situation. We all agree on the damage to the Web Platform that these Partial Implementation issues are causing, as Florian pointed out initially, so that’s a good starting point. There are bug reports on both WebKit and Blink and we are already providing patches for some of them.

We are still discussing about the best approach, but our bet would be to request an intent-to-implement-and-ship for a CSS Box Alignment (for flexbox layout) feature. This approach fits naturally in our initial plans of implementing several independent features from the alignment specification. It seems that it’s what Firefox is doing, which already announced the implementation of CSS Box Alignment (for block layout)

Thanks to Bloomberg for sponsoring this work, as part of the efforts that Igalia has been doing all these years pursuing a better and more open web.

Igalia & Bloomberg logos

By jfernandez at May 03, 2017 08:19 PM

Release Notes for Safari Technology Preview 29

Surfin’ Safari

Safari Technology Preview Release 29 is now available for download for macOS Sierra. If you already have Safari Technology Preview installed, you can update from the Mac App Store’s Updates tab. This release covers WebKit revisions 215271-215859.


  • Implemented Intl.DateTimeFormat.prototype.formatToParts (r215616)
  • Improved Date.parse to accept wider range of date strings (r215359)
  • Implemented Object.isFrozen() and Object.isSealed() according to ECMA specifications (r215272)


  • Added support for percentage gaps for CSS Grid (r215463)
  • Changed :focus-within behavior to match specifications (r215719)


  • Avoided repaints for invisible animations on tumblr.com (r215507)
  • Fixed rendering flexbox children across columns (r215320)
  • Fixed text-align:start and text-align:end behavior in table cells (r215375)
  • Fixed animations with large negative animation-delays that fail depending on machine uptime (r215352)
  • Reduced redundant text measuring during mid-word breaking (r215666)
  • Changed memory handling to keep all of the decoded frames for an animated image if the total memory size of the frames is under 30MB (up from 5MB) (r215557)
  • Fixed <li> content inside <ul> to wrap mid-word when word-break:break-word is set (r215660)
  • Fixed the location of the “recent searches” popover of <input type="search"> in RTL mode (r215830)

Web Inspector

  • Added regular expression support to XHR breakpoints (r215584)
  • Added a pause reason for “All Requests” XHR breakpoint (r215427)
  • Fixed the enabled state of “All Requests” XHR breakpoint to be correctly restored (r215435)
  • Fixed a bug where XHR breakpoints would disappear when the inspected page is reloaded (r215473)
  • Fixed XHR breakpoints restored from settings but not appearing in the sidebar (r215422)
  • Fixed Network datagrid columns to correctly restore their shown or hidden state (r215449)
  • Added tooltips to Network grid items for easier reading when text overflows (r215631)
  • Fixed sorting by Priority column in Network datagrids (r215793)
  • Fixed the display of Web Socket messages with non-latin letters (r215388)
  • Prevented showing the Search tab for location links, prefer the Resources tab (r215630)
  • Changed to treat Uint8ClampedArray as an array, not an object (r215855)
  • Fixed Command-G (⌘G) shortcut to allow Find next to work in the console (r215795)
  • Implemented autocompletion for CSS variables (r215358)
  • Updated the icon for the Ignore resource cache button in the Network Tab (r215440)


  • Added support for ECDSA (r215423)
  • Improved converting an ECDSA signature binary into DER format (r215791)


  • Changed the role description of <hr> from “separator” to “rule” (r215532)


  • Restricted WebKit image formats to a known whitelist (r215706, r215829). WebKit now only loads images of the following formats:
    • PNG (.png)
    • GIF (.gif)
    • JPEG (.jpg), (.jpeg), (.jpe), (.jif), (.jfif), (.jfi)
    • JPEG 2000 (.jp2), (.j2k), (.jpf), (.jpx), (.jpm), (.mj2)
    • TIFF (.tiff), (.tif)
    • MPO (.mpo)
    • Microsoft Bitmap (.bmp), (.dib)
    • Microsoft Cursor (.cur)
    • Microsoft Icon (.ico)

Bug Fixes

  • Fixed an issue where the status bar would not display modifier key information (e.g. “Open * in new tab” when holding the Command key) (r215790)
  • Improved performance of typing on pages with many <input> elements
  • Fixed an issue where a hardware “enter” key would not dismiss JavaScript alert, confirm, or prompt; previously, only the “return” key would dismiss a dialog
  • Fixed QuotaExceededError when saving to localStorage in private browsing mode or WebDriver sessions (r215315)
  • Fixed an issue where the Content-Disposition header filename was ignored when the download attribute is specified (r215736)
  • Fixed escaping ‘<‘ and ‘>’ in attribute values when using XMLSerializer.serializeToString() API (r215648)
  • Fixed issues causing beforeunload dialog to be shown even though the user did not interact with the page (r215404)
  • Changed all CORS requests and cross origin access from file:// to be blocked unless Disable Local File Restrictions is selected from the Develop menu

By Jon Davis at May 03, 2017 05:00 PM

Carlos García Campos: WebKitGTK+ remote debugging in 2.18

Igalia WebKit

WebKitGTK+ has supported remote debugging for a long time. The current implementation uses WebSockets for the communication between the local browser (the debugger) and the remote browser (the debug target or debuggable). This implementation was very simple and, in theory, you could use any web browser as the debugger because all inspector code was served by the WebSockets. I said in theory because in the practice this was not always so easy, since the inspector code uses newer JavaScript features that are not implemented in other browsers yet. The other major issue of this approach was that the communication between debugger and target was not bi-directional, so the target browser couldn’t notify the debugger about changes (like a new tab open, navigation or that is going to be closed).

Apple abandoned the WebSockets approach a long time ago and implemented its own remote inspector, using XPC for the communication between debugger and target. They also moved the remote inspector handling to JavaScriptCore making it available to debug JavaScript applications without a WebView too. In addition, the remote inspector is also used by Apple to implement WebDriver. We think that this approach has a lot more advantages than disadvantages compared to the WebSockets solution, so we have been working on making it possible to use this new remote inspector in the GTK+ port too. After some refactorings to the code to separate the cross-platform implementation from the Apple one, we could add our implementation on top of that. This implementation is already available in WebKitGTK+ 2.17.1, the first unstable release of this cycle.

From the user point of view there aren’t many differences, with the WebSockets we launched the target browser this way:


This hasn’t changed with the new remote inspector. To start debugging we opened any browser and loaded

With the new remote inspector we have to use any WebKitGTK+ based browser and load


As you have already noticed, it’s no longer possible to use any web browser, you need to use a recent enough WebKitGTK+ based browser as the debugger. This is because of the way the new remote inspector works. It requires a frontend implementation that knows how to communicate with the targets. In the case of Apple that frontend implementation is Safari itself, which has a menu with the list of remote debuggable targets. In WebKitGTK+ we didn’t want to force using a particular web browser as debugger, so the frontend is implemented as a builtin custom protocol of WebKitGTK+. So, loading inspector:// URLs in any WebKitGTK+ WebView will show the remote inspector page with the list of debuggable targets.

It looks quite similar to what we had, just a list of debuggable targets, but there are a few differences:

  • A new debugger window is opened when inspector button is clicked instead of reusing the same web view. Clicking on inspect again just brings the window to the front.
  • The debugger window loads faster, because the inspector code is not served by HTTP, but locally loaded like the normal local inspector.
  • The target list page is updated automatically, without having to manually reload it when a target is added, removed or modified.
  • The debugger window is automatically closed when the target web view is closed or crashed.

How does the new remote inspector work?

The web browser checks the presence of WEBKIT_INSPECTOR_SERVER environment variable at start up, the same way it was done with the WebSockets. If present, the RemoteInspectorServer is started in the UI process running a DBus service listening in the IP and port provided. The environment variable is propagated to the child web processes, that create a RemoteInspector object and connect to the RemoteInspectorServer. There’s one RemoteInspector per web process, and one debuggable target per WebView. Every RemoteInspector maintains a list of debuggable targets that is sent to the RemoteInspector server when a new target is added, removed or modified, or when explicitly requested by the RemoteInspectorServer.
When the debugger browser loads an inspector:// URL, a RemoteInspectorClient is created. The RemoteInspectorClient connects to the RemoteInspectorServer using the IP and port of the inspector:// URL and asks for the list of targets that is used by the custom protocol handler to create the web page. The RemoteInspectorServer works as a router, forwarding messages between RemoteInspector and RemoteInspectorClient objects.

By carlos garcia campos at May 03, 2017 03:43 PM

April 20, 2017

A Few Words on Fetching Bytes

Surfin’ Safari

Like all good puzzles, a web browser is composed of many different pieces. Some are all shiny, like your favorite web API. Some are less visible, like HTML parsing and web resource loading.

Even dull pieces require lots of work to standardize their behavior across browsers. For example, HTML parsing originally provided only: Give me HTML and I’ll give you a document. Now, it is much more reliable across browsers because it has been standardized in detail. Similarly, the loading of web resources was somehow consistent up to: give me an HTTP request and I’ll get you a HTTP response. But loading a web resource encompasses much more than that. The Fetch specification thoroughly standardizes those details. As well as specifying how the browser loads resources, the Fetch specification also defines a JavaScript API for loading resources. This API, the Fetch API, is a replacement to XMLHttpRequest, providing the lowest-level set of options possible in the context of a web page. Let’s see how shiny Fetch API might be.

The Fetch API

The Fetch API consists of a single Promise-returning method called fetch. The returned value is a Response object which contains the response headers and body information. Let’s use the Fetch API to retrieve the list of WebKit features:

async function isFetchAPIFeelingGood() {
    let webkitFeaturesURL = "https://svn.webkit.org/repository/webkit/trunk/Source/WebCore/features.json";
    let response = await fetch(webkitFeaturesURL);
    let features = await response.json();
    return features.specification.find((feature) =>
        feature.name == "Fetch API");
isFetchAPIFeelingGood().then((value) => alert(!!value ? "Oh yes!" : "not really!"))

You might notice two await uses in the example above. fetch is returning a promise that gets resolved when the response headers are received. The data being requested is JSON. The second promise resolves when the entire response body is available.

fetch can take either a URL or a Request object. The Request object allows access to a whole new set of options compared to XMLHttpRequest. Let’s try again to check whether fetch API is supported in WebKit, but this time, let’s make sure our cache does not serve us some out-of-date information.

async function isFetchAPIFeelingGoodForReal() {
    let webkitFeaturesURL = "https://svn.webkit.org/repository/webkit/trunk/Source/WebCore/features.json";
    let response = await fetch(new Request(webkitFeaturesURL,
        { cache: "no-cache" }
    let latestFeatures = await response.json();
    return latestFeatures.specification.find((feature) =>
        feature.name == "Fetch API");

fetch also provides more flexible access to the response body. In addition to getting it in various flavors (JSON, arrayBuffer, blob, text…), the response provides a ReadableStream body attribute. This makes it possible to process chunks of bytes progressively as they arrive without buffering the whole data, and even aborting the resource load:

async function featureListAsAReader() {
    let webkitFeaturesURL = "https://svn.webkit.org/repository/webkit/trunk/Source/WebCore/features.json";
    let response = await fetch(new Request(webkitFeaturesURL));
    return response.body.getReader();

function checkChunk(searched, buffer, count)
    var i = 0;
    while (i < buffer.length) {
        if (buffer[i++] == searched.charCodeAt(count)) {
            if (++count == searched.length)
               return count;
        } else if (count) {
            count = 0;
    return count;

async function isFetchAPIFeelingGoodWhileChunky(reader, count)
    reader = reader ? reader : await featureListAsAReader();
    count = count ? count : 0;

    let chunk = await reader.read();
    if (chunk.done)
        return false;

    let searched = "Fetch API";
    count = checkChunk(searched, chunk.value, count);
    if (count == searched.length)
        return true;
    return isFetchAPISupported(reader, count);

Fetching The Future

The Fetch API journey is not finished. New proposals might cover important features of XMLHttpRequest that Fetch currently lacks, like early cancellation and timeout. New proposals might also cover HTTP/2 push and priority, as well as wider use of the Response object in web APIs: media elements, Web Assembly… The Fetch algorithm is also being constantly refined to reach full interoperability of web resource loading. A first iteration of WebKit Fetch API implementation shipped in Safari. The WebKit community is eager to hear about your feedback on this feature. Comments, suggestions, priorities, use cases, tests, bug reports and candies are all very welcome through the usual WebKit channels. That would be so fetch indeed!

View post on imgur.com

By Youenn Fablet at April 20, 2017 06:00 PM

April 19, 2017

Release Notes for Safari Technology Preview 28

Surfin’ Safari

Safari Technology Preview Release 28 is now available for download for macOS Sierra. If you already have Safari Technology Preview installed, you can update from the Mac App Store’s Updates tab. This release covers WebKit revisions 214535-215271.

Power and Performance

  • Changed to pause silent WebAudio rendering in background tabs (r214721)
  • Changed to pause animated SVG images on pages loaded in the background (r214561)
  • Changed to make inaudible background tabs become eligible for memory kill after 8 minutes (r215077)
  • Changed to kill any WebContent process using over 16 GB of memory (r215055)
  • Throttled DOM Timers to 30fps in cross-origin iframes that the user did not interact with (r215116)
  • Throttled requestAnimationFrame callbacks to 30fps in cross-origin iframes the user did not interact with (r215070, r215153)


  • Adapted content-alignment properties to the new baseline syntax (r214624)
  • Adapted place-content alignment shorthand to the new baseline syntax (r214852)
  • Adapted self-alignment properties to the new baseline syntax (r214564)
  • Fixed scroll offset jumps after a programmatic scroll in an overflow container with scroll snapping (r215075)
  • Implemented the place-items shorthand (r214966)
  • Implemented stroke-color CSS property (r215261)
  • Implemented stroke-miterlimit CSS property (r214787)
  • Unprefixed CSS cursor values grab and grabbing (r215146)


  • Fixed objects with gaps between numerical keys getting filled by NaN values (r214714)
  • Fixed Object.seal() and Object.freeze() on global this (r215072)
  • Fixed String.prototype.replace to correctly apply special replacement parameters when passed a function (r214662)


  • Changed _blank, _self, _parent, and _top browsing context names to be case-insensitive (r214944)
  • Cleaned up touch event handler registration when moving nodes between documents (r214819)
  • Fixed <input type="range"> to prevent breaking all mouse events when changing to disabled while active (r214955)
  • Prevented double downloads of preloaded content from when the content is in MemoryCache (r215229)
  • Fixed WebSocket.send (r215102)

Web Inspector

  • Added a preference for Auto Showing Scope Chain sidebar on pause (r214847)
  • Changed the order of Debugger tab sidebar panels: Scope Chain, Resource, Probes (r215047)
  • Changed XHR breakpoints to be global (r214956)
  • Changed hierarchical path component labels to guess directionality based on content for RTL layout (r214862)
  • Fixed RTL alignment of close button shown while docked (r214902)
  • Fixed RTL layout issues in call frame tree elements and async call stacks (r214846)
  • Fixed RTL layout issues in the debugger dashboard putting arrows on the wrong side (r214899)
  • Fixed RTL layout issues in Type Profiler popovers (r214906)
  • Fixed misplaced highlights in Search results of the Search navigation sidebar for RTL layout (r214864)
  • Fixed disappearing section when clicking on the body of a CSS rule after editing (r214863)
  • Fixed showing indicators for hidden DOM element breakpoints in the Elements tab (r214844)
  • Fixed blank Network tab content view after reload (r214551)
  • Made “Enter Class Name” text field wider so the placeholder text doesn’t clip (r215192)
  • Fixed probe values not showing in the Debugger tab sidebar (r214967)
  • Fixed focusing the Find banner immediately after showing it (r214856)
  • Fixed showing Source Map Resources in the Debugger Sources list (r215082)
  • Fixed Styles sidebar warning icon appearing inside property value text (r214617)
  • Fixed broken tabbing in Styles sidebar when additional “:” and “;” are in the property value (r215170)
  • Fixed clipped data in WebSockets data grid (r215206)
  • Fixed staying scrolled to the bottom as new WebSocket log messages get added (r214587)
  • Included additional pause reason details for DOM “subtree modified” breakpoint (r214861)
  • Included more Network information in Resource Details Sidebar (r214903)
  • Included all headers in the Request Headers section of the Resource details sidebar (r215062)


  • Fixed an issue that prevented non-popup windows from being maximized or resized
  • Fixed an issue that caused previously opened tabs to reopen when Safari was launched in order to run a WebDriver test


  • Exposed a new AXSubrole for the explicit ARIA “group” role (r214623)
  • Fixed VoiceOver web article navigation with an article rotor for sites like Facebook and Twitter (r215236)


  • Fixed seeks to currentTime=0 if currentTime is already 0 (r214959)


  • Fixed clipping across page breaks when including <caption>, <thead> or <tbody> in a <table> (r214712)
  • Fixed Japanese fonts in vertical text to support synthesized italics (r214848)
  • Fixed long Arabic text in ContentEditable with CSS white-space=pre to prevent hangs (r214726)
  • Fixed overly heavy fonts on facebook.com by attempting to normalize variation ranges (r214585, r214572)


  • Added support for AES-CTR (r215051)


  • Changed private browsing sessions to not look in keychain for client certificates (r215125)


  • Fixed an issue where Safari would throw an exception when evaluating JavaScript ending with an implied return value, where the final statement doesn’t include the return keyword

By Jon Davis at April 19, 2017 05:00 PM

April 05, 2017

WebGPU Prototype and Demos

Surfin’ Safari

A few weeks ago, we announced the creation of the W3C GPU for the Web Community Group and our proposal, WebGPU. As of Safari Technology Preview Release 26, and WebKit Nightly Build, a WebGPU prototype is available for you to experiment with on macOS.

To enable WebGPU, first make sure the Develop menu is visible using SafariPreferencesAdvancedShow Develop menu in menu bar. Then, in the Develop menu, make sure Experimental FeaturesWebGPU is checked.

We also have written some simple demos to give you an idea of how the API works. Note that our implementation and documented proposal are not quite aligned, so the code in these demos will change over time. We’ve tried to indicate the places in the code where the prototype is behind the proposal. And, to reiterate, this is a proposal – the final API will almost certainly be quite different.

You should be aware that it is not recommended to browse the Web with this feature enabled. Not only is it experimental and non-standard, we haven’t implemented any validation of content, so an error in WebGPU might cause a crash, or worse.

By Dean Jackson at April 05, 2017 10:40 PM

Release Notes for Safari Technology Preview 27

Surfin’ Safari

Safari Technology Preview Release 27 is now available for download for macOS Sierra. If you already have Safari Technology Preview installed, you can update from the Mac App Store’s Updates tab. This release covers WebKit revisions 213822-214535.

Browser Changes

  • Added a “Reload Page From Origin” alternate menu item to the View menu. This action reloads a page without using cached resources.
  • Removed the Option-Command-R (⌥⌘R) keyboard shortcut from “Enter/Exit Responsive Design Mode” and mapped it to “Reload Page From Origin” instead.
  • Removed the Disable Caches menu item in the Develop menu. The equivalent functionality is now available through Web Inspector’s Network tab.


  • Implemented ESNext Object Spread proposal (r214038)
  • Changed to allow labels named let when parsing a statement in non-strict mode (r213850)
  • Fixed const location = "foo" in a worker to not throw a SyntaxError (r214145)


  • Aligned initEvent, initCustomEvent, initMessageEvent with the latest specification (r213825)
  • Aligned Document.elementFromPoint() with the CSSOM specification (r213836)
  • Changed XMLHttpRequest getAllResponseHeaders() to transform header names to lowercase before sorting (r214252)
  • Fixed sending an empty "Access-Control-Request-Headers" in preflight requests (r214254)
  • Implemented self.origin (r214147)
  • Implemented the “noopener” feature for window.open() (r214251)
  • Improved index validation when using uint index values in WebGL (r214086)
  • Prevented beforeunload alerts when the user hasn’t interacted with the web page (r214277)
  • Prevented innerText setter from inserting an empty text node if the value starts with a newline (r214136)
  • Prevented new navigations during document unload (r214365)
  • Prevented WebSQL databases from being openable in private browsing (r214309)
  • Changed serialization of custom properties in longhand to be "", not the value of the shorthand property (r214383)
  • Changed to tear down descendant renderers when a <slot> display value is set to "contents" (r214232)


  • Fixed pausing animated SVG images when they are outside the viewport, or removed from the document (r214503, r214327)
  • Changed asynchronous image decoding to consider when the drawing size is smaller than the size of the image (r213830)
  • Prevented large images from being decoded asynchronously when they are drawn on a canvas (r214450)
  • Fixed the flow state for positioned inline descendants (r214119)
  • Fixed initial letter rendering that follows pagination (r214110)
  • Fixed clipping columns horizontally in multi-column layout (r213832)
  • Fixed animated GIFs that fail to play in multi-column layout (r213826)


  • Fixed an issue where a dynamically applied :empty pseudo class with display:none does not get unapplied (r214290)
  • Unprefixed -webkit-min-content, -webkit-max-content and -webkit-fit-content (r213831)


  • Fixed loading media files in a <video> tag that are served without a filename extension (r214269)
  • Suspended silent videos playback in background tabs to save CPU (r214195)

Web Inspector

  • Added “Disable Caches” toggle in the Network tab that only applies to the inspected page while Web Inspector is open. (r214494)
  • Added “Save Selected” context menu item to Console (r214077)
  • Added RTL support to the Timeline tab (r213925, r213942, r213928, r213997, r213924, r214009, r214062, r214076)
  • Added RTL support for the Find banner (r214048)
  • Added more accurate Resource Timing data in Web Inspector (r213917)
  • Added context menu item to log content of WebSocket frame (r214371)
  • Added icons for SVG Image cluster path components (r214011)
  • Added keyboard shortcut to clear timeline records (r214140)
  • Added a connection indicator for when a WebSocket connection is open or close (r214354)
  • Changed Option-clicking the close tab button to close all other tabs (r214464)
  • Changed to allow the user to copy locked CSS selectors in Style Rules sidebar (r213887)
  • Changed to allow users to click links in inline and user-agent styles (r214366)
  • Changed SVG image content view to allow toggling between the image and source (r213999)
  • Changed Event Listeners detail section to show listeners by element rather than by event (r213874)
  • Changed Event Listeners to add missing ‘once’ and ‘passive’ event listener flags (r213873)
  • Fixed an issue where adding a WebSocket message could change the currently selected resource (r214387)
  • Fixed clicking DOM breakpoint marker to enable and disable breakpoints (r214256)
  • Fixed an exception when clicking on Clear Network Items icon with the timing popover visible (r214199)
  • Fixed local storage keys and values starting with truncated strings (r214308)
  • Fixed empty attributes added to a DOM tree outline element adding whitespace within the tag (r214141)
  • Fixed an exception when fetching computed styles that can break future updates of section (r213961)
  • Fixed syntax highlighting and formatting when inspecting a main resource that is JavaScript or JSON (r214492)
  • Fixed pseudo-class markers overlapping DOM breakpoints and disclosure triangles (r214196)
  • Fixed an issue causing the Resource details sidebar to display previous image metrics when viewing resource where content load failed (r214436)
  • Fixed text selection in the Console to select only message text (r214024)
  • Fixed formatting JSON request data (r214487)
  • Fixed the filename used when saving a resource from the resource image content view (r214133)
  • The file save dialog no longer suggests the top level directory as the default location (r214442)


  • Fixed VoiceOver for editable text on the web (r214112)


  • Added support for SPKI/PKCS8 Elliptic Curve cryptography (r214074)

By Jon Davis at April 05, 2017 05:00 PM

April 04, 2017

Manuel Rego: Announcing a New Edition of the Web Engines Hackfest

Igalia WebKit

Another year, another Web Engines Hackfest. Following the tradition that started back in 2009, Igalia is arranging a new edition of the Web Engines Hackfest that will happen in A Coruña from Monday, 2nd October, to Wednesday, 4th October.

The hackfest is a gathering of participants from the different parts of the open web platform community, working on projects like Chromium/Blink, WebKit, Gecko, Servo, V8, JSC, SpiderMonkey, Chakra, etc. The main focus of the event is to increase collaboration between the different browsers implementors by working together for a few days. On top of that, we arrange a few talks about some interesting topics which the hackfest attendees are working on, and also arrange breakout sessions for in-depth discussions.

Web Engines Hackfest 2016 Main Room Web Engines Hackfest 2016 Main Room

Last year almost 40 hackers joined the event, the biggest number of attendees ever. Previous attendees might have already received an invitation, but if not, just send us a request if you want to attend this year.

If you don’t want to miss any update, remember to follow @webhackfest on Twitter. See you in October!

April 04, 2017 10:00 PM

March 29, 2017

New Web Features in Safari 10.1

Surfin’ Safari

A new version of Safari shipped with the release of iOS 10.3 and macOS Sierra 10.12.4. Safari on iOS 10.3 and Safari 10.1 on macOS adds many important web features and improvements from WebKit that we are incredibly excited about.

While this release makes the web platform more capable and powerful, it also makes web development easier, simplifying the ongoing maintenance of your code. We’re excited to see how web developers will translate these improvements into better experiences for users.

Read on for quick look at the features included in this release.


Fetch is a modern replacement for XMLHttpRequest. It provides a simpler approach to request resources asynchronously over the network. It also makes use of Promises from ECMAScript 2015 (ES6) for convenient, chain-able response handling. Compared to XMLHttpRequest, the Fetch API allows for cleaner, more readable code that is easier to maintain.

let jsonURLEndpoint = "https://svn.webkit.org/repository/webkit/trunk/Source/WebCore/features.json";
fetch(jsonURLEndpoint, {
    method: "get"
}).then(function(response) {
    response.json().then(function(json) {
}).catch(function(error) {

Find out more in the blog post, A Few Words On Fetching Bytes.

CSS Grid Layout

CSS Grid Layout gives web authors a powerful new layout system based on a grid of columns and rows in a container. It is a significant step forward in providing manageable page layout tools in CSS that enable complex graphic designs that respond to viewport changes. Authors can use CSS Grid Layout to more easily achieve designs normally seen in print, that before required the use of layout quirks in existing CSS tools like floats and Flexbox.

Read more in the blog post, CSS Grid Layout: A New Layout Module for the Web.

ECMAScript 2016 & ECMAScript 2017

WebKit added support in Safari 10.1 for both ECMAScript 2016 and ECMAScript 2017, the latest standards revisions for the JavaScript language. ECMAScript 2016 adds small incremental improvements, but the 2017 standard brings several substantial improvements to JavaScript.

ECMAScript 2016 includes the exponentiation operator (x ** y instead of Math.pow(x, y)) and Array.prototype.includes. Array.prototype.includes is similar to Array.prototype.indexOf, except it can find values including NaN.

ECMAScript 2017 brings async and await syntax, shared memory objects including Atomics and Shared Array Buffers, String.prototype.padStart, String.prototype.padEnd, Object.prototype.values, Object.prototype.entries, and allows trailing commas in function parameter lists and calls.

IndexedDB 2.0

WebKit’s IndexedDB implementation has significant improvements in this release. It’s now faster, standards compliant, and supports new IndexedDB 2.0 features. IndexedDB 2.0 adds support for binary data types as index keys, so you’ll no longer need to serialize them into strings or array objects. It also brings object store and index renaming, getKey() on IDBObjectStore, and getPrimaryKey() on IDBIndex.

Find out more in the Indexed Database API 2.0 specification.

Custom Elements

Custom Elements enables web authors to create reusable components defined by their own HTML elements without the dependency of a JavaScript framework. Like built-in elements, Custom Elements can communicate and receive new values in their attributes, and respond to changes in attribute values using reaction callbacks.

For more information, read the Introducing Custom Elements blog post.


The Gamepad API makes it possible to use game controllers in your web apps. Any gamepad that works on macOS without additional drivers will work on a Mac. All MFi gamepads are supported on iOS.

Read more about the API in the Gamepad specifications.

Pointer Lock

In Safari on macOS, requesting Pointer Lock on an element gives developers the ability to hide the mouse pointer and access the raw mouse movement data. This is particularly helpful for authors creating games on the web. It extends the MouseEvents interface with movementX and movementY properties to provide a stream of information even when the movements are beyond the boundaries of the visible range. In Safari, when the pointer is locked on an element, a banner is displayed notifying the user that the mouse cursor is hidden. Pressing the Escape key once dismisses the banner, and pressing the Escape key again will release the pointer lock on the element.

You can get more information from the Pointer Lock specifications.

Keyboard Input in Fullscreen

WebKit used to restrict keyboard input in HTML5 fullscreen mode. With Safari 10.1 on macOS, when using HTML5 fullscreen mode, WebKit removes the keyboard input restrictions.

Interactive Form Validation

With support for HTML Interactive Form Validation, authors can create forms with data validation contraints that are checked automatically by the browser when the form is submitted, all without the need for JavaScript. It greatly simplifies the complexity of ensuring good data entry from users on the client-side and minimizes the need for complex JavaScript.

Read more about HTML Interactive Form Validation in WebKit.

Input Events

Input Events simplifies implementing rich text editing experiences on the web in contenteditable regions. The Input Events API adds a new beforeinput event to monitor and intercept default editing behaviors and enhances the input event with new attributes.

You can read more about Enhanced Editing with Input Events.

HTML5 Download Attribute

The download attribute for anchor elements is now available in Safari 10.1 on macOS. It indicates the link target is a download link that should download a file instead of navigating to the linked resource. It also enables developers to create a link that downloads blob data as files entirely from JavaScript. Clicking a link with a download attribute causes the target resource to be downloaded as a file. The optional value of the download attribute can be used to provide a suggested name for the file.

<a href="https://webkit.org/favicon.ico" download="webkit-favicon.ico">Download Favicon</a>

Find out more from the Downloading resources section in the HTML specification.

HTML Media Capture

In Safari on iOS, HTML Media Capture extends file input controls in forms to allow users to use the camera or microphone on the device to capture data.

File inputs can be used to capture an image, video, or audio:

<input name="imageCapture" type="file" accept="image/*" capture>
<input name="videoCapture" type="file" accept="video/*" capture>
<input name="audioCapture" type="file" accept="audio/*" capture>

More details are available in the HTML Media Capture specification.

Improved Fixed and Sticky Element Positioning

When using pinch-to-zoom, fixed and sticky element positioning has improved behavior using a “visual viewports” approach. Using the visual viewports model, focusing an input field that triggers the on-screen keyboard no longer disables fixed and sticky positioning in Safari on iOS.

Improved Web Inspector Debugging

The WebKit team added support for debugging Web Worker JavaScript threads in Web Inspector’s Debugger tab. There are also improvements to debugger stepping with highlights for the currently-executing and about-to-execute statements. The highlights make it much clearer what code is going to execute during debugging, especially for JavaScript with complex control flow or many expressions on a single line.

Learn more about JavaScript Debugging Improvements in Web Inspector.

CSS Wide-Gamut Colors

Modern devices support a broader range of colors. Now, web authors can use CSS colors in wide-gamut color spaces, including the Display P3 color space. A new color-gamut media query can be used to test if the display is capable of displaying a given color space. Then, using the new CSS color() function, developers can define a color in a specific color space.

@media (color-gamut:p3) {
    .brightred {
        color: color(display-p3 1.0 0 0);

For more information, see the CSS Color Module Level 4 standards specification.

Reduced Motion Media Query

The new prefers-reduced-motion media query allows developers using animation to make accommodations for users with conditions where large areas of motion or drastic movements can trigger physical discomfort. With prefers-reduced-motion, authors can create styles that avoid motion for users that set the reduced motion preference in system settings.

@keyframes decorativeMotion {
    /* Keyframes for a decorative animation */

.background {
    animation: decorativeMotion 10s infinite alternate;

@media (prefers-reduced-motion) {
    .background {
        animation: none;

Read more about Responsive Design for Motion.


We’re looking forward to what developers will do with these features to make better experiences for users. These improvements are available to users running iOS 10.3 and macOS Sierra 10.12.4, as well as Safari 10.1 for OS X Yosemite and OS X El Capitan.

Most of these features were also previewed in Safari Technology Preview over the last few months. The changes included in this release of Safari span Safari Technology Preview releases 14, 15, 16, 17, 18, 19, and 20. You can download the latest Safari Technology Preview release to stay on the forefront of future web features.

Finally, we’d love to hear from you! Send a tweet to @webkit or @jonathandavis and let us know which of these features will have the most impact on your design or development work on the web.

By Jon Davis at March 29, 2017 10:00 PM

March 24, 2017

Michael Catanzaro: A Web Browser for Awesome People (Epiphany 3.24)

Igalia WebKit

Are you using a sad web browser that integrates poorly with GNOME or elementary OS? Was your sad browser’s GNOME integration theme broken for most of the past year? Does that make you feel sad? Do you wish you were using an awesome web browser that feels right at home in your chosen desktop instead? If so, Epiphany 3.24 might be right for you. It will make you awesome. (Ask your doctor before switching to a new web browser. Results not guaranteed. May cause severe Internet addiction. Some content unsuitable for minors.)

Epiphany was already awesome before, but it just keeps getting better. Let’s look at some of the most-noticeable new features in Epiphany 3.24.

You Can Load Webpages!

Yeah that’s a great start, right? But seriously: some people had trouble with this before, because it was not at all clear how to get to Epiphany’s address bar. If you were in the know, you knew all you had to do was click on the title box, then the address bar would appear. But if you weren’t in the know, you could be stuck. I made the executive decision that the title box would have to go unless we could find a way to solve the discoverability problem, and wound up following through on removing it. Now the address bar is always there at the top of the screen, just like in all those sad browsers. This is without a doubt our biggest user interface change:

Screenshot showing address bar visibleDiscover GNOME 3! Discover the address bar!

You Can Set a Homepage!

A very small subset of users have complained that Epiphany did not allow setting a homepage, something we removed several years back since it felt pretty outdated. While I’m confident that not many people want this, there’s not really any good reason not to allow it — it’s not like it’s a huge amount of code to maintain or anything — so you can now set a homepage in the preferences dialog, thanks to some work by Carlos García Campos and myself. Retro! Carlos has even added a home icon to the header bar, which appears when you have a homepage set. I honestly still don’t understand why having a homepage is useful, but I hope this allows a wider audience to enjoy Epiphany.

New Bookmarks Interface

There is now a new star icon in the address bar for bookmarking pages, and another new icon for viewing bookmarks. Iulian Radu gutted our old bookmarks system as part of his Google Summer of Code project last year, replacing our old and seriously-broken bookmarks dialog with something much, much nicer. (He also successfully completed a major refactoring of non-bookmarks code as part of his project. Thanks Iulian!) Take a look:

Manage Tons of Tabs

One of our biggest complaints was that it’s hard to manage a large number of tabs. I spent a few hours throwing together the cheapest-possible solution, and the result is actually pretty decent:

Firefox has an equivalent feature, but Chrome does not. Ours is not perfect, since unfortunately the menu is not scrollable, so it still fails if there is a sufficiently-huge number of tabs. (This is actually surprisingly-difficult to fix while keeping the menu a popover, so I’m considering switching it to a traditional non-popover menu as a workaround. Help welcome.) But it works great up until the point where the popover is too big to fit on your monitor.

Note that the New Tab button has been moved to the right side of the header bar when there is only one tab open, so it has less distance to travel to appear in the tab bar when there are multiple open tabs.

Improved Tracking Protection

I modified our adblocker — which has been enabled by default for years — to subscribe to the EasyPrivacy filters provided by EasyList. You can disable it in preferences if you need to, but I haven’t noticed any problems caused by it, so it’s enabled by default, not just in incognito mode. The goal is to compete with Firefox’s Disconnect feature. How well does it work compared to Disconnect? I have no clue! But EasyPrivacy felt like the natural solution, since we already have an adblocker that supports EasyList filters.

Disclaimer: tracking protection on the Web is probably a losing battle, and you absolutely must use the Tor Browser Bundle if you really need anonymity. (And no, configuring Epiphany to use Tor is not clever, it’s very dumb.) But EasyPrivacy will at least make life harder for trackers.

Insecure Password Form Warning

Recently, Firefox and Chrome have started displaying security warnings  on webpages that contain password forms but do not use HTTPS. Now, we do too:

I had a hard time selecting the text to use for the warning. I wanted to convey the near-certainty that the insecure communication is being intercepted, but I wound up using the word “cybercriminal” when it’s probably more likely that your password is being gobbled up by various  governments. Feel free to suggest changes for 3.26 in the comments.

New Search Engine Manager

Cedric Le Moigne spent a huge amount of time gutting our smart bookmarks code — which allowed adding custom search engines to the address bar dropdown in a convoluted manner that involved creating a bookmark and manually adding %s into its URL — and replacing it with an actual real search engine manager that’s much nicer than trying to add a search engine via bookmarks. Even better, you no longer have to drop down to the command line in order to change the default search engine to something other than DuckDuckGo, Google, or Bing. Yay!

New Icon

Jakub Steiner and Lapo Calamandrei created a great new high-resolution app icon for Epiphany, which makes its debut in 3.24. Take a look.

WebKitGTK+ 2.16

WebKitGTK+ 2.16 improvements are not really an Epiphany 3.24 feature, since users of older versions of Epiphany can and must upgrade to WebKitGTK+ 2.16 as well, but it contains some big improvements that affect Epiphany. (For example, Žan Doberšek landed an important fix for JavaScript garbage collection that has resulted in massive memory reductions in long-running web processes.) But sometimes WebKit improvements are necessary for implementing new Epiphany features. That was true this cycle more than ever. For example:

  • Carlos García added a new ephemeral mode API to WebKitGTK+, and modified Epiphany to use it in order to make incognito mode much more stable and robust, avoiding corner cases where your browsing data could be leaked on disk.
  • Carlos García also added a new website data API to WebKitGTK+, and modified Epiphany to use it in the clear data dialog and cookies dialog. There are no user-visible changes in the cookies dialog, but the clear data dialog now exposes HTTP disk cache, HTML local storage, WebSQL, IndexedDB, and offline web application cache. In particular, local storage and the two databases can be thought of as “supercookies”: methods of storing arbitrary data on your computer for tracking purposes, which persist even when you clear your cookies. Unfortunately it’s still not possible to protect against this tracking, but at least you can view and delete it all now, which is not possible in Chrome or Firefox.
  • Sergio Villar Senin added new API to WebKitGTK+ to improve form detection, and modified Epiphany to use it so that it can now remember passwords on more websites. There’s still room for improvement here, but it’s a big step forward.
  • I added new API to WebKitGTK+ to improve how we handle giving websites permission to display notifications, and hooked it up in Epiphany. This fixes notification requests appearing inappropriately on websites like the https://riot.im/app/.

Notice the pattern? When there’s something we need to do in Epiphany that requires changes in WebKit, we make it happen. This is a lot more work, but it’s better for both Epiphany and WebKit in the long run. Read more about WebKitGTK+ 2.16 on Carlos García’s blog.

Future Features

Unfortunately, a couple exciting Epiphany features we were working on did not make the cut for Epiphany 3.24. The first is Firefox Sync support. This was developed by Gabriel Ivașcu during his Google Summer of Code project last year, and it’s working fairly well, but there are still a few problems. First, our current Firefox Sync code is only able to sync bookmarks, but we really want it to sync much more before releasing the feature: history and open tabs at the least. Also, although it uses Mozilla’s sync server (please thank Mozilla for their quite liberal terms of service allowing this!), it’s not actually compatible with Firefox. You can sync your Epiphany bookmarks between different Epiphany browser instances using your Firefox account, which is great, but we expect users will be quite confused that they do not sync with your Firefox bookmarks, which are stored separately. Some things, like preferences, will never be possible to sync with Firefox, but we can surely share bookmarks. Gabriel is currently working to address these issues while participating in the Igalia Coding Experience program, and we’re hopeful that sync support will be ready for prime time in Epiphany 3.26.

Also missing is HTTPS Everywhere support. It’s mostly working properly, thanks to lots of hard work from Daniel Brendle (grindhold) who created the libhttpseverywhere library we use, but it breaks a few websites and is not really robust yet, so we need more time to get this properly integrated into Epiphany. The goal is to make sure outdated HTTPS Everywhere rulesets do not break websites by falling back automatically to use of plain, insecure HTTP when a load fails. This will be much less secure than upstream HTTPS Everywhere, but websites that care about security ought to be redirecting users to HTTPS automatically (and also enabling HSTS). Our use of HTTPS Everywhere will just be to gain a quick layer of protection against passive attackers. Otherwise, we would not be able to enable it by default, since the HTTPS Everywhere rulesets are just not reliable enough. Expect HTTPS Everywhere to land for Epiphany 3.26.

Help Out

Are you a computer programmer? Found something less-than-perfect about Epiphany? We’re open for contributions, and would really appreciate it if you would try to fix that bug or add that feature instead of slinking back to using a less-awesome web browser. One frequently-requested feature is support for extensions. This is probably not going to happen anytime soon — we’d like to support WebExtensions, but that would be a huge effort — but if there’s some extension you miss from a sadder browser, ask if we’d allow building it into Epiphany as a regular feature. Replacements for popular extensions like NoScript and Greasemonkey would certainly be welcome.

Not a computer programmer? You can still help by reporting bugs on GNOME Bugzilla. If you have a crash to report, learn how to generate a good-quality stack trace so that we can try to fix it. I’ve credited many programmers for their work on Epiphany 3.24 up above, but programming work only gets us so far if we don’t know about bugs. I want to give a shout-out here to Hussam Al-Tayeb, who regularly built the latest code over the course of the 3.24 development cycle and found lots of problems for us to fix. This release would be much less awesome if not for his testing.

OK, I’m done typing stuff now. Onwards to 3.26!

By Michael Catanzaro at March 24, 2017 01:18 AM

March 22, 2017

Release Notes for Safari Technology Preview 26

Surfin’ Safari

Safari Technology Preview Release 26 is now available for download for macOS Sierra. If you already have Safari Technology Preview installed, you can update from the Mac App Store’s Updates tab. This release covers WebKit revisions 213542-213822.



  • Added support for history.scrollRestoration (r213590)
  • Aligned Document.elementFromPoint() with the CSSOM specification (r213646)
  • Changed the parameter to input.setCustomValidity() to not be nullable (r213606)
  • Fixed transitions and animations of background-position with right-relative and bottom-relative values (r213603)
  • Fixed an issue where WebSQL directories were not removed when removing website data (r213547)
  • Made the XMLHttpRequest method setRequestHeader() use “,” (including a space) as the separator (r213766)
  • Prevented displaying the label of an <option> element in quirks mode (r213542)
  • Prevented extra downloads of preloaded CSS (r213672)
  • Dropped support for non-standard document.all.tags() (r213619)


  • Implemented stroke-width CSS property (r213634)


  • Enabled asynchronous image decoding for large images (r213764, r213563)
  • Fixed memory estimate for layers supporting subpixel-antialised text (r213767)
  • Fixed columns getting clipped horizontally in CSS Multicolumn (r213593)

Web Inspector

  • Added DOM breakpoints for pausing on node and subtree modifications (r213626)
  • Added XHR breakpoints for pausing on requests by URL (r213691)
  • Added a “Create Breakpoint” context menu item for linked source locations (r213617)
  • Added settings for controlling Styles sidebar intelligence (r213635)
  • Added cache source information (Memory Cache or Disk Cache) in the Network tab (r213621)
  • Added protocol, remote address, priority, and connection ID in the Network tab (r213682)
  • Added individual messages to the content pane for a WebSocket (r213666)
  • Fixed an issue where the DOM tree is broken if an element has a debounce attribute (r213565)
  • Fixed an issue in the Resources tab navigation bar allowing the same file from a contextual menu item to be saved more than once (r213738)
  • Improved the layout of the compositing reasons in the Layers sidebar popover (r213739)


  • Fixed an issue where automation commands hang making it impossible to navigate back or forward (r213790)


  • Implemented ECDH ImportKey and ExportKey operations (r213560)

By Jon Davis at March 22, 2017 05:00 PM

March 20, 2017

Carlos García Campos: WebKitGTK+ 2.16

Igalia WebKit

The Igalia WebKit team is happy to announce WebKitGTK+ 2.16. This new release drastically improves the memory consumption, adds new API as required by applications, includes new debugging tools, and of course fixes a lot of bugs.

Memory consumption

After WebKitGTK+ 2.14 was released, several Epiphany users started to complain about high memory usage of WebKitGTK+ when Epiphany had a lot of tabs open. As we already explained in a previous post, this was because of the switch to the threaded compositor, that made hardware acceleration always enabled. To fix this, we decided to make hardware acceleration optional again, enabled only when websites require it, but still using the threaded compositor. This is by far the major improvement in the memory consumption, but not the only one. Even when in accelerated compositing mode, we managed to reduce the memory required by GL contexts when using GLX, by using OpenGL version 3.2 (core profile) if available. In mesa based drivers that means that software rasterizer fallback is never required, so the context doesn’t need to create the software rasterization part. And finally, an important bug was fixed in the JavaScript garbage collector timers that prevented the garbage collection to happen in some cases.

CSS Grid Layout

Yes, the future here and now available by default in all WebKitGTK+ based browsers and web applications. This is the result of several years of great work by the Igalia web platform team in collaboration with bloomberg. If you are interested, you have all the details in Manuel’s blog.


The WebKitGTK+ API is quite complete now, but there’s always new things required by our users.

Hardware acceleration policy

Hardware acceleration is now enabled on demand again, when a website requires to use accelerated compositing, the hardware acceleration is enabled automatically. WebKitGTK+ has environment variables to change this behavior, WEBKIT_DISABLE_COMPOSITING_MODE to never enable hardware acceleration and WEBKIT_FORCE_COMPOSITING_MODE to always enabled it. However, those variables were never meant to be used by applications, but only for developers to test the different code paths. The main problem of those variables is that they apply to all web views of the application. Not all of the WebKitGTK+ applications are web browsers, so it can happen that an application knows it will never need hardware acceleration for a particular web view, like for example the evolution composer, while other applications, especially in the embedded world, always want hardware acceleration enabled and don’t want to waste time and resources with the switch between modes. For those cases a new WebKitSetting hardware-acceleration-policy has been added. We encourage everybody to use this setting instead of the environment variables when upgrading to WebKitGTk+ 2.16.

Network proxy settings

Since the switch to WebKit2, where the SoupSession is no longer available from the API, it hasn’t been possible to change the network proxy settings from the API. WebKitGTK+ has always used the default proxy resolver when creating the soup context, and that just works for most of our users. But there are some corner cases in which applications that don’t run under a GNOME environment want to provide their own proxy settings instead of using the proxy environment variables. For those cases WebKitGTK+ 2.16 includes a new UI process API to configure all proxy settings available in GProxyResolver API.

Private browsing

WebKitGTK+ has always had a WebKitSetting to enable or disable the private browsing mode, but it has never worked really well. For that reason, applications like Epiphany has always implemented their own private browsing mode just by using a different profile directory in tmp to write all persistent data. This approach has several issues, for example if the UI process crashes, the profile directory is leaked in tmp with all the personal data there. WebKitGTK+ 2.16 adds a new API that allows to create ephemeral web views which never write any persistent data to disk. It’s possible to create ephemeral web views individually, or create ephemeral web contexts where all web views associated to it will be ephemeral automatically.

Website data

WebKitWebsiteDataManager was added in 2.10 to configure the default paths on which website data should be stored for a web context. In WebKitGTK+ 2.16 the API has been expanded to include methods to retrieve and remove the website data stored on the client side. Not only persistent data like HTTP disk cache, cookies or databases, but also non-persistent data like the memory cache and session cookies. This API is already used by Epiphany to implement the new personal data dialog.

Dynamically added forms

Web browsers normally implement the remember passwords functionality by searching in the DOM tree for authentication form fields when the document loaded signal is emitted. However, some websites add the authentication form fields dynamically after the document has been loaded. In those cases web browsers couldn’t find any form fields to autocomplete. In WebKitGTk+ 2.16 the web extensions API includes a new signal to notify when new forms are added to the DOM. Applications can connect to it, instead of document-loaded to start searching for authentication form fields.

Custom print settings

The GTK+ print dialog allows the user to add a new tab embedding a custom widget, so that applications can include their own print settings UI. Evolution used to do this, but the functionality was lost with the switch to WebKit2. In WebKitGTK+ 2.16 a similar API to the GTK+ one has been added to recover that functionality in evolution.

Notification improvements

Applications can now set the initial notification permissions on the web context to avoid having to ask the user everytime. It’s also possible to get the tag identifier of a WebKitNotification.

Debugging tools

Two new debugged tools are now available in WebKitGTk+ 2.16. The memory sampler and the resource usage overlay.

Memory sampler

This tool allows to monitor the memory consumption of the WebKit processes. It can be enabled by defining the environment variable WEBKIT_SMAPLE_MEMORY. When enabled, the UI process and all web process will automatically take samples of memory usage every second. For every sample a detailed report of the memory used by the process is generated and written to a file in the temp directory.

Started memory sampler for process MiniBrowser 32499; Sampler log file stored at: /tmp/MiniBrowser7ff2246e-406e-4798-bc83-6e525987aace
Started memory sampler for process WebKitWebProces 32512; Sampler log file stored at: /tmp/WebKitWebProces93a10a0f-84bb-4e3c-b257-44528eb8f036

The files contain a list of sample reports like this one:

Timestamp                          1490004807
Total Program Bytes                1960214528
Resident Set Bytes                 84127744
Resident Shared Bytes              68661248
Text Bytes                         4096
Library Bytes                      0
Data + Stack Bytes                 87068672
Dirty Bytes                        0
Fast Malloc In Use                 86466560
Fast Malloc Committed Memory       86466560
JavaScript Heap In Use             0
JavaScript Heap Committed Memory   49152
JavaScript Stack Bytes             2472
JavaScript JIT Bytes               8192
Total Memory In Use                86477224
Total Committed Memory             86526376
System Total Bytes                 16729788416
Available Bytes                    5788946432
Shared Bytes                       1037447168
Buffer Bytes                       844214272
Total Swap Bytes                   1996484608
Available Swap Bytes               1991532544

Resource usage overlay

The resource usage overlay is only available in Linux systems when WebKitGTK+ is built with ENABLE_DEVELOPER_MODE. It allows to show an overlay with information about resources currently in use by the web process like CPU usage, total memory consumption, JavaScript memory and JavaScript garbage collector timers information. The overlay can be shown/hidden by pressing CTRL+Shit+G.

We plan to add more information to the overlay in the future like memory cache status.

By carlos garcia campos at March 20, 2017 03:19 PM

Enrique Ocaña: Media Source Extensions upstreaming, from WPE to WebKitGTK+

Igalia WebKit

A lot of good things have happened to the Media Source Extensions support since my last post, almost a year ago.

The most important piece of news is that the code upstreaming has kept going forward at a slow, but steady pace. The amount of code Igalia had to port was pretty big. Calvaris (my favourite reviewer) and I considered that the regular review tools in WebKit bugzilla were not going to be enough for a good exhaustive review. Instead, we did a pre-review in GitHub using a pull request on my own repository. It was an interesting experience, because the change set was so large that it had to be (artificially) divided in smaller commits just to avoid reaching GitHub diff display limits.

394 GitHub comments later, the patches were mature enough to be submitted to bugzilla as child bugs of Bug 157314 – [GStreamer][MSE] Complete backend rework. After some comments more in bugzilla, they were finally committed during Web Engines Hackfest 2016:

Some unforeseen regressions in the layout tests appeared, but after a couple of commits more, all the mediasource WebKit tests were passing. There are also some other tests imported from W3C, but I kept them still skipped because webm support was needed for many of them. I’ll focus again on that set of tests at its due time.

Igalia is proud of having brought the MSE support up to date to WebKitGTK+. Eventually, this will improve the browser video experience for a lot of users using Epiphany and other web browsers based on that library. Here’s how it enables the usage of YouTube TV at 1080p@30fps on desktop Linux:

Our future roadmap includes bugfixing and webm/vp9+opus support. This support is important for users from countries enforcing patents on H.264. The current implementation can’t be included in distros such as Fedora for that reason.

As mentioned before, part of this upstreaming work happened during Web Engines Hackfest 2016. I’d like to thank our sponsors for having made this hackfest possible, as well as Metrological for giving upstreaming the importance it deserves.

Thank you for reading.


By eocanha at March 20, 2017 11:55 AM

March 15, 2017

Manuel Rego: CSS Grid Layout is Here to Stay

Igalia WebKit

It’s been a long journey but finally CSS Grid Layout is here! 🚀 In the past week, Chrome 57 and Firefox 52 were released, becoming the first browsers to ship CSS Grid Layout unprefixed (Explorer/Edge has been shipping an older, prefixed version of the spec since 2012). Not only that, but Safari will hopefully be shipping it very soon too.

I’m probably biased after having worked on it for a few years, but I believe CSS Grid Layout is going to be a big step in the history of the Web. Web authors have been waiting for a solution like this since the early days of the Web, and now they can use a very powerful and flexible layout module supported natively by the browser, without the need of any external frameworks.

Igalia has been playing a major role in the implementation of CSS Grid Layout in Chromium/Blink and Safari/WebKit since 2013 sponsored by Bloomberg. This is a blog post about that successful collaboration.

A blast from the past

Grids are not something new at all, since we can even find references to them in some of the initial discussions of the CSS creators. Next is an excerpt from a mail by Håkon Wium Lie in June 1995 to www-style:

Grids! Let the style sheet carve up the canvas into golden rectangles, and use an expert system to lay out the elements!! Ok, drop the expert system and define a set of simple rules that we hardcode.. whoops! But grids do look nice!


Since that time the Web hasn’t stopped moving and there have been different solutions and approaches to try to solve the problem of having grid-based designs in HTML/CSS.

At the beginning of the decade Microsoft started to work on what eventually become the CSS Grid Layout initial specification. This spec was based on the Internet Explorer 10 implementation and the experience gathered by Microsoft during its development. IE10 was released in 2012, shipping a prefixed version of that initial spec.

Then Google started to add support to WebKit at the end of 2011. At that time, WebKit was the engine used by both Chromium and Safari; later in 2012 it would be forked to create Blink.

Meanwhile, Mozilla had not started the Grid implementation in Firefox as they had some conflicts with their XUL grid layout type.

Igalia and Bloomberg collaboration

Bloomberg uses Chromium and they were looking forward to having a proper solution for their layout requirements. They detected performance issues due to the limitations of the current layout modules available on the Web. They see CSS Grid Layout as the right way to fix those problems and cover their needs.

Bloomberg decided to push CSS Grid Layout implementation as part of the collaboration with Igalia. My colleagues, Sergio Villar and Xan López, started to work on CSS Grid Layout around the summer of 2013. In 2014, Javi Fernández and I replaced Xan, joining the effort as well. We’ve been working on this for more than 3 years and counting.

At the beginning, we were working together with some Google folks but later Igalia took the lead role in the development of the specification. The spec has evolved and changed quite a lot since 2013, so we’ve had to deal with all these changes always trying to keep our implementations up to date, and at the same time continue to add new features. As the codebase in Blink and WebKit was still sharing quite a lot of things after the fork, we were working on both implementations at the same time.

Igalia and Bloomberg working together to build a better web Igalia and Bloomberg working together to build a better web

The results of this collaboration have been really satisfactory, as now CSS Grid Layout has shipped in Chromium and enabled by default in WebKit too (which will hopefully mean that it’ll be shipped in the upcoming Safari 10.1 release too).

Thanks @jensimmons for the feedback regarding Safari 10.1.

And now what?

Update your browsers, be sure you grab a version with Grid Layout support and start to use CSS Grid Layout, play with it, experiment and so on. We’d love to get bug reports and feedback about it. It’s too late to change the current version of the spec, but ideas for a future version are already being recorded in the CSS Working Group GitHub repository.

If you want to start with Grid Layout, there are plenty of resources available on the Internet:

It’s possible to think that now that CSS Grid Layout has shipped, it’s all over. Nothing is further from the truth as there is still a lot of work to do:

  • An important step would be to complete the W3C Test Suite. Igalia has been contributing to it and it’s currently imported into Blink and WebKit, but it doesn’t cover the whole spec yet.
  • There are some missing features in the current implementations. For example, nobody supports subgrids yet, web authors tell us that they would love to have them available. Another example, in Blink and WebKit is that we are still finishing the support for baseline alignment.
  • When bugs and issues appear they will need to be fixed and some might even imply some minor modifications to the spec.
  • Performance optimizations should be done. CSS Grid Layout is a huge spec so the biggest part effort so far has been done in the implementation. Now it’s time to improve performance of different use cases.
  • And as I explained earlier, people are starting to think about new features for a future version of the spec. Progress won’t stop now.


First of all, it’s important to highlight once again Bloomberg’s role in the development of CSS Grid Layout. Without their vision and support it probably would not be have shipped so soon.

But this is not an individual effort, but something much bigger. I’ll mention several people next, but I’m sure I’ll forget a lot of them, so please forgive me in advance.

So big thanks to:

  • The Microsoft folks who started the spec.
  • The current spec editors: Elika J. Etemad (fantasai), Rossen Atanassov, and Tab Atkins Jr. Especially fantasai & Tab, who have been dealing with most of the issues we have reported.
  • The whole CSS Working Group for their work on this spec.
  • Our reviewers in both Blink and WebKit: Christian Biesinger, Darin Adler, Julien Chaffraix, and many other.
  • Other implementors: Daniel Holbert, Mats Palmgren, etc.
  • People spreading the word about CSS Grid Layout: Jen Simmons, Rachel Andrew, etc.
  • The many other people I’m missing in this list who helped to make CSS Grid Layout the newest layout module for the Web.

Thanks to you all! 😻 And particularly to Bloomberg for letting Igalia be part of this amazing experience. We’re really happy to have walked this path together and we really hope to do more cool stuff in the future.


March 15, 2017 11:00 PM

March 09, 2017

CSS Grid Layout: A New Layout Module for the Web

Surfin’ Safari

People have been using grid designs in magazines, newspapers, posters, etc. for a long time before the Web appeared. At the point when web developers started to create web pages, many of them were based on a grid layout. Different solutions have been used to create grid layouts, like tables, floats, inline blocks, or flexboxes, but all of these techniques have different issues when you try to define a complex grid design.

In order to solve these problems, a new standard was defined to provide a good solution to create grid designs. This specification, called CSS Grid Layout, allows users to very easily create two-dimensional layouts on the Web. It has been designed specifically for this purpose and it brings very powerful features to divide the web page into different regions, granting great flexibility to web authors in order to define the sizing of the different sections and how the elements are positioned in each of them.

Grid Layout has been under development in WebKit for a while, and you can experiment with Grid Layout today using WebKit in Safari Technology Preview.

Basic Concepts

A grid is a structure made up of a series of intersecting lines. The main concepts of the CSS Grid Layout spec are:

  • The grid lines that define the grid: they can be horizontal or vertical,
    and they are numbered starting at 1.
  • The grid tracks, which are the rows (horizontal)
    or columns (vertical) defined in the grid.
  • The grid cells, the intersection of a row and a column.
  • A grid area, one or more adjacent grid cells that define a rectangle.
Grid Concepts

Grid Definition

To create a grid you just need to use a new value for the display property: grid or inline-grid. This is the same syntax as Flexbox, so you might be already used to it.

Then you will need to define the structure of your grid. For example, to define the size of the tracks you can do something like this:

display: grid;
grid-template-rows: 100px 100px;
grid-template-columns: 400px 200px 100px;

This will create a grid with two rows of 100px each, and three columns, with sizes 400px for first column, 200px for the second column, and 100px for the third column. This grid will have four vertical lines (1, 2, 3, 4) and three horizontal lines (1, 2, 3). You can also name the lines, so you can then reference them later easily. For example:

    grid-template-columns: [first] 400px [main] 200px [side] 100px [last];
Grid Definition

Regarding track sizing, you have a lot of flexibility:

  • You can define a fixed size track, setting the length or percentage.
  • You can define an intrinsic-sized track, where the size is based on the size of its content, using auto, min-content, max-content, or fit-content.
  • You can use a new unit fr to take advantage of the available space.

In addition, there are some functions that can be useful to set the track sizes:

  • minmax(), to set the minimum and maximum size of the track, so its size will end up depending on the available space and the size of the rest of the tracks.
  • repeat(), to define a fixed number of repetitions. It can also be used in automatic mode to cause the number of tracks to depend on the available space.

There is a special syntax that allows you to define the grid structure using ASCII art:

    grid-template-areas: "header  header"
                         "sidebar main  "
                         "sidebar footer";

In this example we create a 2×3 grid where the first row is the header, the rest of the first column is the sidebar, the main content is in the second row and second column, and the footer is in the last row and column.

Grid Areas

You can also define the gutter between tracks. For that, you just need to use the grid-row-gap and grid-column-gap properties.

Item Placement

The children of a grid container are called grid items. They can be positioned in the different parts of the grid using the placement properties grid-row-start, grid-row-end, grid-column-start, and grid-column-end. But in most cases you’ll be using the shorthands grid-row, grid-column, and grid-area.

Note that these properties refer to the grid lines, so if you want to put an element on the third row and the second column you can use something like this:

    grid-row: 3;
    grid-column: 2;

The item can also span several lines, so you can use the following syntax to take three rows and two columns:

    grid-row: 2 / 5;
    grid-column: 3 / span 2;
Grid Placement

Apart from that, you can also refer to named lines or areas with these properties, which is very convenient in some scenarios.

As you can imagine, when you’re using Grid Layout you can very easily break the relationship between the DOM order and the visual order. You have to be careful to keep the right order in the DOM to avoid making your content less accessible.

Lastly, there’s also the possibility to let the items place themselves into the grid. If you don’t set any placement property (or if you use auto), the items will be automatically placed on some empty cell of the grid, creating new rows (by default) or columns (if specified through grid-auto-flow property) when required.


One of the big things that come for free when you use CSS Grid Layout is the alignment support. In Grid Layout you can align horizontally and vertically without any issues with just some simple CSS properties.

The alignment capabilities of Grid Layout operate over two different subjects: grid tracks, with regard to the grid container, and grid items in their respective grid areas. In addition, we can operate on both axes, horizontally and vertically.

The CSS properties justify-content and align-content apply to grid tracks to align them horizontally and vertically, respectively. These properties, which define what is known as Content Distribution behavior, can also be used to distribute the grid container’s available space among the tracks following different distributions: between, around, evenly, and stretch. For example, check the following grid:

    display: grid;
    grid-template-rows: 100px 100px;
    grid-template-columns: 150px 150px 150px;
    height: 500px;
    width: 650px;
    align-content: center;
    justify-content: space-evenly;
Grid Alignment Tracks

When it comes to aligning the grid items, the justify-self and align-self properties are used to align horizontally and vertically, respectively. These properties define the Self Alignment behavior of the grid items. It’s possible to define a default behavior for all the items of a grid container by using the Default Alignment properties, align-items and justify-items, which gives an incredible syntactic flexibility for defining the grid’s alignment behavior.

Grid Alignment Items

Responsive Design with Grid

As you can already imagine, all the different Grid Layout properties make it more comfortable to create responsive designs. You can take advantage of the powerful track sizing mechanisms like the fr unit, minmax(), or repeat(). Combine this with media queries to completely change the structure of your grid with just a few CSS lines.

For example:

display: grid;
grid-gap: 10px 20px;
grid-template-rows: 100px 1fr auto;
grid-template-columns: 1fr 200px;
grid-template-areas: "header  header"
                     "content aside "
                     "footer  aside ";

@media (max-width: 600px) {
    grid-gap: 0;
    grid-template-rows: auto 1fr auto auto;
    grid-template-columns: 1fr;
    grid-template-areas: "header "
                         "aside  "
                         "footer ";
Responsive grid using flexible sizes and media queries

And Much More

This is just an introductory blog post about Grid Layout, not a deep review of all the different features that it provides: that would require much more than a single post. The different examples explained in this blog post have been published online. You can start to play with them now!

If you want to learn more about CSS Grid Layout, there are a bunch of good resources out there:

On top of that, several people have been talking about Grid Layout at different conferences and events. You won’t have problems finding some of the talks published online.


CSS Grid Layout is here to stay. We’re looking forward to seeing this soon in shipping versions of Safari and other web browsers. This is very good news for the Web authors that have been waiting for a tool like this for years. We believe this is going to be a huge step forward for the Web.

The implementation of Grid Layout in WebKit has been performed by Igalia’s Web Platform team and sponsored by Bloomberg. If you have any comments or questions, don’t hesitate to contact any of the people working on it: Javi (@lajava77), Manuel (@regocas), or Sergio (@svillarsenin). If you want to keep track of the development you can follow bug #60731. New bug reports are very welcome, especially now that Grid Layout is hitting your browser and testing is easier than ever. Exciting times ahead!

By Manuel Rego at March 09, 2017 06:00 PM

March 08, 2017

Release Notes for Safari Technology Preview 25

Surfin’ Safari

Safari Technology Preview Release 25 is now available for download for macOS Sierra. If you already have Safari Technology Preview installed, you can update from the Mac App Store’s Updates tab. This release covers WebKit revisions 212356-213542.

Resource Timing

  • Added Resource Timing as an experimental feature enabled by default (r212945)
  • Added Resource Timing support in Workers (r212449)
  • Improved gathering timing information with reliable responseEnd time (r212993)
  • Changed loads initiated by media elements to set the initiatorType to their element name (r212994)

User Timing

  • Enabled User Timing by default as an experimental feature (r212945)
  • Changed performance.measure in Workers to throw a SyntaxError if provided mark name is not found (r212806)


  • Added support for AES-CFB (r212736)


  • Added a new webglcontextchanged event that is dispatched when the GraphicsContext3D notices that the active GPU has changed (r212637)
  • Changed the onbeforeunload event return value coercion to match specification behavior (r212625)
  • Exposed Symbol.toPrimitive and Symbol.valueOf on Location instances (r212378)
  • Fixed <input type=color> and <input type=range readonly> to prevent applying the readonly attribute to match specifications (r212617, r212610)
  • Fixed handling of <input>.labels when the input type changes from "text" to "hidden" to "checkbox" (r212522)
  • Prevented aggressive throttling of DOM timers until they’ve reached their maximum nesting level (r212845)

Web Inspector

  • Enabled import() for modules in Web Inspector console (r212438)
  • Changed the zoom level in the Settings tab to use localized formatting (r212578)
  • Changed Web Inspector to use the Resources tab when showing files instead of the Network tab (r212761)
  • Changed the split console to be allowed in the Elements, Resources, Debugger, and Storage tabs when Web Inspector is docked to the bottom (r212400)
  • Changed CSS variable uses that are unresolved to get marked with a warning icon (r213187)
  • Fixed the Zoom level user interface to match the the setting value (r212580)
  • Prevented dismissing popovers when dragging a Web Inspector window (r212427)
  • Improved copy and paste behavior for request headers (r212423)
  • Included additional detail in the display name of Timeline data elements (r212570)


  • Fixed centering text inside a button set to display:flex with justify-content:center (r213173)
  • Unprefixed -webkit-line-break (r213094)


  • Prevented fixed elements from bouncing when scrolling beyond the bottom of the page (r212559)
  • Improved text wrapping consistency where text might wrap when its preferred logical width is used for sizing the containing block (r213008)


  • Fixed local audio-only streams to trigger playback to begin (r212696)

Bug Fixes

  • Changed pending scripts to execute asynchronously after stylesheet loads are completed (r212614)
  • Fixed an issue where font-weight in @font-face can cause a font to be downloaded even when it’s not used (r212513)
  • Made special URLs without a host invalid (r212470)

By Jon Davis at March 08, 2017 06:00 PM

February 22, 2017

Release Notes for Safari Technology Preview 24

Surfin’ Safari

Safari Technology Preview Release 24 is now available for download for macOS Sierra. If you already have Safari Technology Preview installed, you can update from the Mac App Store’s Updates tab. This release covers WebKit revisions 211256-212356.

User Timing

  • Added User Timing as an experimental feature (r211332)
  • Implemented PerformanceObserver for User Timing (r211406)
  • Added support for Performance API (performance.now(), UserTiming) in Workers (r211594)

Link Preload

  • Added <link preload> as an experimental feature (r211341)
  • Added support for speculative resource loading (r211480)
  • Prevented preloaded resources from being cleared after parsing is done (r211649)
  • Addressed memory issues related to clearing preloaded resources (r211673)


  • Changed Location object to throw a TypeError for Object.preventExtensions() (r211778)
  • Changed Pointer Lock to require keyboard focus (r211652)
  • Changed Pointer Lock events to be delivered directly to the target element (r211650)
  • Changed the HTML Form Validation popover to be dismissed when pressing the Escape key (r211653)
  • Changed the HTML Form Validation popover to respect the minimum font size setting (r212325)
  • Fixed an issue causing Fetch to fail when passing undefined as the headers (r212162)
  • Fixed the <details> element to work correctly when content is changed between closing and opening (r212027)
  • Implemented toJSON() for URL objects (r212193)
  • Improved URL specification compliance (r211636, r212279)
  • Prevented a redundant scroll to top-left corner of the page when navigating back to a URL with no fragment (r212197)
  • Made Symbols configurable when exposed on cross-origin Window or Location objects (r211772)


  • Implemented dynamic import operator (r211280)
  • Changed dynamic import through setTimeout() and setInterval() to correctly inherit SourceOrigin (r211314)
  • Changed scripts load priority to ‘high’ (r211334)
  • Fixed Apple Pay line validation to prevent validating line items that are “pending” (r211446)
  • Implemented ArrayBuffer.prototype.byteLength and SharedArrayBuffer.prototype.byteLength (r212196)
  • Implemented lifting template escape sequence restrictions in tagged templates (r211319)


  • Fixed elements with a backdrop-filter and a mask to correctly mask the backdrop (r211305)
  • Updated line-break:auto to match the latest version of Unicode (r212235)

Web Inspector

  • Enabled the console to evaluate dynamic module import() (r211777)
  • Added CSS color keyword entries for all “grey” and “gray” variations (r211452)
  • Added stroke-linecap property values to CSS autocompletion (r211640)
  • Added a horizontal slider for gradient editor angle value where applicable (r211318)
  • Added a limit on Async Call Stacks for asynchronous loops (r211385)
  • Added a setting to preserve network data on navigation for the Network tab (r211451)
  • Added the ability to show the current value of CSS variables in style rules (r212273)
  • Added a warning that webkitSubtle in WebCrypto is deprecated (r212261)
  • Changed docking Web Inspector to collapse the split console in the Timeline and Network tabs (r211976)
  • Fixed jumping from Search tab results to see the resource in other tabs (Resource, Debugger, Network) (r211608)
  • Fixed a Debugger sidebar panel issue that can cause it to have multiple tree selections (r212171)
  • Fixed DOM tree view collapsing when switching back to the Elements tab (r211829)
  • Removed Shift-Command-W (⇧⌘W) shortcut to a close tab (r211485)


  • Fixed text string range from index and length in text controls when there are newlines (r211491)


  • Fixed column progression after enabling pagination on a right-to-left document (r211564)


  • Suspended SVG animations on hidden pages (r211612)
  • Avoided initially creating a layer backing store for elements outside the visible area (r211845)


  • Changed CSS data URL resources to be treated as same origin loads when loaded through HTML <link> elements (r211926)

By Jon Davis at February 22, 2017 06:00 PM

February 15, 2017

JavaScript Debugging Improvements

Surfin’ Safari

Debugging JavaScript is a fundamental part of developing web applications. Having effective debugging tools makes you more productive by making it easier to investigate and diagnose issues when they arise. The ability to pause and step through JavaScript has always been a core feature of Web Inspector.

The JavaScript debugger hasn’t changed in a long time, but the Web and the JavaScript language have. We recently took at look at our debugger to see how we could improve the experience and make it even more useful for you.


Web Inspector now includes extra highlights for the active statement or expression that is about to execute. For previous call frames, we highlight the expression that is currently executing.

Previously, Web Inspector would only highlight the line where the debugger was paused. However, knowing exactly where on the line the debugger was and therefore what was about to execute might not be obvious. By highlighting source text ranges of active expressions we eliminate any confusion and make stepping through code easier and faster.

For example, when stepping through the following code it is always immediately clear what is about to execute, even when we are executing a small part of a larger statement:

Debugger Stepping Highlights
Debugger Stepping Highlights
Debugger Stepping Highlights
Debugger Stepping Highlights
Debugger Stepping Highlights
Debugger Stepping Highlights
Debugger Stepping Highlights
Debugger Stepping Highlights

Highlighting expressions is also useful when looking at previous call frames in the Call Stack. Again, when selecting parent call frames it is always immediately clear where we are currently executing:

Parent Call Frame Expression Highlight
Parent Call Frame Expression Highlight
Parent Call Frame Expression Highlight
Parent Call Frame Expression Highlight

We also made improvements to the stepping behavior itself. We eliminated unnecessary pauses, added pause points that were previously missed, and generally made pausing locations more consistent between old and new syntaxes of the language. Stepping in and out of functions is also more intuitive. Combined with the new highlights stepping through complex code is now easier than ever.


Web Inspector is now smarter and more forgiving about where it resolves breakpoints, making them more consistent and useful.

Previously, setting a breakpoint on an empty line or a line with a comment would create a breakpoint that would never get triggered. Now, Web Inspector installs the breakpoint on the next statement following the location where the breakpoint was set.

We also made it simpler to set a breakpoint for a function or method. Previously, you would have needed to find the first statment within the function and set a breakpoint on that line. Now, you can just set a breakpoint on the line with the function name or its opening brace and the breakpoint will trigger on the first statement in the function.

New Acceptable Breakpoint Locations
New Acceptable Breakpoint Locations
New Acceptable Breakpoint Locations

A new global breakpoint was added for Assertion failures triggered by console.assert. This breakpoint can be found beside the existing global breakpoints, such as pausing on uncaught exceptions.

Asynchronous Call Stacks

Asynchronous Call Stacks

JavaScript functions make it very convenient to evaluate code asynchronously. Callbacks, Events, Timers, and new language features such as Promises and async functions make it easier than ever to run asynchronous code.

Debugging these kinds of asynchronous chains can be complex. Web Inspector now makes it much easier to debug asynchronous code by displaying the call stacks across asynchronous boundary points. Now when your timer fires and you pause inside your callback, you can see the call stack from where the timer was scheduled, and so on if that call stack had been triggered asynchronously.

WebKit currently records asynchronous call stacks in just a few places and is actively bringing it to more features like Promises.

Web Workers

While JavaScript itself is single threaded, Web Workers allow web applications to run scripts in background threads. Web Inspector can now debug scripts in Workers just as easily as scripts in the Page.

Worker Resources in Resources Tab

When inspecting a page with Workers, Worker resources will show in the Resources tab sidebar. Each Worker becomes a top level resource like the Page, allowing you to quickly see the list of active Workers and their scripts and resources.

An execution context picker becomes available in the quick console, allowing you to choose to evaluate JavaScript in either the Page’s context or a Worker’s context. Workers have dramatically improved console logging support, so you will be able to interact with objects logged from a Worker just as you would expect.

Setting breakpoints behaves as expected. When any single context pauses, all other contexts are immediately paused. Selecting call frames inside of a particular thread allows you to step just that individual thread. Use the Continue debugger control to resume all scripts.


When debugging a page with Workers, Web Inspector adds a thread name annotation next to the debugger highlights. If you have multiple Workers, or even Workers and the Page, all paused and stepping through the same script you will be able to see exactly where each thread is.

WebKit currently only supports debugging Workers. Profiling Worker scripts with Timelines will come in the future.

Code Coverage and Type Profiling

Web Inspector also supports Code Coverage and Type profiling.

Previously, Web Inspector had a single button to toggle both profilers. A new [C] button was added to toggle just Code Coverage. The [T] button now only toggles Type Profiler.


You can try out all of these improvements in the latest Safari Technology Preview. Let us know how they work for you. Send feedback on Twitter (@webkit, @JosephPecoraro) or by filing a bug.

By Joseph Pecoraro at February 15, 2017 07:00 PM

February 10, 2017

Carlos García Campos: Accelerated compositing in WebKitGTK+ 2.14.4

Igalia WebKit

WebKitGTK+ 2.14 release was very exciting for us, it finally introduced the threaded compositor to drastically improve the accelerated compositing performance. However, the threaded compositor imposed the accelerated compositing to be always enabled, even for non-accelerated contents. Unfortunately, this caused different kind of problems to several people, and proved that we are not ready to render everything with OpenGL yet. The most relevant problems reported were:

  • Memory usage increase: OpenGL contexts use a lot of memory, and we have the compositor in the web process, so we have at least one OpenGL context in every web process. The threaded compositor uses the coordinated graphics model, that also requires more memory than the simple mode we previously use. People who use a lot of tabs in epiphany quickly noticed that the amount of memory required was a lot more.
  • Startup and resize slowness: The threaded compositor makes everything smooth and performs quite well, except at startup or when the view is resized. At startup we need to create the OpenGL context, which is also quite slow by itself, but also need to create the compositing thread, so things are expected to be slower. Resizing the viewport is the only threaded compositor task that needs to be done synchronously, to ensure that everything is in sync, the web view in the UI process, the OpenGL viewport and the backing store surface. This means we need to wait until the threaded compositor has updated to the new size.
  • Rendering issues: some people reported rendering artifacts or even nothing rendered at all. In most of the cases they were not issues in WebKit itself, but in the graphic driver or library. It’s quite diffilcult for a general purpose web engine to support and deal with all possible GPUs, drivers and libraries. Chromium has a huge list of hardware exceptions to disable some OpenGL extensions or even hardware acceleration entirely.

Because of these issues people started to use different workarounds. Some people, and even applications like evolution, started to use WEBKIT_DISABLE_COMPOSITING_MODE environment variable, that was never meant for users, but for developers. Other people just started to build their own WebKitGTK+ with the threaded compositor disabled. We didn’t remove the build option because we anticipated some people using old hardware might have problems. However, it’s a code path that is not tested at all and will be removed for sure for 2.18.

All these issues are not really specific to the threaded compositor, but to the fact that it forced the accelerated compositing mode to be always enabled, using OpenGL unconditionally. It looked like a good idea, entering/leaving accelerated compositing mode was a source of bugs in the past, and all other WebKit ports have accelerated compositing mode forced too. Other ports use UI side compositing though, or target a very specific hardware, so the memory problems and the driver issues are not a problem for them. The imposition to force the accelerated compositing mode came from the switch to using coordinated graphics, because as I said other ports using coordinated graphics have accelerated compositing mode always enabled, so they didn’t care about the case of it being disabled.

There are a lot of long-term things we can to to improve all the issues, like moving the compositor to the UI (or a dedicated GPU) process to have a single GL context, implement tab suspension, etc. but we really wanted to fix or at least improve the situation for 2.14 users. Switching back to use accelerated compositing mode on demand is something that we could do in the stable branch and it would improve the things, at least comparable to what we had before 2.14, but with the threaded compositor. Making it happen was a matter of fixing a lot bugs, and the result is this 2.14.4 release. Of course, this will be the default in 2.16 too, where we have also added API to set a hardware acceleration policy.

We recommend all 2.14 users to upgrade to 2.14.4 and stop using the WEBKIT_DISABLE_COMPOSITING_MODE environment variable or building with the threaded compositor disabled. The new API in 2.16 will allow to set a policy for every web view, so if you still need to disable or force hardware acceleration, please use the API instead of WEBKIT_DISABLE_COMPOSITING_MODE and WEBKIT_FORCE_COMPOSITING_MODE.

We really hope this new release and the upcoming 2.16 will work much better for everybody.

By carlos garcia campos at February 10, 2017 05:18 PM

February 08, 2017

Release Notes for Safari Technology Preview 23

Surfin’ Safari

Safari Technology Preview Release 23 is now available for download for macOS Sierra. If you already have Safari Technology Preview installed, you can update from the Mac App Store’s Updates tab. This release covers WebKit revisions 210845-211256.


  • Fixed Gamepad support for PS4 controllers (r211220)
  • Exposed more directional pads for other types of gamepads (r211231)

Pointer Lock

  • Fixed sending Pointer Lock events directly to the target element (r211235)
  • Fixed page requests to re-establish Pointer Lock without a user gesture after being released without a user gesture (r211249)


  • Added client notification when the user plays media otherwise prevented from autoplaying (r211226)


  • Fixed Speak Selection for <iframe> elements (r211095)

Web Inspector

  • Added a way to trigger Garbage Collection (r211075)

Bug Fixes

  • Fixed Flash object placeholder painting when Safari reloads pages with Flash objects after Flash is installed (r211114)
  • Improved switching between GPUs for WebGL content in order to maximize battery life (r211244)

By Jon Davis at February 08, 2017 06:00 PM

Michael Catanzaro: An Update on WebKit Security Updates

Igalia WebKit

One year ago, I wrote a blog post about WebKit security updates that attracted a fair amount of attention at the time. For a full understanding of the situation, you really have to read the whole thing, but the most important point was that, while WebKitGTK+ — one of the two WebKit ports present in Linux distributions — was regularly releasing upstream security updates, most Linux distributions were ignoring the updates, leaving users vulnerable to various security bugs, mainly of the remote code execution variety. At the time of that blog post, only Arch Linux and Fedora were regularly releasing WebKitGTK+ updates, and Fedora had only very recently begun doing so comprehensively.

Progress report!

So how have things changed in the past year? The best way to see this is to look at the versions of WebKitGTK+ in currently-supported distributions. The latest version of WebKitGTK+ is 2.14.3, which fixes 13 known security issues present in 2.14.2. Do users of the most popular Linux operating systems have the fixes?

  • Fedora users are good. Both Fedora 24 and Fedora 25 have the latest version, 2.14.3.
  • If you use Arch, you know you always have the latest stuff.
  • Ubuntu users rejoice: 2.14.3 updates have been released to users of both Ubuntu 16.04 and 16.10. I’m very  pleased that Ubuntu has decided to take my advice and make an exception to its usual stable release update policy to ensure its users have a secure version of WebKit. I can’t give Ubuntu an A grade here because the updates tend to lag behind upstream by several months, but slow updates are much better than no updates, so this is undoubtedly a huge improvement. (Anyway, it’s hardly a bad idea to be cautious when releasing a big update with high regression potential, as is unfortunately the case with even stable WebKit updates.) But if you use the still-supported Ubuntu 14.04 or 12.04, be aware that these versions of Ubuntu cannot ever update WebKit, as it would require a switch to WebKit2, a major API change.
  • Debian does not update WebKit as a matter of policy. The latest release, Debian 8.7, is still shipping WebKitGTK+ 2.6.2. I count 184 known vulnerabilities affecting it, though that’s an overcount as we did not exclude some Mac-specific security issues from the 2015 security advisories. (Shipping ancient WebKit is not just a security problem, but a user experience problem too. Actually attempting to browse the web with WebKitGTK+ 2.6.2 is quite painful due to bugs that were fixed years ago, so please don’t try to pretend it’s “stable.”) Note that a secure version of WebKitGTK+ is available for those in the know via the backports repository, but this does no good for users who trust Debian to provide them with security updates by default without requiring difficult configuration. Debian testing users also currently have the latest 2.14.3, but you will need to switch to Debian unstable to get security updates for the foreseeable future, as testing is about to freeze.
  • For openSUSE users, only Tumbleweed has the latest version of WebKit. The current stable release, Leap 42.2, ships with WebKitGTK+ 2.12.5, which is coincidentally affected by exactly 42 known vulnerabilities. (I swear I am not making this up.) The previous stable release, Leap 42.1, originally released with WebKitGTK+ 2.8.5 and later updated to 2.10.7, but never past that. It is affected by 65 known vulnerabilities. (Note: I have to disclose that I told openSUSE I’d try to help out with that update, but never actually did. Sorry!) openSUSE has it a bit harder than other distros because it has decided to use SUSE Linux Enterprise as the source for its GCC package, meaning it’s stuck on GCC 4.8 for the foreseeable future, while WebKit requires GCC 4.9. Still, this is only a build-time requirement; it’s not as if it would be impossible to build with Clang instead, or a custom version of GCC. I would expect WebKit updates to be provided to both currently-supported Leap releases.
  • Gentoo has the latest version of WebKitGTK+, but only in testing. The latest version marked stable is 2.12.5, so this is a serious problem if you’re following Gentoo’s stable channel.
  • Mageia has been updating WebKit and released a couple security advisories for Mageia 5, but it seems to be stuck on 2.12.4, which is disappointing, especially since 2.12.5 is a fairly small update. The problem here does not seem to be lack of upstream release monitoring, but rather lack of manpower to prepare the updates, which is a typical problem for small distros.
  • The enterprise distros from Red Hat, Oracle, and SUSE do not provide any WebKit security updates. They suffer from the same problem as Ubuntu’s old LTS releases: the WebKit2 API change  makes updating impossible. See my previous blog post if you want to learn more about that. (SUSE actually does have WebKitGTK+ 2.12.5 as well, but… yeah, 42.)

So results are clearly mixed. Some distros are clearly doing well, and others are struggling, and Debian is Debian. Still, the situation on the whole seems to be much better than it was one year ago. Most importantly, Ubuntu’s decision to start updating WebKitGTK+ means the vast majority of Linux users are now receiving updates. Thanks Ubuntu!

To arrive at the above vulnerability totals, I just counted up the CVEs listed in WebKitGTK+ Security Advisories, so please do double-check my counting if you want. The upstream security advisories themselves are worth mentioning, as we have only been releasing these for two years now, and the first year was pretty rough when we lost our original security contact at Apple shortly after releasing the first advisory: you can see there were only two advisories in all of 2015, and the second one was huge as a result of that. But 2016 seems to have gone decently well. WebKitGTK+ has normally been releasing most security fixes even before Apple does, though the actual advisories and a few remaining fixes normally lag behind Apple by roughly a month or so. Big thanks to my colleagues at Igalia who handle this work.

Challenges ahead

There are still some pretty big problems remaining!

First of all, the distributions that still aren’t releasing regular WebKit updates should start doing so.

Next, we have to do something about QtWebKit, the other big WebKit port for Linux, which stopped receiving security updates in 2013 after the Qt developers decided to abandon the project. The good news is that Konstantin Tokarev has been working on a QtWebKit fork based on WebKitGTK+ 2.12, which is almost (but not quite yet) ready for use in distributions. I hope we are able to switch to use his project as the new upstream for QtWebKit in Fedora 26, and I’d encourage other distros to follow along. WebKitGTK+ 2.12 does still suffer from those 42 vulnerabilities, but this will be a big improvement nevertheless and an important stepping stone for a subsequent release based on the latest version of WebKitGTK+. (Yes, QtWebKit will be a downstream of WebKitGTK+. No, it will not use GTK+. It will work out fine!)

It’s also time to get rid of the old WebKitGTK+ 2.4 (“WebKit1”), which all distributions currently parallel-install alongside modern WebKitGTK+ (“WebKit2”). It’s very unfortunate that a large number of applications still depend on WebKitGTK+ 2.4 — I count 41 such packages in Fedora — but this old version of WebKit is affected by over 200 known vulnerabilities and really has to go sooner rather than later. We’ve agreed to remove WebKitGTK+ 2.4 and its dependencies from Fedora rawhide right after Fedora 26 is branched next month, so they will no longer be present in Fedora 27 (targeted for release in November). That’s bad for you if you use any of the affected applications, but fortunately most of the remaining unported applications are not very important or well-known; the most notable ones that are unlikely to be ported in time are GnuCash (which won’t make our deadline) and Empathy (which is ported in git master, but is not currently in a  releasable state; help wanted!). I encourage other distributions to follow our lead here in setting a deadline for removal. The alternative is to leave WebKitGTK+ 2.4 around until no more applications are using it. Distros that opt for this approach should be prepared to be stuck with it for the next 10 years or so, as the remaining applications are realistically not likely to be ported so long as zombie WebKitGTK+ 2.4 remains available.

These are surmountable problems, but they require action by downstream distributions. No doubt some distributions will be more successful than others, but hopefully many distributions will be able to fix these problems in 2017. We shall see!

By Michael Catanzaro at February 08, 2017 06:32 AM

Michael Catanzaro: On Epiphany Security Updates and Stable Branches

Igalia WebKit

One of the advantages of maintaining a web browser based on WebKit, like Epiphany, is that the vast majority of complexity is contained within WebKit. Epiphany itself doesn’t have any code for HTML parsing or rendering, multimedia playback, or JavaScript execution, or anything else that’s actually related to displaying web pages: all of the hard stuff is handled by WebKit. That means almost all of the security problems exist in WebKit’s code and not Epiphany’s code. While WebKit has been affected by over 200 CVEs in the past two years, and those issues do affect Epiphany, I believe nobody has reported a security issue in Epiphany’s code during that time. I’m sure a large part of that is simply because only the bad guys are looking, but the attack surface really is much, much smaller than that of WebKit. To my knowledge, the last time we fixed a security issue that affected a stable version of Epiphany was 2014.

Well that streak has unfortunately ended; you need to make sure to update to Epiphany 3.22.6, 3.20.7, or 3.18.11 as soon as possible (or Epiphany 3.23.5 if you’re testing our unstable series). If your distribution is not already preparing an update, insist that it do so. I’m not planning to discuss the embarrassing issue here — you can check the bug report if you’re interested — but rather on why I made new releases on three different branches. That’s quite unlike how we handle WebKitGTK+ updates! Distributions must always update to the very latest version of WebKitGTK+, as it is not practical to backport dozens of WebKit security fixes to older versions of WebKit. This is rarely a problem, because WebKitGTK+ has a strict policy to dictate when it’s acceptable to require new versions of runtime dependencies, designed to ensure roughly three years of WebKit updates without the need to upgrade any of its dependencies. But new major versions of Epiphany are usually incompatible with older releases of system libraries like GTK+, so it’s not practical or expected for distributions to update to new major versions.

My current working policy is to support three stable branches at once: the latest stable release (currently Epiphany 3.22), the previous stable release (currently Epiphany 3.20), and an LTS branch defined by whatever’s currently in Ubuntu LTS and elementary OS (currently Epiphany 3.18). It was nice of elementary OS to make Epiphany its default web browser, and I would hardly want to make it difficult for its users to receive updates.

Three branches can be annoying at times, and it’s a lot more than is typical for a GNOME application, but a web browser is not a typical application. For better or for worse, the majority of our users are going to be stuck on Epiphany 3.18 for a long time, and it would be a shame to leave them completely without updates. That said, the 3.18 and 3.20 branches are very stable and only getting bugfixes and occasional releases for the most serious issues. In contrast, I try to backport all significant bugfixes to the 3.22 branch and do a new release every month or thereabouts.

So that’s why I just released another update for Epiphany 3.18, which was originally released in September 2015. Compare this to the long-term support policies of Chrome (which supports only the latest version of the browser, and only for six weeks) or Firefox (which provides nine months of support for an ESR release), and I think we compare quite favorably. (A stable WebKit series like 2.14 is only supported for six months, but that’s comparable to Firefox.) Not bad?

By Michael Catanzaro at February 08, 2017 05:56 AM