Commit Graph

221 Commits

Author SHA1 Message Date
Zaggy1024
228947b131 LibWeb: Include KeyCode.h where it's used
It was only transitively included through HTMLMediaElement.h in these
files.
2026-02-23 07:27:31 +01:00
Timothy Flynn
f0ecadfae1 LibWeb: Set an ibeam cursor over editable / editing host DOM nodes
This matches the behavior of other browsers.
2026-02-21 01:02:06 +00:00
Aliaksandr Kalenik
004e5f851e LibWeb: Use ExternalContentSource for canvas painting
present() now snapshots the PaintingSurface into an ImmutableBitmap
and publishes it to the ExternalContentSource, so the rendering thread
never touches the live GPU surface — eliminating the data race
described in the ExternalContentSource commit (problem 1).

Canvas elements are registered with Page and presented once per frame
from the event loop, rather than on every individual draw call in
CRC2D::did_draw(). A dirty flag on HTMLCanvasElement ensures the
snapshot is only taken when content has actually changed, and makes
the present() call in CanvasPaintable::paint() a no-op when the
surface has already been snapshotted for the current frame.
2026-02-20 18:41:33 +01:00
Timothy Flynn
7c9b3c08fa LibWeb: Allow selecting text in dialog and label elements
We were previously not allowing the user to select text when the clicked
position represented a click-focusable area. This included text within
dialogs (as the dialog element is click-focusable) and labels (as the
associated input element would be considered click-focusable).

We now no longer consider associated input elements when clicking on a
label. This is handled separately already by the label's activation
behavior steps, so there is no loss of functionality here. In those
steps, though, we now no longer propagate the click event to the input
element if a selection was made during the click. This matches the
behavior of Firefox and Chrome.

With label elements no longer considered here, we can then enter the
character selection mode when click-focusable areas are clicked.
2026-02-17 18:36:54 +01:00
Timothy Flynn
a055e36715 LibWeb: Modernize spec comment and coding style in EventHandler.cpp
* Prefer NB over NOTE for our own comments.
* Wrap comments at ~120 characters.
* Resolve some trivial clangd warnings.
2026-02-17 18:36:54 +01:00
Psychpsyo
68f27e9bbc LibWeb: Don't select text when multi-clicking user-select:none node 2026-02-16 15:57:55 +01:00
Tim Ledbetter
aafaec36ee LibWeb: Fire mouse boundary events before mouse move events 2026-02-15 02:36:01 +00:00
Jelle Raaijmakers
919cdb5143 LibWeb: Tie auto scrolling into the rendering loop
We were using a separately fired timer for auto scrolling ticks, but it
makes more sense to tie this into the rendering steps of which
`::run_the_scroll_steps()` is a part. Should fix the flaky
`Text/input/viewport-auto-scroll.html` test.

Fixes #7939.
2026-02-13 22:44:17 +01:00
Aliaksandr Kalenik
30e4779acb AK+LibWeb: Reduce recompilation impact of DOM/Node.h
Remove includes from Node.h that are only needed for forward
declarations (AccessibilityTreeNode.h, XMLSerializer.h,
JsonObjectSerializer.h). Extract StyleInvalidationReason and
FragmentSerializationMode enums into standalone lightweight
headers so downstream headers (CSSStyleSheet.h, CSSStyleProperties.h,
HTMLParser.h) can include just the enum they need instead of all of
Node.h. Replace Node.h with forward declarations in headers that only
use Node by pointer/reference.

This breaks the circular dependency between Node.h and
AccessibilityTreeNode.h, reducing AccessibilityTreeNode.h's
recompilation footprint from ~1399 to ~25 files.
2026-02-11 20:02:28 +01:00
Aliaksandr Kalenik
901cc28272 LibWeb: Reduce recompilation impact of DOM/Document.h
Remove 11 heavy includes from Document.h that were only needed for
pointer/reference types (already forward-declared in Forward.h), and
extract the nested ViewportClient interface to a standalone header.

This reduces Document.h's recompilation cascade from ~1228 files to
~717 files (42% reduction). Headers like BrowsingContext.h that were
previously transitively included see even larger improvements (from
~1228 down to ~73 dependents).
2026-02-11 20:02:28 +01:00
Jelle Raaijmakers
6c2583eade LibWeb: Implement mouse auto scrolling of scrollable containers
When the mouse is dragged from inside a scrollable container to outside
of it, we now automatically scroll the container so the selection can be
extended. Scroll speed scales with the distance past the scrollport
edge, capped at a maximum. Edges close to the viewport boundary get a
wider activation zone so the speed ramp works predictably even when the
mouse has limited room to move.

