Commit 77f6edaf71 tried to map the promise
returned from the ImageCodecPlugin to the same promise type used for SVG
decoding. However, `map` drops the existing resolution callbacks on the
floor.
Instead, let's keep the ImageCodecPlugin promise alone, and resolve the
returned promise explicitly.
We only supported headless clipboard management in test-web. So when WPT
tests the clipboard APIs, we would blindly try to access the Qt app,
which does not exist.
Note that the AppKit UI has no such restriction, as the NSPasteboard is
accessible even without a GUI.
This prevents the AppKit UI from sending unknown MIME types to LibWeb,
where we would previously blindly dereference the result of parsing the
MIME string. We now ignore unknown MIME types as well.
If a resource appears in a test more than once, such as:
<script src="/foo.png">
<script src="/foo.png">
Then we end up replacing "/foo.png" in the test source that many times
as we iterate over the resource array, like so:
source.replace("/foo.png", "../foo.png")
So we end up with:
<script src="..../foo.png">
<script src="..../foo.png">
Store the resources as a set instead.
Previously, we enqueued a task on the main thread's event loop to
execute the callback. This meant that even though the rendering thread
had finished producing the next frame, there was still a delay before
the main thread notified the UI process.
This change makes the rendering thread execute the callback directly.
This should be safe, as the only pointer captured by the callback is the
traversable `PageClient`, which is expected to remain alive for as long
as the rendering thread exists. The callback then invokes either
`page_did_paint()` or `page_did_take_screenshot()`, both of which
enqueue an IPC message, which is safe to do since `SendQueue` is
protected by a mutex.
Adds pinch event handling that adjusts the VisualViewport scale and
offset. VisualViewport's (offset, scale) is then used to construct a
transformation matrix which is applied before display list execution.
Implements spec algorithm for viewport scrolling that first checks if
it's possible to use delta to move the visual viewport before falling
back to scrolling the layout viewport. This is a part of pinch-to-zoom
support.
A ::marker pseudo-element is created for list item nodes (nodes
with display:list-item).
Before:
- The content of the ::marker element is created magically from
the value of the ordinal (for <ol>) or from a template (for <ul>).
The style `content` is ignored for ::marker pseudo-elements.
After:
- If a "list item node" has CSS `content` specified for its ::marker
pseudo-element, use this to layout the pseudo-element,
https://drafts.csswg.org/css-lists-3/#content-property
- Otherwise, layout the list item node as before.
Introducing cpptrace as the primary backtrace library broke the
backtrace fallback during the code move. This commit properly links AK
to libbacktrace.
It also fixes the function signatures for the fallback backtrace
handlers.
Many clock related functions in Ladybird use the clock type called
CLOCK_MONOTONIC_COARSE to obtain timestamps. This is a less precise
clock and can be skewed by 1 or more milliseconds.
This less precise clock timing is causing the abortsignal-timeout.html
test to fail randomly as it expects the abort signal to arrive after
10ms, but in some cases it arrives at 9ms causing the test to fail. In
some very rare cases it could even arrive in 7ms or 8ms.
Test is changed to accept 9ms as a good result and if that is still
not enough the test also will display the timings so that further
investigations can be made.
This is the second and final commit to remove using-declaration from
.prettierignore. While there is standard formatting changes here, there
is also scoping changes for the 'using' declarations due to the
following error:
Libraries/LibJS/Tests/using-declaration.js: SyntaxError:
Using declaration cannot appear in the top level when source
type is `script` or in the bare case statement.
This contains prettier formatting fixes for using-declaration.js. The
file isn't fully formatted at this state. There is a minor scoping code
change that must happen in the next commit to be able to remove this
file from .prettierignore, but I wanted to separate the code change from
the formatting change to improve the review process.
This contains formatting and changing single quotes to double quotes.
Shorthands should be broken up into their longhands, instead of setting
them directly.
There's a catch here with our "positional value list shorthands" like
`margin`: Setting margin to a single value like `CSSUnitValue(10, "px")`
is supposed to fail here, but our type-checking code thinks it's valid
because our JSON for `margin` says it accepts lengths. This is the same
kind of issue that we had for `cursor` discussed in the
"LibWeb/CSS: Support converting CSSUnitValue to a StyleValue" commit.
Will get us a few subtest passes for every shorthand that's tested.
Unfortunately this doesn't pass a lot of tests, because we strip out
whitespace when parsing property values. In particular, the WPT suite
tests with this:
```js
new CSSUnparsedValue([' ', new CSSVariableReferenceValue('--A')])
```
...which gets the whitespace stripped from the string, meaning when we
convert the value back to JS, we get the equivalent of this:
```js
new CSSUnparsedValue(['', new CSSVariableReferenceValue('--A')])
```
...and that's not the same so the test fails.
As noted in the linked spec issue, it's possible for an author to
construct a CSSUnparsedValue that contains itself, meaning
serialization would be infinitely recursive. So instead, detect that
and then return an empty string, which copies Blink's solution to this
issue.
Stops `css/css-typed-om/cycle-in-unparsed-value-crash.html` from
crashing after we implement converting a CSSUnparsedValue to an
UnresolvedStyleValue, as that relies on serialization.
Typed-OM means that the author can set a property's value to a
CSSUnparsedValue, which may or may not have any arbitrary substitution
functions in it. This VERIFY was just there to catch parsing bugs that
created UnresolvedStyleValues unnecessarily, and removing it is
harmless.
This avoids regressions in the next commit.
See the linked spec issue for details. Without this, we end up doing the
wrong thing in cases like this, from a WPT test:
```js
styleMap.set('transition-duration', '1s', 'var(--A)');
```
`'var(--A)'` is a string, not a CSSVariableReferenceValue or
CSSUnparsedValue. Following the spec literally, we wouldn't throw a
TypeError here, even though we really should: The purpose of the check
is for list-valued properties, to prevent authors putting a series of
tokens that would represent multiple list items, into a single list
item slot.
So, we delay the check until after we've converted strings into values.
This does mean we're checking StyleValues instead of CSSStyleValues,
and it also means we've done more work before rejecting the input as
invalid. But correctness is nice. :^)
A lone CSSUnitValue can now be converted to a dimension StyleValue of
the relevant type, as long as the property allows that type. If the
value is out of the allowed range, it's wrapped in calc().
There are a few failing tests still, involving setting a negative
percentage and expecting to read the computed value as 0. Those also
fail in Chromium, and a similar negative-length test expects a negative
computed value (not 0), so this appears to be an incorrect test.
Also, we regress some of the `cursor` tests. This is because our "does
property X accept type Y?" code is too naive: `cursor` is defined to
accept "number [-∞,∞]" in the JSON, and that value range is used when
clamping the result of calculations or interpolation. But because that
entry is there, we think a single number is a valid value for `cursor`.
Solving this generally is a larger task than I want to take on right
now. :^)
The upstream workflow `head_sha` contains the wrong hash in case the
workflow was run manually against a provided commit hash. We use the
COMMIT file that cpack adds to the archive to determine the actual
commit hash that was used to build the binaries.
Note that this will only work for builds since the introduction of that
file, so we cannot process benchmarks for older commits, unfortunately.
This new file in the root of the archives contains the git commit hash,
to be used by e.g. the js-benchmarks webhook to determine which commit
was used to build the utilities.
This commit replaces the default backtrace logic with cpptrace, for
nicer, colored backtraces. Cpptrace runs on all of our supported
platforms excpet android. As such backtrace.h is left in place.
All the backtrace functions are made noinline to have a consistent
number of frames. A maximum depth parameter is added to dump_backtrace
with a default of 100. This should be enough, and can be easily
changed, and allows for limiting the maximum depth.
Setting the LADYBIRD_BACKTRACE_SNIPPETS environment variable enables
surrouding code snippets in the backtrace. Specifically 2 lines above
and below. This number can be changed by calling snippet_context on the
formatter. For the whole list of options of what can be done with
formatting see the cpptrace repository.
On Windows we skipped frames when verification fails and when
dump_backtrace was added the logic was wrong and would have skipped
frames we care about.
This commit also implements skipping frames on Linux.
The only time where this does not skip all frames is when the call to
backtrace gets intercepted. Then we will end up skipping one frame less
than needed.
To keep delayload on Windows a patch and overlay port is used. When
upstream accepts these changes and vcpkg bumps the version the patch
could be removed to have just the cmake define.
If the Ladybird process crashes or just ends normally, the IPC transport
connection with WebContent may be shutdown after a send sync event (for
example: WebContentClient DidRequestCookie) was sent from WebContent,
but before the Ladybird process provided the matching sync event
response (for example: WebContentClient DidRequestCookieResponse). This
can lead to a runaway WebContent process if other IPC events (for
example: WebContentServer DidPaint, or SetSystemVisibilityState, or
MouseEvent, or CloseServer, etc...) are also queued when the IPC
connection is shutdown.
At the core of the issue is that the loop waiting for the matching
send sync response will prioritize waiting for the response and remain
spinning even if the IPC connection is reporting that it was shutdown,
but only if there happens to be other unrelated events received before
the IPC shutdown is detected. These unrelated events will not be
processed because the loop is stuck waiting for the response that due
to the Ladybird process having stopped, will never be sent.
Because the shutdown of the IPC connection is not handled when other
events happen to be also present, new events may be posted for transfer
by the WebContent process if the page is very active. If many new events
are posted this could lead to a slow or very quick memory leak in the
WebContent process due to the queue growing large, sometimes all the way
to total system memory exhaustion. If no events or only a few new events
are sent, then the leak may be hard to detect.
This PR fixes the faulty IPC shutdown handling by not getting stuck if
any messages are present in the receive queue. Before returning to the
caller any remaining messages will be immediately processed.
This gets rid of a lot of pointer chasing from interpreter to executable
to identifier table to the actual identifier.
1.05x speed-up on Kraken/ai-astar.js
These will generally be cached the vast majority of the time except on
first encounter, and sprinkling [[likely]] gives us a nice boost.
1.10x speed-up on this micro-benchmark:
(() => {
var a = 3;
for (let i = 0; i < 100_000_000; ++i) { a; }
eval("");
})();
The src IDL attribute was previously implemented as an inline getter
that returned the raw attribute value. This broke spec semantics and
sites like Telegram Web that rely on document.currentScript.src to
compute Webpack’s publicPath.
According to the HTML Standard:
https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#reflecting-content-attributes-in-idl-attributes
For URL-reflecting attributes:
1. If contentAttributeValue is null, then return the empty string.
2. Let urlString be the result of encoding-parsing-and-serializing
a URL given contentAttributeValue,
relative to element’s node document.
3. If urlString is not failure, then return urlString.
This patch moves the getter to HTMLScriptElement.cpp and implements
these steps.
Before this change, you could only scroll the current hovered scroll
container, even if it was at the beginning or end and thus having no
effect.
Now, if it doesn't update, it will not be classed as handled and will
move onto the next scroll container.
Instead of converting them to doubles and doing double math, just do the
arithmetic operation in i64 space instead.
This gives us a ~1.25x speed-up on this kind of micro-benchmark:
(() => {
let a = -2124299999;
for (let i = 0; i < 100_000_000; ++i) {
a + a;
}
})()
Same idea for Add, Sub, and Mul.
There's a fair bit of overflowing Int32 arithmetic in some of the
JetStream benchmarks, and this seems like an obvious improvement.
Currently we default to GITHUB_REF for the checkout of js-benchmarks,
and if we've built up a large backlog of benchmark jobs to run, this can
mean we're running against a severely outdated version of js-benchmarks.
This new behavior allows us to see a failed js-benchmarks job, fix the
bug, and restart the failed job. This is important since we're testing a
specific commit and build from the upstream JS/WASM workflow.
Reverts c8bd58c and 0df9c22. These were used to absolutize values stored
within other `StyleValue`s but we should instead store these values as
`StyleValue`s directly instead of within `{Calculated,Percentage}Or`.
This struct will in the future hold information other than a length
resolution context (e.g. context for tree counting functions) and a
single struct is easier to work with than multiple parameters.
The [[Set]] operation on objects will normally end up doing
[[GetOwnProperty]] twice, but if the object and the receiver are one on
the same, we can avoid the double work.
AFAIK this is not observable via proxies or other mechanisms.
1.10x speed-up on MicroBench/object-set-with-rope-strings.js
Pending changes to an ancestor document's layout can affect an element's
computed style e.g. an IFrame's width being changed can affect media
query evaluation and the value of the `vw` unit.
Previously we would always use the window's viewport which was incorrect
if we were within an iframe.
This is likely applicable to all uses of
`Length::ResolutionContext::for_window`.
We were using the font's point size instead of it's pixel size, we were
already computing this information earlier in the function anyway so
let's just use that.
If we ever want to rerun benchmarks for an older commit, e.g. if we
added new benchmarks that we would want historical performance data on,
we need to consider that some benchmarks might fail because of a bug or
missing feature. For manual runs of the upstream build, pass
`--continue-on-failure` so we simply skip these failing benchmarks.
This allows us to manually kick off jobs for the JS/WASM artifacts
build with an explicit reference to build, which is useful if we want to
generate benchmark results for older commits.
Note that this workflow does not actually produce benchmark results -
that's the job of another workflow. The webhook storing the benchmark
results only appends new benchmarks; existing ones will be kept.
Also note that the GitHub checkout action defaults to the default
reference if `inputs.reference_to_build` is not provided, such as in the
case of a push to the master branch.
This reverts commit 8d46a11748.
The updated webhook supports the newer output format of our
js-benchmarks tool, allowing us to store multiple result types per
benchmark and subtest combination.
Per SVG2 spec (§ Geometry Properties: getBBox), getBBox() must throw
InvalidStateError if the element is not rendered and its geometry cannot
be computed. Previously we would crash on null paintables; now we throw
with a clear error instead.
...and use it to make HashMap::ensure() do a single hash lookup instead
of three.
We achieve this by factoring out everything but the bucket construction
logic from HashTable::write_value() into a lookup_for_writing() helper
so we can use it from more places.
We are often forced to convert numbers to strings inside LibJS, e.g when
iterating over the property names of an array, but it's also just a very
common operation in general.
This patch adds a 1000-entry string cache for the numbers 0-999 since
those appear to be by far the most common ones we convert.
To detect system time zone changes on Windows, the event we need to look
for is WM_TIMECHANGE. The problem is how the callback with said message
actually gets invoked is very particular. (1) We must have an active
message pump (event loop) for the message to ever be processed. (2) We
must be a GUI application as WM_TIMECHANGE messages are seemingly sent
to top level windows only. It doesn't say that in the docs for the
event, but attempts of creating a LibTest-based application with a
message pump and a message only window and never receiving the event
point to that probably being true.
This workaround is built off the fact that Qt's message pump defined
internally in QEventDispatcherWin32::processEvents does in fact receive
WM_TIMECHANGE events, even though it is not exposed as a QEvent::Type.
Given the requirements stated above it makes sense that it works here as
the message pump is executing in a QGuiApplication context. So we use a
native event filter to hook into the unexposed WM_TIMECHANGE event and
forward it along to the on_time_zone_changed() callback.
Note that if a Windows GUI framework is done in the future, we'll have
to re-add support to ensure the TimeZoneWatcher still gets invoked.
icu::TimeZone::createDefault() was returning the timezone that was set
when current_time_zone() was first called or the timezone set via
set_current_time_zone().
This meant that even when the system timezone changed and we instructed
all WebContent processes to invoke
ConnectionFromClient::system_time_zone_changed(), the updated timezone
system was not being used as we fetched from icu's default timezone.
icu::TimeZone::detectHostTimeZone() gets the timezone from the current
host system configuration and ensures we are always synced with the host
if we have no timezone cache.
Before this change, we'd construct a ByteBuffer for the internal buffer,
and then move-construct StringBuilder::m_buffer from it.
Due to ByteBuffer's inline capacity, this meant we had to memmove the
inline buffer an extra time for every StringBuilder created.
With this commit, only direct CSSStyleValues created from internal
StyleValues can be converted back to a StyleValue. More subtests will
pass as create_an_internal_representation() is implemented for the
various CSSStyleValue subclasses. :^)
Gets us... a LOT of WPT passes, because there's a ton of coverage for
each property.
When setting style to a CSSStyleValue we need to convert it to a
StyleValue. If we already have one, we might as well use it avoid the
work of serialization and re-parsing.
I realised I misunderstood what "constructed from a USVString" means, so
I've adjusted based on that. It does raise a question on what the source
USVString is if that string resulted in multiple CSSStyleValues being
created - see the linked issue.
Typed-OM requires us to have a generic way of asking "does property X
accept a list or a single value?" so this exists mainly for that.
Coordinating lists are annotated too - I'm not clear on exactly what
will be needed for those, but giving them a unique value now at the
worst will make them easier to find later.
This commit modifies the `compute_foo()` code for `font-style` and
`math-depth`. They previously assumed that their StyleValue was always
a special kind: FontStyleStyleValue or MathDepthStyleValue. This was
always true, because that's how we parse them, but it stops being true
once StylePropertyMap is involved: An author can set font-style to a
CSSKeywordValue of "italic", and this should work.
There are multiple ways that we could solve this, but the simplest and
easiest to maintain seems to be to handle those more basic StyleValues
in this computation code. Going forward, we'll have to be aware that
similar properties could have a basic StyleValue from the typed-OM
instead of the property-specific one we'd expect.
This fixes a crash on initial load of the page http://demo.actualbudget.org.
Minimal repro of the issue (error in the console without this PR):
<script>
const r = indexedDB.open("t", 1);
r.onupgradeneeded = e => e.target.result.createObjectStore("s", { keyPath: "id" });
r.onsuccess = () => r.result.transaction("s", "readonly").objectStore("s").getAllKeys();
</script>
of `PaintableBox` and `PaintableWithLines`.
If we ended up with non-identity transform in `hit_test()` of PB or PWL
and have to account for transforms, means we forgot to skip stacking
context while iterating through children.
- Add missing check to skip paintable that eastablishing a stacking
context in `PaintableBox::hit_test_children()`
- Otherwise it mostly reverts changes done by 4070f5a7e
...before falling back to containing block. Fixes a bug when we can't
scroll innermost scrollable element, because wheel event dispatching
immediately falls back to containing block.
I spotted this leak when WebContent was exiting with ASan enabled on a
page with a media element. MediaPaintable calls Gfx::Font::width(),
which calls through to measure_text_width(), which then drops an
hb_buffer_t* without freeing it.
This is a normative change in the ECMA-262 spec. See:
https://github.com/tc39/ecma262/commit/541b2f6
Note we already handled this case well, but let's update our impl to
match the latest spec text.
The optimization for non-shared ArrayBuffers operates on incorrect
values of from_byte_index and to_byte_index because they will have been
modified in the preceding steps. This causes the incorrect range to be
copied within the buffer.
When trying to repro a failed CI test, it is handy to know the order in
which test-web ran its tests. We've seen in the past that the exact
order can be important to debug flakey tests.
This adds the index of the WebView running the test to verbose log
statements (which is enabled in CI).
I noticed the existing code would end up calling
`computed_properties->property(PropertyID::Custom)`
so let's actually ask for the custom property instead.
StylePropertyMap only ever works with style properties - never
descriptors. Switching `has_property()` and `get_property_style_value()`
to taking PropertyNameAndID skips some duplicate work.
This awkwardly sat as the internal final API for getting a StyleProperty
directly for a given PropertyID, and also the external API for getting
the StyleProperty for a PropertyID. For the latter, it lacked support
for shorthands, and for both it lacked support for custom properties.
This commit:
- Moves the code from get_property() into get_direct_property()
- Makes get_property() call get_property_internal() to support
shorthands
- Adds custom property support for get_direct_property()
This also wins us some WPT points for StylePropertyMap.
We often want to call a function with either a built-in or custom
property, and that means either passing it as a string (and converting
back and forth between strings and PropertyIDs) or using the
PropertyIDOrCustomPropertyName variant, which complicates user code.
PropertyNameAndID is intended to make that easier: Create it with a
string or PropertyID, and it can tell you either one.
property_accepts_type() only looks at the property itself, not any
longhands it might have, so we thought that `font` didn't accept
`<custom-ident>`s, and seeing "-apple-..." makes us throw out the
declaration even though it's valid as a font name.
We'll reject these like any other unrecognized value if it's somewhere
that's not supported, so this was really just an optimization for a
rare edge case, and removing the check doesn't have any observable
effect except fixing this bug and any similar cases.
Changing property_accepts_type() to look at longhands is not
straightforward, as not all longhand values are valid in the shorthand.
The decoder was requiring GIF files to be at least 32 bytes, but the
actual minimum for a valid GIF is only 26 bytes:
- 6 bytes for the header
- 7 bytes for the Logical Screen Descriptor
- 10 bytes for the Image Descriptor
- 2 bytes for the LZW minimum code size and block terminator
- 1 byte for the GIF trailer
This change allows us to load minimal 1x1 GIFs with empty LZW data.
They are commonly used on the web as transparent placeholders with
minimal file size.
`set_source` takes a ByteString but the implementation might require a
specific encoding. Make it fallible so that we don't need to crash in
the case of invalid UTF-8 or similar.
The test includes a sequence of invalid UTF-8 bytes that crash the
browser without this change.
This is supported starting GCC 15.
The warning -Wmaybe-musttail-local-addr complained about &value possibly
escaping (it cannot, but gcc is being pessimistic about
store_to_memory), so a little rearrangement of that function was
necessary.
This is a _significant_ perf improvement as we no longer have to think
about tracking state transitions from empty <-> nonempty.
(corresponds to a ~20% perf improvement in LibWasm)
Instead of doing a naive O(n^2) liveness detection loop, use a bitmap
for values allocated to registers.
This cuts down validating time from 20% to 1.4% of runtime on the same
game as last commit.
Instead of repeatedly removing elements off the vector, this allows for
specifying all the removed indices at once, and does not perform any
extra reallocations or unnecessary moves.
This applies size, inline-size, and style containment in some cases.
There are other WPT tests for that, but we seem to not implement enough
of containment for this to have an effect so I've not imported those.
Gets us 35 WPT subtests.
Use `Float32Array or sequence<GLfloat>` instead of
`BufferSource or sequence<GLfloat>`. This meaningfully changes behavior
for `Float16Array` and `Float64Array`: they are now converted to
`sequence<GLfloat>` by iterating the typed array, rather than being
treated as a `BufferSource`. As a result, many WebGL calls now work
correctly where we previously crashed in `VERIFY_NOT_REACHED()` due to
the assumption that a `BufferSource` was always a `Float32Array`.
Fixes https://github.com/LadybirdBrowser/ladybird/issues/5962
Allows definition of:
`typedef (Float32Array or sequence<GLfloat>) Float32List;`
which did fail to compile before, because `GC::Root<JS::Object>` fails
to implicitly cast into
`AK::Variant<GC::Root<JS::Float32Array>, AK::Vector<float>>`.
Copy parse() method from LibCore::DateTime::parse(). Augment the method
to handle parsing from GMT time. Fix incorrect handling of year in '%D'
format specifier. Remove all format specifiers related to time zones.
Copy relevant tests and add additional ones.
The standard workflow for working with forks is to clone the fork and
add the main repository as upstream. Also recommend using git switch
instead of checkout.
Whether an absbox is positioned below or to the right of its previous
sibling in an `InlineFormattingContext` is determined by the
display-outside value before blockification, so we store the
pre-blockification `display` value in `ComputedValues` to access it in
`InlineFormattingContext` and position the box accordingly.
Before this change, we always used the flex container's full available
space as the width for intrinsic (height) sizing of flex items.
This meant that flex lines with more than one flex item had their
intrinsic height determined as if they were alone on the line.
For flex row layouts, if we've already determined the flex item's main
size, we now use that as the width to get the intrinsic height.
This leads to more correct layouts, and also avoids some redundant work
since we no longer do unnecessary sizing work with the wrong width (and
can hit cache instead).
...instead of taking the Layout::Box. This will allow us to make more
nuanced decisions in those functions by having access to flex layout
internal state.
Provide help with out-of-date openSUSE packages.
Update the libpulse-devel and qt6-multimedia-devel instructions
when dynamic linking errors are encountered.
Width and height are doubles, so get_string() will return nothing and
fail. We just want a JsonValue here without caring what type it is, so
let's just use get() instead.
For whatever reason, this method in particular ends up failing to link
into WebContent with a subsequent change. It's small and simple, so
just inline it.
We were ignoring the dom_element_unique_id field, which meant if we had
more than one inline style sheet on a page, we would not distinguish
between them. This had the effect of halting the style sheet loading
process in the dev tools, with none appearing.
Mark UA style sheets as "system", which makes them read-only in the
Firefox dev tools. Also give them an href with a fake resource:// URL so
that they don't appear as "<inline style sheet>", and don't set the href
for actual inline style sheets, for the opposite reason.
I've kept the title for UA style sheets, because that means we see
`Thing/Default.css` instead of just `Default.css` for all of them.
This release comes with a fix for a bug where certain unicode emoji
characters encoded in UTF-16 were mistakenly parsed as integers. This
manifested in keys of an JS object being coerced into integers, i.e.
`{ "⤵️": 42 }` would become `{ "5": 42 }`.
Relevant upstream PR: https://github.com/fastfloat/fast_float/pull/325
This gets rid of the assumption that the DOM node of an ImageBox is
also its image provider. This will become necessary when generating
the image boxes for view transition pseudos, for which the DOM node
won't be the image provider. (that'll be the pseudo element itself)
As it turns out, SkPath already behaves the way we need for SVG and HTML
canvas elements. Less work for us, yay! This removes a 5% item from the
profile when scrolling on https://imdb.com/
Note that there's a tiny screenshot test expectation change due to
minor antialiasing differences when we no longer do our redundant
subpath modifications.
This makes it so that the bounds for any paint-contained stacking
context are not derived from its children, but rather just set to
the rectangle that they will be clipped to anyways due to the paint
containment. Should make rendering faster on pages that use paint
containment.
This is required because bounding rect used in `saveLayer()` is computed
in stacking context's coordinate space.
Fixes regression introduced in ba2926f
Instead of resolving some viewport-relative sizes on every paint, we now
do them just once in paint-only property update.
This takes SVGPathPaintable::paint() from 15% to 8% in the profile when
scrolling on https://imdb.com/
Before this change, we always updated paint-only properties for every
single paintable after layout or style changes.
This could get very expensive in large documents, so this patch makes
it something we can do partially based on "repaint" invalidations.
This cuts down time spent in paint-only property update when scrolling
https://imdb.com/ from 19% to 5%.
These functions are trivial, and we were actually bleeding a lot of time
in profiles to just function entry/exit.
By marking Length::make_px() as [[nodiscard]], we also exposed some
places that were creating a Length and not using it for anything.
Before this change, we were basically always setting the non-initial
border radii flag on ComputedValues, which made the work-avoiding
optimization based on this flag ineffective.
Teach the display list executor to derive a bounding rectangle for
stacking contexts whose inner commands can all report bounds, that is,
most contexts without nested stacking contexts.
This yields a large performance improvement on https://tc39.es/ecma262/
where the display list contains thousands of groups like:
```
PushStackingContext blending=Multiply
DrawGlyphRun
PopStackingContext
```
Previously, `PushStackingContext` triggered an unbounded `saveLayer()`
even when the glyph run lies wholly outside the viewport. With this
change, we (1) cull stacking contexts that fall outside the viewport and
(2) provide bounds to `saveLayer()` when they are visible.
With this change rendering thread goes from 70% to 1% in profiles of
https://tc39.es/ecma262/. Also makes a huge performance difference on
Discord.
We have a slightly odd setup here. TransformationStyleValue reifies as a
single CSSTransformComponent. It's StyleValueList that actually reifies
as a CSSTransformValue - but only if it only contains
TransformationStyleValues.
+79 WPT subtests.
This is the final CSSStyleValue class used by the per-property test
harness, so those now actually run instead of throwing an exception on
load. 🎉
+39 WPT subtests. (Plus however many from the per-property tests finally
running.)
The two failing serialization tests are also failed by Safari in exactly
the same way, so that seems more like a spec issue. (The spec is
incomplete in quite a few places.) The failing subtest for toMatrix() is
also a spec issue: is2D is handled oddly by CSSMatrixComponent and this
subtest fails because of the `matrix` getter, which is unspecified. See
https://github.com/w3c/css-houdini-drafts/issues/1155 for details.
DOMMatrix.to_string() throws exceptions if any of its values are
non-finite. This ends up affecting CSSStyleValue because its subclass
CSSTransformValue (which is about to be added) serializes
CSSTransformComponents, and one of those is CSSMatrixComponent, which
calls DOMMatrix.to_string().
This is all quite unfortunate, and because at the time the spec for
DOMMatrix was written, CSS couldn't represent NaN or infinity. That's
no longer true, so I'm hoping the spec can be updated and this can be
reverted. https://github.com/w3c/fxtf-drafts/issues/611
Equivalent to the perspective() transform function.
+34 WPT subtests, and the transformvalue-normalization test now runs to
completion instead of throwing an error - though its cases still fail
until CSSTransformValue is implemented.
This is a base type for the various transform functions.
CSSMatrixComponent's to_string() can throw exceptions, so to_string() is
implemented that way. https://github.com/w3c/fxtf-drafts/issues/611
+9 WPT subtests.
Opacity values are unique in that the range which calculated and
interpolated values should be clamped to [0,1] is different from the
range of allowed values [-∞,∞].
This fixes 28 WPT tests that were regressed in #6112
We now:
- Serialize longhands in the correct order
- Support serializing multiple values
- Include default longhands where required (to distinguish
animation-name from that longhand).
We were unnecessarily computing property values within
`collect_animation_into` which we can avoid by ensuring that all calls
to `collect_animation_into` happen after property values are computed.
This change adds the allowed angle range to the `font-style` property
definition. This allows these angles to be clamped after interpolation.
Ideally, the generator should be updated so that we can specify the
angle is in degrees. This would allow us to make use of this
information during parsing, which we can't do currently because we
don't know what the unit is. Using this value for interpolation
purposes is fine because the angle has been converted to its canonical
unit by this point.
When displaying SVGs inside a navigable directly, we want to display
them in the size specified by their width and height attributes instead
of stretching them to the viewport as layout normally would.
However, when doing so, we need to actually check that the SVG we are
laying out is indeed directly inside the navigable. Otherwise we just
blindly overwrite whatever content sizes have been calculated by layout
code for e.g. SVG elements inlined somewhere in an HTML document.
Due to the way this was written originally, the bug was not very
noticable. The code overwrote the content width/height with the computed
width/height, which was often still correct in the sense that those two
had the same value. However, content size may also be the result of
{min,max}-{width,height} constraints, which can make it differ from the
computed values.
This bug was likely a regression introduced in
f5e01192cc.
Add an option to http-test-server.py to return received headers as the
response body. This is useful for checking that outgoing headers are
correct, for example in cookie tests.
...in clip and scroll frames calculation algorithm.
Fix a regression from 719a50c where display-list recording disagreed
with the clipping logic about whether a stacking context is transformed.
`has_css_transform()` returns true whenever the computed transform is
not `none`, which differs from an identity-matrix check. These yield
different results for cases like `translate(0, 0)`.
Before this change we would emit PushStackingContext/PopStackingContext
display list items regardless of whether the stacking context had any
transform/opacity/clip effects.
Display list size on https://x.com/ladybirdbrowser is reduced from ~2700
to ~800 items.
We now fail a few more tests in properties-value-inherit-001.txt as we
no longer overwrite the non-animated value of `line-height` with the
animated value, this is in line with other major browsers.
We were already doing this within `compute_property_values` where
we resolved most relative lengths but the remainder was instead
incorrectly using the font's line-spacing
Weakable is not thread-safe, so taking a strong reference from a
WeakPtr<Thread> may result in a use-after-free. We don't use this
functionality anywhere anyway, so remove it.
I created this file a couple years ago, but had a copy/pasted copyright
comment from another file, without the authors being changed. It's now
corrected to attribute it to myself, as it should have been already.
Buckets being iterated by pointer instead of reference was causing a
compilation error when calling clear_with_capacity() on a HashTable
containing a non-trivially-destructible type.
Set SkPaint anti-aliasing to true when filling rectangles
This improves rendering quality by smoothing jagged edges
update clip-path-transformed.html and ref image with anti-aliasing
Partially fixes#5909
The current HEAD contains a bunch of stuff not supported by wabt (or
us), that also appear to not be fully merged yet; stick to the last
known commit for now.
Timers scheduled with identical `fire_time` could fire out of order
because the heap is not stable. This change assigns a monotonically
increasing `sequence_id` when a timer is scheduled and extend the heap
comparator to order by (`fire_time`, `sequence_id`). This guarantees
FIFO among timers with the same deadline.
This matches the HTML "run steps after a timeout" ordering requirement:
older invocations with <= delay complete before newer ones.
https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#run-steps-after-a-timeout
This change implements a part responsible for this invariant in a more
efficient way:
"Enumerating the properties of the target object includes enumerating
properties of its prototype, and the prototype of the prototype, and so
on, recursively; but a property of a prototype is not processed if it
has the same name as a property that has already been processed by the
iterator's next method."
Previously we inserted `(key, enumerable)` pairs into an
`OrderedHashTable`. That always built and maintained a hash table, even
when no prototype-level filtering was needed.
Now we:
- Collect only enumerable keys into `Vector<PropertyKey>`.
- Track `seen_non_enumerable_properties` so a non-enumerable own
property still shadows prototype properties with the same name.
- Lazily materialize `HashTable<PropertyKey>` only if we encounter an
enumerable property on a prototype and must check for duplicates. In
the common case materialization is avoided, because default Object or
Array prototype properties are non-enumerable.
Before this change, PropertyNameIterator (used by for..in) and
`Object::enumerable_own_property_names()` (used by `Object.keys()`,
`Object.values()`, and `Object.entries()`) enumerated an object's own
enumerable properties exactly as the spec prescribes:
- Call `internal_own_property_keys()`, allocating a list of JS::Value
keys.
- For each key, call internal_get_own_property() to obtain a
descriptor and check `[[Enumerable]]`.
While that is required in the general case (e.g. for Proxy objects or
platform/exotic objects that override `[[OwnPropertyKeys]]`), it's
overkill for ordinary JS objects that store their own properties in the
shape table and indexed-properties storage.
This change introduces `for_each_own_property_with_enumerability()`,
which, for objects where
`eligible_for_own_property_enumeration_fast_path()` is `true`, lets us
read the enumerability directly from shape metadata (and from
indexed-properties storage) without a per-property descriptor lookup.
When we cannot avoid `internal_get_own_property()`, we still
benefit by skipping the temporary `Vector<Value>` of keys and avoiding
the unnecessary round-trip between PropertyKey and Value.
This patch introduces a per-Gfx::Font cache for harfbuzz text shaping
results. As long as the same OpenType features are used, we now cache
the results of harfbuzz shaping, saving massive amounts of time during
text layout.
As an example, it saves multiple seconds when loading the ECMAScript
specification at <https://tc39.es/ecma262>. Before this change, harfbuzz
shaping was taking up roughly 11% of a profile of loading that page.
The cache brings it down to 1.8%.
Note that the cache currently grows unbounded. I've left a FIXME about
adding some limits.
Clipboard handling largely has nothing to do with the individual web
views. Rather, we interact with the system clipboard at the application
level. So let's move these implementations to the Application.
Previously we would clamp the percentage value to the allowed range for
canonical dimension values rather than the percentage value.
Also fixes an issue where we would clamp pure percentages (i.e.
percentages that don't have a hint) against the allowed values for the
first dimension we checked (i.e. angle)
Previously if we would overwrite the non-animated font-size with the
animated font-size if it was set.
Loses us 2 WPT tests but this is in line with other browsers
We now also more closely follow the spec when computing values for
font-weight and we now:
- Support relative lengths in `calc()`s
- Properly clamp `calc()`s
- Support relative keywords (e.g. lighter, bolder)
- Respect that font-weight can be a non-integer number.
This does expose a few false positives in the font-weight-computed.html
WPT test. This is because we don't recompute non-inherited font-weight
within `recompute_inherited_style` which means that relative keyword
values can fall out of sync with their parent's value. These previously
passed as we treated `bolder` and `lighter` as aliases for `bold` and
`normal` respectively.
Remaining test failures in font-size-interpolation-00* are either:
- Rounding of font-size to CSSPixels when setting the expected value
- Not clamping negative values from the point of view of
getComputedStyle (used values are still clamped)
Previously if we would overwrite the non-animated font-size with the
animated font-size if it was set.
Gains us 8 WPT tests and means we now fail 9 others in line with other
browsers.
There are other places we want to convert font-size into it's computed
form than just when we are loading the font (e.g. computing keyframes).
Gains us 36 WPT passes as we now correctly clamp negative calc values.
The overlay shown for the node hovered in the inspector is painted as
part of the normal tree traversal of all paintables. This works well in
most cases, but falls short in specific scenarios:
* If the hovered node or one of its ancestors establishes a stacking
context and there is another element that establishes a stacking
context close by or overlapping it, the overlay and especially the
tooltip can become partially hidden behind the second element. Ditto
for elements that act as if they established a stacking context.
* If the hovered node or one of its ancestors involves clipping, the
clip is applied to the overlay and espicially the tooltip. This can
cause them to be partially invisible.
* Similarly, if the hovered node or one of its ancestors has a defined
mask, the mask is applied to the overlay, often making it mostly
invisible.
* No overlays are shown for SVG nodes because they are painted
differently from HTML documents.
Some of these problems may be fixable with the current system. But some
seem like they fundamentally cannot work fully when the overlays are
painted as part of the regular tree traversal.
Instead we pull out painting the overlay as a separate pass executed
after the tree traversal. This way we ensure that the overlays are
always painted last and therefore on top of everything else. This also
makes sure that the overlays are unaffected by clips and masks. And
since overlay painting is independent from painting the actual elements,
it just works as well.
However we need to be careful, because we still need to apply some of
the steps of the tree traversal to get the correct result. Namely we
need to apply scroll offsets and transforms. To do so, we collect all
ancestors of the hovered node and apply those as if we were in the
normal tree traversal.
The debug option 'Show Line Box Borders' and the inspector overlay for
text nodes are conceptually similar. However they use two different
code paths. This commits unifies both to use the same code.
Previously line box borders were drawn in every phase. This caused
redundent lines to be drawn on top of each other. But it also caused
boxes to appear for text that was not visible on screen because other
elements overlayed it. That was confusing to look at since all text on
the page is highlighted at the same time using this debug functionality.
When T in HashTable<T> has a potentially slow equality check, it can be
very profitable to check for a matching hash before full equality.
This patch adds may_have_slow_equality_check() to AK::Traits and
defaults it to true. For trivial types (pointers, integers, etc) we
default it to false. This means we skip the hash check when the equality
check would be a single-CPU-word compare anyway.
This synergizes really well with things like HashMap<String, V> where
collisions previously meant we may have to churn through multiple O(n)
equality checks.
We shouldn't include spread distance when serializing `text-shadow` as
it is not supported unlike `box-shadow` - to achieve this we store
whether this is a text or box shadow within the ShadowStyleValue and
serialize appropriately.
- Capture PrototypeChainValidity before invoking `internal_get()`. A
getter may mutate the prototype chain (e.g., delete itself). Capturing
earlier ensures such mutations invalidate the cached entry and prevent
stale GetById hits.
- When caching, take PrototypeChainValidity from the base object
(receiver), not from the prototype where the property was found.
Otherwise, changes to an intermediate prototype between the base
object and the cached prototype object go unnoticed, leading to
incorrect cache hits.
Specifically, NotificationOptions has this:
```webidl
dictionary NotificationOptions {
// ...
boolean? silent = null;
// ...
};
```
https://notifications.spec.whatwg.org/#dictdef-notificationoptions
Without this patch, we generate this code, which isn't valid:
```c++
silent_value_11 = static_cast<bool>(null);
```
Treating `null` the same as no default value seems like the best option,
as they're equivalent in our C++ types.
This lets us avoid each UI needing to handle link clicks directly, and
lets actions stored in LibWebView avoid awkwardly going through the link
click callbacks to open URLs.
When building with REGEX_DEBUG or ENABLE_ALL_THE_DEBUG_MACROS there are
two issues with linking of bin/TestRegex
- Libraries/LibRegex/RegexDebug.h:76 with undefined reference
regex::OpCode_Compare::variable_arguments_to_byte_string(
AK::Optional<regex::MatchInput const&>) const
- Libraries/LibRegex/RegexByteCode.h:672 with undefined reference
regex::OpCode::name(regex::OpCodeId)
Add REGEX_API on regex::OpCode and regex::OptCode_Compare to allow
access to the classes in bin/TestRegex
When building with DNS_DEBUG or ENABLE_ALL_THE_DEBUG_MACROS there is a
linking issue with Libraries/LibDNS/Resolver.h:1003 with
undefined reference DNS::Messages::Records::SIG::to_string() const
Add DNS_API on DNS:Messages::Records::SIG definition to allow access
to the class in bin/dns, bin/TestDNSResolver, libexec/RequestServer
We often use Optional<T> in a cache pattern such as:
if (!m_cache.has_value())
m_cache = slow_thing();
return m_cache.value();
The new ::ensure() makes it a bit simpler:
return m_cache.ensure([&] { return slow_thing(); });
We already had IC support in PutById for the following cases:
- Changing an existing own property
- Calling a setter located in the prototype chain
This was enough to speed up code where structurally identical objects
(same shape) are processed in a loop:
```js
const arr = [{ a: 1 }, { a: 2 }, { a: 3 }];
for (let obj of arr) {
obj.a += 1;
}
```
However, creating structurally identical objects in a loop was still
slow:
```js
for (let i = 0; i < 10_000_000; i++) {
const o = {};
o.a = 1;
o.b = 2;
o.c = 3;
}
```
This change addresses that by adding a new IC type that caches both the
source and target shapes, allowing property additions to be fast-pathed
by directly jumping to the shape that already includes the new property.
On macOS Tahoe, it is now recommended to show menu item icons. We use
system symbols for this now. Symbols do not have constant variable names
and must be found via the SF Symbols app.
The symbols chosen here were to match Safari as close as possible.
On macOS Tahoe, the zoom button's border is visible when the button
itself is hidden. This feels like a macOS bug, but for now let's hide
the borders as well.
We currently have the issue that our macOS builds are being hosted by
both Apple M1 and M4 runners. By default, these target `-mcpu=apple-m1`
and `-mcpu=apple-m3` respectively, causing their ccache artifacts to be
incompatible and effectively thrashing each other's ccache cache on each
run.
Add a new CMake option `ENABLE_CI_BASELINE_CPU` that toggles a baseline
`-mcpu/-march` compile option for each of the supported build platforms.
When disabled (the default), we now default to `-march=native` which on
Linux could theoretically lead to better performance.
The new CPU baseline is used by the `lagom-template.yml` and
`js-and-wasm-artifacts.yml` workflows, since they both produce artifacts
or caches that might be picked up by other runners. We also enable it
for Flatpak builds, so they target a fixed architecture instead of
whatever architecture the action runner that picked up the job has.
Previously if the directory returned by `downloads_directory()` didn't
exist (or wasn't a directory) when taking a screnshot in headless mode
we try to ask the user for the download directory and fail with the
unhelpful error: QWidget: Must construct a QApplication before a QWidget
While editing, we need to consider whether removing a <br> has any
effect on layout to determine whether its extraneous. This new condition
finds most cases for extraneous <br>s inside block elements.
Global Privacy Control aims to be a replacement for Do Not Track. DNT
ended up not being a great solution, as it wasn't enforced by law. This
actually resulted in the DNT header serving as an extra fingerprinting
data point.
GPC is becoming enforced by law in USA states such as California and
Colorado. CA is further working on a bill which requires that browsers
implement such an opt-out preference signal (OOPS):
https://cppa.ca.gov/announcements/2025/20250911.html
This patch replaces DNT with GPC and hooks up the associated settings.
The extra representations of a video element are unnecessary to specify
in VideoPaintable, as the playback system itself should take care of
all the details of the representation as specified.
According to RFC 2046, the BNF of the form data body is:
multipart-body := [preamble CRLF]
dash-boundary transport-padding CRLF
body-part *encapsulation
close-delimiter transport-padding
[CRLF epilogue]
Where "epilogue" is any text that "may be ignored or discarded". So we
should stop parsing the body once we encounter the terminating delimiter
("--").
Note that our parsing function is from an attempt to standardize the
grammar in the spec: https://andreubotella.github.io/multipart-form-data
This proposal hasn't been updated in ~4 years, and the fetch spec still
does not have a formal definition of the body string.
This introduces the `TextUnderlinePositionStyleValue` class, it is
possible to represent `text-underline-position` as a `StyleValueList`
but would have required ugly workarounds for either serialization or in
`ComputedProperties::text_underline_position`
Adds inline implementation for the most common case when `Value` is
already an object.
1.47x improvement on the following benchmark:
```js
const o = {};
for (let i = 0; i < 10_000_000; i++) {
o.a = 1;
o.b = 2;
o.c = 3;
}
```
This is an arbitrary set of tests intended to cover the different
CSSStyleValue types without too much overlap.
Right now they all fail, because testsuite.js attempts to create one of
every type of CSSStyleValue on load, and we don't have most of them.
Omitting the `/`s meant that `1` and `0` were parsed as part of
border-slice instead of their intended values.
No functional changes but this will be relied on in a later commit.
There is no direct Win32 API equivalent, but calling WM_CLOSE on
the top-level windows allows for a graceful shutdown where resources
are able to clean themselves up properly
The Request constructor’s mode validation threw
"Mode must not be 'navigate"
missing the closing quote. Add the trailing quote so the error reads:
"Mode must not be 'navigate'".
A new parameter was added to Web::CSS::StyleValue::to_string() in
PR #2820 but this debug message was never updated. If
CSS_TRANSITIONS_DEBUG was enabled, compilation would fail.
Previously, PutById constructed a PropertyKey from the identifier,
which coerced numeric-like strings to numbers. This moves that decision
to bytecode generation: the bytecode generator now emits PutByNumericId
for numeric keys and PutById for string keys. This removes per-execution
parsing from the interpreter.
1.4x speedup on the following microbenchmark:
```js
const o = {};
for (let i = 0; i < 10_000_000; i++) {
o.a = 1;
o.b = 2;
o.c = 3;
}
```
Previously, we were collapsing whitespace in Layout::TextNode and then
passed the resulting string for further processing through ChunkIterator
-> InlineLevelIterator -> InlineFormattingContext -> LineBuilder ->
LineBoxFragment -> PaintableFragment. Our painting tree is where we deal
with things like range offsets into the underlying text nodes, but since
we modified the original string, the offsets were wrong.
This changes the way we generate fragments:
* Layout::TextNode no longer collapses whitespace as part of its
stored "text for rendering", but moves this logic to ChunkIterator
which splits up this text into separate views whenever whitespace
needs to be collapsed.
* Layout::LineBox now only extends the last fragment if its end offset
is equal to the new fragment's start offset. Otherwise, there's a
gap caused by collapsing whitespace and we need to generate a
separate fragment for that in order to have a correct start offset.
Some tests need new baselines because of the fixed start offsets.
Fixes#566.
When we have a `calc` which is a mix of a dimension and a percentage, we
should use the percentage alone for the computed value if the dimension
component is 0 e.g. `calc(50% + 0px)` should use `50%` as it's computed
value.
From the CSS token side, we already have these in FlyString form. From
the generated code side, we can easily return FlyStrings instead of
StringViews. So, let's do that, and save some work converting back and
forth.
There was a warning for the Optional initializer having no effect, but
removing the initializer caused the call to add a track to the HashMap
to complain. A constructor looks a little nicer here anyway.
Most users will only care about the total file duration, and shouldn't
be required to determine the file duration from multiple track
durations. To facilitate that, add a total_duration() function that
returns the demuxer's duration not associated to any particular track.
Some properties like `justify-items`, `grid`, or `display` do affect
layout, but their used values can be obtained without performing a
layout calculation.
This change introduces a new helper,
`property_needs_layout_for_getcomputedstyle()`, specifically for use by
`CSSStyleProperties::property()`. It returns true only for properties
such as `width`, `height`, `margin`, `padding`, `top`, and `left`, where
an up-to-date layout is required to return the correct used value.
This fixes an issue where text decorations (e.g. underlines) of text
split across multiple fragments would have unintended 1px gaps.
Gains us 2 WPT passes (imported)
By migrating the debug menu to LibWebView, the AppKit and Qt UIs are now
in sync - the AppKit UI was previously missing some actions.
Further, this inadvertently fixes bugs around applying debug settings to
new web views, especially across site-isolated processes. We were
previously not applying settings appropriately; this now "just works" in
the LibWebView infra.
This migrates all duplicated context menus from the UIs to LibWebView.
The context menu actions are now largely handled directly in LibWebView,
with some UI-specific callbacks added to display e.g. confirmation
dialogs.
Actions that only ever apply to a specific web view are stored on the
ViewImplementation itself. Actions that need to be dynamically applied
to the active web view are stored on the Application.
We currently duplicate a lot of code to handle application/context menus
and actions. The goal here is to hold the data for the menus and actions
in LibWebView. Each UI will then be able to generate menus from the data
on-the-fly.
The structures added here are meant to support generic and checkable
actions, action groups, submenus, etc.
The result is currently only used as a StringView, but a future commit
will place the result in Web::Clipboard::SystemClipboardRepresentation,
which requires a ByteString (there's no UTF-8 clipboard requirement).
As noted, the chunk of this method that deals with animations could do
with some helpers on AbstractElement, but I'm leaving that until it's
clearer how animations and pseudo-elements should interact.
This doesn't need all of Selector.h and its various includes, it just
needs the PseudoElement enum.
StringStyleValue.h was transitively including ComponentValue.h through
this, so it now includes it directly.
Generating boilerplate is nice! This also has the bonus that we're more
correct: I included all the units listed in the spec before,
(see https://drafts.css-houdini.org/css-typed-om-1/#numeric-factory )
but we're supposed to exactly include ones for the units we support:
> If an implementation supports additional CSS units that do not have a
corresponding method in the above list, but that do correspond to one
of the existing CSSNumericType values, it must additionally support
such a method, named after the unit in its defined canonical casing,
using the generic behavior defined above.
> If an implementation does not support a given unit, it must not
implement its corresponding method from the list above.
Now, our factory functions will exactly match the units we support.
The changed test result is partly the order being different, and partly
that the container-query units are no longer included as we don't
actually support them.
Transitions apply after logical properties are mapped to their physical
counterparts so we should apply this mapping to `transition` properties
Gains us 20 WPT tests.
Using longhands rather than expanded longhands meant for instance that
we wouldn't transition `border-top-width` if we had `border` as the
transition property.
If we are interpolating between a dimension and a percentage value and
the dimension component is 0, we now return a percentage value rather
than a `calc()` value.
This makes it so that view-transition pseudo-element styles are
updated before returning them from window.getComputedStyle(). This
is necessary because they could be outdated, in case JS has
modified the styles of the elements they are trying to stay in sync
with since last frame.
The corresponding WPT test has not been imported, since it still
fails for unrelated reasons.
All remaining failing subtests in border-image-width-interpolation.html
are related to incorrect handling of mixed dimension and percentage
interpolation and are fixed by #6142.
This means that we now calculate the inner width correctly for `display:
inline-block` nodes when we have `box-sizing: border-box` and
`min-width`, as we would previously assume these dimensions were all `0`
Previously, the first `HTMLHtmlELement` in the given document would
always be used when determining whether to propagate background
properties to the body element. This meant the wrong root element was
used for SVG `foreignObject` elements, which could lead to a crash.
Allows formulas to update on Google Sheets, which uses a Worker to
update them and makes cookie authenticated requests, which was failing
before this commit.
This has the limitation that it has to proxy through the WebContent
process, but that's how the current infrastructure is, which is outside
the scope of this commit.
Previously we depended on an associated document on the ESO to get to
the page, but Workers do not have documents. However, we can simply get
to the page with `principal_host_defined_page`, removing the issue.
Continues the work started in #5386 to simplify handling of positional
value list shorthand properties.
Previously we would parse these as `StyleValueList`s and then rely on
`StyleComputer::for_each_property_expanding_shorthands` to expand them
into longhands.
This required a bit of work to handle `ShorthandStyleValue`s for the
`@page` `margin` descriptor.
Previously we would instead parse these as single values and rely on
ad-hoc functionality in `for_each_property_expanding_shorthands` to
expand them to longhands.
This gets us a step closer to removing that ad-hoc functionality.
This also fixes a bug in the view transitions code that was
required to get the imported test to pass. The code for setting
the initial containing block size just did not set the right thing,
since doing so would trigger an error later on.
That later error resulted from walking up the tree, without
considering that the document element has a parent that is not
itself an element. (and then doing element things to it)
...when `LengthOrAutoOrCalculated` holds calculated value. We were
incorrectly assuming that if contained value is not auto, then it must
be a length.
Fixes crashing on https://hollowknightsilksong.com/
The existing conversion was rounding to the nearest millisecond, which
is much less precision than most videos will want. Instead, use only
integer math to directly convert the presentation time to seconds and
nanoseconds for our AK::Duration to represent accurately.
Now follows the same pattern as PaintableBox and StackingContext, where
it exits if hidden, then hit tests children, then hit tests itself if
it's `visible_for_hit_testing()`.
This change removes premature reset of
`block_container_y_position_update_callback`. Also makes callback
private in `BlockMarginState`, because resetting it independently of
currently accumulated margins is incorrect.
Lots of test expectations are updated, but there is no visual
difference.
Fixes https://github.com/LadybirdBrowser/ladybird/issues/6074
Callback registered by
`register_block_container_y_position_update_callback()` is executed
after `layout_block_level_box()` returned, so capturing stack variable
`y` by reference is UB.
We also support interpolating from a CalculatedStyleValue to a
compatible dimension or percentage style value.
This also brings with it a couple of improvements in how we handle
interpolation between mixed dimension and percentage types in terms of:
- Proper simplification of the resulting calc()
- Improved handling of interpolation outside the 0-1 range
The HTTP cache is now stable enough that we can ask more people to help
us testing it. So let's turn it on by default! It can be turned off with
--disable-http-cache if needed.
...navigable shared attribute processing steps.
After e095bf3a5fhttps://wpt.live/html/rendering/pixel-length-attributes.html ends up in
this function with null navigable, which leads to crash while executing
steps. Adding early return in case iframe's document doesn't have a
navigable is enough to make the test pass again.
This commit doesn't import the WPT test, because it's already imported
and we have it disabled since it takes too much time on CI.
This behaviour should only apply to literal percentages as clarified
here: https://github.com/w3c/csswg-drafts/commit/4ee8429
We were also doing this wrong by converting the numeric type of the calc
to Length which was causing values to be defaulted to 1 instead (hence
the new passing tests for computed values as well)
This ensures that we clamp values for properties like padding-* to valid
ranges (non-negative in this case) if they are specified with `calc()`.
The length-related changes in this commit combined with the ones from
the previous commit fix the primary layout issue on https://lwn.net
(yes, not the first place I would have expected problems either).
According to ECMA-262 §15.4.5 (MethodDefinitionEvaluation),
getters and setters defined in class bodies
must create property descriptors with
[[Enumerable]]: false. Previously we incorrectly marked them enumerable.
This patch updates `ClassMethod::class_element_evaluation` so that both
getter and setter descriptors use `.enumerable = false`.
Previously, the hosts file was updated at the same time the WPT repo
was cloned, but updating the hosts file is only necessary for commands
that start the WPT test runner.
SIMD loads/stores checked bit 0x20 of the align immediate to detect a
following memory index, unlike scalar mem ops which use 0x40 per the
multi-memory encoding. This caused the memidx byte to be misparsed as
the next immediate (e.g. offset).
Update both SIMD sites (v128 load/store and lane variants) to check and
clear 0x40, then read LEB128<u32> memidx.
Repro:
(module (memory $m0 1) (memory $m1 1)
(func (export "go")
i32.const 0
v128.load (memory 1)
drop))
Before: printed memidx 0 with offset 1.
After: prints memidx 1 with offset 0.
The opcode entry declared i16x8_replace_lane with pushes = -1, but
replace_lane pops 2 (vector, lane value) and pushes 1 result vector.
Set pushes to 1 to match the other replace_lane opcodes.
Negate was incorrectly returning "== 0", a copy/paste from EqualsZero.
This patch corrects it to return "neg", matching the operator's actual
semantics and WebAssembly mnemonics (f32.neg, f64.neg).
Replaces spin until with GC-allocated counting object that invokes
destruction callback once all child navigable documents are destroyed.
The change doesn't have a test but not using spin until is strictly
better than using it. Also improves https://www.rottentomatoes.com/
where previously we would hang or crash after loading.
...selector. Grammar per spec: `::slotted( <compound-selector> )`, so
we should reject selector as invalid if first compound selector is
followed by something else.
This change makes layout more correct on https://www.rottentomatoes.com/
This has always been a bit of a hack. Initially it made sense as a lot
of properties that accept a length also accept `auto`, but while
convenient, that leads to problems: It's easy to forget to check if a
length is `auto`, and places that don't accept it end up with an
invalid state lurking in the type system, which makes things unclear.
Not every user of this requires an `auto` state, but most do.
This has quite a big diff but most of that is mechanical:
LengthPercentageOrAuto has `resolved_or_auto()` instead of `resolved()`,
and `to_px_or_zero()` instead of `to_px()`, to make their output
clearer.
...instead of `auto` Lengths.
This also fixes interpolating between two `auto` `<bg-size>`s, which
fixes a lot of animation tests for both `background-size` and `mask`.
Any type of Size which has no LengthPercentage value now uses an empty
optional instead of making an auto Length as before.
We also now serialize a `fit-content` Size as `fit-content` instead of
`fit-content(auto)`, though this doesn't affect test results and I
didn't identify where it's actually used.
The spec is a bit awkward here: A few algorithms create an "empty"
SourceSet, and then assign its source-size value a few steps later, so
we have a temporary state with no length. In order to avoid complicating
the types with Optional, I've chosen to just assign it to 0px.
Previously we used `auto`, but `auto` is not a valid value here - it is
used inside the "parse a sizes attribute" algorithm, but that always
returns an actual length (or calc).
We only had one user of this which allows `auto`, which is length_box().
So, inline the code there, remove the `auto` branch from
length_percentage(), and then remove length_percentage_or_fallback()
entirely as nobody uses it any more.
Implements `::slotted()` to enough extent we could pass the imported WPT
test and make substantial layout correctness improvement on
https://www.rottentomatoes.com/
If a node with `contenteditable=true/plaintextonly` is the child of an
editable node or an editing host, we should make it editable instead of
an editing host. This effectively merges nested editing hosts together,
which is how other browsers deal with this as well.
Gains us 5 WPT subtest passes in `editing`.
Previously we did not execute the constructor steps if we constructed a
Blob from a ByteBuffer and a String. Though we only construct a Blob
from ByteBuffer and String internally we still need to run these steps.
By creating the new type 'BlobPartsOrByteBuffer' we can consolidate
those two approaches to creating a Blob into our already existing
constructor steps.
For every ref tests actual and expected screenshots are taken. These
screenshots are only needed while the individual test executes. However,
they are never freed during the run, leading to a continuous increase in
memory usage of the test runner while executing ref tests.
With the number of ref tests growing, this currently amounts to nearly 3
GB of uncompressed bitmap data being held in memory. Lets avoid that by
clearing the screenshot data at the end of each test. With this change
applied, the memory usage of test-web stays stable and below 100 MB for
the entire test run.
Previously, the given test would create an object with the test
property that pointed to itself.
This is because `temp = temp.test || {}` overwrote the `temp` local
register, and `temp.test = temp` used the new object instead of the
original one it fetched.
Allows https://www.yorkshiretea.co.uk/ to load, which was failing in
Gsap library initialization.
We have to prevent from including any SDL headers in LibWeb headers.
Otherwise there will be transitive Windows.h includes that will
re-declare some of our existing forward decls/defines in
LibCore/SocketAddressWindows.h
Previously, an error would occur if an `iterable<T>` was defined before
the required value iterator. An is now also reported if an`iterable<T>`
is defined before a pair iterator, previously this error would only be
reported if the iterable was defined after the pair iterator.
`font-size` can end up with a negative value - either due to `calc`
being resolved using the old method which doesn't clamp the value, or
interpolation - in this case we should clamp negative values to zero.
Gains us 36 new WPT passes and fixes crashes in the three imported
tests.
1a3da3d introduced a crash as we assumed that font-size values were
always stored in their computed forms, this isn't correct for animated
font-size values.
As a temporary workaround until we store animated font-sizes in their
computed form we will return the non-animated value - this restores the
functionality prior to 1a3da3d
Interpolation can leave `padding-*` values as negative - this should be
handled by interpolation clamping it to the allowed range of values
but we don't yet do that. As a stop gap we can clamp this before setting
it in ComputedValues.
This fixes 3 crashes and gains us 11 passes in the imported WPT tests
We used to only walk the paintable root tree from the layout root and
detach paintables from there. In some cases, this could leave paintables
behind, so we added another loop that iterates over all layout nodes and
detaches their paintables, if any remained.
Instead of traversing two trees like this, just traverse the layout tree
once and detach the inclusive descendant's paintables, similar to how we
deal with the DOM tree immediately after that.
This first pass only applies to the following two cases:
- Public functions returning a view type into an object they own
- Public ctors storing a view type
This catches a grand total of one (1) issue, which is fixed in
the previous commit.
DecoderError::formatted() made a ByteString, took a view into it,
dropped the ByteString, then propagated the (now invalid) view back to
the caller as an error.
Since the object has to keep the ByteString alive, keep it as a variant
to make sure the "happy" path with no alloc remains alloc-free.
We could skip doing item's intrinsic min-content layout if we know for
sure that there's no tracks with intrinsic sizing function to distribute
the min-content size to.
Previously we would only trigger change events on insertion, which
resulted in javascript code missing changes due to deletion.
This makes the calculator on the MDN simple web worker demo update on
deletion as well.
Currently, ImageProvider::current_image_bitmap takes a Gfx::IntSize
argument which determines the size of the returned bitmap. The default
value of this argument is 0x0 which causes the function to return
nullptr. This behavior is evidently unintuitive enough that it has lead
to incorrect usage in multiple places. For example, the 2D canvas
drawImage method will never actually draw anything because it calls
current_image_bitmap with no arguments. And the naturalWidth and
naturalHeight of an image will always return 0 (even after the image has
loaded) for the same reason.
To correct this and hopefully avoid similar issues in the future,
ImageProvider::current_image_bitmap will be renamed to
current_image_bitmap_sized, and the default value for the size argument
will be removed. For consistency, a similar change will be made to
SVGImageElement::default_image_bitmap.
The existing current_image_bitmap function will no longer take a size
argument. Instead it will always return a bitmap of the image's
intrinsic size. This seems to be what most existing callers had already
assumed was the function's behavior.
The free_surface_resources() function in OpenGLContext.cpp is
responsible for freeing all GL and EGL objects tied to the lifetime of
the painting surface. It is called when the associated canvas is resized
or destroyed. However, if there are multiple WebGL canvases and another
canvas's context is current when the function is called, it will
unintentionally free GL objects belonging to that other context.
To fix this, we call eglMakeCurrent at the start of
free_surface_resources(). This ensures that we will be deleting the
intended objects.
Note that m_impl->surface could be EGL_NO_SURFACE if
free_surface_resources() is called before the painting surface has been
created, but that should be fine. EGL_KHR_surfaceless_context support is
ubiquitous at this point.
From the SVG spec
The value of the ‘viewBox’ attribute is a list of four numbers <min-x>,
<min-y>, <width> and <height>, separated by whitespace and/or a comma...
Currently try_parse_view_box will fail to parse the attribute if the
values are separated by commas.
This change replaces try_parse_view_box with a more correct
implementation. It will reside in the AttributeParser.cpp. This new
implementation correctly handles comma-separated viewBox values, and is
also more robust against invalid inputs.
Additionally, it adds a new test case to ensure viewBox values with
various syntax are parsed correctly and invalid values are rejected.
This function was implemented in a few classes but is a common element
in all form associated elements and the functionality should be there.
With these minimal changes we get to implement 4 idl functions for free.
What I thought was a spec issue was actually a combination of my own
misunderstanding and a bug in our IDL generator. With that bug fixed, I
can correct this to how it is in the spec.
Reifying the result gets quite ad-hoc. Firstly because "parse a
component value" produces a ComponentValue, not a full StyleValue like
we need for math functions. And second, because not all math functions
can be reified as a CSSNumericValue:
Besides the fact that I haven't implemented CalculatedStyleValue
reification at all yet, there are a lot of math functions with no
corresponding CSSMathValue in the spec yet. If the calculation tree
contains any of those, the best we can do is reify as a CSSStyleValue,
and that isn't a valid return value from CSSNumericValue.parse(). So, I
made us throw a SyntaxError in those cases. This seems to match
Chrome's behaviour. Spec issue:
https://github.com/w3c/css-houdini-drafts/issues/1090
This fixes slow test execution on macOS where localhost resolution
has a 200ms delay due to IPv6 fallback behavior in libcurl.
The XMLHttpRequest-override-mimetype-blob.html test now runs in ~0.6s
instead of ~16s on macOS.
Fixes#4850
See also: https://github.com/curl/curl/issues/2281
If a node that establishes a StackingContext has `pointer-events: none`,
hit testing should first proceed with hit testing the SC's children
before deciding to bail. We were checking for `pointer-events` too
early, causing large parts of certain websites to be noninteractive.
Fixes#6017.
In LayoutState, used_values_per_layout_node should not be modified in
order to determine inline nodes' dimensions - all the required values
should already be in there. In 2585f2da0d
we did accidentally create new values, causing the code further down to
try and get a PaintableBox from an anonymous container and crashing.
Fixes#6015.
Special handling for SVGClipPathElement and SVGMaskElement, which use a
a ViewBox and PreserveAspectRatio value internally, has been moved to
`SVGFormattingContext`.
If we were calculating the static position for an absolutely positioned
inline box that resides in the last line of its containing block, we
would not have yet provided the fragments in that line with their
final positions. Additionally, we would always move the box beneath the
fragment, which was incorrect.
Fixes#5867.
Currently we're relying on LineBuilder's destructor to handle updating
the last line, if required. In order to fix an issue with our absolute
positioning code, we need to be able to update the last line earlier
than that. Remove the destructor and replace it with an explicit call to
LineBuilder::update_last_line().
No functional changes.
One MessagePort can be entangled with another MessagePort, either in the
same agent, or in another agent.
In the same-agent case, the MessagePort objects point to each other via
the MessagePort::m_remote_port field.
In the separate-agent case, they live in separate processes entirely and
thus can't point at each other.
In both cases, the MessagePorts have an underlying transport channel,
which means they are "entangled". However, we can't assume that being
entangled means having a non-null m_remote_port.
This patch simply adds a missing null check for m_remote_port and thus
makes https://vscode.dev/ stop crashing with a null dereference.
This reverts e7890429aa and partly reverts
a59c15481f.
The one pseudo-class that accepted multiple of these was :heading(), and
since that got changed to take integers instead, there's no need to keep
this extra complexity (and memory usage) around.
We originally had special handling for `:host()` as that had been the
only pseudo-class that could be both an identifier or a function.
However, this meant duplicating the serialization logic, and also we
had to manually remember to add the same hack for any other
identifier-and-function cases. Which I forgot to do with `:heading()`!
So instead, for these cases, detect if they actually have arguments
specified and use that to determine which form to serialize as. We do
still have to write a check for each one of these pseudo-classes, but
the VERIFY should make it easier to remember.
We now also store `outline-width` in ComputedValues as a `CSSPixels`
since we know it's an absolute length at `apply_style` time - this saves
us some work in converting to CSSPixels during layout.
Gains us 46 new passes since we now interpolate keywords (thick, thin,
etc) correctly.
Also loses us 4 WPT tests as we longer clamp negative values produced by
interpolation from the point of view of getComputedStyle (although the
'used' value is still clamped).
Gains us 112 new passes since we now interpolate keywords (thick, thin,
etc) correctly.
Also loses us 4 WPT tests as we longer clamp negative values produced by
interpolation from the point of view of getComputedStyle (although the
'used' value is still clamped).
`StyleValue`s stored within `ComputedProperties` should be in their
computed forms, this is for various reasons including:
- Inheritance should be of computed values
- Animations should work on computed values
- Triggering transitions should work on computed values
Currently we store `StyleValue`s in an absolutized version of the
specified value - this is equivalent to the computed form in many cases
which is why this hasn't been causing significant issues but there are
some cases - such as `border-*-width` keywords where this is not the
case.
No functionality change as we are yet to implement any properties
This removes the AnimationRefresh argument from `collect_animation_into`
which was added in a9b8840 - it's only effect was disallowing
`UseInitial`s within keyframes when we were doing animated style
updates which I believe is unintentional.
Gains us 214 WPT tests.
Inline nodes in our layout tree have a position, so let's show it. By
centralizing the logic for this, block nodes now lose their redundant
'content-size' dump info which is already part of the box model dump.
An SVGLength can be read-only, e.g. all animVal values cannot be
modified. Implement this for all instantiations of SVGLength.
While we're here, add `fake_animated_length_fixme()` so we can easily
find all sites where we need to improve our animated length game.
The transform of each paintable was being applied multiple times due to
the recursive nature of the hit testing methods. Previously it used
combined_css_transform to transform the position, and then it would pass
that position to children, which would then apply combined_css_transform
again, and so on.
PaintableBoxes are also not hit tested anymore when having a stacking
context. A similar check is done in PaintableWithLines, but it was
missing from PaintableBox. Without this check some elements can get
returned multiple times from a hit test.
StackingContexts with zero opacity will now also get hit tested, as it
should have been before.
When a test is active in a test-web view, show the relative path to the
test instead of the view's URL. This gives a better starting point for
debugging than whatever the last loaded URL happened to be.
If no test is active, we still show the view's URL.
If an animation got to its finished state before its target's computed
properties could be updated, we would end up with invalid styles. Do not
skip finished animations, but prevent effect invalidation on timeline
updates if the animation is already finished.
This fixes the CI flake on WPT test
`css/css-transitions/inherit-height-transition.html`.
Atlassian login gets the base URL for its module scripts by throwing an
error and pulling out the current script's URL from error.stack with
regex.
Since we only returned a basename for module scripts, it would fail to
match and try and use `/` as a base URL (because it does
[matched_string] + "/"), which is not a valid base URL.
This, along with moving the sources and destination out of the config
object, makes it so we don't have to double-deref to get to them on each
instruction, leading to a ~15% perf improvement on dispatch.
Namely, find an upper bound at validation time so we can allocate the
space when entering the frame.
Also drop labels at once instead of popping them off one at a time now
that we're using a Vector.
This can be done by passing
`--export-js <module>.<fn>[(<arg>:type, ...)][:type]=<source>`,
which uses a js function `(arg...) => source` to resolve the requested
import `module::fn`.
All literal wasm value types (i<n> and v128) are supported as both
parameter and return types.
This still passes the values on the stack, but registers are now allowed
to cross a call boundary.
This is a very significant (>50%) improvement on the small call
microbenchmarks on my machine.
The StyleValue stored in m_property_values is already in it's computed
form and it's trivial to pull the underlying value out so there is no
need to store this separately.
Also removes unnecessary handling of percentage values in
`absolutize_values` - this is already handled within `compute_font`.
Update a couple of focus-related spec steps and their implementations.
The most relevant change is that we no longer allow focusing on elements
that return false for `->is_focusable()`, which necessitates fixing a
broken test that tried to `.focus()` on `<div>`s that were not
focusable. That test's output now more accurately reflects the expected
outcome as seen in other browsers.
And make it a DOM::Node, not DOM::Element. This makes everything flow
much better, such as spec texts that explicitly mention "focused area"
as the fact that we don't necessarily need to traverse a tree of
elements, since a Node can be focusable as well.
Eventually this will need to be a struct with a separate "focused area"
and "DOM anchor", but this change will make it easier to achieve that.
If selection navigation happens through an editing host, we should
enforce that for collapsed navigations (i.e. moving the caret) it can
only happen if the focus node of the selection is editable.
We fill these overload sets from vectors, which means that by the time
we iterated over them, any semblance of their original ordering was
lost. Their ordering is important, because we invoke
define_native_function() for them which eventually stores ordered
properties.
This should not be an issue as long as iterating over a HashMap that was
filled in exactly the same way results in the same ordering. However,
HashTable utilizes kmalloc_good_size() to determine a good allocation
size - and the implementation for kmalloc_good_size() on Linux and macOS
differs, causing a different capacity and ordering on those platforms.
This was not caught by CI, because we run that with sanitizers enabled
which overrides malloc_good_size() on macOS, resulting in the same
behavior as on Linux.
Change the overload sets to be OrderedHashMaps instead and rebaseline
the failing test.
Now elements with position `absolute` properly resolve their position
inside parent elements with `grid`. I also imported some WPT tests
related to that topic.
Part 2 of resolving issues on https://hack4krak.pl
All fragments inside an atomic inline box should stay within that box,
otherwise we'll screw up the paint order and paint them behind things
that they're supposed to be on top of.
This fixes an issue with inline-block content not appearing on sites
like Google Docs and Reddit, among others.
Otherwise, we just keep painting into the old backing store. This fixes
an issue where the main spreadsheet area in Google Sheets was not
visually updating, despite everything looking good in memory.
test_tls in TestDNSResolver was failing to perform the TLSv12
connection due to the following error: "14430000:error:0A000086:SSL
routines:tls_post_process_server_certificate:certificate verify
failed:ssl\statem\statem_clnt.c:2124". To perform the equivalent
on Windows, we can instead load the built in OSSL_STORE for Windows
In SocketWindows, the return value for the ioctl call was not
initialized to zero. This was causing test_udp in TesDNSResolver
to fail as UDPSocket::read_some() was incorrectly failing with
WSAEMSGSIZE due the result of pending_bytes being some
unspecified default value for an uninitialized unsigned long
The BUILD_RPATH/INSTALL_RPATH CMake infrastructure is not supported
on Windows, but we want to ensure Ladybird executables are runnable
after the build phase so there can be an efficient dev loop.
lagom_copy_runtime_dlls() can be used by executable targets so all
their dependent dlls are copied to their output directory in their
post build step.
After LibJS had its symbol exports optimized the targets
js, test-js, test262-runner, test-wasm, and LibWeb began to get linker
errors after the work to add Windows support for test-web and ladybird
targets. These extra JS_API annotations fix all those linker errors.
Fixes bug when we didn't use `tracks_to_grow_beyond_limits` and instead
distributed extra space to all affected tracks. Also implements missing
"when accommodating max-content" part.
Instead of ignoring fields using forward-delcared types, always assume
they inherit from GC::Cell. This improves the worst case from a missed
unvisited field, to a slightly wrong error message.
Fixes#5959.
Our Color::to_premultiplied() and Color::to_unpremultiplied() used
integer truncation.
Apple’s Accelerate framework (and many other libraries) use
round-to-nearest, which avoids bias and produces results that differ
by ±1 in many cases.
This commit switches both helpers to round-to-nearest and clamps the
results to [0,255]. For alpha==0 we now return fully transparent black
(0,0,0,0) to align with common conventions, instead of preserving RGB.
We pass to-fixed-length-buffer.any.html and to-resizable-buffer.any.html
but not to-resizable-buffer-shared.any.html, because LibJS doesn't have
growable SharedArrayBuffers implemented...
This commit adds the toResizableBuffer() and toFixedLengthBuffer()
methods to WebAssembly.Memory. This includes the necessary hook to
HostResizeArrayBuffer. Some modifications to function signatures in
LibWeb/WebAssembly/Memory.h were also made (changing the return type
from WebIDL::ExceptionOr to JS::ThrowCompletionOr) to allow the use of
some code in the aforementioned hook.
Note: the hook for HostGrowSharedArrayBuffer isn't implemented, since
LibJS doesn't seem to have complete support for growable
SharedArrayBuffers; the relevant methods/getters don't even exist on
the prototype, let alone HostGrowSharedArrayBuffer!
This should help pass the WebAssembly.Memory WPT tests included in
Interop 2025, except those pertaining to growable SharedArrayBuffers.
If a memory is imported by a Wasm instance and re-exported, the export's
value should be the exact same WebAssembly.Memory object as the
WebAssembly.Memory object passed for the import.
This cache is referenced by a few parts of the JS API spec, including
the threads spec (such as in toFixedLengthBuffer), as well as the
"refresh the Memory buffer" algorithm, which was implemented as a method
of Memory before this change.
Now, this algorithm can be implemented in a spec-like fashion (though it
mostly seems to add extra complexity). This change also fixes a bug
where memories that were re-exported from an imported WebAssembly.Memory
were given a distinct WebAssembly.Memory object, since the caching that
existed in Instance.cpp was instance-local, not global to the realm.
We also make Memory::m_buffer non-lazy, since we have to implement
"initialize a memory object" correctly anyway.
The relevant type of ArrayBuffer DataBlock is now a struct containing
both a ByteBuffer* and a size_t size, and not just a ByteBuffer*, with
the size being that of the ByteBuffer. This type of DataBlock is only
used for WebAssembly.Memory (see commit 4fd43a8f96), meaning this
change won't affect any other code. This change is required to pass one
WPT subtest in wasm/jsapi/memory/grow.any.html, since old fixed-length
SharedArrayBuffers after a WebAssembly.Memory growth should keep their
length, while the new buffer after the growth will have the updated
length.
For whatever reason, the implementation of "create a fixed length memory
buffer" was borked for shared Wasm memories, in that a new
SharedArrayBuffer was created, with the contents of the Wasm memory
copied into it. This is incorrect, since the SharedArrayBuffer should be
a view into the Wasm memory's span, not a copy of it. This helps pass a
WPT subtest in wasm/jsapi/memory/grow.any.html.
Previously, clicking in the middle of a multi-code point grapheme would
place the cursor at a code unit index somewhere in the middle of the
grapheme. This was not only visually misleading, but the user could then
start typing and insert characters in the middle of the cluster. This
also made text select pretty wonky.
The main issue was that we were treating the glyph index in a glyph run
as a code unit index. We must instead map that glyph index back to a
code unit index with help from LibGfx (via harfbuzz).
The distance computation used here was also a bit off, especially for
the last glyph in a glyph run. We essentially want the cursor to end
up on whichever edge of the clicked glyph it is closest to. The result
of the distance computation limited us to the left edge of the last
glyph. Instead, we can use the same edge tracking we use for form-
associated elements to handle this for us.
We currently have a mixup in LibWeb between code unit offset and glyph
offset during hit testing. These extra fields will allow us to correct
this discrepency.
We were already using the XML parser for SVG files when opening at the
top level. This patch makes things consistent by using the same code
path when parsing SVG-as-image.
We also make some tweaks in SVG presentation attribute handling since
we can no longer rely on the HTML length attribute parsing quirk when
parsing width/height attributes.
The CSSNumericType defined in the spec is a simple dictionary which is
only used for OM purposes. This NumericType class is used internally
and matches the more abstract definition of a "type".
Not having this led to a sneaky bug where, given a Variant like so:
Variant<double, GC::Root<T>>
An incorrectly-written visit() branch for the Root would just cause it
to be cast to a double and call that branch instead.
With the cast made explicit, we get a compiler error, which is far more
useful.
Co-authored-by: Jelle Raaijmakers <jelle@ladybird.org>
Shareable Vulkan image allocation on Linux relies on the dma-buf
interface, which is a Linux-specific thing. Therefore, we should only be
compiling it (and any code that uses it) on Linux. This change adds
preprocessor guards to do that. Enabling similar functionality on other
operating systems will need to leverage analogous interfaces on those
platforms, e.g. win32 handles on Windows.
All Vulkan image code will now be guarded by the USE_VULKAN_IMAGES
preprocessor definition, currently enabled on Linux if Vulkan is
available. Additionally, we shuffle around some code in
OpenGLContext.cpp to simplify the preprocessor conditionals.
`StyleComputer::create_document_style` was the only place this wasn't
the case so we can remove the calls to
`compute_defaulted_property_value`. The call to
`compute_defaulted_values` in `create_document_style` is now redundant
so has been removed`
This was the last thing that `compute_defaulted_values` was doing when
called from here.
It also comes with the added benefit of us correctly inheriting animated
colors.
Fixes rendering of elements with large border-radius values by scaling
radii proportionally when they exceed element dimensions per CSS spec.
Co-authored-by: Samyat Gautam <thesamyatgautam@gmail.com>
As `recompute_inherited_style` works in-place rather than building
ComputedProperties from scratch we need to keep track of which animated
properties are inherited to know whether we should remove them when we
have no more inherited value.
We don't serialize these the way WPT expects, because we don't implement
the comment-insertion rules from CSS-Syntax. We don't implement that
for regular serialization either, so it's something we can worry about
later.
The "subdivide into iterations" part is left as a FIXME for now, until
we have a way of knowing if a property is a list or not.
The parse_a_css_style_value() helper has an unwieldy return type because
of the requirement that it return either one value or a list of values,
but sticking to the spec here seems worthwhile for now.
For us, that's KeywordStyleValue and CustomIdentStyleValue.
CustomIdentStyleValue now has a .cpp file to reduce the number of
includes in its header file.
CSSStyleValue is adjusted to allow for subclasses. Serialization for
CSSKeywordValue is implemented differently than the spec says because
of a spec bug: https://github.com/w3c/csswg-drafts/issues/12545
The output format for js-benchmarks is going to change, and while the
webhook parsing the results has not yet been updated pin the
js-benchmark checkout to a specific commit.
Adds this attribute to BaseAudioContext.idl and adds associated test for
OfflineAudioContext. This gives a set value that can be used to start
implementing OfflineAudioContext::start_rendering(). Updates idlharness
test to account for now implemented renderQuantumSize.
If we programmatically set a selection in an editable element during
document load, we failed to start the cursor blink cycle timer. The
cursor blink logic already takes care of us not having the paintable
yet, so start it unconditionally.
We were constraining the focusing behavior for editing hosts a bit too
much; regardless of how the selection changed, if the start container is
inside an editing host and it's currently not focused, we should focus
it. This fixes focus stealing by other elements that set a selection
inside an editing host on a click event, for example.
This partially reverts commit 3aff3327c4
by removing the code change but keeping the added test.
Now that paintables visibility caching has been reverted, this is no
longer doing anything except causing excessive relayouts on pages
like https://linear.app/
This reverts commit 7dc8062283.
This did not propagate correctly to paintables whose style was inherited
from an ancestor, causing rendering artifacts on https://linear.app/
If we set the same URL that we already had, there's no need to
invalidate style for the base URL changing.
This avoids some style recomputation while loading pages.
PaintableBox::handle_mouseleave is turning off scrollbar updating, but
the user might still have the primary button down to scroll. Don't turn
it off if grabbing the thumb to scroll.
Resolves crashing on MacOSX AppKit and Qt where gutter_size is 0 when
mouse is moved outside window.
This required some changes in LibURL & LibIPC since it has its own
definition of an BlobURLEntry. For now, we don't have a concrete usage
of MediaSource in LibURL so it is defined as an empty struct.
This removes one FIXME in an idl file.
When rounding a CSSPixelRect to a DevicePixelRect, we simply pulled its
width and height through round() and called it a day. Unfortunately this
could negatively affect the rect's perceived positioning.
A rect at { 0.5, 0.0 } with size { 19.5 x 20.0 } should have its right
edge at position 20, but after rounding it would end up at { 1, 0 } with
size { 20 x 20 }, causing its right edge to be at position 21 instead.
Fix this by first rounding the right and bottom edges of the input rect,
and then determining the dimensions by subtracting its rounded position.
Fixes#245.
We can use BorderRadiiData::as_corners() to avoid converting the corners
one by one. Instead of passing all four corners one by one, use a
reference to CornerRadii.
No functional changes.
Both gdb and lldb interrupt execution after attaching to the process, so
no need to send a SIGTRAP immediately after which would require typing
`continue` in the debugger twice.
We added this for String some time ago, so let's give Utf16String the
same optimization. Note that Utf16String was already handling its data
member potentially being null as of 5af99f4dd0.
There are some nuances to creating these wrappers, such as manually
propagating certain text styles that are not inherited by default. We
already have the logic for this in
`NodeWithStyle::create_anonymous_wrapper()`, so reuse that method in our
implementation of the button layout.
Fixes applying certain text styles (such as `text-decoration`) to the
text of a `<button>`.
...by another GFC. When searching for grid item that contains an
abspos box positioned relative to GFC, it's incorrect to assume that the
closest ancestor box whose parent establishes GFC is always the one we
are looking for, because there may be non-positioned GFC in between.
Fixes regression introduced in 80c8e78.
This enabled WebGL on Linux. It uses ANGLE's OpenGL backend running atop
EGL_PLATFORM_SURFACELESS_MESA. Eventually we should probably switch to
the Vulkan backend but that doesn't seem to be enabled in the vcpkg
angle package. Anyway, switching later should be trivial.
The painting surface is allocated through Vulkan and then imported into
EGL as a dma-buf. The DRM format modifier mechanism, along with Vulkan
initializing the image with VK_IMAGE_LAYOUT_GENERAL, should ensure
surface compatibility across the two APIs.
For now, we will synchronize rendering and presentation using glFinish,
although this is admittedly suboptimal. Really we should grab an
EGLSync, export that to an fd, import it into Skia and have it wait for
it before reading from the image. That can be implemented in a future
change, though.
If a WebGL canvas is resized through the set_size function, we will
re-create the painting surface. However, this currently leaks all of the
associated EGL/OpenGL objects. This change introduces the
free_surface_resources function which will free all resources associated
with the painting surface. It will be called before allocating a new
surface and during context destruction. It keeps track of the OpenGL
texture for the color buffer in m_impl instead of just storing it on the
stack.
This adds a new PaintingSurface creation function, create_from_vkimage,
which returns a PaintingSurface backed by a vulkan image. It's analogous
to the existing create_from_iosurface function. In both cases the
backing object will be imported into Skia as a render target and then an
SkSurface will be wrapped around that.
In order to ensure that the image will not be freed while still in use
by Skia, we will manually bump the refcount of the VulkanImage object
before passing it to Skia and then use the releaseCallback parameter of
WrapBackendRenderTarget to register a callback that drops this
reference.
This introduces the ability to allocate Vulkan images which can be
shared across graphics APIs or across processes using the Linux dma-buf
interface.
The create_shareable_vulkan_image function takes a VulkanContext, image
width, height, and format, and an array of DRM format modifiers
representing image memory layouts accepted by the caller. The function
will intersect this list with the list of modifiers supported by the
Vulkan implementation, ensuring the resulting image uses one of those
layouts (exactly which one is up to the implementation). The function
will return a VulkanImage object, which is reference-counted and
encapsulates the VkImage itself as well as the backing memory
allocation. It also stores various image parameters such as usage,
tiling, etc.
The VulkanImage::get_dma_buf_fd function will create a file descriptor
representing the image's backing dma-buf which can then be imported by a
different API or sent over a unix domain socket.
When serializing the "style" attribute, we were incorrectly assuming
that some of the grid-related CSS properties would never contain var()
substitution functions.
With this fixed, we can now book appointments on https://cal.com/ :^)
This changes the maximum number of decimal places from 5 to 6, but 5 was
previously a guess, and not specified behaviour:
> For all of the decimal changes (except color) I couldn't really find a
> spec that mandates any required precision, so I just copied what
> Firefox seems to do, which is limit the output to 5 decimal places.
> https://github.com/SerenityOS/serenity/pull/23449
If `will-change` is set to a property value where that property could
create a stacking context, then we create a stacking context regardless
of the current value of that property.
This property provides a hint to the rendering engine about properties
that are likely to change in the near future, allowing for early
optimizations to be applied.
Previously, it was possible for an up/down arrow press to place the
cursor in the middle of a multi-code point grapheme cluster. We want to
prevent this in a way that matches the behavior of other browsers.
Both Chrome and Firefox will map the starting position to a visually
equivalent position in the target line with harfbuzz and ICU segmenters.
The need for this is explained in a code comment. The result is a much
more natural feeling of text navigation.
When starting transitions we compute the after-change style, for any
inherited properties this should include the non-animated value.
Previously we were only inheriting the animated value and treating it as
non-animated so were instead including the animated value.
This commit fixes that by inheriting both the animated and non-animated
values (with the former being stored in `m_animated_property_values`,
and the latter in `m_property_values`).
This gains us 12 new WPT passes.
This brings with it 252 new WPT fails from the various 'events' tests in
css/css-transitions/properties-value-inherit-001.html, however these
also fail in other browsers (Chrome, Edge and Firefox) and the behaviour
that causes these failures is specifically mentioned in the spec.
This commit updates the CSSTransition constructor to:
- Leave the KeyframeEffect start time unresolved
- Set the KeyframeEffect start delay
Gains us 14 WPT passes but exposes one false positive in
properties-value-inherit-001.html
For button layouts, we were overriding the computed `width` value with
`fit-content` in `TreeBuilder::wrap_in_button_layout_if_needed()`. But
the spec asks us to set the _used value_ instead, so we now actually
calculate the fit-content width and set the box' content width to it.
Fixes#2516.
This suits the spec a bit better, and exposes the fact that we were
allowing `::ImageButton` to use the button layout although it is never
specified that it should do so. Tests were rebaselined for this.
We should calculate whether we need to truncate text with an ellipsis
exclusive of any trailing collapsible whitespace.
This was causing issues where an inline element was automatically sized
(e.g. min-content) as we would calculate available width exclusive of
trailing collapsible whitespace and then our text chunk would be wider,
always inserting an ellipsis.
Fixes the visual element of #4048 but we still are incorrect in how we
collapse whitespace more generally
As of 7dc8062 paintables compute and cache their visibility (which
depends on opacity) at construction - this cached value can fall out of
sync with reality if if the opacity changes to/from zero within the
lifetime of that paintable.
This commit invalidates layout when an opacity changes to/from zero so
that we reconstruct paintables with the correct visibility.
The limitations right now are:
- We don't know if a property is a list or not.
- We always reify as a CSSStyleValue directly.
So, we pass some tests but only ones that expect a CSSStyleValue.
When no better reification form is available, we produce an opaque
CSSStyleValue with a serialized value. For starters, this will be the
only way to reify, and then we'll add others later.
After looking into this more, the `[[declarations]]` slot does not seem
to need to be a literal map of property names and values. Instead, it
can just point at the source (an element or style declaration), and
then direct all read or write operations to that.
This means the `has()` and `delete()` methods actually work now.
A few remaining failures in these tests are because of:
- StylePropertyMap[ReadOnly]s not being iterable yet
- We're not populating an element's custom properties map, which get
fixed whenever someone gets around to producing proper computed
values of them.
This isn't part of the CSSOM API directly, but will be used by
StylePropertyMapReadOnly.has() to avoid doing the work to serialize a
string version of the property's value, just to throw it away again.
We occasionally (frequently) time out in CI. If ctest triggers this
timeout, it sends a SIGSTOP followed by a SIGKILL. Since we want to
gracefully exit the test runner, ask ctest to send a SIGTERM instead.
This should cause active test status reports to show up in CI.
If you interrupt the test runner (Ctrl+C, SIGINT) or if the test runner
is gracefully being terminated (SIGTERM), it now reports the current
status of all the spawned views with their URL and, if an active test is
still being run, the time since the start of the test.
Hopefully this will help gain insight into which tests are hanging.
The local handling of some messages might cause the transport to get
closed. If that's the case, we shouldn't try to send back a response.
This fixes many of the "Trying to post_message during IPC shutdown"
errors I was seeing when terminating Ladybird or when abnormally exiting
from LibWeb tests.
Before porting to UTF-16, these instances held a String. The port to
UTF-16 changed them to hold the original string as a StringView, and
lazily allocated the UTF-16 message as needed. This somehow negatively
impacting the zlib.js benchmark in the Octane suite.
This fixes a bug in the algorithm for determining if radio buttons are
missing their value. Previously it was only checked if the button
itself is required. Now the algorithm checks if the radio button group
contains a required radio button in order to determine if the value is
required.
Flex/grid items are always blockified (have their CSS display forced
into "block") by style computation.
We were doing this by looking at the CSS display of the parent. However,
if the parent has `display: contents`, we must look at the *grandparent*
instead.
This corrects the layout of buttons underneath Reddit article cards.
Before this change, `layout_absolutely_positioned_element()` in GFC
had an assumption that all contained by grid container abspos boxes were
also direct children of the grid container. This change adds handling
for the cases when it's not true and, in order to identify grid area
abspos box belongs to, we have to find ancestor grid item.
Some websites do not specify the MIME type of style sheets, instead
using as= or just leaving it empty.
Both Chromium and Firefox do load them regardless, so let's do it too.
When a subtree is projected through a slot, its root now inherits style
from the slot's parent, rather than the parent of the unprojected root.
This fixes a ton of subtle issues, and is very noticeable on Reddit.
Previously we would paint the cursor the entire height of the text
fragment - this didn't look great with large line-heights. Now we only
paint it the height of the actual text, with the top of the cursor
aligning with the font "ascent" and the bottom the "descent".
Previously we were using the document's window - this was both contrary
to spec and causing crashes when the document did not have a window (for
instance the `temp_document` in `HTMLParser::parse_html_fragment`.
This means we no longer crash when navigating between pages on
https://rocketlabcorp.com
The spec for checking the no-validate state ends with a default return
value of "false". However, we were only hitting this case for form-
associated elements. If the submitter is the form itself, we want to
enter the form validation steps.
We currently delete a single code unit. If the user presses backspace on
a multi code point emoji, they are going to expect the entire emoji to
be removed. This now matches the behavior of Chrome and Firefox.
This effectively reverts da26941b50.
When the user double-clicks a word on screen, they are interacting with
the rendered text, which has e.g. whitespace collapsing applied. If we
acquire word boundaries from the raw text, the resulting selection is
not right.
We still have issues with acquiring the right selection via APIs such as
`document.getSelection`. The offsets computed here are effectively then
applied to the raw text. But this issue is present all over EventHandler
and this patch at least makes the selection visually accurate.
This adapts the implementation of `is_mutable` to align more closely
with the spec. Specifically, it is now also taken into account whether
the element is enabled.
The spec and comments say "set field's user validity to true", but we
now actually set it to true and not false.
This passes one subtest in WPT's css/selectors/user-valid.html.
The current Color::interpolate_color method does not follow the specs
properly. Started improving it by handling premultiplied alpha in color
interpolation.
Only one WPT test covers this (color-transition-premultiplied), which we
currently pass due to a different approach in Color.mixed_with.
Currently you need to use Git Bash or alternative bash implementations
to fully run the pre-commit checks on Windows. This will now allow
for formatting changes without bash.
This ports the lexer to UTF-16 and deals with the immediate fallout up
to the AST. The AST will be dealt with in upcoming commits.
The lexer will still accept UTF-8 strings as input, and will transcode
them to UTF-16 for lexing. This doesn't actually incur a new allocation,
as we were already converting the input StringView to a ByteString for
each lexer.
One immediate logical benefit here is that we do not need to know off-
hand how many UTF-8 bytes some special code points occupy. They all
happen to be a single UTF-16 code unit. So instead of advancing the
lexer by 3 positions in some cases, we can just always advance by 1.
Currently, the lexer holds a ByteString, which is always heap-allocated.
When we create a copy of the lexer for the lookahead token, that token
will outlive the lexer copy. The token holds a couple of string views
into the lexer's source string. This is fine for now, because the source
string will be kept alive by the original lexer.
But if the lexer were to hold a String or Utf16String, short strings
will be stored on the stack due to SSO. Thus the token will hold views
into released stack data. We need to keep the lookahead lexer alive to
prevent UAF on views into its source string.
For the web, we allow a wobbly UTF-16 encoding (i.e. lonely surrogates
are permitted). Only in a few exceptional cases do we strictly require
valid UTF-16. As such, our `validate(AllowLonelySurrogates::Yes)` calls
will always succeed. It's a wasted effort to ever make such a check.
This patch eliminates such invocations. The validation methods will now
only check for strict UTF-16, and are only invoked when needed.
When we build a UTF-16 string, we currently always switch to the UTF-16
storage mode inside StringBuilder. Then when it comes time to create the
string, we switch the storage to ASCII if possible (by shifting the
underlying bytes up).
Instead, let's start out with ASCII storage and then switch to UTF-16
storage once we see a non-ASCII code point. For most strings, this will
avoid allocating 2x the memory, and avoids many ASCII validation calls.
We now define GenericLexer as a template to allow using it with UTF-16
strings. To keep existing users happy, the template is defined in the
Detail namespace. Then AK::GenericLexer is an alias for a char-based
view, and AK::Utf16GenericLexer is an alias for a char16-based view.
* Remove completely unused methods.
* Deduplicate methods that were overloaded with both StringView and
char const* parameters.
A future commit will templatize GenericLexer by char type. This patch
serves to make that a tiny bit easier.
This was a misinterpretation of the spec; we should only indicate focus
if the form associated element supports keyboard input, for which
FormAssociatedTextControlElement is a much better match.
This is everything except some failing ref-tests, and
`css/css-typed-om/the-stylepropertymap/properties/*` because importing
a test for every property feels excessive.
The upcoming `:heading()` pseudo-class takes multiple comma-separated
An+Bs. Also rename this field as the `:nth-[last-]child()`
pseudo-classes are only a subset of the users.
We now clamp the values returned from calc into the allowed range (where
we know it) and censor any `NaN`s to `0` both when we resolve and when
we serialize.
Gains us 76 WPT passes.
Returning this struct will allow us to modify the underlying value of
the `CalculationResult` without requiring us to go through the process
of constructing a whole new `CalculationResult` to return.
This currently only applies to property-level calculation contexts, more
work to be done to generate accepted ranges for other calculation
contexts (e.g. within transformation functions, color functions, etc)
We were handling the special cases of NaN and Infinity in basically the
same way across both functions - we can reduce code duplication by
moving this to before we branch.
This is also required as we will be moving the logic to encode in
scientific notation above the branch in a later commit and the
`convert_floating_point_to_decimal_exponential_form` method doesn't work
with non-finite values.
When converting rotate transform functions `sin` and `cos` can sometimes
be inaccurate. To avoid these inaccuracies we:
- Mod the angle to minimise inaccuracies in the first place.
- Discard tiny (smaller than epsilon) values returned by `sin` and
`cos` as inaccuracies.
This is in line with other browsers (e.g. Gecko and WebKit).
In the following synthetic benchmark, the simdutf version is 4x faster:
BENCHMARK_CASE(find)
{
auto string = u"😀Foo😀Bar"sv;
for (size_t i = 0; i < 100'000'000; ++i)
(void)string.find_code_unit_offset('a');
}
Before this change, clients were kept alive by making them children of
the TCPServer object. This ownership model is going away (and this was
the only remaining use of it!) so let's just put the clients in a hash
table instead.
This is the mechanism that should pages to determine what kind of
policies can be created on their domains mostly based around the HTTP
headers the server responds with.
The TrustedHTML interface represents a string that a developer can
confidently insert into an injection sink that will render it as HTML.
These objects are immutable wrappers around a string, constructed via a
TrustedTypePolicy’s createHTML method.
Partly corresponds to 80ebad5fbf
This is mostly to handle null source_documents, which is something that
needs more work elsewhere. The spec change above is about the deferred
fetch quota.
When a table row (or its group) is set to collapse, the row takes up no
vertical space in the layout.
We have to account for this in multiple places, so I've cached whether a
row is collapsed in the TableGrid::Row.
Call paint_border() recursively, once for the outer line, and once for
the inner one. This is done in a lambda so that we can reuse it for a
couple of other line styles.
Border-radius behaviour doesn't match other browsers, and goes a bit
haywire in some cases. I've left some FIXMEs for someone who
understands the maths here better than I do. 😅
The LineStyle handling is moved to the start of the function, to avoid
unnecessary work.
This regressed in cd15b1a2c9.
If a prefixed number is out-of-range of a u64, stroul would previously
fall back to ULONG_MAX. This patch restores that behavior.
CSS grid specification states that for grid items with a replaced
element and a percentage preferred size or maximum size, the percentage
should be resolved against 0 during content-based minimum size
calculation. This makes sense, as it prevents replaced items from
overshooting their grid track while intrinsic track sizes are
calculated, and allows later track size resolution steps to scale
replaced items to fit their grid track.
When loading Infiltrating the Airship in Ruffle, the copying of these
hash maps/tables were at least 10% of the runtime. This disappears when
returning them by const reference.
CSSUnitValue is a typed-om type which we will implement separately in
the future. However, it still seems useful to give our dimension values
a base class. (Maybe they could be templated in the future?) So instead
of deleting it entirely, rename it to DimensionStyleValue and make its
API match our style better.
This reverts 0e3487b9ab.
Back when I made that change, I thought we could make our StyleValue
classes match the typed-om definitions directly. However, they have
different requirements. Typed-om types need to be mutable and GCed,
whereas StyleValues are immutable and ideally wouldn't require a JS VM.
While I was already making such a cataclysmic change, I've moved it into
the StyleValues directory, because it *not* being there has bothered me
for a long time. 😅
Largely combinations of i32.const and local.get.
This shaves off at most single-digit% number of instructions from
dispatch, which translates to at most ~10% reduced dispatch time.
Across most benchmarks, this gains around ~5% perf increase.
This commit adds a register allocator, with 8 available "register"
slots.
In testing with various random blobs, this moves anywhere from 30% to
74% of value accesses into predefined slots, and is about a ~20% perf
increase end-to-end.
To actually make this usable, a few structural changes were also made:
- we no longer do one instruction per interpret call
- trapping is an (unlikely) exit condition
- the label and frame stacks are replaced with linked lists with a huge
node cache size, as we only need to touch the last element and
push/pop is very frequent.
This is largely unused (only in wasm.cpp)
A future reimplementation can bring it back as a separate interpreter
class that embeds the current bytecode interpreter.
...for the first byte.
This function only really needs to read a single byte at that point, so
read_until_filled() is useless and read_value<u8> is functionally
equivalent to just a read.
This showed up hot in a wasm parse benchmark.
The average wasm function rarely goes over these bounds for the labels
(32 nested control structures), and 8 frames is just enough to clear
most initialization code/start section without allocating anything.
These are quite bottlenecky in wasm, the next commit will try to make
use of this by calling them directly instead of doing a vcall, and
having them inlineable helps the compiler a bit.
If the address is already aligned properly, just read a T from it;
otherwise copy it to a local aligned array. This was a bottleneck on
memory-heavy benchmarks.
This is an editoral change from the fetch spec. Since we already defined
the stream before it being used this only re-numbers the spec steps.
It also corrects a minor typo ('followings' to 'following') which was
corrected in the same editoral spec change.
- Omit calcs that are resolved to `0px` from the serialized value
- Allow CSV to be the 'Z' component in interpolated value.
- Allow calcs with mixed percentages in the first two arguments.
To achieve the third item above the concept of a "special" value parsing
context has been added - this will also be useful for instance for
different arguments of color functions having different contexts.
Gains us 23 WPT tests
We were failing to discriminate between DOM removals happening to SVG
elements cloned as part of an SVG use element instantiation.
When a "use source" element is removed, all clones of that source must
be updated to reflect the change. But when a "use clone" element is
removed, that's fine.
This was causing the surprising disappearance of use element subtrees,
seen for example on https://cal.com/
This lets you access closed shadow roots from JavaScript, even though
they're not normally accessible to JavaScript. This can be used to poke
into UA shadow roots in tests.
Fixes external CSS being blocked on https://beatsaver.com/, where they
have a `style-src` directive set to `'self' 'nonce-[value]'`
Relates to #5643, but does not make the website load.
Technically, env() should not be an ASF. (😱) This is why some tests
still fail - env() as specced is expected to have its syntax checked
fully at parse-time, whereas ASFs are not properly syntax-checked until
later. However, I think this approach was worth doing for a few reasons:
- env() behaves like an ASF otherwise. (It is replaced with a set of
arbitrary component-values that are not known until computed-value
time.)
- env() was defined before the ASF concept existed, so I strongly
suspect it will be updated in the future to match that definition,
with a couple of adjustments. (eg, env() is allowed in some extra
places compared to var() and attr().)
- This was much quicker and easier to implement (under 3 hours in total)
compared to the greater amount of work to implement a whole separate
system just for env().
- Most of these tests are marked tentative, and the spec definition of
env() is still somewhat in flux, so failing some is not a huge deal.
If in the future I turn out to be wrong on this, we can convert it to
its own special thing.
FFC expects parent formatting context to mark size as definite if that's
the case, because otherwise it cannot figure cross line size correctly.
Fixes incorrect alignment when FFC is nested in GFC.
Progress on https://web.telegram.org/a/ layout.
This commit regresses a couple tests related to the mask shorthand
property. This is because we now parse the longhands but there are
errors related to serialization. Some of the failures are fixed again in
the next commit. However, for some animation tests this is not the case.
Those failures were simply masked by the fact that we did not parse the
property correctly.
These will be used for the mask-repeat property as well in an upcoming
commit, hence the more generic names. Also, this more closely matches
the names used in the spec.
Previously we were converting lengths to CSSPixels values when we didn't
need to, this had a couple of effects in that:
- We rounded to CSSPixel resolution prematurely (sometimes giving
incorrect results)
- We converted NaN to 0 when we shouldn't have.
We now avoid prematurely converting lengths to CSSPixels values in two
places:
- `CalculationResult::from_value`
- `CalculatedStyleValue::resolve_length_deprecated` (the new method
already avoided rounding).
Gains us 16 WPT tests.
The test logs tend to get a bit mixed together, so this makes it
possible to identify which values correspond to which test when multiple
are failing at once.
As it turns out, we still have to let the formatting contexts do a bit
of layout work in order to correctly apply the aspect-ratio. Hence we
can't just implicitly transfer definiteness from one size to the other.
This is a revert of 1cfd8b3ac0.
This has quite a lot of fall out. But the majority of it is just type or
UDL substitution, where the changes just fall through to other function
calls.
By changing property key storage to UTF-16, the main affected areas are:
* NativeFunction names must now be UTF-16
* Bytecode identifiers must now be UTF-16
* Module/binding names must now be UTF-16
Before now, you could compare a Utf16View to a StringView, but it would
only be valid if the StringView were ASCII. When porting code to UTF-16,
it will be handy to have a code point-aware implementation for non-ASCII
StringViews.
Fixes crash in the created test as well as https://wpt.live/css/css-text
/word-spacing/reference/word-spacing-percent-001-ref.html. The WPT test
hasn't been imported as it passing is currently a false-positive due to
the fact that we don't yet respect `word-spacing` in most cases.
Updating the hovered node may fire events, and so we can't assume the
layout and paintable nodes we've found via hit testing will be valid
after doing it.
This helps make callers only use the slice of the output buffer that
was written to.
As part of updating the callers of the API several bugs were fixed and
useless code paths were removed:
- The exported data is not host-endianess dependent (always big endian)
- The exported data does not contain leading zeros
- The output buffer is only written up to the result's size
The spec language specifies 'Set maxScopeString to "/", followed by the
strings in XXXX’s path (including empty strings), separated from each
other by "/"': That is, adjacent components are separated by a '/', but
the last component does not get a trailing '/'.
This resulted in the generated scope string ending with '//' in some
cases, incorrectly tripping the 'Service-Worker-Allowed' security check
Without this, any relative url()s in the `content` property don't know
what style sheet they are in, which makes them load relative to the
document instead.
Initializing m_current_screen may not be necessary, but the initial
value of m_preferred_color_scheme is sent to WebContent, so failing to
give it an initializer would cause bugs.
Taking a ColorResolutionContext directly instead of creating one from a
layout node allows us to call this from places where we don't have a
layout node.
Using a generic context argument will allow us to resolve colors in
places where we have all the required information but not in the form of
a layout node as was expected previously.
Now we pass all WPT tests in:
`css/css-properties-values-api/at-property-cssom`.
Note: Failing tests were false positives.
Proper handling of inheriting values and detecting computational
independence will be done in another PR.
QualifiedRule::for_each_as_declaration_list() now takes a rule_name, so
that the error message can actually be useful - we only know what a
qualified rule is by context.
Instead of random dbgln_if(CSS_PARSER_DEBUG) messages, this lets us
report what kind of error it was. Repeated errors are combined instead
of spamming the console.
Ideally this would also record where the error occurred, but not yet.
We have a bunch of TODO/FIXME about supporting applicable specifications
for algorithms that are not mentioned in the spec. There is no plan to
have any, there is nothing to do as of now.
Previously we would omit the letter spacing for the end glyph of each
chunk in a misguided attempt to conform to the spec's instruction that
we "really should not append letter spacing to the right or trailing
edge of a line", this behaviour can be removed entirely as other
browsers (Firefox, Chrome) don't implement it either.
The storage type was being incorrectly set to Session instead of Local,
apparently because of copying the implementation from
`Window::session_storage()`.
Bug introduced in commit 2066ed2318
Previously, the value of the `src` tag would always be used as the
image source URL when requesting an image context menu, which may not
be correct if an image uses a `srcset` or has a parent picture tag.
`aa_translation` is something we inherited from times when
AntiAliasingPainter was a thing. This change replaces it by applying
offset directly to path.
There's no need to have separate display list item for drawing triangle
wave when we could simply use StrokePathUsingColor. By switching to
StrokePathUsingColor we could also reduce painting because it supports
filtering out by bounding box.
As `node->parent()` was being called before comparing `node` with
`stay_within`, the code was incorrectly allowing traversal to the
parent node even when it should not have.
This change ensures that the parent is only checked after
confirming that the current node is not the `stay_within` node.
All `dom/traversal/NodeIterator.html` WPT tests get fixed after this
change.
Applicable FCs with an indefinite width simply shrink in their available
space as long as floats are intruding, but as soon as we have a definite
width we must push the box down until it it has enough space again.
Fixes#4136.
This tests is trying to see if we're taking into account the full margin
box width (75px - 50px) when determining whether there is enough space
to fit the BFC box. No major browser passes this test, and other tests
such as `css/CSS2/floats/new-fc-beside-float-with-margin.html` seem to
require that we ignore those margins.
Output display list dumps with an indentation level to show balanced
commands. It makes it much easier to see what is happening between e.g.
PushStackingContext and PopStackingContext, or SaveLayer and Restore.
PaintContext dates back to a time when display lists didn't exist and it
truly represented "paint context". Renaming it to better align with its
current role.
If an editing host receives focus, we would always set a new selection
range. However, we only need to do that if we're not already part of the
active range. This corresponds to behavior shown by Chrome and Firefox.
When we manually enter a new URL and hit enter, the web view gets
focused. But when the URL changes for other reasons, such as starting
Ladybird with a URL argument, the location field was still focused.
Before committing a new layout (and thus building a new paint tree)
we now go through both the old paint tree and the layout tree and detach
them from each other.
This is a little extra work, but it ensures that there are no lingering
references across the trees, which we were apparently accumulating in
some cases on Discord, causing GC leaks.
The `RecordedNodeValue` struct contains a `GC::Ref` to a DOM node, which
might disappear as a result of a garbage collection. For example, during
the "outdent" command, we record nodes, split the parent of those nodes
potentially resulting in all kinds of DOM changes, and then try to
restore the nodes' values. This caused a crash in the
`editing/run/outdent.html` WPT subtests.
By returning a `ConservativeVector`, we make sure the `GC::Ref` gets
marked during sweeps and nodes do not suddenly disappear.
This parses `anchor-size(..)` functions in CSS, but does not yet result
in a useful `Size`: we need style & layout interleaving similar to
container queries for this, since the resulting value depends on layout
results.
Not supported yet: `anchor-size()` appearing inside a `calc()` node.
Adds 4280 WPT subtest passes in `css/css-anchor-position`.
This allows authors to check if Trusted Type is required for a given
Element's content attribute. This allows to pass the correct type
when they call to Element.setAttribute.
Many wpt test on trusted-types relay on this class being defined to even
begin the test as it declares some event handlers.
This is not really an implementation but the most basic setup needed to
run the tests.
This allows them to keep style sheets alive while loading fonts for
them. Fixes some GC crashes seen on the WPT WOFF2 tests after
66a19b8550 stopped FetchRecord leaks from
keeping various other things alive.
Our previous implementation kept track of an AnimationTimeline being
monotonically increasing, by looking at new time values coming in and
setting `m_monotonically_increasing` to `false` whenever a new value
is before the previous known time value.
As far as I can tell, the spec doesn't really ask us to do so: it just
defines 'monotonically increasing' as a property of a timeline, i.e. it
guarantees that returned time values from `::current_time()` are always
greater than or equal to the last returned value.
This fixes a common crash seen when the last render opportunity lies
before the document's origin time, and `::set_current_time()` was
invoked with a negative value. This was especially visible in the
`Text/input/wpt-import/css/cssom/CSSStyleSheet-constructable.html` test.
If class doesn't have any private fields, we could avoid allocating
PrivateEnvironment for it.
This allows us to skip thousands of unnecessary PrivateEnvironment
allocations on Discord.
Before this change, whenever element's attributes changed, we would add
a flag to "pending invalidation", indicating that all descendants whose
style uses CSS custom properties needed to be recomputed. This resulted
in severe overinvalidation, because we would run invalidation regardless
of whether any custom property on affected element actually changed.
This change takes another approach, and now we decide whether
descendant's style needs to be recomputed based on whether ancestor's
style recomputation results in a change of custom properties, though
this approach adds a little overhead to style computation as now we have
to compare old vs new hashmap of custom properties.
This brings substantial improvement on discord and x.com where, before
this change, advantage of using invalidation sets was lost and we had
to recompute all descendants, because almost all of them use custom
properties.
Compare `Vector<Parser::ComponentValue>` directly instead of
serializing them into strings first.
This is required for the upcoming changes where we would compare
previous and new sets of custom properties to figure out whether we need
to invalidate descendant elements. Without this change `equals()` would
show up being hot in profiles.
According to the spec, `ResizeObserver` needs to live for as long as
it's referenced from script or has observation targets. With this change
we make sure that `ResizeObserver` is unregistered from the `Document`
when it has no target.
Fixes GC leak that caused us to keep all resize observers alive until
document they belong to is destroyed.
`ShadowRoot` register itself in Document` from constructor and
unregister itself from `finalize()`. The problem is that `finalize()`
won't be invoked for as long as `ShadowRoot` is visited by
`Document`, leading to GC leaks.
`DocumentObserver` register itself in Document` from constructor and
unregister itself from `finalize()`. The problem is that `finalize()`
won't be invoked for as long as `DocumentObserver` is visited by
`Document`. By not visiting registered observers from `Document` we
move this responsibility to object that allocated observer, which is
always exactly what we want, e.g. once `SVGUseElement` that uses
observer is gone, observer won't be visited anymore which will lead to
`finalize()` being called.
This patch expands our generated content support beyond single strings
to lists of strings and/or images.
Pseudo-elements like ::before and ::after can now use content:url(...)
to insert anonymous image boxes into the layout tree.
This is heavily used in Google Docs for UI elements.
The faux position we created here is adjusted by the device pixel ratio
later on, which would invoke integer overflow on screens with a DPR
greater than 1.
Instead of creating special data for a mouse move event, let's just add
an explicit leave event handler.
Not accounting for opcode size when calculating incoming jump edges
meant that we were merging nodes where we otherwise shouldn't have been,
for example /.*a|.*b/.
This porting effort makes it pretty clear we will want a UTF-16-aware
GenericLexer. But for now, we can actually make ASCII assumptions about
what we are parsing, and act accordingly.
In 89ba00304c, the box' X position was
capped at 0 to prevent negative X positions to act as if there were
intruding floats on the left side. Instead, we need to check whether the
left side float intrusion we are going to calculate matters at all -
because if there's no matching float box, the intrusion is always going
to be 0 and we don't need to take the box' X position into account.
Fixes the floating publication images on https://lexfridman.com/.
Coverity static analysis reports that the code that scans the queue
families for one that has the graphics bit, can be -1 if none are
found, which could cause a problem when the -1 (signed) value is
used later as an index in a uint32_t (unsigned) variable.
Its not immediately clear how often this could occur, not finding
a queue family with the graphics bit, but adding some protecting
just in case.
Previously, when the mouse left the WebView, the currently hovered node
would remain hovered (including the scroll bar). This felt a bit awkward
and is not how other browsers behave.
Instead of returning whichever argument was NaN, return the canonical
NaN instead. The spec allows the old behavior:
"Following the recommendation that operators propagate NaN payloads
from their operands is permitted but not required."
But Chrome, Firefox and Safari do not propagate the operand payloads.
Fixes 448 WPT subtests in `wasm/core`.
Co-authored-by: Ali Mohammad Pur <ali.mpfard@gmail.com>
Having a setter for `device_pixels_per_css_pixel` was confusing because
display lists are immutable, so it doesn't make sense to override this
value after the display list has been created.
6507d23 introduced a bug when snapshot for iframe is saved in
`PaintNestedDisplayList` and, since display lists are immutable, it's
not possible to update before the next repaint.
This change fixes the issue by moving `ScrollStateSnapshot` for
nested display lists from `PaintNestedDisplayList` to
`HashMap<NonnullRefPtr<DisplayList>, ScrollStateSnapshot>` that is
placed into pending rendering task, making it possible to update
snapshots for all display lists before the next repaint.
This change doesn't have a test because it's really hard to make a ref
test that will specifically check scenario when scroll offset of an
iframe is advanced after display list is cached. We already have
`Tests/LibWeb/Ref/input/scroll-iframe.html` but unfortunately it did
not catch this bug.
Fixes https://github.com/LadybirdBrowser/ladybird/issues/5486
Noticed while working adjacent to these APIs that we take a Utf16String
and pass it around as a Utf16View, only to re-allocate the Utf16String
in many commands. Let's just pass the string itself around.
This migrates TextNode::text_for_rendering() to Utf16String and deals
with the fallout. As a consequence, this effectively reverts commit
3df83dade8.
The layout test expecation file updates are because we now express text
lengths and offsets in UTF-16 code units.
The selection-over-multiple-code-units expectation file update actually
represents a correctness fix. Our result now matches Firefox.
The HTML specification does not explicitly require
a specific return type for parseFromString(),
but according to Web Platform TestsDOMParser-parseFromString.html,
the expected return value for
XML MIME types is a Document—not an XMLDocument.
The spec tells us to reject the promise with a RuntimeError instead of a
LinkError whenever the module's start function fails during module
instantiation. Fixes 1 WPT subtest in `wasm/core`.
Finishes what 7f6b70fafb started.
Having one part use length and another code unit length lead to crashes,
the added test ensures we don't mess that up again.
Fixes race condition introduced in eed47acb when rendering thread
accesses ScrollFrame that could be mutated in the middle of
rasterization by the main thread, resulting in broken rendering.
Fixes https://github.com/LadybirdBrowser/ladybird/issues/5553
This adds a new IDL type, Utf16DOMString. This is the same as DOMString,
except it is UTF-16. This type is temporary - we will want DOMString to
be UTF-16 by default once we've ported enough of LibWeb.
To make this support easier, some string IDL generator handling is moved
directly into `generate_to_string` from the call sites.
Skia allows you to pass a bounding rect to its saveLayer() function as
an optimization when you know that you won't paint outside those bounds.
Unfortunately, we were passing a too-small rectangle that didn't take
into account transformed descendants, etc.
For now, simply pass null instead of a bounding rect. This way, Skia
figures it out internally. It may allocate larger temporary bitmaps than
needed this way, but at least we get more correct results. I've left
re-enabling the optimization as a FIXME in the code.
This fixes unwanted clipping in various parts of the Discord UI.
Both sides of the Editing internals now have to deal with some awkward
converting between UTF-8 and UTF-16, but the upside is that it
immediately exposed an issue with the `insertText` command: instead of
dealing with code units, it was iterating over code points causing the
selection to be updated only once instead of twice. This resulted in the
final selection potentially ending up in between a surrogate pair.
Fixes#5547 (pasting/typing surrogate pairs).
Originally I added this to use it in Utf16View::ends_with(), but the
final implementation ended up a lot simpler. I chose to keep this anyway
since it mirrors Span::starts_with().
This prevents empty matches from overwriting non-empty captures in
quantified alternations. Fixes patterns like (a|a?)+ where the optional
branch would incorrectly overwrite meaningful captures with empty
strings.
This will build both aarch64 and x86_64 flatpaks nightly. The test jobs
I did with the default GitHub runners took ~1h30m for aarch64 and
~2h30m for x86_64, but this will hopefully improve over time as the
cache is built up. And be better time-wise on the blacksmith runners.
Disk space is a large concern with these flatpak builds. A naive script
on my local machine showed that we needed a max of 10.3 GiB of free
space for the x86_64 build, with clang as the compiler. For some reason,
building with default gcc 14 uses more disk space than that, bumping
up against the default 14 GiB free space limit guaranteed by GitHub for
their default runners.
`AnimationTimeline` visits pointers of all registered animations, so if
element is removed from DOM tree but its animations remain registered in
timeline, then `Animation` and owner `Element` will be kept alive until
`AnimationTimeline` is destroyed.
flatpak-builder doesn't respect .gitignore when creating its local build
directory, so we need to explicitly skip potentially large ignored
directories to avoid bloating the flatpak build directory during builds.
This behavior is part of the cyclic percentage contribution logic from
CSS-SIZING-3 which explicitly only applies to non-replaced boxes.
This fixes an issue on Discord where buttons in the settings UI were
cropped to a narrower width than intended.
Fixes#3572
This uses a `foo>bar` notation in the `valid-identifiers` field of
Properties.json, to say "replace `foo` with `bar`".
The motivation here is to avoid calling `parse_css_value_for_property()`
inside the per-property switch in `parse_css_value()`. Eventually we'll
need to be able to call that switch from
`parse_css_value_for_properties()` so that shorthands can make use of
any bespoke parsing code to parse their longhands.
We should not compare code point offsets to byte offsets, but compare
the consumed code points to the input's length expressed in code points
instead.
Relates to #5547.
This reverts commit c14173f651. We
should only annotate the minimum number of symbols that external
consumers actually use, so I am starting from scratch to do that
RegExp was the only caller relying on being able to provide an offset
larger than the string length. So let's do a pre-check in RegExp and
then enforce that the offsets we receive in Utf16View are valid.
There were a couple of issues here, including the following computation
could actually overflow to NumericLimits<size_t>::max():
code_unit_offset -= it.length_in_code_units();
And do the same for Utf8View::code_point_offset_of(). Some of these
`VERIFY`s of the view's length were introduced recently, but they caused
the parsing of named capture groups in RegexParser to crash in some
situations.
Instead, allow indexing at the view's length: the byte offset of code
point `length()` is known, even though that code point does not exist in
the view. Similarly, we know the code point offset at byte offset
`byte_length()`. Beyond those offsets, we still crash.
Fixes 13 failures in test262's `language/literals/regexp/named-groups`.
Partial interfaces have the same name as the interface they extend, and
can appear in any order. In practice, we import the partial interfaces
into the main interface's IDL.
`curl_easy_recv` must be called in a loop until it returns EAGAIN,
because it may cache data, but only activate the read notifier once.
Additionally, the data received can contain multiple WebSocket frames
and only activate the notifier once, so we have to keep reading frames
until there isn't enough data.
We also have to do this immediately after connecting a WebSocket,
since the server may immediately send data when the WebSocket opens
and before we create the read notifier.
This makes Discord login faster and more reliable, and makes Discord
activities start loading.
Before this change, calc() would resolve to different types depending on
the nearest containing value context. This meant that rgb(calc(), ...)
by itself worked correctly due to fallbacks, but rgb(calc(), ...) inside
e.g a linear-gradient would create a calc() value that resolves to a
length, which subsequently got rejected by the color value parser.
Fixing this makes various little gradients show up on Discord.
There apparently is a bit of a disconnect between the spec asking us to
construct the pattern using code points and LibRegex not being able to
swallow those. Whenever we had multi-byte code points in the pattern and
tried to match that in unicode mode, we would fail.
Change the parser to encode all non-ASCII code units. Fixes 2 test262
cases in `language/literals/regexp`.
We were calling into `view.length()`, which potentially returned the
code _point_ length for Utf16Views. Make sure we use the code unit
length instead, since we're only indexing into code units.
At some point `hue-rotate` was changed to use `AngleOrCalculated`
rather than `Angle`, but `Angle` was still being used in a `visit`,
which otherwise defaulted to zero. This caused all `hue-rotate` angles
to serialize to zero.
`operator[]` -> `code_point_at`
`code_unit_at` -> `unicode_aware_code_point_at`
`unicode_aware_code_point_at` returns either a code point or a code unit
depending on the Unicode flag.
Fixes bug when `build_matching_rule_set()` mistakenly included all
unlayered rules twice. This was caused by mistakenly including all
unlayered rules into `""` named "service" layer, because we couldn't
tell if FlyString = `""` means no layer or layer named `""`.
This was a cache race condition between the fuzzers and sanitizer
builds, where the vcpkg binary cache could have been updated before the
sanitizer builds started doing their vcpkg install, causing the source
assets to never be updated at all.
Previously, an SVG with width of zero would have am intrinsic aspect
ratio of zero. With this change, if an SVG has a width or height of
zero, the intrinsic aspect ratio is determined by the SVG's viewbox.
...for `text-justify: inter-character`.
We previously had this mapped in Enums.json, but the behaviour is
different: `a=b` in Enums.json keeps `a` around but makes it behave the
same as `b`. A legacy name alias is instead expected to replace `a`
with `b`, so we have to do that separately.
We don't yet have a system for "legacy value aliases", but until we have
a lot of them we can handle them manually.
We also have to do this in two places because
parse_css_value_for_property() doesn't call any property-specific
parsing code.
Before this change we were running the CSS cascade machinery twice per
element:
- First, to compute the "logical alias mapping context" based on
writing-mode and pals.
- Then, to compute all properties.
This patch factors out the heaviest work from the cascade machinery
to a separate step that can be run only once. This step will:
- Collect all the matching rules for the element
- Resolve custom properties for the element
We still perform the per-element cascade twice, but now this is hogging
less than 1% of CPU time when typing on Discord (compared to 9% before.)
The specification [1] indicates that the tentative used width and height
should be computed first, and if they exceed the `max-width` or
`max-height`, the rules should be applied again using the computed
values of `max-width` and `max-height`.
The only required change to follow the spec is to remove the early
`return` statements, in both `compute_width_for_replaced_element`
and `compute_height_for_replaced_element`.
Fixes#5100.
[1] https://www.w3.org/TR/CSS22/visudet.html#min-max-widths
To make {,de}serialization of ImageBitmap work we also had to add
support for creating an ImageBitmap from a HTMLCanvasElement in
WindowOrWorkerGlobalScopeMixin::create_image_bitmap_impl().
This refactors out the reading part of Gfx::Bitmap from
HtmlCanvasElement::surface(). We can then reuse this from
WindowOrWorkerGlobalScopeMixin::create_image_bitmap_impl() when we
create an ImageBitmap from a HtmlCanvasElement.
1. Fix typos in some macro invocations of these error types. We now use
a single xmacro to instantiate error definitions to prevent such
errors in the future.
2. Use the "WebAssembly." prefix as needed.
3. Allocate the error constructors and prototypes with `realm.create`
rather than `heap.allocate`. The latter does not invoke `initialize`
methods. This exposed the next issue:
4. Use the correct intrinsic prototype in the error constructor. We were
using the base native error prototype. We unfortunately cannot invoke
OrdinaryCreateFromConstructor from LibJS directly with the correct
prototype, so an implementation was added here.
5. Use intrinsic accessors to create the constructors. I don't think
this one was actually a fix, but it makes the setup look more like
other built-ins.
This fixes an issue where only the last KeyframeEffect applied to an
element would actually have an effect on the computed properties.
It was particularly noticeable when animating a shorthand property like
border-width, since only one of the border edges would have its width
actually animate.
By deferring the invalidation until all animations have been processed,
we also reduce the amount of work that gets done on pages with many
animations/transitions per element. Discord is very fond of this for
example.
Using the new hooks in the XML Parser's listener interface, we now
append DOM nodes for CDATASections and ProcessingInstructions
to the document as they are encountered. This commit also fixes where
comment nodes are appended, ensuring they are added to the current node
instead of the document root.
This allows listeners to be notified when a CDATASection or
ProcessingInstruction is encountered during parsing. The non-listener
path still has the incorrect behavior of silently treating CDATASection
as Text nodes, but this allows listeners to handle them correctly.
...elements. Adds missing pseudo-element type passed into computed
properties getter.
Previously, due to this bug, we were using the element's computed
properties as the previous computed properties for its pseudo-elements.
This caused an excessive number of unintended CSS transitions to run.
The issue was particularly noticeable in Discord's emoji picker, where
each emoji has `::after` pseudo-element. We were incorrectly triggering
transitions on all their properties, resulting in significant
unnecessary work in style computation and animation event dispatching.
...and setter. We had lots of places where we check if pseudo-element
type is specified and then use `pseudo_element_computed_properties()` or
`computed_properties()`. This change moves these checks from caller side
to the getter and setter.
Utf16FlyString more or less works exactly the same as FlyString. It will
store the raw encoded data of the string instance. If the string is a
short ASCII string, Utf16FlyString holds the ShortString bytes; else,
Utf16FlyString holds a pointer to the Utf16StringData.
The underlying storage used during string formatting is StringBuilder.
To support UTF-16 strings, this patch allows callers to specify a mode
during StringBuilder construction. The default mode is UTF-8, for which
StringBuilder remains unchanged.
In UTF-16 mode, we treat the StringBuilder's internal ByteBuffer as a
series of u16 code units. Appending a single character will append 2
bytes for that character (cast to a char16_t). Appending a StringView
will transcode the string to UTF-16.
Utf16String also gains the same memory optimization that we added for
String, where we hand-off the underlying buffer to Utf16String to avoid
having to re-allocate.
In the future, we may want to further optimize for ASCII strings. For
example, we could defer committing to the u16-esque storage until we
see a non-ASCII code point.
This is a strictly UTF-16 string with some optimizations for ASCII.
* If created from a short UTF-8 or UTF-16 string that is also ASCII,
then the string is stored in an inlined byte buffer.
* If created with a long UTF-8 or UTF-16 string that is also ASCII,
then the string is stored in an outlined char buffer.
* If created with a short or long UTF-8 or UTF-16 string that is not
ASCII, then the string is stored in an outlined char16 buffer.
We do not store short non-ASCII text in the inlined buffer to avoid
confusion with operations such as `length_in_code_units` and
`code_unit_at`. For example, "😀" would be stored as 4 UTF-8 bytes
in short string form. But we still want `length_in_code_units` to
be 2, and `code_unit_at(0)` to be 0xD83D.
This was a mistake. Consider U+201C (LEFT DOUBLE QUOTATION MARK). This
code point is encoded as the bytes 0x1c 0x20 in UTF-16LE. Both of these
bytes are ASCII if interpreted as UTF-8. But the string itself is most
certainly not ASCII.
We now do the proper thing in terms of:
- Allowing percentages
- Returning the computed value in getComputedStyle
- Handling values out of the [0,1] range
Gains us 13 WPT passes in the imported tests.
Most locations already make this assumption, but we had a few that would
silently ignore data mismatches. Let's just always assume the type is
correct for now. If a bad actor has a hold of our transport socket, it's
probably better to crash WebContent than to continue on with incorrect
data.
In the future, maybe we will want to throw an exception instead.
Now that these serializers are internal to StructuredSerialize.cpp,
let's put them above Serializer so they don't have to be forward-
declared and explicitly instantiated.
Our structured serialization implementation had its own bespoke encoder
and decoder to serialize JS values. It also used a u32 buffer under the
hood, which made using its structures a bit awkward. We had previously
worked around its data structures in transferable streams, which nested
transfers of MessagePort instances. We basically had to add hooks into
the MessagePort to route to the correct transfer receiving steps, and
we could not invoke the correct AOs directly as the spec dictates.
We now use IPC mechanics to encode and decode data. This works because,
although we are encoding JS values, we are only ultimately encoding
primitive and basic AK types. The resulting data structures actually
enforce that we implement transferable streams exactly as the spec is
worded (I had planned to do that in a separate commit, but the fallout
of this patch actually required that change).
No need to manually prepare / clean up a context. We also previously
would not have done the clean up steps if structured deserialization
threw an exception.
Instead of every branch being of the form:
if (value.is_object() && is<SomeType>(value.as_object()) {
auto& some_type = static_cast<SomeType&>(value.as_object());
}
Let's extract the `is_object` check to an outer branch, and use `as_if`
to check the type.
No functional change, but this makes a future change simpler to review.
This will allow structured deserialization in LibWeb to create shared
buffers without having to go through CreateSharedByteDataBlock. That
will let us pass in the underlying ByteBuffer, rather than having to
allocate a second buffer via CreateSharedByteDataBlock and memcpy the
data into it.
Add global registry for registered properties and partial support
for `@property` rule. Enables registering properties with initial
values. Also adds basic retrieval via `var()`.
Note: This is not a complete `@property` implementation.
When dumping the DOM tree, only prefix the element's local name with its
short namespace identifier if it's not the document's default namespace.
This gets rid of the excessive "html:" and "svg:" prefixes in context of
an HTML or SVG document, respectively.
More things need this than just the `<path>` element, so let's avoid
having to include `SVGPathElement.h` in places that don't need it.
Minor changes at the same time:
- Wrap it in a Path class
- Specify underlying type for PathInstructionType
- Make a couple of free functions into methods
- Give PathInstruction an operator==
No functionality changes.
With the newly supported fuzzy matching in our test-web runner, we can
now define the expected maximum color channel and pixel count errors per
failing test and set a baseline they should not exceed.
The figures I added to these tests all come from my macOS M4 machine.
Most discrepancies seem to come from color calculations being slightly
off.
WPT reference tests can add metadata to tests to instruct the test
runner how to interpret the results. Because of this, it is not enough
to have an action that starts loading the (mis)match reference: we need
the test runner to receive the metadata so it can act accordingly.
This sets our test runner up for potentially supporting multiple
(mis)match references, and fuzzy rendering matches - the latter will be
implemented in the following commit.
This produces more granural information on the actual pixel errors
present between two bitmaps. It now also asserts that both bitmaps are
the same size, since we should never compare two differently sized
bitmaps anyway.
While 788d5368a7 took care of better text
marker positioning, this improves graphical marker positioning instead.
By looking at how Firefox and Chrome render markers, it's clear that
there are three parts to positioning a graphical marker:
* The containing space that the marker resides in;
* The marker dimensions;
* The distance between the marker and the start of the list item.
The space that the marker can be contained in, is the area to the left
of the list item with a height of the marker's line-height. The marker
dimensions are relative to the marker's font's pixel size: most of them
are a square at 35% of the font size, but the disclosure markers are
sized at 50% instead. Finally, the marker distance is always gauged at
50% of the font size.
So for example, a list item with `list-style-type: disc` and `font-size:
20px`, has 10px between its start and the right side of the marker, and
the marker's dimensions are 7x7.
The percentages I've chosen closely resemble how Firefox lays out its
list item markers.
This change converts `Node::invalidate_style()` (invalidation sets
overload) from eagerly doing tree traversal that marks elements affected
by invalidation set to instead adding "pending invalidation sets" into
`StyleInvalidator`, processing of which is deferred until the next
`update_style()`. By doing that we sometimes substantially reduce amount
of work done performing tree traversal that marks elements for style
recalculation.
Improves performance on Discord, were according to my measurements we
were previously spending 20% of time in style invalidation, but now it's
down to <1%.
This change introduces StyleInvalidator as a preparation for upcoming
change that will make `perform_pending_style_invalidations()` take care
of pending invalidation sets.
Note that it's not actually executing tasks in parallel, it's still
throwing them on the HTML event loop task queue, each with its own
unique task source.
This makes our fetch implementation a lot more robust when HTTP caching
is enabled, and you can now click links on https://terminal.shop/
without hitting TODO assertions in fetch.
This contains an API change that disallows setting the salt to a null
value. See:
4f5ffddfcb
This seems to be the opposite of the intended effect of that change,
but this patch includes a workaround nonetheless.
Co-Authored-By: devgianlu <altomanigianluca@gmail.com>
`<syntax>` is a limited subset of the "value definition syntax" used in
CSS specs. It's used for `@property`'s `syntax` descriptor, and for the
`type()` function in `attr()`.
UnresolvedStyleValue::create() has one user where we know if there are
any arbitrary substitution functions in the list of CVs, and two users
where we don't know and just hope there aren't any. I'm about to add
another user that also doesn't know, and so it seems worth just making
UnresolvedStyleValue::create() do that work instead.
We keep the parameter, now Optional<>, so that we save some redundant
work in that one place where we do already know.
A couple of arbitrary substitution functions require us to get or
produce some style value, and then substitute its ComponentValues into
the original ComponentValue list. So this commit gives CSSStyleValue a
tokenize() method that does so.
Apart from a couple of unusual cases like the guaranteed-invalid value,
style values can all be converted into ComponentValues by serializing
them as a string, and then parsing that as a list of component values.
That feels unnecessarily inefficient in most cases though, so I've
implemented faster overrides for a lot of the basic style value
classes, but left that serialize-and-reparse method as the fallback.
`CSSColorValue`s which have unresolved `calc` components should be able
to be resolved. Previously we would always resolve them but with
incorrect values.
This is useful as we will now be able to now whether we should serialize
colors in their normalized form or not.
Slight regression in that we now serialize (RGB, HSL and HWB) colors
with components that rely on compute-time information as an empty
string, but that will be fixed in the next commit.
These new methods are built on top of the spec's
`simplify_a_calculation_tree` algorithm where the old methods were
ad-hoc.
These methods are not used anywhere yet as callers will need to be
migrated over from the deprecated methods one-by-one to account for
differences in behaviour.
No functionality changes.
The existing resolve methods are not to spec and we are working to
replace them with new ones based on the `simplify_a_calculation_tree`
method.
These are marked as deprecated rather than replaced outright as work
will need to be done on the caller side to be made compatible with the
new methods, for instance the new methods can fail to resolve (e.g.
if we are missing required context), where the existing methods will
always resolve (albeit sometimes with an incorrect value).
No functionality changes.
When setting a declaration for a property in a logical property group,
it should appear after all other declarations which belong to the same
property group but have different mapping logic (are/aren't a logical
alias).
Gains us 1 WPT pass.
We should not serialize a group of properties `longhands` as a single
shorthand if there is any property declared between the first and
last property in `longhands` which is not part of `longhands` but
belongs to the same logical property group, and has different mapping
logic to any of property in `longhands`
This ensures that when we set an overlay port directory for building
the vcpkg cache, we set the default (and host) triplet to match the
triplet files we have in each directory.
Of the available 71 screenshot tests that we have, 42 fail on macOS
arm64. Let's make it possible to skip those and run the remaining
succeeding screenshot tests on arm64 anyway.
When parsing values in `process_a_keyframes_argument` we don't expand
properties using `StyleComputer::for_each_property_expanding_shorthands`
unlike most other places - this means that if we parse a `border` we end
up with the `border`'s sub-properties (`border-width`, `border-style`,
`border-color`) still in their unexpanded forms (`CSSKeywordValue`,
`LengthStyleValue`, `StyleValueList`, etc) rather than
`ShorthandStyleValue`s which causes a crash when serializing the
`border` value in `KeyframeEffect::get_keyframes`.
The proper fix here is to parse `border`'s sub-properties directly to
`ShorthandStyleValue`s instead of relying on
`StyleComputer::for_each_property_expanding_shorthand` to do this
conversion for us but this may be a while off.
This commit also imports the previously crashing tests.
We now clean up installed helper tools, includes from dependencies, and
pkgconfig/CMake files. This decreases the size of the flatpak from
~206MiB to ~150 MiB on my machine.
The manifest is also mostly clean of linter warnings from the
flatpack-builder manifest linter, with the exception of the overly broad
session bus policy.
The docs at https://docs.flathub.org/docs/for-app-authors/linter list a
method for selecting the correct session bus policies, but it is unclear
how to actually get the full set.
On FreeBSD some symbols like `environ` or `__progname` are not exported
anywhere and are filled in by the dynamic loader. `environ` is
a special case because we make use of it explicitly so we need to mark
it a weak symbol so the linker doesn't complain.
This is a workaround for the fact that on FreeBSD the system icu has
symbol renaming disabled which causes our build to clash with the
expectations of the system QT.
This commit is a three-parter that is hard to separate without breaking
marker rendering:
1. Any marker style that results in a string, except for a literal
string (e.g. `list-style-type: "@"`), should get the string ". "
appended. We forgot to do this for the alpha and roman types.
2. Instead of using the "pixel size rounded up" from a font and adding
an arbitrary 1 to that, we now use the exact pixel size for as long
as possible to improve our vertical positioning of markers.
3. Instead of always adding a "default marker width" to the marker
content width, we now only do this if we did not have text metrics
available (i.e. the marker style is not a text type). This greatly
improves horizontal positioning of text markers.
For contenteditable `Selection` in collapsed state represents cursor
position, so whenever it's update, we should also reset the blink timer.
Fixes bug on Discord when cursor is blinking while it is being moved by
pressing arrow keys.
Both functions schedule HTML event loop processing but that's
unnecessary, because we schedule a rendering task that checks if
style/layout needs an update 60/s anyway.
We were previously handling this ad-hoc via logic in
`get_property_internal` but this didn't cover all contexts (for
instance `CSSStyleProperties::serialized`.
Gains us 9 more WPT tests as we now cover properties which weren't
included in the previous ad-hoc approach.
Some shorthand properties work differently to normal in that mapping of
provided values to longhands isn't necessarily 1-to-1 and depends on the
number of values provided, for example `margin`, `border-width`, `gap`,
etc.
These properties have distinct behaviors in how they are parsed and
serialized, having them marked allows us to implement theses behaviors
in a generic way.
No functionality changes.
Our currently implementation of structured serialization has a design
flaw, where if the serialized/transferred type was not used in the
destination realm, it would not be seen as exposed and thus we would
not re-create the type on the other side.
This is very common, for example, transferring a MessagePort to a just
inserted iframe, or the just inserted iframe transferring a MessagePort
to it's parent. This is what Google reCAPTCHA does.
This flaw occurred due to relying on lazily populated HashMaps of
constructors, namespaces and interfaces. This commit changes it so that
per-type "is exposed" implementations are generated.
Since it no longer relies on interface name strings, this commit
changes serializable types to indicate their type with an enum,
in line with how transferrable types indicate their type.
This makes Google reCAPTCHA work on https://www.google.com/recaptcha/api2/demo
It currently doesn't work on non-Google origins due to a separate
same-origin policy bug.
If the MessagePort is not entangled, then m_transport is null, meaning
it's not valid to read from the transport.
This fixes the cross-piping streams WPT crash test crashing in the
upcoming commit.
Make sure we have a parent element before trying to look at it!
I've also pulled out a stub function for getting a custom property's
initial value, so that there's only one place to change once we support
`@property` more.
We were always creating an anonymous container for the inline contents
of table cells, but the layout node we spawn for the table cells
themselves already is capable of dealing with inline nodes. Regular
logic should kick in for dealing with the block/inline node invariant.
Because we defined `th { text-align: center }` in our UA stylesheet, it
received a higher precedence than inherited (inline) styles. Firefox
deals with this by defining a custom `text-align` value that prioritizes
any inherited value before defaulting to `text-align: center`.
We now do this as well :^)
When layouting a replaced element with natural width and height (e.g. a
raster graphic), the replaced element would correctly end up with its
natural size in the main-axis dimension. For the cross axis dimension
however, the replaced element was stretched or squished to the flex
containers inner cross size, which is wrong. Instead, we need to respect
the replaced elements aspect ratio.
Since the touched code does not have a direct correspondence to any spec
text, I am not fully certain that the change is completely correct.
However, tests agree with it, so the new code seems more correct than
the old one at least.
This fixes 50 WPT subtests in `css/css-flexbox`, most of which are
already in-tree. I have also created a new test for a scenario that did
not seem to be covered by WPT.
By keeping track of the enclosing range around all Unicode ranges of a
FontCascadeList entry, we can quickly reject any code point that's
outside all ranges.
This knocks font_for_code_point() from 7% to 3% in the profile when
scrolling on https://screenshotone.com/
Until now, every paint phase of every PaintableBox injected its own
clipping sequence into the display list:
```
before_paint: Save
AddClipRect (1)
...clip rectangles for each containing block with clip...
AddClipRect (N)
paint: ...paint phase items...
after_paint: Restore
```
Because we ran that sequence for every phase of every box, Skia had to
rebuild clip stack `paint_phases * paintable_boxes` times. Worse,
usually most paint phases contribute no visible drawing at all, yet we
still had to emit clipping items because `before_paint()` has no way to
know that in advance.
This change takes a different approach:
- Clip information is now attached as metadata `ClipFrame` to each
DisplayList item.
- `DisplayListPlayer` groups consecutive commands that share a
`ClipFrame`, applying the clip once at the start of the group and
restoring it once at the end.
Going from 10 ms to 5 ms in rasterization on Discord might not sound
like much, but keep in mind that for 60fps we have 16 ms per frame and
there is a lot more work besides display list rasterization we do in
each frame.
* https://discord.com/channels/1247070541085671459/1247090064480014443
- DisplayList items: 81844 -> 3671
- rasterize time: 10 ms -> 5 ms
- record time: 5 ms -> 3 ms
* https://github.com/LadybirdBrowser/ladybird
- DisplayList items: 7902 -> 1176
- rasterize time: 4 ms -> 4 ms
- record time: 3 ms -> 2 ms
In the upcoming change, device pixel conversion of ClipFrame will
happen during display list replay, where PaintContext is not available,
so let’s move it out of PaintContext.
Before this change, we were always behaving as if box-sizing were
content-box for block-level replaced element widths.
This fixes the squishy logo on https://videolan.org/
Introduces a few ad-hoc modifications to the DAFSA aimed to increase
performance while keeping the data size small.
- The 'first layer' of nodes is extracted out and replaced with a lookup
table. This turns the search for the first character from O(n) to O
(1), and doesn't increase the data size because all first characters
in the set of named character references have the
values 'a'-'z'/'A'-'Z', so a lookup array of exactly 52 elements can
be used. The lookup table stores the cumulative "number" fields that
would be calculated by a linear scan that matches a given node, thus
allowing the unique index to be built-up as normal with a O(1) search
instead of a linear scan.
- The 'second layer' of nodes is also extracted out and searches of the
second layer are done using a bit field of 52 bits (the set bits of
the bit field depend on the first character's value), where each set
bit corresponds to one of 'a'-'z'/'A'-'Z' (similar to the first
layer, the second layer can only contain ASCII alphabetic
characters). The bit field is then re-used (along with an offset) to
get the index into the array of second layer nodes. This technique
ultimately allows for storing the minimum number of nodes in the
second layer, and therefore only increasing the size of the data by
the size of the 'first to second layer link' info which is 52 * 8 =
416 bytes.
- After the second layer, the rest of the data is stored using a
mostly-normal DAFSA, but there are still a few differences:
- The "number" field is cumulative, in the same way that the
first/second layer store a cumulative "number" field. This cuts
down slightly on the amount of work done during the search of a
list of children, and we can get away with it because the
cumulative "number" fields of the remaining nodes in the DAFSA
(after the first and second layer nodes were extracted out) happens
to require few enough bits that we can store the cumulative version
while staying under our 32-bit budget.
- Instead of storing a 'last sibling' flag to denote the end of a
list of children, the length of each node's list of children is
stored. Again, this is mostly done just because there are enough
bits available to do so while keeping the DAFSA node within 32
bits.
- Note: Together, these modifications open up the possibility of
using a binary search instead of a linear search over the
children, but due to the consistently small lengths of the lists
of children in the remaining DAFSA, a linear search actually seems
to be the better option.
The new data size is 24,724 bytes, up from 24,412 bytes (+312, -104 from
the 52 first layer nodes going from 4-bytes to 2-bytes, and +416 from
the addition of the 'first to second layer link' data).
In terms of raw matching speed (outside the context of the tokenizer),
this provides about a 1.72x speedup.
In very named-character-reference-heavy tokenizer benchmarks, this
provides about a 1.05x speedup (the effect of named character reference
matching speed is diluted when benchmarking the tokenizer).
Additionally, fixes the size of the named character reference data when
targeting Windows.
When the XML parser appends child nodes to a template element, it must
actually append the template element's contents. This special behavior
caused us to return to the wrong parent element after adding child
nodes to a template element, leading to a crash.
The `shorthands_for_longhand`, `longhands_for_shorthand`, and
`expanded_longhands_for_shorthand` methods can be pretty hot in
profiles where we serialize a lot of CSS properties.
By returning a const reference to a static vector instead of allocating
and returning a new vector every time we can avoid a decent amount of
work.
Overall runtime for the particularly serialization heavy
wpt.live/css/cssom/cssom-getPropertyValue-common-checks.html
decreased by ~20% comparing before and after this change.
It's useful to have tests that dump display list items, so we can more
easily see how changes to the display list recording process affect the
output. Even the small sample test added in this commit shows that we
currently record an unnecessary AddClipRect item for empty paint phases.
For now, the dump doesn't include every single property of an item, but
we can shape it to include more useful information as we iterate on it.
Previously, calling `BlockContainer::paintable_with_lines()` would cast
a `PaintableBox` to a `PaintableWithLines` without verifying that the
cast was valid, which isn't the cast for `FieldsetPaintable`, for
example. This method now returns null if it isn't poossible to cast to
`PaintableWithLines`.
Recently, we moved the backing store manager into Navigable, which means
we now try to allocate a backing store for all navigables, including
those corresponding to SVG image documents. This change disables that
behavior for all navigables except top-level non-SVG traversables,
because otherwise it causes issues when we stop repainting: the browser
process was notified about an allocated backing stores that does not
correspond to the page, and then all subsequent repaints are ignored
until the window is resized.
For `vertical-align: middle` and `vertical-align: text-bottom`, we used
just the content height of the inline box to determine its alignment
position. This caused incorrect positioning when padding is applied.
This fixes the button alignment on our GitHub page.
Fixes#290.
This fixes an issue where we'd make an absolute mess from nested SVG
roots with display:block. Before this fix, the inner SVG root would
trigger the inline continuation logic and try to split the tree.
This ensures that percentages resolve against the foreignObject's size
instead of the size of its containing block.
This makes user profile pictures clip correctly in the "Friends" view
of the Discord app.
83b6bc4 went too far by forbidding SVGSVGElement from establishing a
stacking context. This element type does follow the behavior of CSS
boxes, unlike inner SVG elements like `<rect>`, `<circle>`, etc., which
are not supposed to be aware of concepts like stacking contexts,
overflow clipping, scroll offsets, etc.
This change allows us to delete overrides of `before_paint()` and
`after_paint()` in SVGPaintable and SVGSVGPaintable, because display
list recording code has been rearranged to take care of clipping and
scrolling before recursing into SVGSVGPaintable descendants.
`Screenshot/images/css-transform-box-ref.png` expectation is updated and
fixes a bug where a rectangle at the very bottom of the page was not
clipped correctly.
`Screenshot/images/svg-filters-lb-website-ref.png` has a more subtle
difference, but if you look closely, you’ll see it matches other
browsers more closely now.
These actually were always working since we first enabling LibGfx
on Windows. I was just running them outside of the ctest context
and therefore had the wrong working directory so the test-inputs folder
could not be found
Whenever we end up with a scrollable overflow rect that goes beyond
either of its axes (i.e. the rect has a negative X or Y position
relative to its parent's absolute padding box position), we need to clip
that rect to prevent going into the "unreachable scrollable overflow".
This fixes the horizontal scrolling on https://ladybird.org (gets more
pronounced if you make the window very narrow).
Due to removal of local ca-certificates we need to use system's
certificate. However, on Android it is stored in multiple files.
Ladybird doesn't support multiple certificates yet, so we just
concatenate all of them into one big file.
Vulkan seems to have been disabled due to not being able to compile.
However, it compiles on my machine and it works on my phone.
As for ANGLE, someone just forgot about Android.
While some of the changes are due to syntax and have no effect on
the functionality, others are more important.
The major changes are
- Use Painter instead of now removed DeprecatedPainter
- Remove the need of LibArchive by using Java's native zip support
- Have a proper C++23 compiler by updating NDK to r29 beta 2
- Store user data and config in an user accessible way
- Update AGP to 8.11 and update compile target to SDK level 35
We forgot to implement a couple of "otherwise," statements from the
"populating a session history entry" spec. While we're here, let's
update the spec copy where relevant.
We had typo'd using ClassSetReservedDoublePunctuator which was
resulting in a parse error for the regex:
([^\\:]+?)
With the 'v' flag set.
Co-Authored-By: Ali Mohammad Pur <mpfard@serenityos.org>
Since it does more than removing the quotes by escaping the string too
It makes sense to change the name of the flag to something more close
to what it's really doing.
Destubs AudioNode::disconnect() and its related overloads.
Ensures that inverse connections are properly removed
when disconnecting AudioNodeConnections. Adds associated
WPT but skips them for now because they rely on
OfflineRenderContext::start_rendering to be fully implemented.
For some reason, with CMake 4.0.3 and the Swift language enabled, this
target was getting random tokens in the compile commands. Moving it up
to the top of the file seems to fix this.
This is an active proposal at stage 3 of the TC39 proposal process.
See: https://tc39.es/proposal-dynamic-code-brand-checks/
See: https://github.com/tc39/proposal-dynamic-code-brand-checks
This proposal essentially adds support for the TrustedScript type from
the Trusted Types specification to eval and Function. This in turn
pipes support for the type into the CSP hook to check if the CSP allows
dynamic code compilation.
However, it currently doesn't support ShadowRealms, so the
implementation here is a close approximation, using PerformEval as the
basis.
See: https://github.com/tc39/proposal-dynamic-code-brand-checks/issues/19
This is required to support the new function signature for the CSP
hook, and will allow us to slot in Trusted Types support in the future.
These existed because of their `vcpkg_ci` base preset, whose goal was to
enable vcpkg-supported caching on GitHub. We now handle vcpkg caching in
the CI steps, removing the necessity for all these *_CI preset variants.
This allows us to reuse `inputs.build_preset` in the test step, and we
can do away with the Windows-specific test step since it is now almost
identical to the Linux/macOS test step.
I've left in the Windows_CI presets, because that one actually results
in a different set of compiled files compared to the
Windows_Experimental presets.
I've set up a shared vcpkg source assets cache using Azurite. By
default, it runs in read-only mode allowing anyone who builds Ladybird
to use the cache to speed up downloads of source tarballs. This should
alleviate some of the more slower vcpkgs downloads I've been seeing
lately.
CI runs on master put vcpkg in readwrite mode, updating the cache for
everyone.
For macOS, we now default to ENABLE_QT=OFF and use the same build step
as for the other platforms. We keep a single separate macOS + Qt build
step to prevent bitrotting that part of the code.
The Windows step ran in a different directory and skipped the install
step; we can just use the Linux behavior here.
This adds an overlay port for curl that adds the features required for
HTTP/3.
This is not quite compatible with the upstream vcpkg.json, because
enabling HTTP/2 makes it use the default SSL backend, which is
sectransp for macOS and schannel on Windows. These backends are not
compatible with ngtcp2. Additionally, we can not build curl with
multiple SSL backends when using ngtcp2.
I couldn't find a way to selectively disable/enable dependencies based
on what features are enabled, so I made HTTP/2 pick OpenSSL in our
overlay port. Upstream vcpkg will likely want to support wolfSSL and
GnuTLS backends for ngtcp2, so they'll be additional work to get this
into upstream.
By avoiding recompilation every time `apply_mask_bitmap()` is called, we
save ~5 ms (20ms -> 15ms) in rendering of browser channel on Discord on
my machine.
Previously if we encountered a keyword other than `fill` when parsing
`<border-image-slice` we would return a nullptr.
This could cause issues when we parse `<border-image-slice>` as part of
parsing `border-image`, for example `border-image: 100% none` would fail
as we would try parse `none` as part of the `<border-image-slice>`
instead of `<border-image-source>`.
This change makes it so that we don't consume the token and leave it to
be parsed as part of the next section of the grammar.
The attack unfortunately still slows us down, but this prevents us from
OOMing. Currently, we don't save the value of `var(--foo)` after
computing it once, so in this example, we end up computing `--prop1` 4
times to compute `--prop3`, but then we start again from scratch when
computing `--prop4`:
```css
--prop1: lol;
--prop2: var(--prop1) var(--prop1);
--prop3: var(--prop2) var(--prop2);
--prop4: var(--prop3) var(--prop3);
}
```
This should be solvable later if we update the computed values as we go.
"Arbitrary substitution functions" are a family of functions that
includes var() and attr(). All of them resolve to an arbitrary set of
component values that are not known at parse-time, so they have to be
substituted at computed-value time.
Besides it being nice to follow the spec closely, this means we'll be
able to implement the others (such as `if()` and `inherit()`) more
easily.
The main omission here is the new "spread syntax", which can be
implemented in the future.
This has an extra parameter to allow stopping at the first comma token,
which we need for var() and attr()'s "argument grammar".
Co-authored-by: Tim Ledbetter <tim.ledbetter@ladybird.org>
Custom properties are required to produce a computed value just like
regular properties. The computed value is defined in the spec as
"specified value with variables substituted, or the guaranteed-invalid
value", though in reality all arbitrary substitution functions should be
substituted, not just `var()`.
To support this, we parse the CSS-wide keywords normally in custom
properties, instead of ignoring them. We don't yet handle all of them
properly, and because that will require us to cascade them like regular
properties. This is just enough to prevent regressions when implementing
ASFs.
Our output in this new test is not quite correct, because of the awkward
way we handle whitespace in property values - so it has 3 spaces in the
middle instead of 1, until that's fixed.
It's possible this computed-value production should go in
cascade_custom_properties(), but I had issues with that. Hopefully once
we start cascading custom properties properly, it'll be clearer how
this should all work.
We often want to identify a property, but if we have a PropertyID we
don't want to have to convert it to a string to then convert it back
again. However, custom properties don't have a useful PropertyID. So,
here's a type with a verbose name.
Treating these like any other ComponentValue means not having to convert
between different types of Vector, and that we will be able to use
TokenStream to parse the "argument grammars" of arbitrary substitution
functions.
Previously the type argument in attr() could be the name of a CSS type
on its own. This has changed, and now only `raw-string`
(previously `string`) or the name of a dimension unit is allowed. Other
types and more complex grammar use the `type()` function, which we
don't yet support.
I've updated the syntax comment, but not the algorithm itself, which
will be reimplemented in a later commit.
Having <link rel=match> in here is confusing. I've also removed the uses
of `length` and `color` as types, as this is no longer valid according
to the spec.
Add `create_foo()` static methods for the missing Token::Types, and use
them in the Tokenizer. This means we slightly deviate from the spec now:
it says "create foo token... set its bar to 32", but we now just wait
and construct the Token fully-formed. But those cases are short so it
should still be clear what we're doing.
This makes it possible to construct all kinds of Token elsewhere, such
as for testing purposes.
This is according to the default user-agent style from the SVG2 spec.
In order for this to work correctly, we also have to assign width and
height to foreignObject boxes during SVG layout, since they are handled
manually by SVGFormattingContext.
Before this change, we would never apply CSS rules where the selector
had a mixed-case tag name. This happened because our rule caches would
key them on the lowercased tag name, but we didn't lowercase the tag
name when fetching things from the cache.
This uncovered the fact that the SVG2 spec has a bunch of style applied
to non-rendered elements in a way that doesn't match other browsers.
Instead of blindly following the spec, we now match other browsers.
This patch does two things:
1. Makes TreeBuilder never cross the foreignObject boundary when looking
for an appropriate insertion parent. Before this change, we would
sometimes make things inside the foreignObject DOM subtree have
layout nodes outside the foreignObject.
2. Makes foreignObject boxes participate in the anonymous wrapping of
inline-level boxes. This is particularly imporant for absolutely
positioned elements inside foreignObject, which were previously
getting incorrectly wrapped if there was any text (even empty)
preceding the abspos element.
We were already always doing this, but through an unusual mechanism:
SVG layout creates a BFC on the stack when laying out foreignObject
subtrees.
This change makes the rest of the layout system aware of this, and
also allows it to be reflected in layout dumps.
No functional changes. The main difference is renaming the cursor enum
to match the spec term `<cursor-predefined>`, which is a bit more
verbose but clearer in meaning.
Corresponds to 1a57a4025c
By the time we calculate the min-content height, the width is already
known, so we can use it to calculate the height based on the natural
aspect ratio.
This build depends on the KDE Flatpak SDK, and builds any missing
dependencies manually as source modules.
The flatpak can be built with the following command:
```sh
flatpak-builder --user --force-clean --install-deps-from=flathub \
--ccache --repo=Build/repo --install Build/flatpak \
Meta/CMake/flatpak/org.ladybird.Ladybird.json
```
After building, the flatpak can be run with:
```sh
flatpak run --user --devel org.ladybird.Ladybird
```
If there are issues launching RequestServer, the .pid and .sock files
under $XDG_RUNTIME_DIR may need removed.
```sh
flatpak run --user --command=sh --devel org.ladybird.Ladybird
rm -f $XDG_RUNTIME_DIR/Ladybird.*
```
These files are lifted from the ladybird-gtk4 repository and adapted
to work with the Qt UI port. They are installed by default on Linux, but
can be installed via a CMake option on other platforms.
Co-Authored-By: Sergey Bugaev <bugaevc@serenityos.org>
Co-Authored-By: Nicolas Ramz <nicolas.ramz@adevinta.com>
Co-Authored-By: Beckett Normington <beckett@b0ba.dev>
Co-Authored-By: Xexxa <93391300+Xexxa@users.noreply.github.com>
To support this, how we declare logical property aliases has changed.
Instead of `logical-alias-for` being a list of properties, it's now an
object with a `group` and `mapping`. The group is the name of a logical
property group in LogicalPropertyGroups.json. The mapping is which
side/dimension/corner this property is. Hopefully it's self-explanatory
enough.
The generated code is very much a copy of what was previously in
`StyleComputer::map_logical_alias_to_physical_property_id()`, so there
should be no behaviour change.
This brings parsing of grid-row-* and grid-column-* properties (and
their associated shorthands) more inline with spec.
Changes:
- Only set omitted properties for combined-value shorthands (e.g.
`grid-row: a` rather than `grid-row: a / b`) if the single value is
`<custom-ident>`.
- `[ [ <integer [-∞,-1]> | <integer [1,∞]> ] && <custom-ident>? ]`:
- Properly resolve `calc`s for `<integer>` that rely on compute-time
information.
- `[ span && [ <integer [1,∞]> || <custom-ident> ] ]`
- Allow `calc`s for `<integer>`
- Allow `<custom-ident>`
There is still work to be done to properly use these parsed values.
Gains us 46 WPT tests.
Pseudo elements are only dumped if they have computed style.
Custom properties are only dumped on their originating element, because
of how we currently store them.
Using `const` should not be warned about everywhere if it does not have
a clear advantages. Compilers are able to deduce constness in most cases
and on top of that, it's generally accepted that using `const`
communicates developer intent above all else.
(...) fallbacks"
This reverts commit 9e7b40747f. This
caused most bold headings to display as regular headings, since Arial
Unicode MS does not support other styles (as opposed to Arial).
We need a better font selection algorithm to properly support selecting
fonts for specific glyphs. Issue #2332 exists to keep track of
supporting less frequently used glyphs.
The issue with that refactor was that the same fd can be used in more
than one notifier. This reverts us back to using 2 members to track the
notifiers in play.
Cuts display list size, mostly because now we avoid lots of FillRect
previusly recorded for boxes with transparent background.
Website | DisplayList Items Before | DisplayList Items After
-------------|--------------------------|-------------------------
ladybird.org | 1431 | 1117
null.com | 4714 | 4484
discord.com | 5360 | 4992
`paint_background()` is invoked for each PaintableBox, so by avoiding
save/restore pair emitted for each call, we substantially decrease
display list size.
Website | DisplayList Items Before | DisplayList Items After
-------------|--------------------------|-------------------------
ladybird.org | 2753 | 1431
null.com | 5298 | 4714
discord.com | 6598 | 5360
POLLHUP is set when the remote end of the monitored fd is closed. There
may still be some buffered data to read from the socket, however. Some
systems do not set POLLIN in these cases. So we should just always try
to read from fds when we receive this event.
One benefit of using `poll` over `select` is that we can re-use the poll
structure list. But there's no guarantee that the underlying system will
reset the `revents` field back to 0. So let's explicitly do so.
Using ladybird_lib() adds all sorts of extra goodies to the target, such
as installation, soname setting, a custom target name, adding lagom- to
the name of the library, etc. All we need for this impl lib is the
generated sources support, so move to a bare add_library() call instead.
The previous call was also wrong, and always created liblagom-TYPE.so.
Initially ClippableAndScrollable was introduced, because we had
PaintableBox and InlinePaintable and both wanted to share clipping and
scrolling logic. Now, when InlinePaintable is gone, we could inline
ClippableAndScrollable implementation into PaintableBox.
A "namespace prefix map", see:
https://w3c.github.io/DOM-Parsing/#the-namespace-prefix-map
Is meant to also hold null namespaces:
> where namespaceURI values are the map's unique keys
> (which can include the null value representing no namespace)
Which we previously neglected. This resulted in a crash for
the updated WPT test.
To enable storing it in a hashmap. 13 is a somewhat arbitrary
value, something like 0 is not appropriate since a lot of types
return 0 as a hash for an invalid / empty state.
Previously, we always applied the enclosing clip rectangle for all paint
phases except overlays, and the own clip rectangle for the background
and foreground phases. The problem is that applying a clip rectangle
means emitting an AddClipRect display list item for each clip rectangle
in the containing block. With this change, we choose whether to include
the own clip based on the paint phase and this way avoid emitting
AddClipRect for enclosing clip rectangles twice.
By default, if multiple requests start to a newly seen origin, curl
will not wait for a connection to open to figure out if the server
supports multiplexing and will instead open a new connection for each
request (including a new TLS session and such)
This is particularly an issue for initial page load, where a complex
website could, for example, request tens of items at once (e.g. a bunch
of scripts).
We can be kinder to servers that support multiplexing by telling curl
to wait till an initial connection is established to determine if
multiplexing is supported.
On my machine and internet connection, this reduces the amount of
connections to github.githubassets.com on initial load of
https://github.com/LadybirdBrowser/ladybird from 12 to 2.
We haven't required a local copy of the ca-certificates since switching
to OpenSSL as the backend for TLS. Remove the script to download the
PEM file, and update the tests to use the system's CA certificates.
Own clip rect is alredy applied in `PaintableBox::before_paint()` for
all paintables with lines, so there's no need to do it once again in
`PaintableWithLines::paint()`.
Own clip rect is alredy applied in `PaintableBox::before_paint()` for
all image paintables, so there's no need to do it once again in
`ImagePaintable::paint()`.
Unbalanced save and restore means that effects only relevant to a
stacking context leak outside, which is never expected behavior. Having
a `VERIFY()` for that makes it much easier to catch such issues.
These were only used in SVGSVGPaintable to apply scroll frame id, which
is already handled by `before_paint()` and `after_paint()` hooks in
PaintableBox.
Unbalanced save/restore within display list items recorded for a
paintable means that some state only relevant for the paintable leaks to
subsequent paintables, which is never expected behavior.
...with inline children. This fixes an issue when we ignore abspos boxes
contained by PaintableWithLines while calculating overflow rect size.
Lots of layout tests are affected, because now PaintableWithLines has
overflow rect.
`Text/input/DOM/Element-set-scroll-left.html` is also affected and now
matches other browsers.
Some SVG presentation attributes are only supported on certain
elements. We now support these special cases for attributes and
elements that we currently have implemented.
We were always delegating hit tests to PaintableBox if a
PaintableWithLines has no fragments, which means that anonymous
containers could overlap with previous siblings and prioritize their
border box rect. Instead, the nearest non-anonymous ancestor should take
care of hit testing the children so the correct order is maintained.
To achieve this, we no longer do an early hit test in
PaintableWithLines::hit_test() if there are no fragments and default
to the later PaintableBox::hit_test() call that does take anonymous
containers into account.
Fixes the issue seen in #4864.
This way we can reuse the logic between PaintableWithLines and
PaintableBox. It also introduces the .is_positioned() check for the
children of a PaintableWithLines, which makes sure to skip positioned
child nodes since those are handled by the StackingContext.
A PaintableWithLines will first try to see if there are any fragments
that have a hit. If not, it falls back to hit testing against its border
box rect.
However, inline content is often hoisted out of its parent into an
anonymous container to maintain the invariant that all layout nodes
either have inline or block level children. If that's the case, we
should not check the border box rect of the anonymous container, because
we might trigger a hit too early if the node has previous siblings in
its original parent node that overlap with their bounds.
By ignoring anonymous nodes, we leave the border box hit testing to the
nearest non-anonymous ancestor, which correctly applies the hit testing
order to its children.
Note that the border box rect checks whether the _untransformed_ point
is inside of it, which mirrors the behavior of PaintableBox::hit_test().
We should not need to check if the result of a hit test is actually
visible for hit testing, because if it wasn't, it should not have been
returned from PaintableBox::hit_test() in the first place.
The included WPT test passes through -1 which ends up modolo'ing
to u32 max at the IDL conversion layer, resulting in an unsigned
overflow when checking bounds.
For simplicity, this requires that the setlike Foo class has a
`void on_set_modified_from_js(Badge<Bindings::FooPrototype>)` method.
This will be called after the set is modified from a generated `add()`,
`delete()`, or `clear()` method.
Now, when Skia backend context is available by the time backing stores
are allocated, there is no need to have a separate BackingStore class.
This allows us to get rid of BackingStore -> PaintingSurface cache.
Making navigables responsible for backing store allocation will allow us
to have separate backing stores for iframes and run paint updates for
them independently, which is a step toward isolating them into separate
processes.
Another nice side effect is that now Skia backend context is ready by
the time backing stores are allocated, so we will be able to get rid of
BackingStore class in the upcoming changes and allocate PaintingSurface
directly.
* Error and ErrorOr are not themelves constexpr, so a function returning
these types cannot be constexpr.
* The UDL was trying to call Utf16View::validate, which is not constexpr
itself. The compiler will actually already raise an error if a UTF-16
literal is invalid, so let's just avoid the call altogether.
Previously we could not create a `Length::ResolutionContext` using the
`for_layout_node` method if the provided node's document did not have a
layout node.
We now provide a workaround for this in the case that the
provided layout is that root layout node.
This is useful for instance if we want to create a length resolution
context when calling `NodeWithStyle::apply_style` on the root node.
When there is an active insertion point, it's necessary to tokenize
code-point-by-code-point to handle the case of document.write being
used to insert a named character reference one code point at a time.
However, when there is no insertion point defined, looking ahead at the
input and doing the matching all-at-once is more efficient since it
allows:
- Avoiding the work done in next_code_point between each code point
being matched (leading to better CPU cache usage in theory)
- Skipping ahead to the end of the match all at once, which does less
work overall than the equivalent number of next_code_point calls
(that is, skip(N) does less work than next_code_point called N times)
In my benchmarking, this provides a small performance boost (fewer
instructions, fewer cpu cycles, fewer branch misses) essentially for
free.
We were only dumping a PaintableBox' dimensions if its layout node was a
Layout::Box as well, causing us to not dump the dimensions of paintables
for inline nodes in the paintable tree.
This change fixes at least two issues:
- `update_associated_selection()` is responsible for selectionchange
dispatch, and we were incorrectly dispatching this event on ranges
that were not associated with a selection.
- `Range::get_client_rects()` was using `update_associated_selection()`
to refresh the selection state in the paintable tree for the current
range, but since a range might not be associated with a selection,
this could make the painted selection reflect the state of an
arbitrary range instead of the actual selection range.
Fixes a bug on Discord where any text typed into the message input would
get selected.
Our floating point number parser was based on the fast_float library:
https://github.com/fastfloat/fast_float
However, our implementation only supports 8-bit characters. To support
UTF-16, we will need to be able to convert char16_t-based strings to
numbers as well. This works out-of-the-box with fast_float.
We can also use fast_float for integer parsing.
By definition, the web allows lonely surrogates by default. Let's have
our string APIs reflect this, so we don't have to pass an allow option
all over the place.
To prepare for an upcoming Utf16String, this migrates Utf16View to store
its data as a char16_t. Most function definitions are moved inline and
made constexpr.
This also adds a UDL to construct a Utf16View from a string literal:
auto string = u"hello"sv;
This let's us remove the NTTP Utf16View constructor, as we have found
that such constructors bloat binary size quite a bit.
These were mostly removed in 7628ddfaf7.
This removes the few remaining cases, as no callers are providing any
non-host endianness. This is just to prevent weird API dissymmetry
between Utf16View and an upcoming Utf16String.
Much of the web requires us to allow lonely surrogates in UTF-16 data.
The default behavior to disallow such code units has not been changed
here - that will be changed in an upcoming commit.
This declaration is in the AK namespace. The real declaration is in
StringData.h, in the AK::Detail namespace. as is its implementation
in FlyString.cpp. So the declaration removed here was actually unused.
(This was confusing while implementing a UTF-16 flyweight string.)
This check technically isn't necessary in
`SVGForeignObjectPaintable::paint()` because
`PaintableWithLines::paint(context, phase);` does the check already, but
I've added it there anyway to save some debugging time if someone does
add more code there. :^)
The flake was reproducible by running the entire LibWeb test suite over
and over again with sanitizers enabled. By making the test async and run
at window `load` time instead of document `DOMContentLoaded` time, I've
not been able to reproduce the issue locally.
Ideally I was able to find the underlying cause for this bug, but for
now I'd rather run this regression test.
This stops `::before` and `::after` nodes showing up for every single
element in the inspector tree. Unfortunately there's no way for us to
detect that one of these doesn't exist in layout but has *some* style
specified for it, but that seems like a rare use case.
In particular, if a node does not have a computed style, we must still
include the "computed" object in the response. Otherwise, DevTools will
continue to display the properties from the previously selected node.
This replaces the --devtools-port flag with a --devtools flag, which
optionally accepts a port. If the --devtools flag is set, we will now
automatically launch the DevTools server.
This copies the latest generated code in tree and then removes code
generation for the WebGL rendering contexts. This is because it didn't
add much value, and we can maintain the generated output instead of
both that and the generator itself.
When a test has a `reftest-wait` class, we now wait for fonts to load
and then for 2 `requestAnimationFrame` callbacks. This matches the
behavior of the WPT runner and allows more imported WPT tests to work
correctly.
Previously, we would allow calc values such as `calc(min(1 2))`, which
would be simplified to `calc(3)` because we assumed that numbers not
separated by an operator represented a sum. We now validate that the
number of operators we see is as we would expect before collecting
these values into a sum node.
These are used by all the *-src attributes, to check if a given URL,
origin and redirect count matches a source list entry specified in
the *-src attribute's values, if it's allowed to.
This follows the implementation method that was used for the
implementation of ISO8601 parsing for Temporal in LibJS. Doing it this
way allows us to have state transactions, and thus pick out individual
parse nodes that the specification steps want to use.
We were failing to actually climb up the containing block chain,
causing this API to infinite loop for anything but the most
trivial cases.
By fixing the loop structure, we also make a bunch of the already
imported WPT tests pass. :^)
The primary purpose of these is to add bounds checking to older OpenGL
API calls that take arbitrarily sized buffers, but don't know the size
of the buffer and thus rely on the application being certain the buffer
is large enough.
Since these API calls are exposed to arbitrary JS which can make
arbitrarily sized buffers, it is not safe to use the non-robust
variants, as we cannot know the size of the buffer ahead of time, nor
the amount of data required by the API call.
The robust variants provided by ANGLE adds a buffer size parameter,
where it'll calculate the amount of data it needs for that API call
for us and return an error if it's bigger than the given buffer size.
Credit to https://github.com/s41nt0l3xus for finding this during a CTF
and providing a write up that exploits this.
See: 92efbaed6c/gpnctf-2025/WebGL-bird
Add OffscreenCanvas to TexImageSource and CanvasImageSource.
Implement all the necessary features to make it work in all cases where
these types are used.
This implements the basic interface, classes and functions for
OffscreenCanvas. Many are still stubbed out and have many FIXMEs in
them, but it is a basic skeleton.
Factor out canvas parsing algorihtm for CanvasRenderingContext2DSettings
from JS::Value. This was only used in one place but needs to be usable
from other places too in the future.
Previously we would never get a valid `consistent_type` as we were
trying to make the node types consistent with the initial empty type
which isn't possible.
Gains us 7 WPT tests.
For the AO defined in the URL specification, in the case the
domain does not match against the PSL, we should be returning
the TLD. This fixes a crash for a bunch of WPT tests using the
Document.domain setter when the test is being served by WPT
locally.
We should be doing similar logic in registrable_domain, but that
unfortunately runs into some other issues, so just leave a FIXME
for now.
It is confusing to have both URL::Host::public_suffix and
URL:get_public_suffix, both with slightly different semantics.
Instead, use PublicSuffixData for cases that just want a direct
match against the list, and URL::Host::public_suffix in LibWeb
land as the URL spec defined AO.
The color picker implementation allows for live updates to the input
element until the final color is confirmed by the user, but previously
it was marked as closed immediately after the first update.
I believe this is in the specification since the spec technically
requires passing through a valid unicode string. However, our
implementation already handles a non valid unicode string, and will
do the replacement character substitution.
All the file-based tests left out build, but they all fail at run time
with the error "No such file or directory" or a Core::File-based
assertion failure for the Benchmark test
The libjxl port is required to add the `msvc-remove-libm` patch.
Otherwise LibGfx attempts to link with 'm.lib' which is not valid
for MSVC as the CRT bundles math functions implicitly unlike on Unix
The `muted` content attribute should only affect the state of the
`muted` IDL property when the media element is first created. The
attribute should have no dynamic effect.
Opaque origins are meant to be unique in terms of equality from
one another. Since this uniqueness needs to be across processes,
use a nonce to implement the uniqueness check.
Documents created via DOMParser.parseFromString()
are parsed synchronously and do not participate in the
browsing context's loading pipeline.
This patch ensures that if the document has no browsing context
(i.e. was parsed via DOMParser),
its readiness is set to "complete" synchronously.
Fixes WPT:
domparsing/xmldomparser.html
This is wrong and leads to invalid numbers. We've been kind of
unfortunate in not catching this earlier because we skipped the key
validation part.
Many tests would fail with the next commits if this wasn't fixed.
There is no need to have `RSAPrivateKey`, `RSAPublicKey`, `ECPrivateKey`
and `ECPublicKey` to be templatize to utilize different implementation
of numbers.
Fix various TODO by checking the validity of ECDSA and ECDH keys when
they are imported. There are no checks in place for raw import because
the spec doesn't contemplate them yet.
Also add some internal tests since WPT doesn't seem to provide them.
The opcode may have last been accessed by
block_satisfies_atomic_rewrite_precondition, which would set it to a
state that no longer exists.
Set the state to the correct one unconditionally to ensure we're looking
at the right value.
Fixes#5145.
Partly corresponds to this which adds numbering to some substeps:
d426109ea1
This is not a complete review of all the spec steps to check that
they're up to date - I just updated the parts affected by that above
commit, and then added some `->` marks to places I noticed it was
missing. There may be actual spec differences still.
An actual change that needs tackling later is that `handle_in_head()`'s
branch for `<template>` has some new steps related to custom element
registries.
Corresponds to dad91f49ef
The spec text doesn't actually require any changes from us, but I
noticed we were incorrectly calling `is_shadow_including_ancestor_of()`
instead of `is_shadow_including_inclusive_ancestor_of()`, so that's
fixed.
Previusly the implementation only was serializing PseudoElements if they
were the last element in the CompoundSelector. This caused bugs on
Javascript code that referenced their selectorText, where it would be
wrong.
This implements enough of the Geolocation spec that it is now possible
for websites to retrieve the current geo position or try to watch for
updates (which currently never happen).
As it stands now, it only returns a single emulated position that points
to San Francisco.
Documents created by DOMParser and fragment documents do not
have an origin set on the document by the spec. These documents
also happen to never become fully active.
By properly implementing the steps for the <img> element to only
update the image data for documents which are fully active, this
fixes a crash for img elements in these types of documents.
Unfortunately, this is not a full fix for the microtask queue case.
This is because it seems possible for node document for an <img>
element to be changed during the microtask queue for that document.
It is not clear to me how this can be fixed in a nice way.
When AK is a shared library, the flag should be applied to the link
of the dll. When it's a static library, we need to apply it to the
executable that links against it instead.
Co-Authored-By: ayeteadoe <ayeteadoe@gmail.com>
The CI runs are supposed to upload test dumps for failed LibWeb tests as
artifacts. However, the path for the artifact upload was wrong, it
likely regressed in 9a5b31ccd1.
Previously we would incorrectly map these in
`CSSStyleProperties::convert_declarations_to_specified_order`, aside
from being too early (as it meant we didn't maintain them as distinct
from their physical counterparts in CSSStyleProperties), this meant
that we didn't yet have the required context to map them correctly.
We now map them as part of the cascade process. To compute the mapping
context we do a cascade without mapping, and extract the relevant
properties (writing-direction and direction).
As conflict resolution depends on whether the property was set directly
or via a shorthand, we have to store the non-expanded values in the
resolved keyframe properties.
When we try to insert a disallowed (non-nested) statement into a
CSSGroupingRule we should throw a `HierarchyRequestError` as it being
disallowed is a "constraint specified by CSS". Previously we would rely
on `Parser::is_valid_in_the_current_context` and throw a Syntax error.
There are more constraints to be implemented.
This commit implements the fallback to the documents fallback base url
if the href of the first base element is a data or javascript url.
Additionally the frozen base url is set, if a base element becomes the
first base element with an href content attribute because the previous
one got removed.
`collapse_auto_fit_tracks_if_needed()` had a check that does collapsing
only if auto-fit is used like
`grid-template-columns: repeat(auto-fit, 1px);`, and it didn't work for
valid cases when `repeat(auto-fit)` is placed in the middle of
definition like `grid-template-columns: 1px repeat(auto-fit, 1px) 1px;`.
Spec says that definite grid container size should be used as free space
so there's no need to use `get_free_space()` that does iteration over
tracks and subtracts definite sizes from available space.
When building a static liblagom-ak.a, the delayload link option gets
dropped on the floor if it's a PRIVATE link option. Use an interface
one instead.
This fixes the TestDelayLoadWindows unit test in static windows
builds.
Now we won't be building both debug and release for all ports when
using a release, distribution, or sanitizer preset.
Eventually we can use this to build all our ports with clang-cl.exe.
That doesn't work at all out of the box, and needs a bunch of extra
legwork. Likely legwork for every port we build.
Having the pull_request 'labeled' event trigger the main CI is much too
impactful, since it cancels running jobs and does not start anything if
the label is anything else than 'windows'. Let's go with a different
approach and put the Windows CI job in a separate workflow.
How this works:
* Jobs are only run if the 'windows' label is present on the PR.
* If a PR is opened or updated, existing jobs are canceled.
* If a PR is (un)labeled, existing jobs are only canceled if the label
was 'windows'. Other labels cause the job to be rescheduled.
As far as I can see, there's no way to prevent the job from being
rescheduled when labels other than 'windows' are being added or removed.
However, by not canceling the existing Windows job, we can try to create
a cache so the next run will be much quicker.
Each matrix item now defines whether it is enabled, and if not, the job
conditionally disables itself. Apparantly we cannot use expressions in
`matrix.exclude`, but it should work in the items' definitions.
This has the added benefit that this makes the job show up as "skipped",
which could serve as a hint that it could be run on a PR.
Our CI matrix now includes Windows if the 'windows' label is added to
the PR. The job still takes too long to include it for every PR, but it
is certainly useful to have it run on Windows-specific PRs and PRs that
might break Windows builds.
`getComputedStyle()` for grid tracks returns style value produced during
layout. This is needed to return resolved track sizes values which are
thrown away after layout is done. Now GFC produces more correct style
value by not ignoring grid line names.
Reimplements `grid`, `grid-template`, `grid-template-rows`, and
`grid-template-columns` in a way that uses a separate function for each
grammar rule defined in the specification. This change results in many
additional passing tests from the already imported WPT suite. Most of
the remaining test failures are related to incorrect serialization of
grid properties.
Any optional or nullable attribute will end up in an `if/else` branch
when we collect the attribute values, and this is inherently
incompatibly with an `auto {attr}_wrapped = ...` expression. Define the
variable as an `JS::Value` before generating the wrap statement so we
can properly support `toJSON()` for an attribute like:
readonly attribute double? altitude;
In `InlineLevelIterator`, whenever we call `skip_to_next()` and enter a
node with box model metrics, we could potentially accumulate leading and
trailing metrics. This lead to a weird situation where an element with
`display: inline-block` could adopt the leading metrics of an inline
element that follows it, since we perform the call to
`add_extra_box_model_metrics_to_item()` too late.
Move `skip_to_next()` down so it no longer interferes with the `Item`
we're creating.
The test expectation for
`atomic-inline-with-percentage-vertical-align.html` is updated, although
neither the old nor new results are 100% accurate since either box jumps
one pixel to the right.
When expanding "required line breaks", we now write directly into the
final StringBuilder instead of doing a pass of Vector remove/insert
operations first.
This removes a hot profile item on https://serpapi.com/
There are multiple things happening here which are interconnected:
- We now use AbstractElement to refer to the source of a counter, which
means we also need to pass that around to compute `content`.
- Give AbstractElement new helper methods that are needed by
CountersSet, so it doesn't have to care whether it's dealing with a
true Element or PseudoElement.
- The CountersSet algorithms now walk the layout tree instead of DOM
tree, so TreeBuilder needs to wait until the layout node exists
before it resolves counters for it.
- Resolve counters when creating a pseudo-element's layout node. We
awkwardly compute the `content` value up to twice: Once to figure out
what kind of node we need to make, and then if it's a string, we do
so again after counters are resolved so we can get the true value of
any `counter()` functions. This will need adjusting in the future but
it works for now.
This is one of those cases where the spec says "element" and
means "element or pseudo-element". The easiest way to handle both is to
make these be free functions that take an AbstractElement, and then
give AbstractElement some helper methods so that the caller doesn't
have to care which it's dealing with.
There are some FIXMEs here because PseudoElement doesn't have a
CountersSet yet, and because the CountersSet currently uses a
UniqueNodeID to identify counter sources, which doesn't support
pseudo-elements.
We were calculating the scroll delta based on the last known mouse
position, even if that position ventured far beyond the scroll bar's
rect. This caused weird behavior such as scrolling when the mouse was
clearly not on the scrollbar.
This reworks the scrollbar logic to use the mouse's absolute position
instead of a delta, and to always calculate and set the absolute scroll
offset. This makes it much easier to reason about the scrollbar's
position, plus we don't need the last mouse position anymore.
As far as I can tell, our scroll bar behavior now closely resembles
Firefox' behavior.
We were seeing lower ccache hitrates using Blacksmith's cache, and after
some investigation it turned out that actions running on our `master`
branch were pulling the caches from PRs. Blacksmith is looking into
this - for now revert to GitHub's cache until the issue is resolved.
These use the `readarray` command which isn't available in the older
version of Bash available on macOS. However, they're also not needed on
macOS, so let's skip them entirely.
Ref: https://github.com/LadybirdBrowser/ladybird/issues/5118
Gfx::Bitmap only supports a bit depth of 8, therefore we refused to
load AVIF images which didn't have this bit depth.
However, we can tell the libavif decoder to reduce the output depth by
setting avifRGBImage.depth to 8. This allows us to support any input
depth.
Makes images load on https://www.ikea.com/ which uses Cloudflare Images
to re-encode their images to 16-bit AVIF.
This list we are iterating over is removed from when there are
no more GC references to an ESO. This may be triggered by a GC
allocation. Since
UniversalGlobalScopeMixin::notify_about_rejected_promises performs
GC allocations (by, for example, allocating a GC function), it
is not safe to simply iterate over this list.
Fix this by taking a strong reference to all registered ESOs by
copying them across to a RootVector before iteration.
Fixes: #4652
Sets up the basic infrastructure for the audio node graph and
implements the AudioNode `connect()` method with its related overides.
AudioNodes store vectors of AudioNodeConnections and
AudioParamConnections to represent links between nodes.
`TypedArray` objects need to know their own constructor objects to allow
copying. This was implemented by storing a function pointer to the
`Intrinsic` object's method which returns the constructor object.
The problem is that function pointers aren't polymorphic, we can't
legally just cast e.g. a `Derived* (*ptr)(void)` to `Base*
(*ptr)(void)` (this is why the code needed a `bit_cast` to even
compile). But this wasn't actually a problem in practice because their
ABIs were the same. But with pointer authentication (Apple's `arm64e`
ABI) this signature mismatch becomes a hard failure and crashes the
process.
Fix this by adding a virtual function that returns the intrinsic
constructor (actually, a `NativeFunction`, as typed arrays constructors
don't inherit from the base `TypedArray` constructor) instead of the
function pointer.
With this, test-js passes and Ladybird launches correctly when built
(with a lot of vcpkg hacks) for arm64e.
Github Actions just updated windows-2025 to LLVM 20, which is the
minimum version required for us to build and run tests with sanitizers
Now that we've added support, enable the Sanitizer build in CI.
Without this annotation, the MSVC ABI is reluctant to apply EBO even
in cases that are basically guaranteed on the Itanium ABI by modern
compilers. This fixes an UBSAN issue with Variant on Windows.
Instead, porting over all users to use the newly created
Origin::create_opaque factory function. This also requires porting
over some users of Origin to avoid default construction.
As part of the effort of removing the default constructor of
Origin, since document has the origin set after construction,
port Document's origin over to an Optional<Origin>.
This exposes that we were never setting the origin of the document
during fragment parsing. For now, to maintain previous behaviour,
let's explicitly set it to an opaque origin.
Instead, we can just use the scope type to determine if a scope is a
function scope.
This fixes using `this` for parameter default values in arrow functions
crashing. This happened by `uses_this_from_environment` was not set in
`set_uses_this`, as it didn't think it was in a function scope whilst
parsing parameters.
Fixes closing modal dialogs causing a crash on https://www.ikea.com/
No test262 diff.
Reverts the functional part of 08cfd5f, because it was a workaround for
this issue.
All other viewport-related dimensions are referenced to by 'viewport',
so let's rename the member that stores the viewport size to prevent
further confusion.
Corresponds to d3effb701c
What a "fixed position container" is isn't clear to me, and we don't
seem to use that elsewhere, so I've left the steps using that as FIXMEs
for now.
There's no test coverage for this in WPT yet and I'm not confident
enough in the specific behaviour to write one myself. So, waiting on
https://github.com/web-platform-tests/wpt/issues/53214
For every invocation of `::before_paint()` and `::after_paint()`, we
would reach into the node's computed values to determine its visibility.
Let's just do this once during construction of the paintable instead,
since this was showing up in profiles.
In `StackingContext::paint_descendants()`, we don't need to obtain the
computed values nor the Z-index of a child unless certain other
conditions are true. Let these conditions short-circuit before actually
reaching into the computed values, which shows up in profiles.
This commit removes the /J flag when compiling with clang-cl. The /J
flag changes the default char type from signed char to unsigned char
which is the opposite of what we want. Now char will be signed, which is
the default on msvc and what we set on linux.
This commit increases compilation speed when using clang-cl. It also
decreases object size as well as adds -fstrict-aliasing to match the
default on linux. The linker option added is not recognized by link.exe
so we enable lld-link by default, which will also increase compilation
speed by itself, and allow for LTO.
FIXME: Rendering modifications to a list is sometimes not pixel-perfect
vs. reference (likely a bug). After this is fixed, screenshot
tests from this commit will likely fail + can be moved to
ref tests.
The following tests also expose bugs before this PR:
- Layout/input/ol-render-item-values.html: negative ordinal values
- Layout/input/ol-render-deep-hybrid-list-item-list.html: ordinals
deep into the list owner subtree
`Element::ordinal_value` is called for every `li` element in
a list (ul, ol, menu).
Before:
`ordinal_value` iterates through all of the children of the list
owner. It is called once for each element: complexity $O(n^2)$.
After:
- Save the result of the first calculation in `m_ordinal_value`
then return it in subsequent calls.
- Tree modifications are intercepted and trigger invalidation
of the first node's `m_ordinal_value`:
- insert_before
- append
- remove
Results in noticeable performance improvement rendering' large
lists: from 20s to 4s for 20K elements.
Before:
`is<HTMLOLListElement>` and other similar calls in this commit
are resolved to `dynamic_cast`, which incurs runtime overhead
for resolving the type. The Performance hit becomes apparent
when rendering large lists. Callgrind analysis points to a
significant performance hit from calls to `is<...>` in
`Element::list_owner`.
Reference: Michael Gibbs and Bjarne Stroustrup (2006) Fast dynamic
casting. Softw. Pract. Exper. 2006; 36:139–156
After:
Implement inline `fast_is` virtual method that immediately
resolves the type. Results in noticeable performance improvement
2x-ish for lists with 20K entries.
Bonus: Convert starting value for LI elements to signed integer
The spec requires the start attribute and starting value to be
"integer". Firefox and Chrome support a negative start attribute.
FIXME: At the time of this PR, about 134 other objects resolve
`is<...>` to `dynamic_cast`. It may be a good idea to coordinate
similar changes to at least [some of] the ones that my have impact
on performance (maybe open a new issue?).
The spec assumes that we only store values against expanded longhands,
there are however limited circumstances where we store against
shorthands directly in addition to the expanded longhands. For example
if the value of the shorthand is unresolved we store an
UnresolvedStyleValue against the shorthand directly and a
PendingSubstitutionStyleValue against each of the longhands.
This commit updates the logic so that in the case we serialize a
shorthand directly we should also mark it's longhands as serialized to
avoid serializing them separately.
This also avoids the scenario where we tried to create and serialize a
ShorthandStyleValue with PendingSubstitutionStyleValue longhands, so we
can remove the check and related FIXME for that.
Fixes at least three WPT test that were previously timing out:
- html/semantics/embedded-content/media-elements/error-codes/error.html
- html/semantics/embedded-content/media-elements/location-of-the-media-resource/currentSrc.html
- html/semantics/embedded-content/the-video-element/video_crash_empty_src.html
Skia's SkColorSpace::Make() doesn't seem to like ICC v2 profiles
containing table-based L* transfer curves. Now we use
skcms_ApproximateCurve() to convert these tables to parametric curves
that Skia supports in case Skia's SkColorSpace::Make() fails.
For zlib is not necessarily an error state but the web standards do not
support this feature and the WPT tests explicitly check for this case
to be handled as an error.
If we find ourselves in a situation where zlib can't make any progress,
we don't have any more data to feed in and no output has been produced,
we need to raise an error as the compressed data is incomplete.
This used to lead to an infinite busy loop where we keep calling
zlib to decompressed but is not able. This causes the promise on the
read side of the transformer to never fulfill.
This gives us at least 24 more WPT tests :)
GCC 16 trunk has started diagnosing calls to `__has_trivial_destructor`
if the destructor is inaccessible. At the same time, they added a
Clang-compatible `__is_trivially_destructible` built-in trait, so let's
just use that.
We run these steps when focusing with a mouse pointer, and it seems
sensible to implement the same behavior for keyboard navigation so we
e.g. correctly unwind the previous focus chain.
Once an event loop manager is installed, we want to be sure we only use
that manager in the current process going forward. Mixing event loop
implementations can only cause problems.
More to the point, this ensures that we have installed the AppKit or Qt
event loop managers before the first time EventLoopManager::the() is
invoked. Now that we defer this installation until we know whether we
are running headlessly, we want to be extra sure that we have done so
before any services using the event loop have started.
When we have an unresolved value for a shorthand (e.g. `border-style:
var(--border-style)`, `keyframe_values` will contain an
`UnresolvedStyleValue` for the shorthand and
`PendingSubstitutionStyleValue`s for each of it's longhands.
When we come across the shorthand's `UnresolvedStyleValue` we will
resolve the value and set all of the relevant longhands.
If the longhand's `PendingSubstitutionStyleValue` was processed after
(which isn't always the case as the iteration order depends on a
HashMap) would overwrite the correctly resolved longhand.
To avoid this we just skip any `PendingSubstitutionStyleValue`s we come
across and rely on the resolution of the shorthand to set those
properties.
Resolves a crash @tcl3 was experiencing when adding a new
"border-image-repeat" property.
Without these fixes, RequestServer was likely to crash if the client
crashed (e.g. WebContent). This was because there was no error handling
for when writing to the client failed.
This is particularly an issue because RequestServer has shared
instances, so it would then crash every other client of RequestServer.
Then, because another RequestServer instance is not currently spun up,
it becomes impossible to start any clients that need a RequestServer
instance. Recreating a RequestServer should also be handled, but that's
not in the scope of this change.
We can tell curl that we failed to write data to the client and that
the request should be aborted by returning `CURL_WRITEFUNC_ERROR` from
the write callback.
It is also possible for requests to be destroyed with buffered data,
which is normal to happen if the client disappears
(i.e. ConnectionFromClient is destroyed) or the request is cancelled by
the client. We log a warning in case this is not expected, to assist
with debugging related issues.
We generated `PaintableFragment`s with a start and length represented in
UTF-8 byte offsets, but failed to consider that the offsets in a
`DOM::Range` are actually expressed in UTF-16 code units.
This is a bit of a mess: almost all web specs use UTF-16 code units as
the unit for indexing into text nodes, but we almost exclusively use
UTF-8 in our code base. Arguably the best thing would for us to use
UTF-16 everywhere as well: it prevents these mismatches in our
implementations for the price of a bit more memory usage - and even that
could potentially be optimized for.
But for now, try to do the correct thing and lazily allocate UTF-16 data
in a `PaintableFragment` whenever we need to index into it or if we're
asked to determine the code unit offset of a pixel position.
When clicking on a glyph or starting a selection on it, we would use the
glyph's offset/index as the position which represents the left side of
the glyph, or the position between the glyph and the glyph before it.
Instead of looking at which glyph is under the mouse pointer, look at
which glyph boundary is closer. Now, if you click to the right of a
glyph (but still on that glyph), it correctly selects the next glyph's
offset as the position.
We were passing in byte offsets instead of UTF-16 code unit offsets,
which could lead to crashes if the offsets found exceeded the number of
code units in text fragments on the page.
Fixes#4908.
Co-authored-by: Tim Ledbetter <tim.ledbetter@ladybird.org>
The text track processing model would previously spin forever waiting
for the track URL to change. It would then recursively invoke itself
to handle the new URL, again entering the spin loop. This meant that
tracks could easily cause event loop hangs.
We now have an observer system to be notified when the track state
changes instead. This lets us exit the processing model and move on.
We have a test for localStorage that repeatedly adds new items until the
quota is exceeded:
`webstorage/storage_local_setitem_quotaexceedederr.window.html`.
This test becomes significantly slower when localStorage is backed by
SQL database. Let's disable database usage in test mode for now, as this
test is likely to be flaky on CI due to timeouts.
This change follows the pattern of our cookies persistence
implementation: the "browser" process is responsible for interacting
with the sqlite database, and WebContent communicates all storage
operations via IPC.
The new database table uses (storage_endpoint, storage_key, bottle_key)
as the primary key. This design follows concepts from the
https://storage.spec.whatwg.org/ and is intended to support reuse of the
persistence layer for other APIs (e.g., CacheStorage, IndexedDB). For
now, `storage_endpoint` is always "localStorage", `storage_key` is the
website's origin, and `bottle_key` is the name of the localStorage key.
In upcoming changes StorageBottle will own pointers to GC-allocated
objects, so it needs to be a GC-allocated object itself to avoid
introducing more GC roots.
The "longhands" array is populated in the code generator to avoid the
overhead of manually maintaining the list in Properties.json
There is one subtest that still fails in
'cssstyledeclaration-csstext-all-shorthand', this is related to
us not maintaining the relative order of CSS declarations for custom vs
non-custom properties.
This makes it easier to ensure everyone is using the same version of
Swift when building the project, especially for CI environments.
`swiftly install` will automatically read this file and install the
specified version if it is not already installed. It also tells swiftly
what version to use for the project, independent of the global default
version.
Previously this function's return value was not reliable, as available
data on the underlying socket did not necessarily translate to available
application data on the TLS socket.
url() has some limitations because of allowing unquoted URLs as its
contents. For example, it can't use `var()`. To get around this, there's
an alternative `src()` function which behaves the same as `url()` except
that it is parsed as a regular function, which makes `var()` and friends
work properly.
There's no WPT test for this as far as I can tell, so I added our own.
This function is bogus, but it's still getting called a lot during media
query evaluation, so let's at least cache the font instead of recreating
it every single time.
Instead, collect a list of all the elements with content-visibility:auto
after layout.
This way we can skip the tree traversal when updating the rendering.
This was previously eating up ~300 µs of the 60fps frame budget on
our GitHub repo pages (and even more on large pages).
In particular, we need to defer creating the process manager until after
we have decided whether or not to create a UI-specific event loop. If we
create the process manager sooner, its event loop signal registration
does not work, and we don't handle child processes exiting.
You would have to just know that you need to define the constructor with
this declaration. Let's allow subclasses to define constructors as they
see fit.
This is causing errors on the WPT runner, which does not have a display
output. To do this requires shuffling around the Main::Arguments struct,
as we now need access to it from overridden WebView::Application methods
after construction.
As we now are only officially supporting the Ninja generator for
Windows, the old preset structure can now be simplified. Also, we
now follow the naming conventions of the non-hidden presets.
Now that headless mode is built into the main Ladybird executable, the
headless-browser's only purpose is to run tests. So let's move it to the
testing directory and rename it to test-web (a la test-js / test-wasm).
We currently create a separate headless-browser application to serve two
purposes:
1. Allow headless browsing to take a screenshot of a page or print its
layout tree / internal text.
2. Run the LibWeb test framework.
This patch migrates (1) to the main Ladybird executable. The --headless
flag enables this mode. This matches the behavior of other browsers, and
means we have one less executable to ship at distribution time.
We want to avoid creating too many AppKit / Qt facilities in headless
mode. So this involves some shuffling of application init to ensure we
don't create them until after we've parsed the command line arguments.
Namely, we avoid creating the NSApp in AppKit and QCoreApplication in
Qt. Doing so also requires that we don't create the application event
loop until we've parsed the command line as well, because the loop we
create depends on whether we're creating those UI facilities.
We currently create web views through the headless Application, so that
the Application can store the views for easy iteration/management. We
would like to move HeadlessWebView into LibWebView to make headlessness
a feature of the primary Ladybird binaries. In order to do so, we need
to remove this indirection, as we won't have this test-only Application
class in Ladybird.
I left this here originally thinking that black and ruff are compatible,
so either could be used as a local formatter. But it turns that while
code formatted with ruff will be unchanged by black, the reverse is not
always true. So let's just enforce using ruff.
With the Metal backend, glFlush flushes the command buffer, but doesn't
wait for the commands to be scheduled on the GPU.
eglWaitUntilWorkScheduledANGLE does wait, hence the name.
This fixes flickering on Rive animations rendered with WebGL.
This will be the returned egl configuration attribute for
EGL_BIND_TO_TEXTURE_TARGET_ANGLE once we transition to using the
Metal ANGLE backend directly.
We could use flake8 for linting, but ruff is compatible with black
formatting out-of-the-box. It also seems to catch more than flake8,
such as unnecessary f-strings.
When a ::before or ::after pseudo-element covered an anchor element
events were not successfully sent to the underlying anchor.
This fix allows before and after pseudo-elements
to be dispatched correctly.
Fixes#5020
Removes the associated FIXME in match_an_audio_or_video_type_pattern().
Sniffing process is a simplified version of the full spec, as it only
checks one frame of the mp3. To fully align with the spec, it would
also have to check a second frame by calculating frame size as
described in the spec.
Some instances of CSSStyleProperties can lack an owner node, for
instance the return value of a call to `window.getComputedStyle` where
the specified pseudo-element is invalid. In this case we should treat
the computed style as empty, as there is no node to compute the style
for.
Previously we would just throw it away and construct a new (empty) one
when required. This doesn't work as any existing references to the old
instance will contain out of date information. Now we retain and update
the existing instance instead.
Resolves a FIXME in `CSSRuleList::insert_a_css_rule`. Gets us a bit
closer to passing https://wpt.live/css/cssom/at-namespace.html but that
requires more work around parsing of selectors with namespaces (namely
disallowing use of undeclared selectors), which I have added a FIXME
for.
The spec requires us to store properties in their shorthand-expanded
form and in the "specified" order, removing duplicates prefering based
on "cascading order". We already enforced this in `set_property` but
not at creation time (e.g. in stylesheets) or in `set_css_text` (e.g.
updating style attribute).
This commit enforces the spec requirements at all the relevant points.
We no longer include logical properties in the return value of
`getComputedStyle` as they are mapped to their physical equivalents in
`StyleComputer::for_each_property_expanding_shorthands`, but resolving
that requires a relatively large rework of how we handle logical
properties, (namely moving when we map them to their physical
equivalents from parse time to style computation time).
This also exposes two false positive tests in
wpt-import/css/cssom/border-shorthand-serialization.html related to us
not yet supporting the border-image css property.
This change implements following behavior defined in the spec:
https://html.spec.whatwg.org/multipage/web-messaging.html#examples-5
> The start() method, whether called explicitly or implicitly (by
setting onmessage), starts the flow of messages: messages posted on
message ports are initially paused, so that they don't get dropped on
the floor before the script has had a chance to set up its handlers.
Now we don't read bytes from the underlying transport socket until the
message port transitions to the enabled state. This required the
following places to explicitly enable the message port, because now,
when it actually matters, we must do so, or otherwise sent messages will
get stuck:
- `onmessage` attribute setter in DedicatedWorkerGlobalScope, because
it implicitly sets the onmessage handler for the worker's underlying
port.
- Stream API operations where the message port enabling steps were
previously marked as FIXMEs.
We assume elsewhere that any abspos element's containing block must be
some kind of Layout::Box, so let's enforce that when deciding if a box
can be such a container.
This fixes a bad downcast on https://serpapi.com/
By default, matrix jobs generate a name for themselves by concatenating
their job name and all matrix variables into a big string. Changing the
runner labels causes the job name to change, which means we need to go
into GitHub and change the required checks since those are name-based.
Give all matrix workflows an explicit, more stable name.
The GitHub-provided runner frequently times out and is plain slow most
of the time. And since Blacksmith does not yet offer macOS runners,
let's use our self-hosted runner that is currently idle most of the time
(when it's not running JS benchmarks).
This is now always a JSON array of runner labels, inside a string. We
need it to be a string because `workflow_call` works with inputs that
do not natively support an array type.
No functional changes.
An early return was occurring between the emission of
PushStackingContext and PopStackingContext, resulting in a
PushStackingContext without a corresponding PopStackingContext in the
display list, which caused broken painting.
Fixes black screen on Discord login page.
`BlockFormattingContext::compute_width()` stores the left and right
margins in the layout state at the very end of the function. However,
before doing so, it calls `FormattingContext::calculate_inner_width()`
which ends up calling `FormattingContext::calculate_stretch_fit_width()`
if the current box has `width: fit-content`.
Due to this, `calculate_stretch_fit_width()` would always see the
margins from the layout state as zero and therefore not take them into
account. Subsequently, the calculated width ended up being wrong.
Saving margins on the layout state earlier, before calling
`calculate_inner_width()`, makes sure that the width is calculated
correctly.
An earlier variant of the commit following this one introduced a
regression for the behavior tested here, but did not fail any in-tree
tests. So lets add an explicit regression test to make that easier to
catch in the future.
In a clean environment, building only headless-browser neglected to
install the resource files needed to run the browser. These were only
installed by the main Ladybird target.
Based very scientifically on what's listed here:
https://harfbuzz.github.io/what-does-harfbuzz-do.html
I've moved the code into LibGfx because including a HarfBuzz header
directly from LibWeb is a little unpleasant. But the Gfx::FontTech enum
follows the CSS definitions for font features for simplicity.
TrueType collections are supported. SVG and Embedded OpenType are not,
but they're not widely supported by other browsers so that's fine.
Most of the features are completely supported by HarfBuzz, so we can
just return true. Graphite support is optional (and it appears we use a
build of HarfBuzz without it) but there's a define we can check.
Incremental Font Transfer is a whole separate thing that we definitely
don't support yet.
A couple of differences from before:
- Only the fixed set of strings are allowed. Some formats can only be an
ident (eg, svg).
- We don't allow these foo-variations values in ident form.
- The comparison is done case-insensitively. It's unclear if this is
more or less correct, but as most things in CSS are insensitive,
including idents, it makes sense that these would be too.
...of Array. If array has simple storage, which implies that attributes
of all indexed properties are default, and newly added property also
has default attribute, we can do a fast path and skip lots of checks
that happen in `Object::internal_define_own_property()`.
The install command was failing with 'Namespace object has no
attribute args' error because the argument parser for the
install command was missing the 'args' parameter that allows
passing additional arguments to the build system.
This fix adds the missing argument to match the behavior of
other commands like build, run, and debug.
We previously checked the cell's computed values for the border-collapse
property, but a cell is only in separated-borders mode if the table has
border-collapse set to separate. Curiously in some other placed where
this mode is checked we already did the correct thing.
For getComputedStyle(), we must return an absolute URL for image style
values. We currently return the raw parsed URL.
This fixes loading the marker icons on https://usermap.serenityos.org.
When marking a part of the layout tree for rebuild, if the subtree root
that we're marking has an anonymous parent, we now mark from the nearest
non-anonymous ancestor instead.
This ensures that subtrees inside anonymous wrappers don't just get
duplicated (i.e recreated but inserted instead of replaced).
If array has packed index property storage without holes, we could check
if indexed property is present simple by checking if it's less than
array's length.
Makes the following program go 1.1x faster:
```js
function f() {
let array = [];
for (let i = 0; i < 3_000; i++) {
array.push(i);
}
for (let i = 0; i < 10_000; i++) {
array.map(x => x * 2);
}
}
f();
```
This one is required to cover the case when new empty elements are
introduced by assigning to element with index > length, like:
```js
var x = [];
x[0] = 1;
x[2] = 2;
```
Static analysis tool cppcheck reports that
LibWeb/Internals/Internals.cpp:65 has a variable named
hit_tеsting_result with a Cyrillic e in the 'testing' portion of the
name, instead of the more common ASCII e. No other use of Unicode
characters for identifiers in the Ladybird code base noted by cppcheck,
so assuming that this is unintended use.
...by avoiding `CreateListFromArrayLike` in cases when we could directly
use elements of underlying object's indexed properties storage.
Makes this program go 2.1x faster:
```js
function target(a, b, c) {
return a + b + c;
}
const args = [1, 2, 3];
let result = 0;
(function() {
for (let i = 0; i < 10_000_000; i++) {
result += target.apply(null, args);
}
})();
```
A change to a counter "definition" propagates to all subsequent
instances of this counter: descendents, siblings and their descendents
(the "next tree slice"). Rebuilding the layout tree (from the parent
node) covers at least the "next_tree_slice".
Some callers need the raw nul-terminated c-string in this callback, to
pass to some other ICU method. But other callers will want a StringView.
We know the length already in `icu_string_enumeration_to_list`, so let's
just pass it along to avoid `strlen`.
We were manually doing this for the calendar keyword, and would need to
do so for the collation keyword as well. I wasn't aware of this API
originally, so let's start using it.
For example, button inputs shouldn't have a cursor
displayed in their text since they're not editable,
and are not meant to be editable.
Fixes#4140
Co-authored-by: Sam Atkins <sam@ladybird.org>
On Windows, ICU does not look at the TZ environment variable at all. So
to support changing time zones in test-js, let's set ICU's default time
zone directly.
Note that we no longer deal with "null" time zone strings. We just cache
whatever ICU thinks is the current time zone before attempting to change
it, for which we never have a null result.
Co-authored-by: Andrew Kaster <andrew@ladybird.org>
Before this change each built-in iterator object has a boolean
`m_next_method_was_redefined`. If user code later changed the iterator’s
prototype (e.g. `Object.setPrototypeOf()`), we still believed the
built-in fast-path was safe and skipped the user supplied override,
producing wrong results.
With this change
`BuiltinIterator::as_builtin_iterator_if_next_is_not_redefined()` looks
up the current `next` property and verifies that it is still the
built-in native function.
The test CSSStyleDeclaration-has-indexed-property-getter is a frequent
source of merge conflicts between PRs that are adding to or otherwise
modifying the list of supported CSS properties.
This is primarily because the test prints out a numeric index of each
property along with the property. As far as I can tell the indexes are
inconsequential for what the test is trying to verify. So lets modify
the printout to only contain the properties without indexes.
This mirrors the existing caching logic for int32 constants.
Avoids duplication of string constants in m_constants which could
result in stack overflows for large scripts with a lot of similar
strings.
run:sqlite3 $HOME/Library/Application\ Support/com.apple.TCC/TCC.db "INSERT OR IGNORE INTO access VALUES ('kTCCServiceMicrophone','/usr/local/opt/runner/provisioner/provisioner',1,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1687786159,NULL,NULL,'UNUSED',1687786159);"
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.