| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2021-02-09 21:23:50 +01:00
										 |  |  |  * Copyright (c) 2020-2021, Andreas Kling <kling@serenityos.org> | 
					
						
							| 
									
										
										
										
											2021-05-18 13:13:58 +02:00
										 |  |  |  * Copyright (c) 2021, Max Wipfli <mail@maxwipfli.ch> | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2021-04-22 01:24:48 -07:00
										 |  |  |  * SPDX-License-Identifier: BSD-2-Clause | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <LibGUI/Event.h>
 | 
					
						
							|  |  |  | #include <LibGUI/Window.h>
 | 
					
						
							| 
									
										
										
										
											2020-12-06 19:51:55 +01:00
										 |  |  | #include <LibWeb/DOM/Range.h>
 | 
					
						
							| 
									
										
										
										
											2020-08-02 12:10:01 +02:00
										 |  |  | #include <LibWeb/DOM/Text.h>
 | 
					
						
							| 
									
										
										
										
											2020-07-28 17:21:23 +02:00
										 |  |  | #include <LibWeb/HTML/HTMLAnchorElement.h>
 | 
					
						
							|  |  |  | #include <LibWeb/HTML/HTMLIFrameElement.h>
 | 
					
						
							| 
									
										
										
										
											2020-10-02 19:01:51 +02:00
										 |  |  | #include <LibWeb/HTML/HTMLImageElement.h>
 | 
					
						
							| 
									
										
										
										
											2021-09-08 11:27:46 +02:00
										 |  |  | #include <LibWeb/Layout/InitialContainingBlock.h>
 | 
					
						
							| 
									
										
										
										
											2021-05-30 12:36:53 +02:00
										 |  |  | #include <LibWeb/Page/BrowsingContext.h>
 | 
					
						
							| 
									
										
										
										
											2020-07-28 19:27:41 +02:00
										 |  |  | #include <LibWeb/Page/EventHandler.h>
 | 
					
						
							| 
									
										
										
										
											2021-08-24 16:28:08 +02:00
										 |  |  | #include <LibWeb/Page/Page.h>
 | 
					
						
							| 
									
										
										
										
											2020-11-21 19:15:57 +00:00
										 |  |  | #include <LibWeb/UIEvents/EventNames.h>
 | 
					
						
							| 
									
										
										
										
											2020-07-28 17:21:23 +02:00
										 |  |  | #include <LibWeb/UIEvents/MouseEvent.h>
 | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace Web { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-21 20:15:00 +00:00
										 |  |  | static Gfx::StandardCursor cursor_css_to_gfx(Optional<CSS::Cursor> cursor) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (!cursor.has_value()) { | 
					
						
							|  |  |  |         return Gfx::StandardCursor::None; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     switch (cursor.value()) { | 
					
						
							|  |  |  |     case CSS::Cursor::Crosshair: | 
					
						
							|  |  |  |     case CSS::Cursor::Cell: | 
					
						
							|  |  |  |         return Gfx::StandardCursor::Crosshair; | 
					
						
							|  |  |  |     case CSS::Cursor::Grab: | 
					
						
							|  |  |  |     case CSS::Cursor::Grabbing: | 
					
						
							|  |  |  |         return Gfx::StandardCursor::Drag; | 
					
						
							|  |  |  |     case CSS::Cursor::Pointer: | 
					
						
							|  |  |  |         return Gfx::StandardCursor::Hand; | 
					
						
							|  |  |  |     case CSS::Cursor::Help: | 
					
						
							|  |  |  |         return Gfx::StandardCursor::Help; | 
					
						
							|  |  |  |     case CSS::Cursor::None: | 
					
						
							|  |  |  |         return Gfx::StandardCursor::Hidden; | 
					
						
							|  |  |  |     case CSS::Cursor::Text: | 
					
						
							|  |  |  |     case CSS::Cursor::VerticalText: | 
					
						
							|  |  |  |         return Gfx::StandardCursor::IBeam; | 
					
						
							|  |  |  |     case CSS::Cursor::Move: | 
					
						
							|  |  |  |     case CSS::Cursor::AllScroll: | 
					
						
							|  |  |  |         return Gfx::StandardCursor::Move; | 
					
						
							|  |  |  |     case CSS::Cursor::Progress: | 
					
						
							|  |  |  |     case CSS::Cursor::Wait: | 
					
						
							|  |  |  |         return Gfx::StandardCursor::Wait; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case CSS::Cursor::ColResize: | 
					
						
							|  |  |  |         return Gfx::StandardCursor::ResizeColumn; | 
					
						
							|  |  |  |     case CSS::Cursor::EResize: | 
					
						
							|  |  |  |     case CSS::Cursor::WResize: | 
					
						
							|  |  |  |     case CSS::Cursor::EwResize: | 
					
						
							|  |  |  |         return Gfx::StandardCursor::ResizeHorizontal; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case CSS::Cursor::RowResize: | 
					
						
							|  |  |  |         return Gfx::StandardCursor::ResizeRow; | 
					
						
							|  |  |  |     case CSS::Cursor::NResize: | 
					
						
							|  |  |  |     case CSS::Cursor::SResize: | 
					
						
							|  |  |  |     case CSS::Cursor::NsResize: | 
					
						
							|  |  |  |         return Gfx::StandardCursor::ResizeVertical; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case CSS::Cursor::NeResize: | 
					
						
							|  |  |  |     case CSS::Cursor::SwResize: | 
					
						
							|  |  |  |     case CSS::Cursor::NeswResize: | 
					
						
							|  |  |  |         return Gfx::StandardCursor::ResizeDiagonalBLTR; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case CSS::Cursor::NwResize: | 
					
						
							|  |  |  |     case CSS::Cursor::SeResize: | 
					
						
							|  |  |  |     case CSS::Cursor::NwseResize: | 
					
						
							|  |  |  |         return Gfx::StandardCursor::ResizeDiagonalTLBR; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         return Gfx::StandardCursor::None; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-22 15:53:01 +01:00
										 |  |  | static Gfx::IntPoint compute_mouse_event_offset(const Gfx::IntPoint& position, const Layout::Node& layout_node) | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     auto top_left_of_layout_node = layout_node.box_type_agnostic_position(); | 
					
						
							|  |  |  |     return { | 
					
						
							|  |  |  |         position.x() - static_cast<int>(top_left_of_layout_node.x()), | 
					
						
							|  |  |  |         position.y() - static_cast<int>(top_left_of_layout_node.y()) | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-30 12:36:53 +02:00
										 |  |  | EventHandler::EventHandler(Badge<BrowsingContext>, BrowsingContext& frame) | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  |     : m_frame(frame) | 
					
						
							| 
									
										
										
										
											2020-12-01 23:35:47 +01:00
										 |  |  |     , m_edit_event_handler(make<EditEventHandler>(frame)) | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | EventHandler::~EventHandler() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-08 11:27:46 +02:00
										 |  |  | const Layout::InitialContainingBlock* EventHandler::layout_root() const | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     if (!m_frame.document()) | 
					
						
							|  |  |  |         return nullptr; | 
					
						
							| 
									
										
										
										
											2020-07-10 23:52:06 +02:00
										 |  |  |     return m_frame.document()->layout_node(); | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-08 11:27:46 +02:00
										 |  |  | Layout::InitialContainingBlock* EventHandler::layout_root() | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     if (!m_frame.document()) | 
					
						
							|  |  |  |         return nullptr; | 
					
						
							| 
									
										
										
										
											2020-07-10 23:52:06 +02:00
										 |  |  |     return m_frame.document()->layout_node(); | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-22 19:45:41 +01:00
										 |  |  | bool EventHandler::handle_mousewheel(const Gfx::IntPoint& position, unsigned int buttons, unsigned int modifiers, int wheel_delta) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2021-02-22 19:48:24 +01:00
										 |  |  |     if (!layout_root()) | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // FIXME: Support wheel events in subframes.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto result = layout_root()->hit_test(position, Layout::HitTestType::Exact); | 
					
						
							|  |  |  |     if (result.layout_node) { | 
					
						
							| 
									
										
										
										
											2021-03-02 08:36:58 +11:00
										 |  |  |         if (result.layout_node->handle_mousewheel({}, position, buttons, modifiers, wheel_delta)) | 
					
						
							|  |  |  |             return true; | 
					
						
							| 
									
										
										
										
											2021-03-02 08:39:07 +11:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (auto* page = m_frame.page()) { | 
					
						
							|  |  |  |         page->client().page_did_request_scroll(wheel_delta); | 
					
						
							| 
									
										
										
										
											2021-02-22 19:48:24 +01:00
										 |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-22 19:45:41 +01:00
										 |  |  |     return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-10 10:57:59 +02:00
										 |  |  | bool EventHandler::handle_mouseup(const Gfx::IntPoint& position, unsigned button, unsigned modifiers) | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-07-10 23:43:25 +02:00
										 |  |  |     if (!layout_root()) | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  |         return false; | 
					
						
							| 
									
										
										
										
											2020-09-11 18:15:47 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (m_mouse_event_tracking_layout_node) { | 
					
						
							|  |  |  |         m_mouse_event_tracking_layout_node->handle_mouseup({}, position, button, modifiers); | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  |     bool handled_event = false; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-22 15:53:01 +01:00
										 |  |  |     auto result = layout_root()->hit_test(position, Layout::HitTestType::Exact); | 
					
						
							| 
									
										
										
										
											2020-09-11 18:15:47 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (result.layout_node && result.layout_node->wants_mouse_events()) { | 
					
						
							|  |  |  |         result.layout_node->handle_mouseup({}, position, button, modifiers); | 
					
						
							| 
									
										
										
										
											2020-09-12 17:55:19 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-22 15:53:01 +01:00
										 |  |  |         // Things may have changed as a consequence of Layout::Node::handle_mouseup(). Hit test again.
 | 
					
						
							| 
									
										
										
										
											2020-09-12 17:55:19 +02:00
										 |  |  |         if (!layout_root()) | 
					
						
							|  |  |  |             return true; | 
					
						
							| 
									
										
										
										
											2020-11-22 15:53:01 +01:00
										 |  |  |         result = layout_root()->hit_test(position, Layout::HitTestType::Exact); | 
					
						
							| 
									
										
										
										
											2020-09-11 18:15:47 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-22 14:46:36 +01:00
										 |  |  |     if (result.layout_node && result.layout_node->dom_node()) { | 
					
						
							|  |  |  |         RefPtr<DOM::Node> node = result.layout_node->dom_node(); | 
					
						
							| 
									
										
										
										
											2020-07-28 18:20:36 +02:00
										 |  |  |         if (is<HTML::HTMLIFrameElement>(*node)) { | 
					
						
							| 
									
										
										
										
											2021-06-24 19:53:42 +02:00
										 |  |  |             if (auto* subframe = verify_cast<HTML::HTMLIFrameElement>(*node).nested_browsing_context()) | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  |                 return subframe->event_handler().handle_mouseup(position.translated(compute_mouse_event_offset({}, *result.layout_node)), button, modifiers); | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         auto offset = compute_mouse_event_offset(position, *result.layout_node); | 
					
						
							| 
									
										
										
										
											2021-04-15 20:50:02 +03:00
										 |  |  |         node->dispatch_event(UIEvents::MouseEvent::create(UIEvents::EventNames::mouseup, offset.x(), offset.y(), position.x(), position.y())); | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  |         handled_event = true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-09 14:02:45 +01:00
										 |  |  |     if (button == GUI::MouseButton::Left) | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  |         m_in_mouse_selection = false; | 
					
						
							|  |  |  |     return handled_event; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-10 10:57:59 +02:00
										 |  |  | bool EventHandler::handle_mousedown(const Gfx::IntPoint& position, unsigned button, unsigned modifiers) | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-07-10 23:43:25 +02:00
										 |  |  |     if (!layout_root()) | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  |         return false; | 
					
						
							| 
									
										
										
										
											2020-09-11 18:15:47 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (m_mouse_event_tracking_layout_node) { | 
					
						
							|  |  |  |         m_mouse_event_tracking_layout_node->handle_mousedown({}, position, button, modifiers); | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-06 19:41:10 +02:00
										 |  |  |     NonnullRefPtr document = *m_frame.document(); | 
					
						
							| 
									
										
										
										
											2020-11-29 16:39:56 +01:00
										 |  |  |     RefPtr<DOM::Node> node; | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-29 16:39:56 +01:00
										 |  |  |     { | 
					
						
							|  |  |  |         auto result = layout_root()->hit_test(position, Layout::HitTestType::Exact); | 
					
						
							|  |  |  |         if (!result.layout_node) | 
					
						
							|  |  |  |             return false; | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-29 16:39:56 +01:00
										 |  |  |         node = result.layout_node->dom_node(); | 
					
						
							|  |  |  |         document->set_hovered_node(node); | 
					
						
							| 
									
										
										
										
											2020-09-12 17:55:19 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-29 16:39:56 +01:00
										 |  |  |         if (result.layout_node->wants_mouse_events()) { | 
					
						
							|  |  |  |             result.layout_node->handle_mousedown({}, position, button, modifiers); | 
					
						
							|  |  |  |             return true; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-09-11 18:15:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-29 16:39:56 +01:00
										 |  |  |         if (!node) | 
					
						
							|  |  |  |             return false; | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-29 16:39:56 +01:00
										 |  |  |         if (is<HTML::HTMLIFrameElement>(*node)) { | 
					
						
							| 
									
										
										
										
											2021-06-24 19:53:42 +02:00
										 |  |  |             if (auto* subframe = verify_cast<HTML::HTMLIFrameElement>(*node).nested_browsing_context()) | 
					
						
							| 
									
										
										
										
											2020-11-29 16:39:56 +01:00
										 |  |  |                 return subframe->event_handler().handle_mousedown(position.translated(compute_mouse_event_offset({}, *result.layout_node)), button, modifiers); | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-29 16:39:56 +01:00
										 |  |  |         if (auto* page = m_frame.page()) | 
					
						
							| 
									
										
										
										
											2021-05-30 12:36:53 +02:00
										 |  |  |             page->set_focused_browsing_context({}, m_frame); | 
					
						
							| 
									
										
										
										
											2020-08-14 11:33:20 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-29 16:39:56 +01:00
										 |  |  |         auto offset = compute_mouse_event_offset(position, *result.layout_node); | 
					
						
							| 
									
										
										
										
											2021-04-15 20:50:02 +03:00
										 |  |  |         node->dispatch_event(UIEvents::MouseEvent::create(UIEvents::EventNames::mousedown, offset.x(), offset.y(), position.x(), position.y())); | 
					
						
							| 
									
										
										
										
											2020-11-29 16:39:56 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // NOTE: Dispatching an event may have disturbed the world.
 | 
					
						
							|  |  |  |     if (!layout_root() || layout_root() != node->document().layout_node()) | 
					
						
							| 
									
										
										
										
											2020-07-10 23:43:25 +02:00
										 |  |  |         return true; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-02 19:01:51 +02:00
										 |  |  |     if (button == GUI::MouseButton::Right && is<HTML::HTMLImageElement>(*node)) { | 
					
						
							| 
									
										
										
										
											2021-06-24 19:53:42 +02:00
										 |  |  |         auto& image_element = verify_cast<HTML::HTMLImageElement>(*node); | 
					
						
							| 
									
										
										
										
											2020-10-02 19:01:51 +02:00
										 |  |  |         auto image_url = image_element.document().complete_url(image_element.src()); | 
					
						
							| 
									
										
										
										
											2020-11-12 18:23:05 +01:00
										 |  |  |         if (auto* page = m_frame.page()) | 
					
						
							| 
									
										
										
										
											2021-05-30 12:36:53 +02:00
										 |  |  |             page->client().page_did_request_image_context_menu(m_frame.to_top_level_position(position), image_url, "", modifiers, image_element.bitmap()); | 
					
						
							| 
									
										
										
										
											2020-10-02 19:01:51 +02:00
										 |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-28 18:20:36 +02:00
										 |  |  |     if (RefPtr<HTML::HTMLAnchorElement> link = node->enclosing_link_element()) { | 
					
						
							| 
									
										
										
										
											2020-07-06 19:41:10 +02:00
										 |  |  |         auto href = link->href(); | 
					
						
							|  |  |  |         auto url = document->complete_url(href); | 
					
						
							| 
									
										
										
										
											2021-01-09 14:02:45 +01:00
										 |  |  |         dbgln("Web::EventHandler: Clicking on a link to {}", url); | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  |         if (button == GUI::MouseButton::Left) { | 
					
						
							|  |  |  |             if (href.starts_with("javascript:")) { | 
					
						
							| 
									
										
										
										
											2020-07-06 19:41:10 +02:00
										 |  |  |                 document->run_javascript(href.substring_view(11, href.length() - 11)); | 
					
						
							| 
									
										
										
										
											2020-07-05 14:50:38 +02:00
										 |  |  |             } else if (href.starts_with('#')) { | 
					
						
							|  |  |  |                 auto anchor = href.substring_view(1, href.length() - 1); | 
					
						
							|  |  |  |                 m_frame.scroll_to_anchor(anchor); | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  |             } else { | 
					
						
							| 
									
										
										
										
											2021-06-18 16:42:34 -06:00
										 |  |  |                 document->set_active_element(link); | 
					
						
							| 
									
										
										
										
											2021-05-30 12:36:53 +02:00
										 |  |  |                 if (m_frame.is_top_level()) { | 
					
						
							| 
									
										
										
										
											2020-11-12 18:23:05 +01:00
										 |  |  |                     if (auto* page = m_frame.page()) | 
					
						
							|  |  |  |                         page->client().page_did_click_link(url, link->target(), modifiers); | 
					
						
							| 
									
										
										
										
											2020-06-07 14:45:59 +02:00
										 |  |  |                 } else { | 
					
						
							|  |  |  |                     // FIXME: Handle different targets!
 | 
					
						
							| 
									
										
										
										
											2020-07-07 17:25:33 +02:00
										 |  |  |                     m_frame.loader().load(url, FrameLoader::Type::Navigation); | 
					
						
							| 
									
										
										
										
											2020-06-07 14:45:59 +02:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  |             } | 
					
						
							|  |  |  |         } else if (button == GUI::MouseButton::Right) { | 
					
						
							| 
									
										
										
										
											2020-11-12 18:23:05 +01:00
										 |  |  |             if (auto* page = m_frame.page()) | 
					
						
							| 
									
										
										
										
											2021-05-30 12:36:53 +02:00
										 |  |  |                 page->client().page_did_request_link_context_menu(m_frame.to_top_level_position(position), url, link->target(), modifiers); | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  |         } else if (button == GUI::MouseButton::Middle) { | 
					
						
							| 
									
										
										
										
											2020-11-12 18:23:05 +01:00
										 |  |  |             if (auto* page = m_frame.page()) | 
					
						
							|  |  |  |                 page->client().page_did_middle_click_link(url, link->target(), modifiers); | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         if (button == GUI::MouseButton::Left) { | 
					
						
							| 
									
										
										
										
											2020-11-22 15:53:01 +01:00
										 |  |  |             auto result = layout_root()->hit_test(position, Layout::HitTestType::TextCursor); | 
					
						
							| 
									
										
										
										
											2020-11-22 14:46:36 +01:00
										 |  |  |             if (result.layout_node && result.layout_node->dom_node()) { | 
					
						
							| 
									
										
										
										
											2021-02-15 23:24:45 +01:00
										 |  |  |                 m_frame.set_cursor_position(DOM::Position(*result.layout_node->dom_node(), result.index_in_node)); | 
					
						
							| 
									
										
										
										
											2020-08-21 17:54:44 +02:00
										 |  |  |                 layout_root()->set_selection({ { result.layout_node, result.index_in_node }, {} }); | 
					
						
							| 
									
										
										
										
											2020-08-05 16:55:56 +02:00
										 |  |  |                 m_in_mouse_selection = true; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-07-28 17:21:23 +02:00
										 |  |  |         } else if (button == GUI::MouseButton::Right) { | 
					
						
							| 
									
										
										
										
											2020-11-12 18:23:05 +01:00
										 |  |  |             if (auto* page = m_frame.page()) | 
					
						
							| 
									
										
										
										
											2021-05-30 12:36:53 +02:00
										 |  |  |                 page->client().page_did_request_context_menu(m_frame.to_top_level_position(position)); | 
					
						
							| 
									
										
										
										
											2020-06-27 14:21:58 -06:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-10 10:57:59 +02:00
										 |  |  | bool EventHandler::handle_mousemove(const Gfx::IntPoint& position, unsigned buttons, unsigned modifiers) | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-07-10 23:43:25 +02:00
										 |  |  |     if (!layout_root()) | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  |         return false; | 
					
						
							| 
									
										
										
										
											2020-09-11 18:15:47 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (m_mouse_event_tracking_layout_node) { | 
					
						
							|  |  |  |         m_mouse_event_tracking_layout_node->handle_mousemove({}, position, buttons, modifiers); | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  |     auto& document = *m_frame.document(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bool hovered_node_changed = false; | 
					
						
							|  |  |  |     bool is_hovering_link = false; | 
					
						
							| 
									
										
										
										
											2021-02-21 20:15:00 +00:00
										 |  |  |     Gfx::StandardCursor hovered_node_cursor = Gfx::StandardCursor::None; | 
					
						
							| 
									
										
										
										
											2020-11-22 15:53:01 +01:00
										 |  |  |     auto result = layout_root()->hit_test(position, Layout::HitTestType::Exact); | 
					
						
							| 
									
										
										
										
											2020-07-28 18:20:36 +02:00
										 |  |  |     const HTML::HTMLAnchorElement* hovered_link_element = nullptr; | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  |     if (result.layout_node) { | 
					
						
							| 
									
										
										
										
											2020-09-11 18:15:47 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (result.layout_node->wants_mouse_events()) { | 
					
						
							| 
									
										
										
										
											2020-11-22 14:46:36 +01:00
										 |  |  |             document.set_hovered_node(result.layout_node->dom_node()); | 
					
						
							| 
									
										
										
										
											2020-09-11 18:15:47 +02:00
										 |  |  |             result.layout_node->handle_mousemove({}, position, buttons, modifiers); | 
					
						
							|  |  |  |             // FIXME: It feels a bit aggressive to always update the cursor like this.
 | 
					
						
							| 
									
										
										
										
											2020-11-12 18:23:05 +01:00
										 |  |  |             if (auto* page = m_frame.page()) | 
					
						
							|  |  |  |                 page->client().page_did_request_cursor_change(Gfx::StandardCursor::None); | 
					
						
							| 
									
										
										
										
											2020-09-11 18:15:47 +02:00
										 |  |  |             return true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-22 14:46:36 +01:00
										 |  |  |         RefPtr<DOM::Node> node = result.layout_node->dom_node(); | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-28 18:20:36 +02:00
										 |  |  |         if (node && is<HTML::HTMLIFrameElement>(*node)) { | 
					
						
							| 
									
										
										
										
											2021-06-24 19:53:42 +02:00
										 |  |  |             if (auto* subframe = verify_cast<HTML::HTMLIFrameElement>(*node).nested_browsing_context()) | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  |                 return subframe->event_handler().handle_mousemove(position.translated(compute_mouse_event_offset({}, *result.layout_node)), buttons, modifiers); | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         hovered_node_changed = node != document.hovered_node(); | 
					
						
							|  |  |  |         document.set_hovered_node(node); | 
					
						
							|  |  |  |         if (node) { | 
					
						
							|  |  |  |             hovered_link_element = node->enclosing_link_element(); | 
					
						
							| 
									
										
										
										
											2020-11-19 22:21:16 +01:00
										 |  |  |             if (hovered_link_element) | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  |                 is_hovering_link = true; | 
					
						
							| 
									
										
										
										
											2021-02-21 20:15:00 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |             auto cursor = result.layout_node->computed_values().cursor(); | 
					
						
							|  |  |  |             if (node->is_text() && cursor == CSS::Cursor::Auto) | 
					
						
							|  |  |  |                 hovered_node_cursor = Gfx::StandardCursor::IBeam; | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |                 hovered_node_cursor = cursor_css_to_gfx(cursor); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  |             auto offset = compute_mouse_event_offset(position, *result.layout_node); | 
					
						
							| 
									
										
										
										
											2021-04-15 20:50:02 +03:00
										 |  |  |             node->dispatch_event(UIEvents::MouseEvent::create(UIEvents::EventNames::mousemove, offset.x(), offset.y(), position.x(), position.y())); | 
					
						
							| 
									
										
										
										
											2020-11-29 16:39:56 +01:00
										 |  |  |             // NOTE: Dispatching an event may have disturbed the world.
 | 
					
						
							|  |  |  |             if (!layout_root() || layout_root() != node->document().layout_node()) | 
					
						
							| 
									
										
										
										
											2020-07-10 23:43:25 +02:00
										 |  |  |                 return true; | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |         if (m_in_mouse_selection) { | 
					
						
							| 
									
										
										
										
											2020-11-22 15:53:01 +01:00
										 |  |  |             auto hit = layout_root()->hit_test(position, Layout::HitTestType::TextCursor); | 
					
						
							| 
									
										
										
										
											2020-11-22 14:46:36 +01:00
										 |  |  |             if (hit.layout_node && hit.layout_node->dom_node()) { | 
					
						
							| 
									
										
										
										
											2021-02-15 23:24:45 +01:00
										 |  |  |                 m_frame.set_cursor_position(DOM::Position(*hit.layout_node->dom_node(), result.index_in_node)); | 
					
						
							| 
									
										
										
										
											2020-08-21 17:54:44 +02:00
										 |  |  |                 layout_root()->set_selection_end({ hit.layout_node, hit.index_in_node }); | 
					
						
							| 
									
										
										
										
											2020-08-05 16:55:56 +02:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-11-12 18:23:05 +01:00
										 |  |  |             if (auto* page = m_frame.page()) | 
					
						
							|  |  |  |                 page->client().page_did_change_selection(); | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-08-17 12:54:41 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-12 18:23:05 +01:00
										 |  |  |     if (auto* page = m_frame.page()) { | 
					
						
							| 
									
										
										
										
											2021-02-21 20:15:00 +00:00
										 |  |  |         page->client().page_did_request_cursor_change(hovered_node_cursor); | 
					
						
							| 
									
										
										
										
											2020-11-12 18:23:05 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (hovered_node_changed) { | 
					
						
							| 
									
										
										
										
											2021-03-30 12:06:06 -04:00
										 |  |  |             RefPtr<HTML::HTMLElement> hovered_html_element = document.hovered_node() ? document.hovered_node()->enclosing_html_element_with_attribute(HTML::AttributeNames::title) : nullptr; | 
					
						
							| 
									
										
										
										
											2020-11-12 18:23:05 +01:00
										 |  |  |             if (hovered_html_element && !hovered_html_element->title().is_null()) { | 
					
						
							| 
									
										
										
										
											2021-05-30 12:36:53 +02:00
										 |  |  |                 page->client().page_did_enter_tooltip_area(m_frame.to_top_level_position(position), hovered_html_element->title()); | 
					
						
							| 
									
										
										
										
											2020-11-12 18:23:05 +01:00
										 |  |  |             } else { | 
					
						
							|  |  |  |                 page->client().page_did_leave_tooltip_area(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (is_hovering_link) | 
					
						
							|  |  |  |                 page->client().page_did_hover_link(document.complete_url(hovered_link_element->href())); | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |                 page->client().page_did_unhover_link(); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-14 19:40:37 +02:00
										 |  |  | bool EventHandler::focus_next_element() | 
					
						
							| 
									
										
										
										
											2020-08-02 12:10:01 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-08-14 19:40:37 +02:00
										 |  |  |     if (!m_frame.document()) | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     auto* element = m_frame.document()->focused_element(); | 
					
						
							|  |  |  |     if (!element) { | 
					
						
							|  |  |  |         element = m_frame.document()->first_child_of_type<DOM::Element>(); | 
					
						
							|  |  |  |         if (element && element->is_focusable()) { | 
					
						
							|  |  |  |             m_frame.document()->set_focused_element(element); | 
					
						
							|  |  |  |             return true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (element = element->next_element_in_pre_order(); element && !element->is_focusable(); element = element->next_element_in_pre_order()) | 
					
						
							|  |  |  |         ; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     m_frame.document()->set_focused_element(element); | 
					
						
							|  |  |  |     return element; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool EventHandler::focus_previous_element() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // FIXME: Implement Shift-Tab cycling backwards through focusable elements!
 | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-01 10:01:11 +02:00
										 |  |  | constexpr bool should_ignore_keydown_event(u32 code_point) | 
					
						
							| 
									
										
										
										
											2021-05-18 13:13:58 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-06-01 10:01:11 +02:00
										 |  |  |     // FIXME: There are probably also keys with non-zero code points that should be filtered out.
 | 
					
						
							|  |  |  |     return code_point == 0; | 
					
						
							| 
									
										
										
										
											2021-05-18 13:13:58 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-14 19:40:37 +02:00
										 |  |  | bool EventHandler::handle_keydown(KeyCode key, unsigned modifiers, u32 code_point) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (key == KeyCode::Key_Tab) { | 
					
						
							|  |  |  |         if (modifiers & KeyModifier::Mod_Shift) | 
					
						
							|  |  |  |             return focus_previous_element(); | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             return focus_next_element(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-01 23:36:12 +01:00
										 |  |  |     if (layout_root()->selection().is_valid()) { | 
					
						
							| 
									
										
										
										
											2020-12-06 19:51:55 +01:00
										 |  |  |         auto range = layout_root()->selection().to_dom_range()->normalized(); | 
					
						
							| 
									
										
										
										
											2020-12-14 10:58:10 +01:00
										 |  |  |         if (range->start_container()->is_editable()) { | 
					
						
							|  |  |  |             m_frame.document()->layout_node()->set_selection({}); | 
					
						
							| 
									
										
										
										
											2020-12-01 23:36:12 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 10:58:10 +01:00
										 |  |  |             // FIXME: This doesn't work for some reason?
 | 
					
						
							|  |  |  |             m_frame.set_cursor_position({ *range->start_container(), range->start_offset() }); | 
					
						
							| 
									
										
										
										
											2020-12-03 18:20:17 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 10:58:10 +01:00
										 |  |  |             if (key == KeyCode::Key_Backspace || key == KeyCode::Key_Delete) { | 
					
						
							| 
									
										
										
										
											2020-12-01 23:36:12 +01:00
										 |  |  |                 m_edit_event_handler->handle_delete(range); | 
					
						
							|  |  |  |                 return true; | 
					
						
							| 
									
										
										
										
											2021-05-18 13:13:58 +02:00
										 |  |  |             } else if (!should_ignore_keydown_event(code_point)) { | 
					
						
							| 
									
										
										
										
											2020-12-14 10:58:10 +01:00
										 |  |  |                 m_edit_event_handler->handle_delete(range); | 
					
						
							|  |  |  |                 m_edit_event_handler->handle_insert(m_frame.cursor_position(), code_point); | 
					
						
							| 
									
										
										
										
											2021-05-18 22:09:15 +02:00
										 |  |  |                 m_frame.increment_cursor_position_offset(); | 
					
						
							| 
									
										
										
										
											2020-12-14 10:58:10 +01:00
										 |  |  |                 return true; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-12-01 23:36:12 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-01 23:35:47 +01:00
										 |  |  |     if (m_frame.cursor_position().is_valid() && m_frame.cursor_position().node()->is_editable()) { | 
					
						
							|  |  |  |         if (key == KeyCode::Key_Backspace) { | 
					
						
							| 
									
										
										
										
											2021-05-18 22:09:15 +02:00
										 |  |  |             if (!m_frame.decrement_cursor_position_offset()) { | 
					
						
							| 
									
										
										
										
											2021-05-18 13:08:25 +02:00
										 |  |  |                 // FIXME: Move to the previous node and delete the last character there.
 | 
					
						
							|  |  |  |                 return true; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-12-02 15:00:55 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-18 22:09:15 +02:00
										 |  |  |             m_edit_event_handler->handle_delete_character_after(m_frame.cursor_position()); | 
					
						
							| 
									
										
										
										
											2020-12-02 15:00:55 +01:00
										 |  |  |             return true; | 
					
						
							|  |  |  |         } else if (key == KeyCode::Key_Delete) { | 
					
						
							| 
									
										
										
										
											2021-05-18 22:09:15 +02:00
										 |  |  |             if (m_frame.cursor_position().offset_is_at_end_of_node()) { | 
					
						
							| 
									
										
										
										
											2021-05-18 13:08:25 +02:00
										 |  |  |                 // FIXME: Move to the next node and delete the first character there.
 | 
					
						
							|  |  |  |                 return true; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-05-18 22:09:15 +02:00
										 |  |  |             m_edit_event_handler->handle_delete_character_after(m_frame.cursor_position()); | 
					
						
							| 
									
										
										
										
											2020-12-02 15:00:55 +01:00
										 |  |  |             return true; | 
					
						
							|  |  |  |         } else if (key == KeyCode::Key_Right) { | 
					
						
							| 
									
										
										
										
											2021-05-18 22:09:15 +02:00
										 |  |  |             if (!m_frame.increment_cursor_position_offset()) { | 
					
						
							| 
									
										
										
										
											2021-05-18 13:08:25 +02:00
										 |  |  |                 // FIXME: Move to the next node.
 | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-12-02 15:00:55 +01:00
										 |  |  |             return true; | 
					
						
							|  |  |  |         } else if (key == KeyCode::Key_Left) { | 
					
						
							| 
									
										
										
										
											2021-05-18 22:09:15 +02:00
										 |  |  |             if (!m_frame.decrement_cursor_position_offset()) { | 
					
						
							| 
									
										
										
										
											2021-05-18 13:08:25 +02:00
										 |  |  |                 // FIXME: Move to the previous node.
 | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-08-02 16:05:59 +02:00
										 |  |  |             return true; | 
					
						
							| 
									
										
										
										
											2021-05-18 13:13:58 +02:00
										 |  |  |         } else if (!should_ignore_keydown_event(code_point)) { | 
					
						
							| 
									
										
										
										
											2020-12-02 13:41:58 +01:00
										 |  |  |             m_edit_event_handler->handle_insert(m_frame.cursor_position(), code_point); | 
					
						
							| 
									
										
										
										
											2021-05-18 22:09:15 +02:00
										 |  |  |             m_frame.increment_cursor_position_offset(); | 
					
						
							| 
									
										
										
										
											2021-05-18 13:13:58 +02:00
										 |  |  |             return true; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             // NOTE: Because modifier keys should be ignored, we need to return true.
 | 
					
						
							| 
									
										
										
										
											2020-12-02 13:41:58 +01:00
										 |  |  |             return true; | 
					
						
							| 
									
										
										
										
											2020-08-02 16:05:59 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-08-02 12:10:01 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-12-01 23:35:47 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-02 15:53:31 +02:00
										 |  |  |     return false; | 
					
						
							| 
									
										
										
										
											2020-08-02 12:10:01 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-22 15:53:01 +01:00
										 |  |  | void EventHandler::set_mouse_event_tracking_layout_node(Layout::Node* layout_node) | 
					
						
							| 
									
										
										
										
											2020-09-11 18:15:47 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     if (layout_node) | 
					
						
							|  |  |  |         m_mouse_event_tracking_layout_node = layout_node->make_weak_ptr(); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         m_mouse_event_tracking_layout_node = nullptr; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2020-12-03 18:46:56 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-07 14:40:38 +02:00
										 |  |  | } |