Commit graph

78741 commits

Author SHA1 Message Date
R-Goc
520a7c8ebd AK+LibWeb: Centralize FFI helper functions
This commit creates a central FFIHelpers.h header which implements
common conversions from FFI.
2026-05-28 14:15:43 -05:00
Tim Ledbetter
7752bc5915 LibWeb: Stretch aspect-ratio flex items only when container is definite
A flex item with a preferred aspect ratio but no natural width or
height and no definite cross size is stretched to fill its container's
main size as a fallback. This was applied unconditionally, but when
the container itself is being measured for an intrinsic size, the
container's main size is indefinite and the size evaluated to zero.
This clobbered the max-content size the flex algorithm had already
computed as the intrinsic contribution.
2026-05-28 20:42:02 +02:00
Zaggy1024
6d84918eb7 Tests: Add a test set for file buffered ranges 2026-05-28 10:30:20 -05:00
Zaggy1024
c88b1ca8f7 LibMedia: Reduce the amount of WAV data loaded before playback starts
Apparently FFmpeg probes WAV files for 32 packets before returning the
stream info. With the default of 19200 bytes per packet, this could end
up waiting for up to 5 seconds of data to be downloaded.

Setting the max_size option only affects WAV and W64 in our build of
libavformat. No other formats we care about will be affected.
2026-05-28 10:30:20 -05:00
Zaggy1024
c901896972 LibMedia: Implement buffered range scanning for Ogg
Unfortunately, this necessarily involves parsing codec frames to get
their durations. Ogg's granule positions indicate the last sample of
the last complete frame of the page, so the navigator has to determine
the durations of every packet in the page to offset it back to its
start.

Vorbis is an especially involved codec to determine that for, since it
has initial data defining a mapping of indices to big or small block
sizes that has to be held onto, and that mapping is preceded by a bunch
of conditionally parsed bits. Also, a frame's block size calculation
involves the block size of the previous frame for an overlap add. To
avoid bringing that complexity directly into LibMedia, we delegate the
parsing/calculation to FFmpeg's av_vorbis_parse functions.
2026-05-28 10:30:20 -05:00
Zaggy1024
76a5c2b91e LibMedia: Factor out Opus frame duration parsing from Matroska::Reader
This will be useful for Ogg buffered ranges.
2026-05-28 10:30:20 -05:00
Zaggy1024
16f5a3405f LibMedia: Implement buffered ranges for MP3
A new MP3Navigator class is added, which determines timestamps for byte
positions by resyncing to a frame and then interpolating between known
points on either side. The known points start out as the first frame's
position in the file at timestamp 0, and EOF at the timestamp for
FFmpeg's file duration estimate. New buffered ranges are interpolated
between those two points, but also between the end of a prior range and
the start of the next.

Since MP3 can have variable bitrate without declaring it in the file
header, we have to allow buffered ranges to shift forward as new data
arrives to make room for underestimated durations. This is done for all
ranges following the first that has been appended to, keeping the start
of the current range consistent, so that subsequent seeks within that
range remain consistent.

Seeking is also implemented within the navigator to ensure that the
byte<->timestamp mapping is consistent and the buffered ranges begin
exactly where the seek landed.
2026-05-28 10:30:20 -05:00
Zaggy1024
9f788cb80f LibMedia: Implement CBR seeking through ContainerNavigator
This mainly acts as a proof of concept for manual seeking
implementations, which may prove useful for other formats than WAV.
2026-05-28 10:30:20 -05:00
Zaggy1024
454830c7cc LibMedia: Always clear EOF/error flags in AVIOContext when seeking
We could end up seeked within AVIOContext's internal buffer without it
checking whether new data could be buffered without hitting EOF again,
so we could get an unexpected read error.
2026-05-28 10:30:20 -05:00
Zaggy1024
5bb108dd5c LibMedia: Calculate accurate buffered ranges for FLAC
Add a new FLACNavigator class that can scan for frames both forward and
backward from a byte offset to get the exact buffered ranges. The reads
are done in chunks, which keeps each call pretty cheap.

The ranges themselves are resolved by its ScanningContainerNavigator
base class, which reconciles cached ranges against the incoming ones to
avoid repeating work unnecessarily. With those combined optimizations,
the calls normally take under 1 microsecond.
2026-05-28 10:30:20 -05:00
Zaggy1024
9f1a4d7536 LibMedia: Add some reading helpers to MediaStreamCursor 2026-05-28 10:30:20 -05:00
Zaggy1024
99fef15c7f LibWeb: Remove now-unused HTMLMediaElement::toggle_playback()
This function never worked properly anyway.
2026-05-28 10:30:20 -05: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
3098c0fb62 LibMedia: Implement buffered ranges for FFmpegDemuxer
The default mode is to grab the index and use it to determine the start
and end of the buffered ranges. This works well for MP4.

