Ladybird Browser Year in Review: What We Did in 2022!
2022 is rapidly coming to an end, and of course we've been busy all year round in the SerenityOS project! Especially LibJS and LibWeb — also known as the Ladybird Browser Project — received a huge amount of work from dozens of contributors; and since they are what I work on and am most familiar with as well, let's look at some Ladybird highlights from the past year!
If you want to get a summary of the last 12 months of development for the whole SerenityOS project, take a look at the monthly update videos (30-40 minutes each).
ES Modules support in LibJS
This is from January, but easily one of my favourite LibJS changes of the entire year: davidot single-handedly added support for parsing, loading, and executing ECMAScript modules to LibJS! Actually, not just that, but some additional goodies like top-level
await and dynamic
import() as well — check out #11957 for a full list :^)
Initially limited to our standalone
js interpreter, this was later followed up with a PR from networkException, who implemented support for
<script type="module"> in LibWeb.
100/100 on Acid3
Acid3 is a popular, albeit a bit dated, browser test checking the compliance with features from a variety of web standards. I don't remember how we started chasing the full score, but a lot of people chipped in and we quickly went from 50/100 in February to 100/100 at the end of March, with Ali going as far as making an entire XML parser for XHTML support to get us that last point :^)
Shadows, Gradients, Filters
I think I still haven't fully grasped the amount of fancy CSS features that we started supporting in the last year, it's truly impressive! There's everything from antialiased rendering, to improved box shadows, support for all kinds of gradients, various
backdrop-filters, and more. Most of this was done by MacDue!
The beginnings of WebGL
Usually we get to watch people when they work on cool projects in SerenityOS, but this one came out of nowhere:
<Lubrsi> my secret project worked out <Lubrsi> everyone, I present to you, WebGL! <awesomekling> bruh :poggie:
Yeah, Luke just did that. 1.5k line PR, approval from the folks working on LibGL, and done :^)
Not much has happened since then, but I hear the recent work on adding support for shaders to LibGL might be beneficial 👀
GC all the things
This effort was led by Andreas who wanted to do this back when he was working on WebKit, and now managed to do it in LibWeb instead :^)
It's all architectural and there's no screenshot for this one, but it's one of the nicest fundamental LibWeb changes we've had in years so it deserves a mention: basically we got to really embrace LibJS's garbage collector and replaced a whole bunch of ref-counted implementation classes, each having a GC'd wrapper object, with a single GC'd object where the implementation is the JS object itself and doesn't need a wrapper.
This also works for things that aren't directly exposed to user code, so we can fully avoid the ref-counting cycles there as well.
Flexbox should be in every web developer's toolbox by now and we've had partial support for a while. Next up on the list is CSS Grid, which Martin started implementing in August and has continued to work on in the months since, making steady progress!
Ladybird: A new cross-platform browser project
…was the title of Andreas' blog post officially announcing the Ladybird browser project in September, but the journey started earlier! Initially in mid-2019 with LibHTML, the earliest iteration of what is now LibWeb; but also the cross-browser aspect of it, which is all thanks to Dexesttp who started porting LibWeb to Linux (and, by extension, other Unix-like platforms — still no Windows port) in March, resulting in a cross-platform, LibWeb-powered
headless-browser utility that would later serve as the baseline for the Ladybird Qt GUI.
Since then, development of Ladybird as a cross-platform browser has of course led to better abstractions of platform-specific code in LibWeb, and even though it was a standalone project for a while, Andrew went ahead and imported it back into the mono repo after we broke the build with upstream API changes a few dozen times.
WebDriver and steps towards running WPT
WebDriver is an HTTP-driven interface for automated control of web browsers, and integral to running and processing results of test suites such as the Web Platform Tests in an automated fashion.
Implementing WebDriver support in LibWeb and both the LibGUI and Qt browser GUIs involved a whole bunch of people: we had an initial PR from Orphis back in May, which Sam then revived and finished in October, followed by implementing most of the endpoints with lots of help from TobyAsE, and finally integrating it with Ladybird by Tim, as well as lots of tweaks in the initial architecture and code structure to make things fully work and allow sharing most code between different embedders of LibWeb.
There's still a few things missing, but overall this progressed nicely and allows any WebDriver client to leverage this new functionality!
With lots and lots of hacks I already made the Browser run a single test via WPT, but running the entire suite needs more work. Next year!
LibJS representation at TC39
Back in April littledan reached out and asked if we're interested in participating in TC39, and of course we were! Fast forward to November and I became an Invited Expert to represent the LibJS engine, and even managed to travel to A Coruña for their most recent in-person meeting.
Attending for the first time definitely had something surreal to it as I didn't know anything about JS engines before starting to work on ours less than three years ago, but I'm super proud that we got to this point!
Bring-up work on complex web apps
Developing unrelated features in isolation only gets you so far, trying to get some real websites to load is when you truly see how far along the browser has (or hasn't) come. We've seen support for many major websites mature over the year (source: Andreas' Twitter feed 🐦), but what's even more impressive is when web apps start to load as those are usually vastly more complex in every category imaginable!
One of those was improving support for Discord, our main communication hub, initially done by Andreas as a video series earlier in the year. More recently, Luke has done a few as well, and I think we could call it a series at this point!
- LibWeb: Implement enough to make YouTube load :^)
- LibWeb: Implement enough features to load and type into a Google Doc :^)
- LibJS+LibWeb: Implement enough to load Discord messages and send GIFs :^)
Obviously all of these are far from fully working, but it's exciting to see that bad performance is slowly () replacing missing APIs as one of our biggest issues!
I implemented support for
Promise in LibJS back in 2020-2021, which is the foundation for many modern Web APIs, such as
fetch(). Funnily enough I also predicted that I would eventually implement that, but for a while nothing happened beyond a few failed attempts.
My website was (and still is) using fetch for dynamically getting information from the GitHub API though, and the only way of getting that to work in Ladybird was to implement
fetch() so I started doing that (yes, this is how a surprising number of things get implemented). It took a few months working on infrastructure and the JS API on and off, but eventually I arrived at a working
fetch() method :^)
It's not completely to spec as we don't have the Streams standard implemented, but the foundations are solid and already used in other places (navigation, XHR) as well, as intended by those specs. I'm super happy that I managed to implement such a fundamental part of the modern web in LibWeb at last, but I also have to give some credit to Luke for their thorough testing and bug fixes!
This one is still in progress, but I'm eagerly looking forward to it as I'm writing this on a HiDPI laptop which makes websites look tiny compared to the window frame with our old assumption of
1px in CSS is one pixel on the display:
Sam, our local CSS expert, has gone and converted the entire LibWeb CSS layer to a new CSS Pixel unit, which then converts to physical pixels only when rendering. This leads to much nicer results than just 2x scaling a website rendered with the old approach, and has probably been supported by the browser you're reading this in for years. Soon also coming to a Ladybird Browser near you :^)
Of course we'll continue working on new Web APIs, performance, layout, rendering, and everything else there is to making a browser! As usual there's no roadmap so I can't tell you what exactly will and won't be implemented, but I'm excited to see what everyone decides to hack on next year :^)
If you want to help out with development definitely join the Discord server, and for semi-regular updates follow me on Mastodon. You can also sponsor me on GitHub so that I can do more of this!
Happy new year! 🎉