Welcome to the first of many monthly newsletters from the Ladybird Browser project!
Launching a nonprofit
On July 1st, we launched the Ladybird Browser Initiative, a 501(c)(3) nonprofit corporation in California. Its mission is to drive development of Ladybird as a truly independent web browser and make it available for free, forever, without engaging in any kind of user monetization.
Welcoming new sponsors
Ladybird is funded entirely by sponsorships and donations from companies and individuals who care about the open web.
In July, we’ve welcomed the following new sponsors:
- FUTO with $201,000
- Packet Clearing House with $10,000
- Playbit with $10,000
- Null Games with $10,000
- Tuple with $5,000
- Bastian Müller with $5,000
We’ve also received $7,572 in donations from 230 individual supporters!
Web Platform Tests
There’s been incredible progress on the Web Platform Tests in July!
WPT is a shared project that all browsers contribute to. Its goal is to accumulate tests for the web platform that browsers can run to verify correct functionality. It has over a million subtests (although over 60% of them are focused on legacy Chinese, Japanese and Korean text encodings!)
We’ve been working on a Ladybird WPT runner for some time, and things are finally starting to come together.
As of this month, we’ve begun publishing runs to the staging area of the common WPT dashboard at wpt.fyi! Our runs are not yet automated (Tim is running them overnight on his home PC!) but we’ve recently gotten a dedicated machine and we’re working on moving them over. Once we have automated runs going, we’ll begin publishing them to wpt.fyi proper.
For anyone curious about getting into Ladybird development, the WPT dashboard is an absolute treasure trove of approachable unit test failures that you can figure out and fix!
You can take a look at our current WPT progress here.
Web Assembly compliance progress
Ladybird supports Web Assembly through the LibWasm library, which is separate from the JavaScript implementation in LibJS. Similar to how JavaScript has its specification tests in the test262 test suite, and the web platform has its tests in the Web Platform Tests test suite, Web Assembly has a test suite maintained by the specification authors.
As of this month, LibWasm has hit a 100% pass rate on the Wasm spec test suite! Contributors Diego Frias and Ali Mohammad Pur have put in excellent work fixing bugs and implementing missing SIMD features in LibWasm to push us from approximately 60% back at the beginning of June to 100% of tests passing late this month.
Have a look at the progress graphs on our development tracking website here.
More 3rd party libraries
We’re continuing to lean on more of the OSS ecosystem. This month we’ve integrated the following 3rd party libraries to improve our functionality and performance:
- libjxl: JPEG XL image support
- libavif: AVIF image support
- libwebp: WebP image support
- simdutf: High-performance Unicode and Base64 functions
Skia is now our default 2D graphics library
We’re now using the open-source Skia library to rasterize 2D graphics. This is significantly faster than the home-grown LibGfx rasterizer we inherited from SerenityOS.
With Skia, we get:
- GPU acceleration! If a device supports GPU acceleration, Skia will use the Ganesh backend with a Metal context on macOS and a Vulkan context on Linux.
- Better surface allocation! macOS uses
IOSurface
for backing stores, which means we avoid copying data from Skia’s render target before passing it through IPC to the browser process to display it on the screen. In the future a similar optimisation will be implemented for Linux through Vulkan. - More speed! Before switching to Skia, the rasterization process dominated performance profiles on many websites. Now recording a display list that describes what needs to be rasterized often takes longer than the rasterization process itself.
- CSS 2D transforms just work! With LibGfx, CSS transforms support was limited to
translate()
andscale()
, but with Skia, we automatically gained support formatrix()
,rotate()
,skew()
, and more.
We’re also using Skia to rasterize text, although text layout and shaping is still performed by our legacy LibGfx code. That will change in the near future.
Pseudo-element style invalidation
We now update the rendering when style changes happen to a pseudo-element. An example of this is when you hover over a generated ::before
or ::after
pseudo-element.
This makes the interactive part of the Acid2 test finally work as intended. (You can now hover the nose to make it turn blue!)
CSS counters
This month, we gained some basic support for CSS counters. Numbered lists have been a part of HTML since the early days, but more recently CSS gave web authors the ability to create their own automatically-incrementing counters using the counter-set
, counter-reset
, and counter-increment
properties, and display them on the page with the counter()
and counters()
in the content
property. A common use for this is to automatically number page headings.
While not complete, we now support enough of this that we are able to use it for the line numbers of Ladybird’s “view source” feature!
More CSS color functions
Early in the month, we gained support for the hwb()
, oklab()
and oklch()
color functions in CSS. Recent versions of the color specification provide a variety of different ways of creating colors in different color spaces, and this moves us closer to matching other browsers.
New CSS selectors
This month we’ve added support for the :has
and :host
selectors.
:has
is going to need a fair bit of optimization work still, but at least the basic functionality is in place.
CSS Grid layout now supports fit-content()
After reading about Ladybird on the Dutch website Tweakers, we spent some time making their main page look better in Ladybird as well!
As you can see in the before/after screenshots, CSS Grid layout with fit-content()
was a big issue!
Before:
After:
More new web APIs
As usual, we’ve added various new web APIs this month. Here are some:
- Element.checkVisibility()
- HTMLMediaElement.textTracks
- HTMLMediaElement.addTextTrack()
- HTMLOptionsCollection indexed setter
- KeyboardEvent.initKeyboardEvent()
- MouseEvent.initMouseEvent()
- Navigator.doNotTrack
- Node.isDefaultNamespace()
- Node.lookupNamespaceURI()
- Node.lookupPrefix()
- Node.normalize()
- SVGAElement.relList
- SVGElement.className
- SVGElement.ownerSVGElement
- TextTrack.mode
- And many more..
Some nice optimizations
- Our
StringBuilder
class can now construct the finalString
without reallocating the data storage. Commit - We now pre-allocate the final buffer when resolving rope strings. Commit.
- The JavaScript
typeof
operator was made faster by caching all the possible results (there aren’t that many!). Commit - We now avoid converting from UTF-8 to UTF-16 if all we wanted to know was the length in UTF-16 code units. Commit
- We changed
background-repeat: repeat
to use an optimized shader for repeated image painting instead of rendering each repetition unit as a separate image. Commit
Credits
We thank the following people who contributed code to Ladybird in July 2024:
Alec Murphy, Alex Studer, Ali Mohammad Pur, Aliaksandr Kalenik, Andreas Kling, Andrew Kaster, Antoni Duda, Arthur Hartwig Carlsson, Aziz Berkay Yesilyurt, Bastiaan van der Plaat, BenJilks, Braydn, Caitlin Potter, CheewyOFF, Colin Reeder, Daeraxa, Dan Klishch, Daniel Bertalan, Dario Castañé, Dennis Camera, Diego, Diego Frias, Edwin Hoksberg, Enver Balalic, Francesco Gazzetta, Gingeh, Harm133, Hendiadyoin1, Holger Hans Peter Freyther, Jacob Wischnat, Jamie Mansfield, Jason Fairchild, Jess, Jörg Strebel, Keith Cirkel, Kemal Zebari, Kenneth Myhra, Kevin Meyer, Kotaro Ichihara, Lawrence Gimenez, Lucas CHOLLET, Luke Warlow, Maciej, Mohamed amine Bounya, Natsuki Ikeguchi, Nico Weber, Nicolas Danelon, Olekoop, Saksham Mittal, Salem Yaslem, Sam Atkins, Samuel Eisenhandler, Sebastian Zaha, Shannon Booth, Thomas Klausner, Tim Ledbetter, Tim Schumacher, Timothy Flynn, Timur Sultanov, Victor Tran, bbb651, circl, doctortheemh, fish4terrisa-MSDSM, lalitrn44, lmutter, luozhiya, matjojo, mbal, mendhak, mobounya, paaspaas00, rmg-x, sideshowbarker, simonkrauter, Ángel Carias