The logic is encapsulated in AutoScrollHandler, which EventHandler
creates lazily on mouse selection start.
2026-02-11 11:04:53 +01:00
Jelle Raaijmakers
2d4728d353 LibWeb: Keep cursor in view for text controls
When editing or changing the selection inside an <input> or <textarea>,
we should scroll the container so the cursor is always visible. Note
that currently the cursor might still become invisible at the end of the
container since we do not reserve enough space for it to be made
visible.
2026-02-11 11:04:53 +01:00
Timothy Flynn
8d97389038 LibHTTP+Everywhere: Move the cookie implementation to LibHTTP
This will allow parsing cookies outside of LibWeb.

LibHTTP is basically becoming the home of HTTP WG specs.
2026-02-10 12:21:20 +01:00
Aliaksandr Kalenik
e76cf3e225 LibWeb: Remove Document.h include from Layout/Node.h
This reduces the recompilation cascade when Document.h is modified.
Add explicit includes to files that relied on the transitive dependency.
2026-02-08 18:51:13 +01:00
Jelle Raaijmakers
2a2f8ef90b LibWeb+UI: Support triple clicking and dragging paragraphs
When triple clicking on text, we should select the entire paragraph, or
entire line in <input>s and <textarea>s. If the mouse button is held
down and the user starts dragging, the selection expands with additional
paragraphs or lines.

