Commit Graph

156 Commits

Author SHA1 Message Date
Timothy Flynn
cfe7ddc805 LibWeb: Add support for handling drag-and-drop events of DOM elements
This allows dragging elements on the page and dropping them onto other
elements. This does not yet support dragging text.

The test added here is manual; the WPT tests rely heavily on WebDriver
actions.
2026-04-05 11:34:42 -04:00
Timothy Flynn
b7076c366d LibWeb: Work around a spec bug regarding cancelling dragenter events
The spec dictates that dragenter events must be cancelled in order for
drops to be accepted on the entered element. Web reality disagrees, as
all three major browsers do not have this requirement.
2026-04-05 11:34:42 -04:00
sasetz
e17d797bdb LibWeb: Remove forceful resetting cursor in nested navigables 2026-03-23 09:05:13 +01:00
Zaggy1024
07cf09a0f2 UI/AppKit+LibWeb: Handle the Ctrl+click context menu in EventHandler
Changing Ctrl+click to a secondary click is incorrect. It prevents
sites from using Ctrl+click themselves. Instead, just maybe open the
context menu in mousedown for primary clicks with Ctrl pressed.

Fixes the autofire shortcut not working in the Humble Mozilla Bundle's
asm.js FTL.
2026-03-17 04:01:29 -05:00
Zaggy1024
7236f5adfc LibWeb: Open the context menu on mousedown instead of mouseup
This matches the behavior on KDE, GNOME and macOS.

Windows will need an override to switch this to mouseup.
2026-03-17 04:01:29 -05:00
Zaggy1024
18c594aba5 LibWeb: Continue to fire mousemove/up when dragging outside the window
The spec specifies that we may do this. Other browsers target the html
element when the cursor leaves the window during a drag, so we do the
same.
2026-03-17 04:01:29 -05:00
Zaggy1024
ee45cdfb09 LibWeb: Refactor pointer event handling/dispatch to work closer to spec
Pieces of the down, move, and up handlers are moved to separate
functions. Some part actually have specs, so the ones I've found thus
far have been brought in to make things more spec-aligned. A lot of
FIXMEs are added for things that the spec mentions or implies.

Pointer events are intended to be handled per pointer device, but this
still treats them the same as legacy mouse events. However, the PREVENT
MOUSE EVENT flag is implemented to block legacy mouse events for the
duration of a drag.

Behavior changes should be minimal.

One notable change is that auxclick is now fired for all non-primary
buttons, which matches the spec and other browsers.
2026-03-17 04:01:29 -05:00
Zaggy1024
2291e3d551 LibWeb: Set button MouseEvents' detail attributes to the click count 2026-03-17 04:01:29 -05:00
Zaggy1024
a51967311e Everywhere: Consolidate double/triple click handling to use click count
This moves normal/double/triple click checking into WebContent, the
client only has to send a click count in order to activate a double
or triple click in the content. This means that the AppKit UI will no
longer fire multiple double clicks when clicking in place more than 3
times. This matches the behavior of other browsers on macOS.

We will now also fire the click event regardless of whether a dblclick
event will follow, as the spec requires.
2026-03-17 04:01:29 -05:00
Zaggy1024
8197359287 LibWeb: Always end selection on mouseup
Not sure why this goto was here, but we should always stop selection if
mouseup occurs, regardless of any preconditions for the actual hit
testing or event dispatch.
2026-03-17 04:01:29 -05:00
Zaggy1024
d94293cc25 LibWeb: Use an abstract class for scrollbar and resize handle input
This unifies the implementations of the element resize and the scroll
mouse inputs, so the actual code involved in handling the events can
be simplified, and it only should require one object per event.

The cursor override is now part of this ChromeWidget class as well, so
that the hit test's cursor doesn't need to be passed around as much.
2026-03-17 04:01:29 -05:00
Zaggy1024
44ed698d4f LibWeb: Separate the active element and the element being activated
We were conflating elements being the active element and elements being
activated. The :active pseudo class is supposed to be based on whether
an element will have its activation behavior run upon a button being
released.

Store whether an element is being activated as a flag that is set/reset
by EventHandler.

Doing this allows label elements to visually activate their control
without doing a weird paintable hack, so the Labelable classes have
been yeeted.
2026-03-17 04:01:29 -05:00
Aliaksandr Kalenik
834675aea3 LibWeb: Add PaintableBox::inverse_transform_point()
Extract the pattern of inverse-transforming a screen position (removing
the effect of CSS transforms) into a helper method. Used to compute
mouse event offsets relative to the target element.
2026-03-11 02:31:30 +01:00
Aliaksandr Kalenik
eae94a8a46 LibWeb: Route repaint requests through paintables, not Document
Rename Document::set_needs_display() to set_needs_repaint() and make it
private. External callers must now go through Node/Paintable which
route the request to the document internally.

Fix one existing misuse in AnimationEffect that was calling
document-level set_needs_display() instead of routing through the
target element's paintable.

This is preparation for per-paintable display list command caching:
repaint requests must go through specific paintables so their cached
command lists can be invalidated.
2026-03-04 19:35:45 +01:00
Jelle Raaijmakers
d73b268445 LibWeb: Update layout after dispatching initial mouse events
Since #8182, we've been verifying "is the layout up to date" in more
places. After dispatching mouseup/pointerup, the layout could have been
changed again and we need to update it before trying to run activation
behaviors.

Fixes opening/closing an email's details in Roundcube webmail.
2026-03-02 17:52:55 +01:00
Timothy Flynn
ae8181b467 LibWeb+LibWebView+UI: Add a context menu item to toggle fullscreen state 2026-03-01 15:41:43 -06:00
Psychpsyo
b83c11a911 LibWeb: Deduplicate code for dispatching events to nested navigables 2026-02-27 12:40:04 +01:00
Andreas Kling
4ac4b92d06 LibWeb: Update layout after event dispatch in EventHandler
Event handlers (mousedown, mousemove, doubleclick) may trigger DOM
mutations that invalidate layout. Instead of checking if the paint root
changed as a heuristic for world disturbance, properly verify the active
document hasn't changed and run update_layout() to ensure we work with
up-to-date layout information.
2026-02-26 21:09:08 +01:00
Jelle Raaijmakers
90a211bf47 LibWeb: Use device-pixel coordinates in display list and AVC
Stop converting between CSS and device pixels as part of rendering - the
display list should be as simple as possible, so convert to DevicePixels
once when constructing the display list.
2026-02-26 07:43:00 +01:00
Simon Farre
5613760e06 LibWeb: Allow close requests to exit fullscreen 2026-02-23 18:44:26 +00:00
Zaggy1024
aa6a7026da LibWeb: Skip UA shadow tree nodes when opening context menus
This makes right clicking on media element controls open the media
element's context menu instead of the shadow DOM element's.
2026-02-23 07:27:31 +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
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
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
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
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
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
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
Gingeh
37c33c8215 LibWeb: Don't crash when clicking on display: contents element 2026-01-16 10:11:07 +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
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
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