Input elements with a placeholder were positioned lower than inputs
without a placeholder or inputs with text. This was caused by the
placeholder element missing height height and overflow properties that
the inner text element had.
This fix makes sure both the placeholder and inner text elements let
show the same position of the input field.
d146adf made the fetch callbacks use the media element via weak
references. This caused the `error` event not to fire on media elements
that are detached from the document and go out of scope, if the GC got
to them before the fetch completed.
Instead of relying on weak references in the callbacks, we can stop the
ongoing fetch when the document becomes inactive to allow it to be GCed
after that point. By storing the FetchData on the media element, we're
able to resume the fetch where it left off if the document becomes
active again.
We could potentially figure out a way to make elements with no event
handlers and no parent stop their fetches in order to be GCed sooner,
but that is probably a bit fiddly, so may not be worth it for now.
Fixes a rare flake in WPT's `html/semantics/embedded-content/media-
elements/error-codes/error.html` test. A test to force the bug using
`Internals::gc()` has been added.
This change means the right click context menu is displayed in the right
place when clicking inside an iframe on a scrolled page, including when
the iframe has CSS transforms applied to it.
This fixes a crash that would occasionally happen in media-load-during-
track-setup.html, where the media element would add new tracks to the
AudioTrackList or VideoTrackList after the src attribute changed and
caused the element to clear those lists.
In order to make this safe, the on_unsupported_format_error needs to
queue a task to invoke the failure callback which eventually clears
the playback manager, or ~PlaybackManager() will try to destroy the
enclosing lambda.
We found an HTML spec issue that implies that media element steps that
mutate the DOM should run in tasks rather than awaiting a stable state.
Awaiting a stable state implies running in a microtask, which is
apparently not supposed to be used to mutate.
Add unsafe_layout_node(), unsafe_paintable(), and unsafe_paintable_box()
accessors that skip layout-staleness verification. These are for use in
contexts where accessing layout/paintable data is legitimate despite
layout not being up to date: tree construction, style recalculation,
painting, animation interpolation, DOM mutation, and invalidation
propagation.
Also add wrapper APIs on Node to centralize common patterns:
- set_needs_display() wraps if (unsafe_paintable()) ...set_needs_display
- set_needs_paint_only_properties_update() wraps similar
- set_needs_layout_update() wraps if (unsafe_layout_node()) ...
And add Document::layout_is_up_to_date() which checks whether layout
tree update flags are all clear.
Layout may have been invalidated by previous rendering steps (e.g. view
transitions). Re-run layout before intersection observations since they
need up-to-date geometry.
Replace the Window::scroll_by(0, 0) call at the end of
Document::update_layout() with a dedicated
Navigable::clamp_viewport_scroll_offset() that directly clamps the
viewport scroll offset to valid bounds.
The old approach re-entered layout from within layout, since scroll_by()
would trigger another layout update. The new approach is called from the
event loop's rendering steps, after layout is complete.
Fixes the included imported test. Note that this required a minor
edit of the WPT import to work with our test harness setup to
try and create a non secure context setup as both file:// and
localhost are considered secure contexts.
Note that this is done using the serialized versions of these objects
as this is always used across different processes and the javascript
realm should never be relevant for owner set.
This is somewhat awkward as the spec refers to 'is secure context'
with respect to these objects 'relevant settings object'. A natural
way of implementing this could be storing a pointer to the relevant
settings object like the JS representations of these objects do
(and then changing is_secure_context to accept this representation
too), but for now it seems much simpler to just store a boolean for
this purpose and sidestep both problems above.
perform_a_scroll_of_the_viewport() accesses paintable_box() without
ensuring layout is up to date. This can lead to a null dereference
if the paintable tree was torn down (e.g. by adding a dialog to the top
layer via showModal()) between the last layout update and the scroll.
One concrete path: Window::scroll() has an optimization that skips
update_layout when scrolling to (0, 0), but still calls
perform_a_scroll_of_the_viewport if the viewport is at a non-zero
position.
Fix by adding an update_layout call at the top of
perform_a_scroll_of_the_viewport.
As FontFaces are added or removed from a FontFaceSet, and as they load
or fail, the FontFaceSet moves them between a few different lists, and
updates its loading/loaded status. In the spec, this is how the
FontFaceSet.[[ReadyPromise]] gets fulfilled: When the document has
finished loading and FontFaceSet.[[LoadingFonts]] is empty, it resolves
the promise.
To support this, FontFace now keeps a set of FontFaceSets that it is
contained in.
This lets us remove the non-spec resolve_ready_promise() call in
EventLoop which was sometimes triggering before any fonts had attempted
to load.
As noted, there's a spec issue with the ready promise: If nothing
modifies the document's fonts, then it would never resolve. My ad-hoc
fix is to also switch the FontFaceSet to the loaded state if it is
empty, which appears to solve the issues but is not ideal.
In `TraversableNavigable::apply_the_history_step()`, we have a
`spin_until(..)` that pumps the event loop. If it's invoked as a result
of `Navigable::begin_navigation()` and we've received an IPC call at the
same time, we might reenter `begin_navigation()` which then drops the
new navigation as there is an ongoing navigation.
The IPC call most likely causing tests to time out, is
`page_did_finish_loading`.
This is a workaround until we get rid of the `spin_until()`. It fixes
almost all of the test timeouts I had locally on macOS.
The set_viewport_size and set_device_pixel_ratio IPC messages were sent
separately, potentially causing a race condition when the DPR changes
(e.g. moving a window between screens): the DPR message would arrive
and use a stale viewport size, computing a temporarily wrong CSS
viewport. Combine both into a single set_viewport IPC that updates the
device viewport size and DPR together.
The guard for setting top-level navigation initiator origin called
top_level_traversable()->parent() == nullptr, which is tautologically
true: top_level_traversable() already walks to the topmost traversable,
whose parent is always null. This caused the field to be set on every
navigation, including child navigable navigations inside iframes.
The value was also read from document_state()->origin() instead of
document_state()->initiator_origin(), giving the document's own origin
rather than the origin of whoever initiated the navigation.
Use is_top_level_traversable() and initiator_origin() to match the
spec step.
Instead of passing through window's associated document's URL as
an extra argument to starting up a worker. This will allow for
improving the representation of 'outside settings' when setting
up a Worker.
PlaybackManager's ref counting was only used to keep it alive in a few
callbacks. Instead, the callbacks can use weak references that can only
be used from the thread that the PlaybackManager was created on, to
ensure that the PlaybackManager can't be destroyed while being
accessed.
This ensures that:
- The PlaybackManager is destroyed immediately when it is reassigned
by HTMLMediaElement
- No callbacks are invoked after that point
This fixes the crash initially being addressed by #8081. The test from
that PR has been included as a regression test.
Instead of using a custom paintable to draw the controls for video and
audio elements, we build them out of plain old HTML elements within a
shadow root.
This required a few hacks in the previous commits in order to allow a
replaced element to host children within a shadow root, but it's
fairly self-contained.
A big benefit is that we can drive all the UI updates off of plain old
DOM events (except the play button overlay on videos, which uses the
video element representation), so we can test our media and input event
handling more thoroughly. :^)
The control bar visibility is now more similar to how other browsers
handle it. It will show upon hovering over the element, but if the
cursor is kept still for more than a second, it will hide again. While
dragging, the controls remain visible, and will then hide after the
mouse button is released.
The icons have been redesigned from scratch, and the mute icon now
visualizes the volume level along with indicating the mute state.
This is part of the rendering spec, but we had neglected to do this
before. It causes one WPT check to fail, but other browsers get the
same result on that check, so I guess we can call that a win. :^)
These are the same code, so we may as well move them up the chain. This
becomes useful in a later commit, where it will be used to rewrite
inline-flow to inline-block for layout of shadow DOM.