Commit graph

21 commits

Author SHA1 Message Date
Zaggy1024
338c33a0ed LibWeb: Pin the media controls' time progress to the scrub position
When scrubbing, make the timeline progress match exactly to the cursor
position. Also, set the timestamp to match that progress. Both are not
allowed to change until the scrub completes.

This makes the UI stable while scrubbing after the end of the media
data in subsequent commits that jump the time to the duration at EOS.
2026-06-11 05:49:14 -05:00
Zaggy1024
2f9a42ff44 LibWeb: Swallow rejected play() promises in media controls
Whenever the controls' timeline is clicked, it pauses the media element
before seeking, then play()s on mouseup. However, the play() returns a
promise that resolves when the media actually becomes playable at the
new position. If that takes long enough that a second click pauses the
element again, then that play() promise gets rejected, and an unhandled
rejection is logged.

To prevent that, mark all play promises as handled to silence them.
2026-06-11 05:49:14 -05:00
Zaggy1024
6af0f54b15 LibWeb: Update the media controls' timeline upon progress firing
Otherwise, we don't update the buffered ranges visual when paused for
a blocked seek.
2026-06-11 05:49:14 -05:00
Andreas Kling
164ed80244 Meta: Enable exit-time destructor warnings for libraries
Enable -Wexit-time-destructors for all in-tree library targets and
update process-lifetime library statics so they no longer register
exit-time destructors. Long-lived caches, lookup tables, singleton
registries, and generated constants now use NeverDestroyed or leaked
references where the data is intended to live until process exit.

Update LibWeb, LibLine, and the binding generators so regenerated
sources follow the same rule instead of reintroducing destructed
statics.
2026-06-04 19:20:49 +02:00
Zaggy1024
f02e9174c7 LibWeb: Don't use toggle_playback() in MediaControls' play/pause button
This function checks potentially_playing(), which means the button
doesn't do anything if the player is buffering. We don't want that.
2026-05-28 10:30:20 -05:00
Zaggy1024
e8dd9a1716 LibWeb: Remove two unused static vectors in MediaControls.cpp 2026-05-28 10:30:20 -05:00
Zaggy1024
45c2681943 LibWeb: Make buffered ranges visible on the media controls' timeline
The timeline will appear brightened in portions that are buffered,
including sections prior to the current position.
2026-05-28 10:30:20 -05:00
Zaggy1024
948e625f32 LibWeb: Simplify formatting of media timeline progress width style
Factoring this out will let us reuse it for the buffered ranges.
2026-05-28 10:30:20 -05:00
Zaggy1024
8cc00c09fa LibWeb: Only update the media controls' timeline while playing 2026-05-19 16:37:59 -05:00
Shannon Booth
5adfd1c43a LibWeb/Bindings: Generate struct definitions from IDL dictionaries
Previously we were inconsistent by generating code for enum definitions
but not generating code for dictionaries. With future changes to the
IDL generator to expose helpers to convert to and from IDL values
this produced circular depdendencies. To solve this problem, also
generate the dictionary definitions in bindings headers.
2026-05-09 10:49:49 +02:00
Zaggy1024
f213ef455d LibWeb: Cancel the animation frame callback in MediaControls destructor
Otherwise, when hiding controls, we would get a UAF on MediaControls::
update_timeline() and crash.
2026-03-17 06:00:40 -05:00
Zaggy1024
73c27f3448 LibWeb: Use requestAnimationFrame to update media controls timeline
The media element's timeupdate event only fires every 250ms. To make
the timeline update more smoothly, poll currentTime to update the
timeline every frame.
2026-03-17 01:48:59 -05:00
Zaggy1024
6f73b537f7 LibWeb: Simplify getting the Window in MediaControls callbacks 2026-03-17 01:48:59 -05:00
Zaggy1024
6cc13dbfa2 LibWeb: Skip assigning an unchanged timeline style in media controls 2026-03-17 01:48:59 -05:00
Zaggy1024
fe702847f8 LibWeb: Simplify the HTMLMediaElement null check in ~MediaControls() 2026-03-17 01:48:59 -05:00
Zaggy1024
63113cf5c9 Meta+LibWeb: Use a code generator to create the media controls' DOM
Instead of manually writing code to instantiate DOM elements in
MediaControls.cpp, use a Python script to generate a separate C++
struct to create and store the DOM elements.

The generator reads an HTML file and the HTML/SVG tags/attributes
headers to create C++ source that instantiates the DOM elements.

To enable embedding of stylesheets in shadow DOM, the generator
replaces `<link rel="stylesheet">` elements with plain `<style>`
elements containing the source from the linked stylesheet.

Elements that should be stored in the resulting struct should be marked
have the `data-name` attribute, which will be converted to snake_case
and used as the public field's name.

Optional elements can be marked with a 'data-option' attribute. Each
unique option value will be converted to PascalCase and added to a
bitwise enum named `Options` nested within the struct. Optional
elements and all their children will not be instantiated unless their
option is set in the constructor argument.

The MediaControls class stores the generated MediaControlsDOM struct
and sets up event handlers to implement user interactions.
2026-03-05 02:28:47 -06:00
Timothy Flynn
bfef5c460f LibWeb: Display video controls while the placeholder icon is visible
This matches the behavior of Firefox.
2026-03-03 16:53:23 +01:00
Timothy Flynn
3a9ae0eb02 LibWeb: Toggle the built-in media player fullscreen state on doubleclick 2026-03-01 15:41:43 -06:00
Timothy Flynn
24aacfea48 LibWeb: Add a button to the built-in media player to toggle fullscreen 2026-03-01 15:41:43 -06:00
Timothy Flynn
e95db70d2d LibJS+LibWeb: Return GC::Ptr from Value::as_if 2026-02-27 17:19:33 +01:00
Zaggy1024
21019c2fa9 LibWeb: Use UA shadow DOM for media elements' controls
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.
2026-02-23 07:27:31 +01:00