Introduce a descriptor table keyed by `ColorType` that encodes
per-space metadata: channel kind, percent reference value, clamp
bounds, function name and serialization behavior.
This descriptor table is then used so that a single class can back
every CSS color type. Resolution, serialization, and absolutization
are driven by the descriptor.
Animation updates propagate inherited animated values by walking the
animated target's subtree and calling `recompute_inherited_style()` on
each element. Elements inserted during the same rendering update may
not have computed properties yet, which violates an existing assertion,
causing a crash.
Fix this by skipping unstyled descendants during this walk. The
subsequent recursive style update computes their style from scratch.
This tightens the implementation of video element sizing to the spec by
implementing two spec concepts:
- The media resource's natural width and height, and
- The video element's natural width and height.
The element's natural dimensions change based on the representation,
which has many inputs, so update checks are triggered from many
locations.
The resize event is fired when the media resource's natural dimensions
change, and the layout is invalidated if the element's natural
dimensions change.
Tests for a few important resize triggers have been added.
This state will indicate to the media element that it's not guaranteed
to have a frame yet, for the purposes of determining the ready state.
JavaScript should be sure that video elements with a ready state of
HAVE_CURRENT_DATA or greater represent the current video frame already.
To allow the state to be exited if audio is disabled, audio tracks are
now only added to the buffering set on enable if the audio sink exists,
since without the sink starting the data provider, it will never be
removed.
This is a step towards making video ref tests.
This allows us to differentiate between having no data available yet,
having current data, and having future data. The main purpose of this
is to allow a new starting state to explicitly force HAVE_METADATA
instead of >= HAVE_CURRENT_DATA.
Note that the SeekingStateHandler returns Current instead of None. This
is deliberate, since the buffered ranges from the demuxer(s) can be
used to inform whether the possibly-current data is actually available
at the seek target.
A while ago, we removed the relayout upon rendering a new frame. In
doing so, it became possible for the layout to remain stale after the
video metadata had loaded, leaving the video drawn in a 0x0 box.
Otherwise, the PlaybackManager may get stuck waiting for enough data to
read the metadata and call on_metadata_parsed.
This is unfortunately difficult to test without direct control over the
fetching process, but it could cause flakes in tests that wait for
loadeddata.
When we are recomputing inherited styles, we should already have
computed style for that element at least once, so cascaded and computed
properties should exist at that point. So make the invariant explicit.
`recompute_inherited_style()` assumed that there is no work to do if the
element has no layout node. This however is not necessarily true.
In particular, the following can happen:
1. The element in question is a descendant at least two layers below an
element that has `display: none`, i.e. with at least one other
element between them. (If it is a direct child, a full style
recomputation will be forced for unrelated reasons).
2. TreeBuilder decides to skip creating layout nodes for the `display:
none` element and all its descendants.
3. Due to some change on the ancestor (e.g. class added, id changed),
the value of a property that can be inherited changes on the
ancestor.
4. The property value of the descendant now also needs to change.
In that scenario, we won't compute the entire style of the descendant,
since that already happened. But we do need to update its inherited
properties because the old ones are now stale. At that point we still
don't have a layout node for the element since it will only be created
after this style update.
Instead of skipping the update for inherited properties, simply allow
`recompute_inherited_style()` to run even in absence of a layout node.
And then apply the style to the layout node only if one exists. If none
exists, the style will be applied later if and when a corresponding
layout node is created.
This partially fixes the blank main navigation menus on
https://bleepingcomputer.com.
The iterator returned by SinglyLinkedList::remove() left `m_prev`
default-initialized to `nullptr`. If the caller removed another element
without first advancing, the previous node's next pointer was left
dangling to the freed node.
This caused a UAF in FinalizationRegistry's `remove_by_token()` when
two consecutive records shared an unregister token.
Previously, a character class containing any builtin (\d, \w, \s)
forced the compiler down the slow "complex class" path, which emits
a disjunction of alternatives and backtracks at runtime.
For non-unicode, non-unicode-sets, non-negated classes, \w and \d
can be inlined as their raw ASCII code-point ranges. The resulting
class stays on the fast path and compiles into a single sorted
CharClass instruction.
The unicode/unicode_sets and negation guards are required for
correctness: with the /u + /i flags, \w gains non-ASCII members
via case folding (e.g. U+017F, U+212A), and negated classes have
a separate, smarter compilation path.
When curl invokes the socket callback to tell us it only wants one
polling direction (e.g. CURL_POLL_IN without CURL_POLL_OUT, or vice
versa), we previously had no way to disable the other direction's
notifier. Once created, a notifier stayed enabled and kept firing
curl_multi_socket_action() for events curl was no longer interested in.
Merge the read and write branches into a single helper that also
disables the notifier for a direction when its CURL_POLL_* flag is
absent from the mask. This measurably improves performance by avoiding
redundant curl_multi_socket_action() calls on sockets curl has asked
us to stop watching in a given direction.
By implementing this method ourselves, we no longer go through
::supported_property_names() and skip both the vector allocation and
sorting, which we don't need to determine if a property name is present.
Calling into ::compare_document_position() for each node comparison
inside quick_sort() is quite expensive - it calculates more than we need
and allocates. Replace it with TreeNode::is_before() which does not, and
gives us the required positional info.
Generator::allocate_register used to scan the free pool to find the
lowest-numbered register and then Vec::remove it, making every
allocation O(n) in the size of the pool. When loading https://x.com/
on my Linux machine, we spent ~800ms in this function alone!
This logic only existed to match the C++ register allocation ordering
while transitioning from C++ to Rust in the LibJS compiler, so now
we can simply get rid of it and make it instant. :^)
So drop the "always hand out the lowest-numbered free register" policy
and use the pool as a plain LIFO stack. Pushing and popping the back
of the Vec are both O(1), and peak register usage is unchanged since
the policy only affects which specific register gets reused, not how
aggressively.
Passing the browser command line and executable path to every WebContent
process just in case we load about:version always felt a bit weird. We
now use the WebUI framework to load this information on demand.
After b1d708dd16, the Toolchain directory
was removed from the repository. Some documentation and scripts still
referenced it, so this commit removes those references. The only
remaining references are in the gitignore file, to prevent bisections
from being polluted by the presence of a Toolchain directory in the
working copy.
Previously, the LibWeb bindings generator would output multiple per
interface files like Prototype/Constructor/Namespace/GlobalMixin
depending on the contents of that IDL file.
This complicates the build system as it means that it does not know
what files will be generated without knowledge of the contents of that
IDL file.
Instead, for each IDL file only generate a single Bindings/<IDLFile>.h
and Bindings/<IDLFile>.cpp.
Globally linking to anything isn't a good thing to do and this doesn't
seem to be necessary. If it ends up breaking any platform it can be
readded as a specific link later.