Ver Fonte

LibWeb: Protect DOM node while preparing to send mouse events

The Help application was hooking HtmlView::on_link_click, which would
get invoked before DOM event dispatch. Since we were holding on to the
clicked node with a Node*, the DOM node was gone after returning from
the on_link_click callback.

Fix this by keeping DOM nodes in RefPtrs in the event management code.
Also move DOM event dispatch before widget hook invocation, to try and
keep things sane on the LibWeb side of things.

Fixes #1605.
Andreas Kling há 5 anos atrás
pai
commit
9eec63e471
1 ficheiros alterados com 11 adições e 11 exclusões
  1. 11 11
      Libraries/LibWeb/HtmlView.cpp

+ 11 - 11
Libraries/LibWeb/HtmlView.cpp

@@ -176,9 +176,9 @@ void HtmlView::mousemove_event(GUI::MouseEvent& event)
     auto result = layout_root()->hit_test(to_content_position(event.position()));
     auto result = layout_root()->hit_test(to_content_position(event.position()));
     const HTMLAnchorElement* hovered_link_element = nullptr;
     const HTMLAnchorElement* hovered_link_element = nullptr;
     if (result.layout_node) {
     if (result.layout_node) {
-        auto* node = result.layout_node->node();
+        RefPtr<Node> node = result.layout_node->node();
         hovered_node_changed = node != document()->hovered_node();
         hovered_node_changed = node != document()->hovered_node();
-        document()->set_hovered_node(const_cast<Node*>(node));
+        document()->set_hovered_node(node);
         if (node) {
         if (node) {
             hovered_link_element = node->enclosing_link_element();
             hovered_link_element = node->enclosing_link_element();
             if (hovered_link_element) {
             if (hovered_link_element) {
@@ -188,7 +188,7 @@ void HtmlView::mousemove_event(GUI::MouseEvent& event)
                 is_hovering_link = true;
                 is_hovering_link = true;
             }
             }
             auto offset = compute_mouse_event_offset(event.position(), *result.layout_node);
             auto offset = compute_mouse_event_offset(event.position(), *result.layout_node);
-            const_cast<Node*>(node)->dispatch_event(MouseEvent::create("mousemove", offset.x(), offset.y()));
+            node->dispatch_event(MouseEvent::create("mousemove", offset.x(), offset.y()));
         }
         }
         if (m_in_mouse_selection) {
         if (m_in_mouse_selection) {
             layout_root()->selection().set_end({ result.layout_node, result.index_in_node });
             layout_root()->selection().set_end({ result.layout_node, result.index_in_node });
@@ -200,7 +200,7 @@ void HtmlView::mousemove_event(GUI::MouseEvent& event)
         window()->set_override_cursor(is_hovering_link ? GUI::StandardCursor::Hand : GUI::StandardCursor::None);
         window()->set_override_cursor(is_hovering_link ? GUI::StandardCursor::Hand : GUI::StandardCursor::None);
     if (hovered_node_changed) {
     if (hovered_node_changed) {
         update();
         update();
-        auto* hovered_html_element = document()->hovered_node() ? document()->hovered_node()->enclosing_html_element() : nullptr;
+        RefPtr<HTMLElement> hovered_html_element = document()->hovered_node() ? document()->hovered_node()->enclosing_html_element() : nullptr;
         if (hovered_html_element && !hovered_html_element->title().is_null()) {
         if (hovered_html_element && !hovered_html_element->title().is_null()) {
             auto screen_position = screen_relative_rect().location().translated(event.position());
             auto screen_position = screen_relative_rect().location().translated(event.position());
             GUI::Application::the().show_tooltip(hovered_html_element->title(), screen_position.translated(4, 4));
             GUI::Application::the().show_tooltip(hovered_html_element->title(), screen_position.translated(4, 4));
@@ -224,11 +224,13 @@ void HtmlView::mousedown_event(GUI::MouseEvent& event)
     bool hovered_node_changed = false;
     bool hovered_node_changed = false;
     auto result = layout_root()->hit_test(to_content_position(event.position()));
     auto result = layout_root()->hit_test(to_content_position(event.position()));
     if (result.layout_node) {
     if (result.layout_node) {
-        auto* node = result.layout_node->node();
+        RefPtr<Node> node = result.layout_node->node();
         hovered_node_changed = node != document()->hovered_node();
         hovered_node_changed = node != document()->hovered_node();
-        document()->set_hovered_node(const_cast<Node*>(node));
+        document()->set_hovered_node(node);
         if (node) {
         if (node) {
-            if (auto* link = node->enclosing_link_element()) {
+            auto offset = compute_mouse_event_offset(event.position(), *result.layout_node);
+            node->dispatch_event(MouseEvent::create("mousedown", offset.x(), offset.y()));
+            if (RefPtr<HTMLAnchorElement> link = node->enclosing_link_element()) {
                 dbg() << "HtmlView: clicking on a link to " << link->href();
                 dbg() << "HtmlView: clicking on a link to " << link->href();
                 if (on_link_click)
                 if (on_link_click)
                     on_link_click(link->href());
                     on_link_click(link->href());
@@ -239,8 +241,6 @@ void HtmlView::mousedown_event(GUI::MouseEvent& event)
                     m_in_mouse_selection = true;
                     m_in_mouse_selection = true;
                 }
                 }
             }
             }
-            auto offset = compute_mouse_event_offset(event.position(), *result.layout_node);
-            const_cast<Node*>(node)->dispatch_event(MouseEvent::create("mousedown", offset.x(), offset.y()));
         }
         }
     }
     }
     if (hovered_node_changed)
     if (hovered_node_changed)
@@ -255,9 +255,9 @@ void HtmlView::mouseup_event(GUI::MouseEvent& event)
 
 
     auto result = layout_root()->hit_test(to_content_position(event.position()));
     auto result = layout_root()->hit_test(to_content_position(event.position()));
     if (result.layout_node) {
     if (result.layout_node) {
-        if (auto* node = result.layout_node->node()) {
+        if (RefPtr<Node> node = result.layout_node->node()) {
             auto offset = compute_mouse_event_offset(event.position(), *result.layout_node);
             auto offset = compute_mouse_event_offset(event.position(), *result.layout_node);
-            const_cast<Node*>(node)->dispatch_event(MouseEvent::create("mouseup", offset.x(), offset.y()));
+            node->dispatch_event(MouseEvent::create("mouseup", offset.x(), offset.y()));
         }
         }
     }
     }