This will be used in generated code to represent missing optionals i.e.
`<foo> <bar>?` with only a `<foo>` value will be represented by a
`StyleValueList` containing the relevant `<foo>` style value and an
`EmptyOptionalStyleValue`
Whenever an ancestor's container-name or container-type changes, it
affects the matching of any `@container` queries, and so can affect the
style of any descendant.
MatchingRules now have a container_rule member which stores the nearest
ancestor CSSContainerRule, if any. When populating the rule cache, we
maintain a stack of CSSContainerRules that we are within, and use
record the last one on the MatchingRule, so that it's O(1) instead of
having to walk up the rule's ancestors each time. This does mean we
have reimplement some "for each rule" code.
When collecting rules to apply to an element, we see if the MatchingRule
has a container_rule, and if so, we evaluate that rule's query to see
if the element has a matching container. We then also match any ancestor
container rules, using the cached parent container rule.
Add a custom test to cover the case of nested name-only `@container`s,
which WPT lacks currently as far as I can tell.
ContainerQuery now stores its feature requirements. When evaluated, it
uses these and the passed-in container name to identify a container
element to match against, then evaluates its condition against that
element.
None of this is yet in use anywhere, but will be soon.
A given element may be a container in different ways, depending on its
`container-type` property. For a container query to match an element,
that element must have the required container type for each feature
that the query checks. This commit implement a step to collect those
required types, so that we can quickly eliminate potential container
elements that lack a required containment type.
Once we start evaluating `@container` matches, we will need to check if
any ancestor `@container`s also match. Caching the nearest one, if any,
will let us skip walking the entire ancestor chain.
Different users of BooleanExpression have different requirements for
evaluation:
- `@media` needs a Document
- `@supports` doesn't need anything
- `@container` needs a container Element
To support these without expanding the API, replace the Document*
parameter with a BooleanExpressionEvaluationContext type which contains
these different values.
No behaviour changes.
Create new windows with the size of the previously active window, and
maximized if it was maximized. This matches the behaviour of other
browsers, and solves an annoying issue where new windows would always
be tiny.
Application::new_window() now takes a WindowConfiguration struct that
lets you specify the position, size, and maximized-ness of the window.
All previous callers of new_window() now use this instead of modifying
the window state afterwards.
WindowConfiguration is slightly awkwardly broken up into individual x/y
and width/height fields instead of a position and a size, for the sake
of compatibility with HTML::WebViewHints.
Maintain a stack of URLs and when they were closed, and allow popping
the most recent one.
These are stored directly on HistoryStore instead of its Storage object,
because they should never persist regardless of which backend we're
using. Even so, we still clear them along with other history data.
This test only checked that the end state, after clearing the storage,
didn't contain the entry. This is the same behaviour we'd expect if it
wasn't disabled, so to test for that, run the same "is this empty?"
check after each step.
HistoryStore always had a TransientStorage even though that went unused
if it also had a PersistentStorage. We also had repeated branching to
make sure we accessed the correct storage, and this is a bit of a
footgun. Instead, just hold a single Storage via OwnPtr and use that
for all storage actions.
Previously, and according to the spec, `a::part(foo)::before` would be a
single CompoundSelector, even though it matches against 3 different
targets. This meant some awkward swapping of targets in the middle of
matching, and in particular it made `::part()` and `::slotted()` quite
hacky, requiring them to track extra data on the MatchContext to then
use later. This was scattered around and difficult to follow.
Partly inspired by Gecko, this commit instead introduces an invisible
PseudoElement combinator. After parsing a selector, we find any
CompoundSelectors that contain a pseudo-element and split them up, so
that each CompoundSelector only has a single target in the end. Where
the pseudo-element was at the start of a CompoundSelector, we insert an
invisible universal selector before it to represent its originating
element.
So now, a CompoundSelector deals with one target, and switching targets
is done at the combinator.
The one inconsistency is that we match the target of ::slotted()
and ::part() in pseudo_element_transition_target(), instead of before
then when processing the SimpleSelector. This is to avoid repeating the
same computations twice.
No outward-facing behaviour changes, though the invalidation metrics
have changed.
Store the error traces on a map until they're all done, then sort them
and print them out in alphabetical order by type. This test was
sometimes flaking and printing the module stack before the classic
stack, which this prevents.
Avoids us having to maintain a separate hardcoded list.
This does mean we don't support parsing of `decibel` but it's not used
anywhere yet and will be supported automatically when added to
Units.json
When a link element's href changes, the spec expects the callback
to check if "el contributes a script-blocking style sheet"
(step 6). This check examines current fetch state, which fails
when old fetch callbacks run after a new fetch has started.
Use FetchController::stop_fetch() instead of abort() to prevent
old fetch callbacks from executing entirely. This ensures only the
current fetch's callback runs, allowing it to correctly check
current state per spec without race conditions.
Wheel deltas were truncated to int at the platform input boundary,
which dropped the sub-pixel tail of trackpad momentum scrolls. Each
NSEvent's scrollingDeltaY arrived as a CGFloat, got cast to int, and
flowed through IPC, EventHandler, and PaintableBox::scroll_by as int,
losing fractional information that never came back.
Widen Web::MouseEvent::wheel_delta_{x,y} to double and propagate
through Page, EventHandler, Paintable, PaintableBox, and the AppKit,
Qt, and GTK input paths.
Keep compositor-side scroll snapshots aligned with async viewport
scrolling when main-thread scroll state arrives while an async viewport
offset is pending. A stale scroll-state-only update could otherwise
replace the snapshot used for display list replay and wheel hit-testing
with an older viewport offset, even though the compositor had already
presented newer async scroll positions.
Teach AsyncScrollTree to set a node scroll offset directly and use it
when reconciling both display-list and scroll-state updates. Recompute
the main-thread viewport rect after display list recording as pending
async scroll adoption can move the viewport before presentation.
Avoid recursing into atomic inline-level descendants during the ancestor
float sweep.
CSS 2.2 paints inline-block and inline-table boxes in the inline-level
painting step, as if they created their own stacking contexts. Paint
their internal floats during
BackgroundAndBordersForInlineLevelAndReplaced instead.
Previously, we weren't too consistent about the definition of frame and
sample when it relates to raw audio data. This brings all the usages in
the context of raw data in line (hopefully), with samples referring to
a single PCM value, and frames referring to the multiple samples that
make up an instant's audio across all channels.
With this last piece done, we can now connect a DecodedAudioProducer
directly to an AudioPlaybackSink instead of being forced to go through
the mixer. This should open up options for other pipeline setups if
needed in the future.
Now, all nodes are connected through Sink::connect_input() and
disconnect_input().
AudioMixer now derives from a base AudioProcessor class that inherits
from both AudioSink and AudioProducer. It is the only current node that
can accept multiple inputs, tracking each one by its pointer identity.
This is the new way of handling fast seeks. Instead of delegating the
logic all the way down the pipeline to the decoder thread's seek
handler, we can just determine the timestamp we want to seek to ahead
of time.
Seeking is now unified under one single method signature implemented by
all producers and transmitted through the pipeline by all sinks. By
doing it this way, we can simply instantaneously notify each node of
the pipeline that it needs to stop what it's doing and seek. For nodes
that are threaded (particularly the source providers), this causes them
to stop pushing data to their queue immediately, so that no stale data
makes it through to the output. Then, when new data does come through,
that is a clear indication that the seek has completed.
Note that track enablement is now through the pipeline as well, which
means that SuspendedStateHandler no longer has a way to suspend newly-
enabled tracks. Decoder suspension will need to be reworked to fit into
this new pipeline, sleeping/disposing and restarting entirely based on
the pull() timing in the producers.
Using a callback shared by all producers in the pipeline, notify the
AudioPlaybackSink when it needs to wake up and start processing data
again. Prior to this commit, it was simply burning CPU spinning until
data was produced.
This is an intermediate step towards unifying the pipeline around new
Producer/Sink interfaces. Producers now have a pull() method that gets
the next piece of data from them. The pull() method returns a status
that can indicate whether it has current data, and if not, why it's
unavailable. This signal will be passed down the pipeline to the final
sink, which can expose the signal to its user, which in the normal
playback pipeline is PlaybackManager. The signal can be used to
transition between playback states. Currently, this is only hooked up
to the buffering state, but should be used later for ending playback
as well as decoding error propagation.
Buffering is now determined solely based on whether the pipeline is
blocked on incomplete data, so the ready state for video now progresses
past HAVE_METADATA immediately after playback manager initializes. This
will change when files have buffered ranges.
This will allow reuse of the allocations, instead of reallocating a
FixedArray for every block that changes size. Generally, it will be
possible to reuse AudioBlock memory throughout most of the pipeline
at least while in a single process.
- Provider -> producer
- (Audio|Video)DataProvider -> Decoded(Audio|Video)Producer
- MediaTimeProvider remains suffixed Provider, moves out of the
Providers folder to the root of LibMedia
This brings the naming more in line with the intended split
functionality split between different nodes in the pipeline.
This doesn't actually change things too much from the prior commit, but
acts as a step towards making mixing into a sink/provider combo in the
new pipeline model.
While mixing doesn't cost much time at the moment, moving audio
processing off the callback thread means that the callback itself can
block for a minimal amount of time regardless of the amount of time
needed to actually process the audio data.
This matters a lot for AudioUnit, where the entire daemon can start to
glitch if delays occur.
The goal of this change is to split mixing off into a separate class,
and process audio on both ends of the mixer synchronously. This should
allow a more declarative approach to processing audio, where inserting
a time stretching processor, for example, becomes much simpler.
In this commit, the thread spin-waits for new upstream data. Making it
wait on a condition variable here would overcomplicate this commit, so
it's deferred until a later commit establishes that forward wakeup.
This gives us a cheap way to wake up all PlaybackStream implementations
when they are sleeping due to an underrun. The new function is meant to
be very cheap so that it can be unconditionally called when new data is
ready to be written.
This will allow the audio sink to rely on streams to track the time in
written audio frames instead of writing silence when data isn't ready.
The WASAPI implementation was actually polling for new data every 10ms
after hitting an underrun, so now it drains the buffers and stops when
entering the underrun-paused state.
The playback stream is never recreated currently, so this wasn't
actually doing anything. This is now made explicit by never resetting
the playback stream creation flag when it succeeds.
Instead of skipping setting this if the playback stream isn't ready, we
need to store the time so that the stream creation resolution callback
can begin the seek later.
Recalculating after suspend isn't really useful if the PlaybackStream
implementations ensure that the time doesn't advance past the data that
has been written so far.
Previously, writing less data than the stream requested would result in
the stream advancing its playback time past the enqueued frames. This
breaks the PlaybackStream contract, and was simply hidden by a similar
clamping at the AudioMixingSink. That is going away in the next commit.