mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-21 12:05:15 +00:00
LibWeb: Ensure EventHandler visits its mouse selection target
We hold a raw pointer to the mouse selection target, which is a mixin- style class inherited only by JS::Cell classes. By not visiting this object, we sometime had a dangling reference to it after it had been garbage collected.
This commit is contained in:
parent
18a160e0e9
commit
d5be18617e
Notes:
github-actions[bot]
2025-02-27 09:54:17 +00:00
Author: https://github.com/trflynn89 Commit: https://github.com/LadybirdBrowser/ladybird/commit/d5be18617ed Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3713 Reviewed-by: https://github.com/AtkinsSJ ✅
7 changed files with 56 additions and 2 deletions
|
@ -14,7 +14,8 @@
|
|||
|
||||
namespace Web::DOM {
|
||||
|
||||
class EditingHostManager : public JS::Cell
|
||||
class EditingHostManager
|
||||
: public JS::Cell
|
||||
, public InputEventsTarget {
|
||||
GC_CELL(EditingHostManager, JS::Cell);
|
||||
GC_DECLARE_ALLOCATOR(EditingHostManager);
|
||||
|
@ -45,6 +46,8 @@ public:
|
|||
private:
|
||||
EditingHostManager(GC::Ref<Document>);
|
||||
|
||||
virtual GC::Ref<JS::Cell> as_cell() override { return *this; }
|
||||
|
||||
GC::Ref<Document> m_document;
|
||||
GC::Ptr<DOM::Node> m_active_contenteditable_element;
|
||||
};
|
||||
|
|
|
@ -15,6 +15,8 @@ class InputEventsTarget {
|
|||
public:
|
||||
virtual ~InputEventsTarget() = default;
|
||||
|
||||
virtual GC::Ref<JS::Cell> as_cell() = 0;
|
||||
|
||||
virtual void handle_insert(String const&) = 0;
|
||||
virtual void handle_return_key() = 0;
|
||||
|
||||
|
|
|
@ -969,4 +969,9 @@ GC::Ptr<DOM::Position> FormAssociatedTextControlElement::cursor_position() const
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
GC::Ref<JS::Cell> FormAssociatedTextControlElement::as_cell()
|
||||
{
|
||||
return form_associated_element_to_html_element();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -160,7 +160,8 @@ enum class SelectionSource {
|
|||
DOM,
|
||||
};
|
||||
|
||||
class FormAssociatedTextControlElement : public FormAssociatedElement
|
||||
class FormAssociatedTextControlElement
|
||||
: public FormAssociatedElement
|
||||
, public InputEventsTarget {
|
||||
public:
|
||||
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-textarea/input-relevant-value
|
||||
|
@ -231,6 +232,8 @@ protected:
|
|||
void relevant_value_was_changed();
|
||||
|
||||
private:
|
||||
virtual GC::Ref<JS::Cell> as_cell() override;
|
||||
|
||||
void collapse_selection_to_offset(size_t);
|
||||
void selection_was_changed();
|
||||
|
||||
|
|
|
@ -1375,6 +1375,9 @@ void EventHandler::visit_edges(JS::Cell::Visitor& visitor) const
|
|||
{
|
||||
m_drag_and_drop_event_handler->visit_edges(visitor);
|
||||
visitor.visit(m_mouse_event_tracking_paintable);
|
||||
|
||||
if (m_mouse_selection_target)
|
||||
visitor.visit(m_mouse_selection_target->as_cell());
|
||||
}
|
||||
|
||||
Unicode::Segmenter& EventHandler::word_segmenter()
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
PASS (didn't crash)
|
|
@ -0,0 +1,37 @@
|
|||
<!DOCTYPE html>
|
||||
<iframe id="iframe"></iframe>
|
||||
<script src="../include.js"></script>
|
||||
<script>
|
||||
const runTest = () => {
|
||||
return new Promise(resolve => {
|
||||
let iframe = document.getElementById("iframe");
|
||||
|
||||
iframe.onload = () => {
|
||||
internals.movePointerTo(20, 40);
|
||||
internals.mouseDown(20, 40);
|
||||
internals.movePointerTo(60, 40);
|
||||
|
||||
iframe.onload = () => {
|
||||
setTimeout(() => {
|
||||
internals.movePointerTo(20, 40);
|
||||
resolve();
|
||||
});
|
||||
};
|
||||
|
||||
iframe.src = "data:text/html,<p contenteditable>Text 2</p>";
|
||||
};
|
||||
|
||||
iframe.src = "data:text/html,<p contenteditable>Text 1</p>";
|
||||
});
|
||||
};
|
||||
|
||||
asyncTest(async done => {
|
||||
for (let i = 0; i < 10; ++i) {
|
||||
await runTest();
|
||||
internals.gc();
|
||||
}
|
||||
|
||||
println("PASS (didn't crash)");
|
||||
done();
|
||||
});
|
||||
</script>
|
Loading…
Add table
Reference in a new issue