Add `ECMAScriptRegex`, LibRegex's C++ facade for ECMAScript regexes.
The facade owns compilation, execution, captures, named groups, and
error translation for the Rust backend, which lets callers stop
depending on the legacy parser and matcher types directly. Use it in the
remaining non-LibJS callers: URLPattern, HTML input pattern handling,
and the places in LibHTTP that only needed token validation.
Where a full regex engine was unnecessary, replace those call sites with
direct character checks. Also update focused LibURL, LibHTTP, and WPT
coverage for the migrated callers and corrected surrogate handling.
When parsing declarations within a nested grouping rule, we don't store
these directly, but within a "nested declarations rule", in most cases
this is `CSSNestedDeclarations`, but this isn't always the case e.g.
`@function` rules and others (e.g. @media) within them should instead
use `CSSFunctionDeclarations`
Some at-rules (i.e. `@function`) require us to support custom
descriptors (e.g. `--foo`).
We do this by adding `DescriptorID::Custom` and using a new
`DescriptorNameAndID` class in a bunch of places where we previously
just used `DescriptorID`
With apply_to() now self-contained (carrying its own replacement
DocumentState rather than reading from the live entry), the clone at
the traversal call site is no longer needed.
The clone previously served two purposes:
1. Input snapshot: freeze entry fields before deferred population.
Now solved by changing populate_session_history_entry_document() to
take explicit input parameters, snapshotted before the
deferred_invoke.
2. Output isolation: absorb apply_to() and post-population adjustments
without mutating the live entry during unload. Now solved by storing
the PopulateSessionHistoryEntryDocumentOutput on the continuation
state and deferring all mutations (including the origin-based
classic_history_api_state reset and navigable_target_name clear)
to after_potential_unload.
The post-population adjustments run unconditionally in
after_potential_unload, covering both the population path and the
non-population path (e.g. traversal to an already-populated error
entry).
Previously, populate_session_history_entry_document() took a
SessionHistoryEntry as both input and output — reading URL and
document_state fields while also mutating the entry across a chain of
async functions. This made it very hard to reason about data flow.
Refactor the internal helpers
(create_navigation_params_from_a_srcdoc_resource,
create_navigation_params_by_fetching, NavigationParamsFetchStateHolder,
perform_navigation_params_fetch) to take individual field values instead
of reading from the entry, and accumulate redirect mutations on the
state holder rather than writing them to the entry immediately.
Introduce PopulateSessionHistoryEntryDocumentOutput, a GC cell that
collects all mutations (document, redirect URL, classic history API
state, replacement document state, resource cleared flag, and
finalization data). The completion_steps callback now receives this
output object (or nullptr on cancellation), and callers apply it to the
entry via apply_to().
The replacement DocumentState for the redirect path is built eagerly at
redirect time from values captured on the state holder, making
apply_to() fully self-contained — it never reads from the target entry's
live document_state. This is important for the traversal path where the
entry may be mutated during unload (e.g. window.name writes
navigable_target_name through the active session history entry).
This IDL change is needed for webaudio's WaveShaperNode, where a
null BufferSource for a curve attribute results in a zero-length buffer.
WebGL also has a nullable BufferSource arg in bufferData(...). But
there, a null data/srcData value returns GL_INVALID_VALUE.
We pump the event loop just before these steps which can cause the
displayed document to be destroyed and lose its navigable. This was a
cause for crashes in the `encoding` WPT tests.
In `::spin_processing_tasks_with_source_until()`, we would first take a
set of tasks based on a filter, and then run them one by one. If there
was more than one task matched and put in that vector, they could
interfere with each other's runnability by making later tasks
permanently unrunnable.
The `::take_tasks_matching()` API is a footgun - remove it in favor of
an API that takes tasks one by one, performing the runnability check
just in time.
`close_top_level_traversable()` checks the `is_closing` flag to prevent
duplicate closes, but it is only set by callers of
`definitely_close_top_level_traversable()`. The flag is a bit in between
specs as things move from browsing contexts to navigables, but its
purpose is clear: without setting it, the check is ineffective and
`definitely_close_top_level_traversable()` runs multiple times for the
same traversable when the page has child navigables. This queues
duplicate session history traversal steps, where the second step
accesses the already-destroyed active document and segfaults.
For some text decorations (e.g. underline) we were using the line's top
edge as the Y-coordinate to draw the line at, which combined with the
line's thickness meant that it was positioned too high up.
Correct this by calculating the line's center Y position.
Use Skia's SkTextBlob::getIntercepts() to find where glyph outlines
cross the underline/overline band, then split the decoration line into
segments with gaps around those intersections.
Previously we waited until used-value time to apply handling for the
z-index value that we should have applied at declared or computed-value
time, which was papered over by returning the used rather than computed
value as the resolved value. This is no longer required.
This allows us to unmark z-index as requiring a layout node to get
resolved value.
The `HTMLFormControlsCollection` filter iterates all descendants of the
form's root, which may include non HTMLElement elements such as SVG
elements. The unchecked `as<FormAssociatedElement>` cast would crash on
these elements. Use `as_if` with a null check instead.
This fixes a regression introduced in 9af3e34875.
Currently this only applies to the `@property` `syntax` descriptor.
As with custom properties in the previous commit we assumed that any
consumed values were valid but that's not the case.
The definition of syntax in the "css-properties-values-api" spec (which
is used for the `@property/syntax` descriptor) is slightly different
from the definition of `<syntax>` in the "css-values" spec (which we
implement) in that it limits literal idents to exclusively
`<custom-ident>`s (i.e. not CSS-wide keywords or "default").
`<custom-ident>`s are also case-sensitive so that behavior is
implemented for syntax matching here as well
Previously we would consider an alternative syntax child to be a match
as long as parsing produced a value, even if there were trailing tokens
(which would later invalidate it within `parse_with_a_syntax`). This
meant that we wouldn't consider later alternatives which may actually
produce a valid match.
The previous implementation checked text-overflow and overflow-x
on the text node's direct parent during inline item iteration.
Since these are non-inherited properties, ellipsis only worked
for text directly inside the block container, not when wrapped
in inline elements like <span> or <a>.
Move ellipsis truncation to a post-processing step after line
boxes are constructed, checking the containing block instead.
Other browsers appear to only do this for form submission, not for
all javascript URL navigations. Let's remove the handling in the
general javascript URL navigation handling so that our behaviour
diference to other browsers is limited specifically to form
elements, instead of the general case.
Unfortunately this does (expectedly) cause the test added in
3e0ea4f62 to start timing out, so that test is marked as skipped.
Previously, this wasn't done when placing the first inline content in a
block, which caused long unbreakable words to overlap with floats
instead of being moved below them.