This expands on the work of Kai Wildberger (PR #7681) but was adjusted
for the work that happened previously to support double click + drag
moves and includes triple click support for our Qt UI.

Co-authored-by: Kai Wildberger <kiawildberger@gmail.com>
2026-02-06 14:18:10 +00:00
Jelle Raaijmakers
7f8d052b7e LibWeb: Support double click word selection dragging
In EventHandler, we now keep track of a mouse selection mode which is
either None, Character or Word. By double clicking a word and
immediately dragging, you can now extend the selection word by word
instead of by character.
2026-02-06 14:18:10 +00:00
Jelle Raaijmakers
c56c933014 LibWeb+WebContent: Instantly update DPI for painting and media queries
If our UI informed the page of a DPI change, we would store the new
device pixel ratio and leave it at that. It would take a layout/style
update (e.g. by clicking the page) to actually render the page using the
new DPI. This is very visible on macOS when moving the Ladybird window
from a 1x resolution monitor to a HiDPI 2x monitor.

We now instantly update the backing stores and mark media queries for
reevaluation. Moving the Ladybird window on macOS now immediately
updates the page when dragging it to a HiDPI monitor.
2026-02-06 09:01:26 +01:00
Timothy Flynn
0482b6bb57 LibWeb+LibWebView+WebContent: Implement versioning for document cookies
This patch introduces a cookie cache in the WebContent process to reduce
blocking IPC calls when JS accesses document.cookie. The UI process now
maintains a cookie version counter per-domain in shared memory. When JS
reads document.cookie, we check whether we have a valid cached cookie by
comparing the current shared version to the last used version. If they
match, the cached cookie is returned without IPC.

This optimization is based on Chromium's shared versioning, in which it
was observed that 87% of document.cookie accesses were redundant. See:
https://blog.chromium.org/2024/06/introducing-shared-memory-versioning-to.html

Note that this cache only supports document.cookie, not HTTP Cookie
headers. HTTP cookies are attached to requests with varying URLs and
paths. The cookies that match the document URL might not match the
request URL, which we wouldn't know from WebContent. So attaching the
cached document cookie would be incorrect.

On https://twinings.co.uk, we see approximately 600 document.cookie
requests while the page loads. This patch reduces the time spent in
the document.cookie getter from ~45ms to 2-3ms.
2026-02-05 07:28:07 -05:00
Aliaksandr Kalenik
2738f6c9c6 LibWeb: Fix double-inversion of visual viewport transform
The AccumulatedVisualContext tree already handles the visual viewport
transform for hit testing (via transform_point_for_hit_test) and offset
computation (via inverse_transform_point). Passing viewport_position
(which has map_to_layout_viewport already applied) to these functions
caused a double-inversion during pinch-to-zoom.
2026-01-31 19:20:09 +01:00
Aliaksandr Kalenik
24c08b7d42 LibWeb: Fix mouse event offset computation with nested CSS transforms
compute_mouse_event_offset() only inverted the target element's own CSS
transform, ignoring ancestor transforms. This caused incorrect offsetX/
offsetY values when elements were nested inside transformed parents.

Use AccumulatedVisualContext::inverse_transform_point() to invert the
full ancestor transform chain instead.
2026-01-31 16:56:05 +01:00
Tim Ledbetter
74ca89017c LibWeb: Use insertLineBreak input type for form controls on Enter key
This matches the behavior of other engines.
2026-01-31 13:30:33 +01:00
Jelle Raaijmakers
e05503dbcb LibWeb: Send InputEvent with right .inputType on insert and delete
Applies to `<input>` and `<textarea>`. Editing commands in
`contenteditable` already sent the right events and input types.

Fixes #7668
2026-01-29 15:08:06 +01:00
Tim Ledbetter
e04446802f LibWeb: Implement label activation behavior in the DOM layer
Previously, click handling for labels was handled in layout and
painting code. This change implements activation_behavior on
HTMLLabelElement, which clicks and focuses the element.
2026-01-27 18:35:38 +01:00
Jelle Raaijmakers
746362e5de LibWeb: Handle WebDriver special keys and Mod_Keypad in keyboard events
Add webdriver_key_to_key_code() in Internals.cpp to properly translate
WebDriver special key codes (0xE000-0xE05D) to KeyCode values with
appropriate modifiers. This ensures keys like Enter, Backspace, and
arrow keys are handled correctly when sent via Internals::send_text().

In EventHandler::handle_keydown(), strip Mod_Keypad when determining
Enter key behavior since it only indicates key location (numpad vs
standard keyboard), not a behavior change. The modifier is still passed
through to KeyboardEvent for the location property.

This gains us 656 WPT subtest passes in `editing`.
2026-01-23 14:21:35 +01:00
Jelle Raaijmakers
da01b0c389 LibWeb: Insert newlines for line breaks in preformatted white-space
When inserting a line break in a contenteditable with preformatted
white-space (pre, pre-line, pre-wrap), insert a newline character (\n)
instead of a <br> element. Use <br> only for padding at end of line to
ensure the cursor can be placed on the new line.
2026-01-23 14:21:35 +01:00
Andreas Kling
838a0fcaa6 LibWeb: Validate scale_delta is finite when decoding PinchEvent from IPC
Reject NaN and Inf values for scale_delta since they don't make sense
for a pinch gesture and could cause issues in downstream calculations.
2026-01-22 17:38:15 +01:00
Shannon Booth
c6fab541b7 LibWeb: Fix storage set broadcast event never broadcasting old value
We had skipped some steps in the spec and were:
 * Always broadcasting an old value of null, instead of what it
   actually was previously.
 * Still broadcasting a storage event even if the value had
   not changed in storage compared to the last value.

Fix both issues by returning what the old value is in the setter and
implementing the missing logic.
2026-01-21 22:27:59 +01:00
Tim Ledbetter
f8d6314db6 LibWeb: Account for scroll offset in iframe mouse event coordinates
When delegating mouse events to iframes, coordinate transformations
were not accounting for scroll offsets. This caused clicks inside
iframes to be incorrectly positioned when the parent page was scrolled.
2026-01-19 06:22:18 +01:00
Adam Colvin
3a6d82245b LibWeb: Implement Screen.isExtended attribute
- Add WindowManagement to PolicyControlledFeature enum
- Add screen_count() virtual method to PageClient
- Store all screen rects in WebContent::PageClient, derive both
  screen_rect() and screen_count() from stored data
- Implement screen_count() overrides in SVGPageClient and PageHost
- Replace FIXME stub in Screen.cpp with spec-compliant implementation
2026-01-16 20:34:58 +01:00
Jelle Raaijmakers
bf77aeb3dc Tests/LibWeb: Support WPT variant meta tags in test-web
Add support for WPT test variants, which allow a single test file to be
run multiple times with different URL query parameters. Tests declare
variants using `<meta name="variant" content="?param=value">` tags.

When test-web encounters a test with variants, it expands that test into
multiple runs, each with its own expectation file using the naming
convention `testname@variant.txt` (e.g., `test@run_type=uri.txt`).

Implementation details:
- WebContent observes variant meta tags and communicates them to the
  test runner via a new `did_receive_test_variant_metadata` IPC call
- test-web dynamically expands tests with variants during execution,
  waking idle views after each test completion to pick up new work
- Use index-based test tracking to avoid dangling references when the
  test vector grows during variant expansion
- Introduce TestRunContext to group test run state, and store a static
  pointer to it for signal handler access

This enables proper testing of WPT tests that use variants, such as the
html5lib parsing tests (which test uri, write, and write_single modes)
and the editing/bold tests (which split across multiple ranges).
2026-01-16 16:44:13 +00:00
Gingeh
37c33c8215 LibWeb: Don't crash when clicking on display: contents element 2026-01-16 10:11:07 +01:00
Andreas Kling
681d00c218 LibDevTools: Pass request initiator type to network panel
Propagate the request initiator type (e.g., "xmlhttprequest", "fetch",
"script", "stylesheet") from LibWeb through the IPC layer to DevTools.

This enables Firefox DevTools to correctly identify XHR/fetch requests
and display appropriate cause types in the Network panel's "Initiator"
column.
2026-01-15 20:10:19 +01:00
Andreas Kling
31ffd2e8e5 LibDevTools: Add request and response body viewing to network panel
This adds support for viewing request payloads (POST data) and response
bodies in the Firefox DevTools network panel.

Request bodies are captured when network requests start and passed
through IPC to the NetworkEventActor, which returns them via the
getRequestPostData protocol method.

Response bodies are streamed via a new IPC message as data is received,
accumulated in NetworkEventActor (with a 10MB size limit to prevent
memory issues), and returned via getResponseContent. Text content is
returned as UTF-8, while binary content (images, etc.) is base64.
2026-01-15 20:10:19 +01:00
Andreas Kling
cf010885d5 LibDevTools: Add Firefox DevTools network monitoring support
Hook ResourceLoader to emit network request lifecycle events through
IPC to the UI process, where FrameActor creates NetworkEventActor
instances that serialize requests using Firefox's Remote Debug Protocol.

The Network panel now shows requests with method, URL, status, MIME
type, size, and timing information. Several features remain stubbed
(POST data, response content, cause detection) marked with FIXMEs.
2026-01-15 20:10:19 +01:00
Jonathan Gamble
8f1cb4cbb0 LibWeb: Implement resizing for eligible elements and update scrollbars
Add ElementResizeAction to Page (maybe there's a better place). It's
just a mousemove delegate that updates styles on the target element.

Add ChromeMetrics for zoom-invariant chrome like scrollbar thumb
thickness, resize gripper size, paddings, etc. It's not user-stylable
but separates basic concerns in a way that a visually gifted
designer unlike myself can adjust to taste.

These values are pre-divided by zoom factor so that PaintableBox can
continue using device_pixels_per_css_pixel calls as normal.

The adjusted metrics are computed on demand from Page multiple times
per paint cycle, which is not ideal but avoids lifetime management and
atomics. Maybe someone with more surety about the painting flow control
can improve this, but it won't be a huge win. If profiling shows
this slowing paints, then Ladybird is in good shape.

Update PaintableBox to draw the resize gripper and deconflict
the scrollbars. Set apropriate cursors for scrollbars and gripper in
mousemove. We override EventHandler's cursor handling because nothing
should ever come between a man and his resize gripper.

Chrome metrics use the CSSPixels class. This is good because it's
broadly compatible but bad because they're actually different units
when zoom is not 1.0. If that's a problem, we could make a new type
or just use double.
2026-01-12 11:00:14 +00:00
Jonathan Gamble
fc22c9ea38 LibWeb+WebContent: Allow WebContent to disentangle zoom from css pixels
So Ladybird can paint scrollbar & resizer chrome at the same size
regardless of zoom level while still respecting device pixel ratio
2026-01-12 11:00:14 +00:00
Jonathan Gamble
f84e6f8acf LibWeb: Make input controls relinquish focus on outside clicks
Model "viewport focus" with Document::focused_area == nullptr.

Focus.cpp:
  When a blur occurs, remove the document entry from the old chain
  before running the focusing steps. This ensures the document atop the
  new chain is not discarded. Focus::run_focus_update_steps will then
  set focused_area to nullptr, indicating viewport focus.

EventHandler.cpp:
  Split hit testing in handle_mousedown. Use an exact hit test for
  focus/blur decisions, and a subsequent cursor hit test for
  selection/caret.
2026-01-09 18:09:09 +01:00
Jonathan Gamble
ed568fcada LibWeb: Reduce nesting in handle_mousedown. No functional changes 2026-01-09 18:09:09 +01:00
Sam Atkins
8a0ba904b9 LibWeb/HTML: Return Promises from Window scroll methods
A version of this was added in a610639119
and reverted in 70671b4c11. The bugs
there (confusing scroll-to-position and scroll-by-delta, and not having
an execution context in some cases) have been fixed in this version.
2026-01-08 14:50:09 +00:00
Andreas Kling
a9cc425cde LibJS+LibWeb: Add missing GC marking visits
This adds visit_edges(Cell::Visitor&) methods to various helper structs
that contain GC pointers, and makes sure they are called from owning
GC-heap-allocated objects as needed.

These were found by our Clang plugin after expanding its capabilities.
The added rules will be enforced by CI going forward.
2026-01-07 12:48:58 +01:00
Tim Ledbetter
70671b4c11 Revert "LibWeb/HTML: Return Promises from Window scroll methods"
This reverts commit a610639119.
2025-12-26 19:33:51 +01:00
Aliaksandr Kalenik
8af78cff30 LibWeb: Skip scroll promise allocation in mouse event handling
Fixes crashing introduced in a610639 when `scroll_viewport_by_delta()`
is called from `EventHandler::handle_mousewheel()` and there's no
running execution context to grab current realm from to allocate a
promise.
2025-12-23 17:36:48 +01:00
Sam Atkins
a610639119 LibWeb/HTML: Return Promises from Window scroll methods
Corresponds to part of:
c548a9a1d4
2025-12-23 14:24:28 +01:00
Sam Atkins
c77db4135d LibWeb: Implement web-exposed available screen area
This is allowed to behave the same as the web-exposed screen area, so
we'll do that for now.
2025-12-12 10:17:00 +00:00
Sam Atkins
03857698a5 LibWeb: Update spec text for web_exposed_screen_area()
Corresponds to:
6fb99c813c
2025-12-12 10:17:00 +00:00
Timothy Flynn
96806a3f90 LibWeb: Update cursor and tooltip UI state regardless of event handlers
If a script on the page cancels a mousemove event, we would return early
and neglect to update the cursor. This is seen regularly on "Diablo Web"
where they set the cursor to "none" on the main canvas, and also cancel
mousemove events.
2025-12-03 12:23:56 +01:00
InvalidUsernameException
28ba610f32 Everywhere: Avoid large rebuilds when editing (Immutable)Bitmap headers
This reduces the number of recompiled files as follow:
- Bitmap.h: 1309 -> 101
- ImmutableBitmap.h: 1218 -> 75
2025-11-28 18:32:48 +01:00
Aliaksandr Kalenik
2a18b6b802 LibWeb: Prevent default on pointerdown/mousedown should skip focus steps
Fixes a bug in the ChatGPT model dropdown where clicking it immediately
closes the menu because focus is being stolen.
2025-11-21 08:30:32 +01:00
Andreas Kling
66263f142b LibWeb: Add StyleScope to keep style caches per Document/ShadowRoot
Before this change, we've been maintaining various StyleComputer caches
at the document level.

This made sense for old-school documents without shadow trees, since
all the style information was document-wide anyway. However, documents
with many shadow trees ended up suffering since any time you mutated
a style sheet inside a shadow tree, *all* style caches for the entire
document would get invalidated.

This was particularly expensive on Reddit, which has tons of shadow
trees with their own style elements. Every time we'd create one of their
custom elements, we'd invalidate the document-level "rule cache" and
have to rebuild it, taking about ~60ms each time (ouch).

This commit introduces a new object called StyleScope.

Every Document and ShadowRoot has its own StyleScope. Rule caches etc
are moved from StyleComputer to StyleScope.

Rule cache invalidation now happens at StyleScope level. As an example,
rule cache rebuilds now take ~1ms on Reddit instead of ~60ms.

This is largely a mechanical change, moving things around, but there's
one key detail to be aware of: due to the :host selector, which works
across the shadow DOM boundary and reaches from inside a shadow tree out
into the light tree, there are various places where we have to check
both the shadow tree's StyleScope *and* the document-level StyleScope
in order to get all rules that may apply.
2025-11-14 22:05:33 +01:00
Luke Wilde
82bd3d3891 LibWeb: Avoid invoking Trusted Types where avoidable
Prevents observably calling Trusted Types, which can run arbitrary JS,
cause crashes due to use of MUST and allow arbitrary JS to modify
internal elements.
2025-11-06 11:43:06 -05:00