For WAV, the index is incomplete, so instead use a much simpler method,
just determining the ranges based on the constant bitrate of the file.

This is implemented through a new virtual ContainerNavigator class.
2026-05-28 10:30:20 -05:00
Zaggy1024
16f1f19aa3 LibMedia: Move the bitwise operators for FrameFlags to Media:: 2026-05-28 10:30:20 -05:00
Zaggy1024
14a85b0c33 LibWeb: Fire the progress event when new media data is received
Also, update the ready state when the progress event is fired.
Otherwise, we won't autoplay if 5 seconds of data aren't available in
on_metadata_parsed().
2026-05-28 10:30:20 -05:00
Zaggy1024
8576527d8a LibMedia: Actually adjust incremental stream's request positions
This was unintentionally clobbering the prior modification to the
request position. Requesting data slightly earlier in the file is
intended to ensure that we have data if the demuxer decides to seek
backwards.
2026-05-28 10:30:20 -05:00
Zaggy1024
7d3dd2d641 LibMedia: Implement buffered time range scanning for Matroska 2026-05-28 10:30:20 -05:00
Zaggy1024
be089ce24c LibMedia: Make some Matroska::Reader functions const
These don't need to be mutable.

has_cues_for_track() was also removed, as it was unused.
2026-05-28 10:30:20 -05:00
Zaggy1024
52b6b40493 LibMedia: Allow Matroska::SampleIterator to iterate all tracks 2026-05-28 10:30:20 -05:00
Zaggy1024
36ddc5015a LibMedia: Return an error if a Matroska octet couldn't be read 2026-05-28 10:30:20 -05:00
Zaggy1024
fea33aa02f LibMedia+Tests: Add a method to remove data from incremental streams
This will later be used to test updating of buffered time ranges when
data is removed. It will also be needed when data eviction is
implemented.
2026-05-28 10:30:20 -05:00
Zaggy1024
054d6d1b17 Tests: Add tests for available incremental stream byte ranges 2026-05-28 10:30:20 -05:00
Zaggy1024
617f50813a LibMedia: Ensure that overlapped incremental stream chunks are merged
Returning early if an added chunk didn't overlap the previous one could
result in overlapping chunks or 0-byte gaps if a chunk was after but
within the new one. Instead, fall through to allow the merging to
continue as normal.

Also, make the joining condition check if the new chunk spans multiple
existing chunks to merge/remove those.
2026-05-28 10:30:20 -05:00
Zaggy1024
ecae6f42cd AK: Add a method to remove an iterated node from a RedBlackTree
This will also advance the passed iterator so that it remains valid.
2026-05-28 10:30:20 -05:00
Zaggy1024
c4514c27ab LibMedia: Add a method to get the available bytes from a MediaStream
This will be used to determine the buffered time ranges.
2026-05-28 10:30:20 -05:00
Zaggy1024
c7eee655c2 LibMedia: Split out Matroska::SampleIterator and Streamer 2026-05-28 10:30:20 -05:00
Zaggy1024
732663dcc4 LibMedia: Prevent a crash when Matroska reads a block before a cluster 2026-05-28 10:30:20 -05:00
Zaggy1024
f62af69dcd LibMedia: Allow MediaStreamCursor to never block on missing data
This is necessary to allow the main thread to read out frames to
determine the buffered ranges, without affecting the request position
of an IncrementallyPopulatedStream or causing a deadlock waiting for
data to come in.
2026-05-28 10:30:20 -05:00
Zaggy1024
0c830caade LibMedia: Avoid crashing in tests appending data to incremental streams
We would ignore whether the callback/event loop had been set up for the
stream. Tests appending enough data for it to start a new request after
the new data would cause a crash.
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
8a85cafd36 LibWeb: Move media controls' timeline fill to an inner div
This will allow us to contain the buffered ranges within the timeline's
area.
2026-05-28 10:30:20 -05:00
Timothy Flynn
47b6f5e607 LibWeb: Do not send every decoded favicon to the UI process
If a page contains multiple <link rel="icon"> elements, we would send
each of them to the UI process. We would then just use whichever was
sent last as the favicon in the UI.

