This Week in Ladybird #2
Overview of changes across the Ladybird Browser project in the week from March 27 to April 2 (plus everything merged Sunday evening) :^)
Summary
In chronological order:
- Ladybird: Open target _blank links in new tab
- LibWeb: Implement custom element name validation and fix bug in element name validation
- LibWeb: Don't force relayout whole page on programmatic scroll
- Ladybird: Enable and document build and debug steps with Xcode
- Browser+Ladybird: Show current zoom level in the view menu
- LibWeb: Stop returning the left padding for resolved padding-bottom
- LibWeb: Fix condition to early return in intrinsic sizing for TFC
- LibWeb: Handle flex column items with auto height that depends on auto width
- LibWeb: Clamp fit-content widths in flex layout to min/max-width
- Tests/LibWeb: Add layout test for layout fix in PR #15780
- LibWeb+LibWasm: Implement and use the "reset the Memory buffer" steps
- Ladybird+Browser: Add (reset) zoom level button to toolbar
- LibWeb: Parse Element.style url functions relative to the document
- LibWeb: Resolve percentage vertical-align values against line-height
- LibWeb: Implement HTMLAnchorElement.text and .referrerPolicy properties
- LibWeb: Implement CRC2D.imageSmoothingEnabled
- LibWeb: Remove redundant invocation of children changed in HTMLParser
- LibWeb: Don't re-sort StyleSheetList on every new sheet insertion
- LibWeb: Actually visit rules and media queries in imported style sheets
- LibWeb: Split CalculatedStyleValue out of StyleValue.{h,cpp}
- LibJS: Add fast path to Value::to_u32() if Value is a positive i32
- LibWeb: Begin implementing the Streams API
- Ladybird+Browser: Add tooltip to reset zoom level button
- LibWeb: Don't churn HTML::EventLoop while in microtask checkpoint
- LibWeb: Fix application of intrinsic aspect ratio to flex column items
- LibWeb+Tests: Allow subdirectories in layout_test.sh and add grid tests
- LibJS: Fix parsing of mixed
CoalesceExpression
andLogical{AND,OR}Expression
- LibWeb: Fix a few font scaling issues
- LibWeb: Don't apply element inline style & presentational hints to associated pseudo elements
Ladybird: Open target _blank links in new tab
This makes Ladybird (as in the Qt application) behavior match Browser (as in the LibGUI application) for the following actions:
target="_blank"
links open in a new activated tab- Links clicked while Ctrl is pressed open in a new background tab
- Links middle-clicked open in a new background tab
In the future we might make these configurable, but for now these are better defaults most people will be familiar with :^)
LibWeb: Implement custom element name validation and fix bug in element name validation
We now validate the name of custom elements according to the spec so that valid names create an HTMLElement
while invalid names create an HTMLUnknownElement
.
LibWeb: Don't force relayout whole page on programmatic scroll
This implements two optimizations for page scrolling:
- Reuse the layout tree if it is already up-to-date instead of always forcing a layout
- Skip this completely when scrolling to (0, 0), which is always known to be a valid position and doesn't require an upfront layout update
Note that JS-invoked page scroll currently uses a different code path, so we're possibly missing out on this optimization in some places :^)
Ladybird: Enable and document build and debug steps with Xcode
I'm not an Xcode user myself, but it's always nice to have proper documentation for more development platforms! Now if someone could document the steps to debug a WebContent process with gdbβ¦ π
Browser+Ladybird: Show current zoom level in the view menu
We now tell you the current zoom level in both Browser and Ladybird, which you previously had to estimate yourself! The zoom actions have moved into a submenu for that to happen:
LibWeb: Stop returning the left padding for resolved padding-bottom
I accidentally broke this 8 months ago and nobody noticed. π
I'm not sure how we managed to do that but thanks for the fix Sam!
LibWeb: Fix condition to early return in intrinsic sizing for TFC
This fixes an incorrect auto
height of a Table Formatting Context (TFC).
LibWeb: Handle flex column items with auto height that depends on auto width
Layout is like magic to me, so I'll trust you to understand this from the title alone :^)
LibWeb: Clamp fit-content widths in flex layout to min/max-width
More layout magic:
In situations where we need a width to calculate the intrinsic height of a flex item, we use the fit-content width as a stand-in. However, we also need to clamp it to any min-width and max-width properties present.
Tests/LibWeb: Add layout test for layout fix in PR #15780
More tests = more good, even when the fix was from five months ago!
LibWeb+LibWasm: Implement and use the "reset the Memory buffer" steps
#18079 by @alimpfard
This implements reset the Memory buffer from the WebAssembly JS API spec, which is part of our checklist of features required for the Ruffle Flash Player emulator.
Ladybird+Browser: Add (reset) zoom level button to toolbar
Similar to Firefox we also show a button to quickly reset the current zoom level next to the URL bar when it is not 100%.
LibWeb: Parse Element.style url functions relative to the document
url()
s in CSS applied via HTMLElement.style
are parsed now relative to that element's document URL.
This fixes the images on Steam's store carousel, for example:
LibWeb: Resolve percentage vertical-align values against line-height
Even more layout fixes. Andreas really did a lot of that!
LibWeb: Implement HTMLAnchorElement.text and .referrerPolicy properties
This implements the following APIs:
HTMLAnchorElement.referrerPolicy
HTMLAnchorElement.text
, an alias forNode.textContent
However we don't use the value of referrerPolicy
yet when following the link.
LibWeb: Implement CRC2D.imageSmoothingEnabled
This implements the following APIs:
This means that pages can now choose whether we use the bilinear interpolation or nearest-neighbor interpolation (i.e. pixelated) when painting scaled images on a canvas. Previously bilinear interpolation was always used, matching the default of imageSmoothingEnabled = true
.
Note that imageSmoothingQuality
is not actually honored as LibGfx doesn't support this concept yet.
LibWeb: Remove redundant invocation of children changed in HTMLParser
A simple fix to avoid doing duplicate work, one of the easiest ways to make code faster :^)
Setting the
data
of a text node already triggers children changed per spec, so there's no need for an explicit call.
LibWeb: Don't re-sort StyleSheetList on every new sheet insertion
Another performance optimization:
This was causing a huge slowdown when loading some pages with weirdly huge number of style sheets. For example,
amazon.com
has over 200 style elements, which meant we had to resort theStyleSheetList
200 times. Instead of sorting, we now look for the correct insertion point when adding new style sheets, and we start the search from the end, which is where style sheets are typically added in the vast majority of cases.
And the result:
This removes a 600ms time sink when loading Amazon on my machine! :^)
Editor's note: Amazon really needs to get its websites under control. Andreas also shared the following screenshot earlier:
LibWeb: Actually visit rules and media queries in imported style sheets
This ensures that we also consider @media
queries in style sheets loaded via CSS @import
, which previously wouldn't happen due to a bogus getter:
bool has_import_result() const { return !m_style_sheet; }
LibWeb: Split CalculatedStyleValue out of StyleValue.{h,cpp}
Another refactor of some CSS machinery, aimed at reducing dependency cycles and improving build times πππ
LibJS: Add fast path to Value::to_u32() if Value is a positive i32
This change nicely demonstrates the kind of low hanging performance fruit we still have in LibJS!
6.6% speed-up on Kraken's stanford-crypto-aes subtest. :^)
This is the entire diff:
--- a/Userland/Libraries/LibJS/Runtime/Value.cpp
+++ b/Userland/Libraries/LibJS/Runtime/Value.cpp
@@ -947,6 +947,10 @@ ThrowCompletionOr<i32> Value::to_i32(VM& vm) const
// 7.1.7 ToUint32 ( argument ), https://tc39.es/ecma262/#sec-touint32
ThrowCompletionOr<u32> Value::to_u32(VM& vm) const
{
+ // OPTIMIZATION: If this value is encoded as a positive i32, return it directly.
+ if (is_int32() && as_i32() >= 0)
+ return as_i32();
+
// 1. Let number be ? ToNumber(argument).
double number = TRY(to_number(vm)).as_double();
LibWeb: Begin implementing the Streams API
With the exception of an empty ReadableStream
interface, no one had done any work on implementing the Streams API yet β until now!
This implements the following APIs:
ReadableStream
:ReadableStreamDefaultController
:ReadableStreamDefaultReader
:
With those we can already run the Simple random stream example from MDN!
Ladybird+Browser: Add tooltip to reset zoom level button
A follow-up to the previous UI changes around zooming to make the new button's purpose more clear.
LibWeb: Don't churn HTML::EventLoop while in microtask checkpoint
This was the reason my Serenity VM's CPU was spinning at 100% for the entirety of the March update video (caused by having two GitHub tabs open) π
Luckily Andreas looked into it and found the cause: the event loop would constantly re-schedule itself even while we're performing a microtask checkpoint, except queued tasks wouldn't get processed in that state!
LibWeb: Fix application of intrinsic aspect ratio to flex column items
Only when using flex-direction: row{,-reverse}
the intrinsic aspect ratio was calculated correctly, not when using a column{,-reverse}
layout.
As many layout-related things this is somewhat vaguely defined in the spec, so it's easy to miss:
β¦then the flex base size is calculated from its inner cross size and the flex itemβs intrinsic aspect ratio.
LibWeb+Tests: Allow subdirectories in layout_test.sh and add grid tests
An initial set of 12 layout tests for CSS grid, which we use to ensure that changes don't regress layout β a rather complex part of the engine β by accident.
LibJS: Fix parsing of mixed CoalesceExpression
and Logical{AND,OR}Expression
Bugs in the JS parser have mostly been flushed out over the years, but still occur at times; especially when we throw megabytes of JS from the web at it :^)
This specific bug prevented us from parsing an expression like this, which occurred on vscode.dev
:
0 ?? 0 ? 0 : 0 || 0;
To be clear, I'm neither an expert on our JS parser nor do I really enjoy working on it, but I promised Andreas to fix the bug if he'd reduce it, which he did, so here we are. No test262 tests fixed, sadly π
LibWeb: Fix a few font scaling issues
Even now that fonts scale properly with the CSS pixel mechanism we still occasionally find cases where device pixels are used. This fix corrected the scaling of text shadows and the markers of ordered lists (<ol>
).
LibWeb: Don't apply element inline style & presentational hints to associated pseudo elements
This fixes a bug where inline styles (<foo style="...">
) and presentational hints (e.g. <foo width="...">
) would leak into the element's pseudo elements (::before
, ::after
) by accident β they should only apply to the element itself.
Screenshots
I didn't do this last week, but the browser engineer in me always gets excited when people share progress in form of a screenshot showing a mildly broken website so I think a section of random screenshots people shared is worth having π₯Ή
And that concludes the second post of the This Week in Ladybird series!
Also check out the SerenityOS update (March 2023) video if you haven't done that yet: