diff options
author | Andreas Kling <kling@serenityos.org> | 2020-11-29 16:39:56 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-11-29 16:43:12 +0100 |
commit | 2dd03a4200463ca5b2387edc227db4da7071ed5b (patch) | |
tree | 2f49e98f75e1fd0abf0bde7dcf3238e1988d917e /Libraries/LibWeb/Page | |
parent | 4ebb57298b72e39d6a7439ffaf343d040fa6b2ca (diff) | |
download | serenity-2dd03a4200463ca5b2387edc227db4da7071ed5b.zip |
LibWeb: Abort event handling if underlying layout tree disappears
We didn't notice that the layout tree had disappeared after dispatching
a mousedown event, because we only checked EventHandler::layout_root()
which happily returned the *new* layout tree after a window.reload().
This patch fixes that by verifying that the frame is still showing the
same DOM's layout tree after event dispatch.
Fixes #4224.
Diffstat (limited to 'Libraries/LibWeb/Page')
-rw-r--r-- | Libraries/LibWeb/Page/EventHandler.cpp | 50 |
1 files changed, 28 insertions, 22 deletions
diff --git a/Libraries/LibWeb/Page/EventHandler.cpp b/Libraries/LibWeb/Page/EventHandler.cpp index 8cd28f59dc..0f2ef8951f 100644 --- a/Libraries/LibWeb/Page/EventHandler.cpp +++ b/Libraries/LibWeb/Page/EventHandler.cpp @@ -126,34 +126,39 @@ bool EventHandler::handle_mousedown(const Gfx::IntPoint& position, unsigned butt } NonnullRefPtr document = *m_frame.document(); + RefPtr<DOM::Node> node; - auto result = layout_root()->hit_test(position, Layout::HitTestType::Exact); - if (!result.layout_node) - return false; + { + auto result = layout_root()->hit_test(position, Layout::HitTestType::Exact); + if (!result.layout_node) + return false; - RefPtr<DOM::Node> node = result.layout_node->dom_node(); - document->set_hovered_node(node); + node = result.layout_node->dom_node(); + document->set_hovered_node(node); - if (result.layout_node->wants_mouse_events()) { - result.layout_node->handle_mousedown({}, position, button, modifiers); - return true; - } + if (result.layout_node->wants_mouse_events()) { + result.layout_node->handle_mousedown({}, position, button, modifiers); + return true; + } - if (!node) - return false; + if (!node) + return false; - if (is<HTML::HTMLIFrameElement>(*node)) { - if (auto* subframe = downcast<HTML::HTMLIFrameElement>(*node).content_frame()) - return subframe->event_handler().handle_mousedown(position.translated(compute_mouse_event_offset({}, *result.layout_node)), button, modifiers); - return false; - } + if (is<HTML::HTMLIFrameElement>(*node)) { + if (auto* subframe = downcast<HTML::HTMLIFrameElement>(*node).content_frame()) + return subframe->event_handler().handle_mousedown(position.translated(compute_mouse_event_offset({}, *result.layout_node)), button, modifiers); + return false; + } - if (auto* page = m_frame.page()) - page->set_focused_frame({}, m_frame); + if (auto* page = m_frame.page()) + page->set_focused_frame({}, m_frame); - auto offset = compute_mouse_event_offset(position, *result.layout_node); - node->dispatch_event(UIEvents::MouseEvent::create(UIEvents::EventNames::mousedown, offset.x(), offset.y())); - if (!layout_root()) + auto offset = compute_mouse_event_offset(position, *result.layout_node); + node->dispatch_event(UIEvents::MouseEvent::create(UIEvents::EventNames::mousedown, offset.x(), offset.y())); + } + + // NOTE: Dispatching an event may have disturbed the world. + if (!layout_root() || layout_root() != node->document().layout_node()) return true; if (button == GUI::MouseButton::Right && is<HTML::HTMLImageElement>(*node)) { @@ -255,7 +260,8 @@ bool EventHandler::handle_mousemove(const Gfx::IntPoint& position, unsigned butt is_hovering_link = true; auto offset = compute_mouse_event_offset(position, *result.layout_node); node->dispatch_event(UIEvents::MouseEvent::create(UIEvents::EventNames::mousemove, offset.x(), offset.y())); - if (!layout_root()) + // NOTE: Dispatching an event may have disturbed the world. + if (!layout_root() || layout_root() != node->document().layout_node()) return true; } if (m_in_mouse_selection) { |