We now only send the favicon that was chosen for the document. This
will either be the largest icon decoded from a link element, or the
singular fallback icon.
2026-05-28 16:01:30 +02:00
Timothy Flynn
5f3ea017f5 LibWeb: Select the largest decoded favicon as the active page favicon
We currently pick the first favicon in reverse tree order. But we are
encouraged by the spec to pick the most appropraite icon. We now
consider the size of the decoded icon, and choose the largest.
2026-05-28 16:01:30 +02:00
Sam Atkins
d3ad37e635 Meta: Define helper processes for Ladybird and test-web in one place
These both require the same helper processes, and maintaining the same
list in multiple places is error-prone. For example, I spent too long
debugging why test-web was crashing, when the issue was that Compositor
hadn't been rebuilt as test-web didn't depend on it. That problem can
no longer happen if we define the same dependency list for both.
2026-05-28 14:45:48 +01:00
Suraj Yadav
ec2b96f4bf Meta: Restore serenity_gdb.py
Restore serenity_gdb.py => Meta/gdb/PrettyPrinters/ak.py.
Remove VirtualAddress and AKFixedStringBuffer.
Fix Hashmap, IntrusiveList, Optional and Vector printers.
2026-05-28 14:33:25 +01:00
Sam Atkins
2000fd38c1 DevTools+WebContent: Support the flexbox highlighter 2026-05-28 12:58:46 +01:00
Sam Atkins
5b2c649eda LibWeb/Painting: Paint flexbox inspector overlays 2026-05-28 12:58:46 +01:00
Sam Atkins
d465a5f32f DevTools: Implement Firefox flexbox layout actors 2026-05-28 12:58:46 +01:00
Sam Atkins
0229fd9ee1 WebContent+LibWebView: Add flexbox inspection plumbing 2026-05-28 12:58:46 +01:00
Sam Atkins
fb34ca41c0 LibWeb: Preserve flex layout geometry for DevTools 2026-05-28 12:58:46 +01:00
sideshowbarker
aec2439d5e LibWeb: Skip user-select:none when computing selection state
Problem: Select All draws the selection highlight across
user-select:none content — breaking compat with Chrome and Firefox,
which leave such content unhighlighted.

Cause: ViewportPaintable::recompute_selection_states walks the Range and
assigns SelectionState::Start|::Full|::End to each layout node within.
The walk filters out is_inert() nodes — but not user-select: none nodes.

Fix: Extend the existing inert-only guards into a helper that also
rejects nodes whose used value of user-select is ‘none’. Such nodes stay
at SelectionState::None from the initial reset — so the selection
highlight skips them.

Fixes https://github.com/LadybirdBrowser/ladybird/issues/9695
2026-05-28 12:15:21 +01:00
sideshowbarker
03f6f25b11 LibWeb: Skip user-select:none when extracting selected text
Problem: Select All (Ctrl+A or the context menu) followed by Ctrl+C
unexpectedly copies text from elements with user-select:none — breaking
compat with Chrome and Firefox, which both exclude user-select:none
content from the clipboard.

Cause: Navigable::selected_text() walks the selection range via
visible_text_in_range() and concatenates each text node’s data. The walk
filters out nodes without a layout, but not nodes whose used value of
user-select is ‘none’.

Fix: Add a user-select check at each visible_text_in_range() walk point.
The Selection range itself is left unchanged. Selection.toString() still
returns the full text per spec — but the clipboard-extraction path now
excludes user-select: none subtrees, per spec
2026-05-28 12:15:21 +01:00
Suraj Yadav
a5b925fdec Meta: Add lldb pretty printers for AK types
fix string printer

Use lldb command to import printer

fix order and use nonsynthetic value

fix optional
2026-05-28 11:55:24 +01:00
Tim Ledbetter
3049d77979 LibWeb: Use advance width for canvas text alignment
Previously, `text_path() used the glyph outline bounding box width to
compute text alignment offsets and maxWidth scaling. The bounding box
only covers visible glyph outlines, excluding the advance of spaces and
glyph side bearings. This caused text with `textAlign` "end", "right",
or "center" to be mispositioned. We now use the sum of glyph run
advance widths instead.
2026-05-28 10:40:44 +02:00
Tim Ledbetter
8039419775 LibWeb: Account for floats when computing IFC abspos static position
Previously, when no previous sibling has a line box fragment, the
static position for inline-level elements defaulted to (0, 0), ignoring
float intrusion into the line box. We now use
`leftmost_inline_offset_at()` so the hypothetical box is placed on the
float-shortened line.
2026-05-28 10:40:21 +02:00
Tim Ledbetter
bd046f43d7 LibWeb: Walk all previous siblings in IFC abspos static position search
Previously, we only checked the immediate previous sibling for line box
fragments. We now walk backwards through all previous siblings instead,
so that intermediate siblings without fragments do not cause the search
to end prematurely.

Also use `m_containing_block_used_values` for the fragment search
instead of the sibling containing block, which for absolutely
positioned elements returns the nearest positioned ancestor rather than
the IFC parent that owns the line boxes.
2026-05-28 10:40:21 +02:00
Tim Ledbetter
37cc4eebc0 LibWeb: Skip non-rendered elements before querying view transition name
Previously, starting a view transition on an element inside a
`display:none` subtree  would crash because querying the view
transition name unconditionally accessed `computed_properties()`, which
is not calculated for these elements unless explicitly requested. We
now skip these non-rendered elements early, before querying the view
transition name, to avoid the crash.
2026-05-28 10:39:26 +02:00