LibWeb: Fix a crash when selecting across an element with no layout box
Problem: Crash when dragging a text selection across an element with no layout box (e.g., a display:contents element). Cause: set_user_selection() looks for a user-select:contain ancestor by walking up the tree via two while-loop conditions that called layout_node()->user_select_used_value() for each element. But elements without layout boxes have no layout nodes. So that can dereference null. Fix: Check layout_node() in the tree-walking while conditions. Fixes: https://github.com/LadybirdBrowser/ladybird/issues/10062
This commit is contained in:
parent
67030ceead
commit
c2db5c0dcb
3 changed files with 28 additions and 2 deletions
|
|
@ -1836,7 +1836,7 @@ static void set_user_selection(GC::Ptr<DOM::Node> anchor_node, size_t anchor_off
|
|||
// focus node, as this means they are inside the same contain element, or not in a contain element at all.
|
||||
// This takes care of the "selection trying to escape from a contain" case.
|
||||
while (
|
||||
(!potential_contain_node->is_element() || potential_contain_node->layout_node()->user_select_used_value() != CSS::UserSelect::Contain) && potential_contain_node->parent() && !potential_contain_node->is_inclusive_ancestor_of(*focus_node)) {
|
||||
(!potential_contain_node->is_element() || !potential_contain_node->layout_node() || potential_contain_node->layout_node()->user_select_used_value() != CSS::UserSelect::Contain) && potential_contain_node->parent() && !potential_contain_node->is_inclusive_ancestor_of(*focus_node)) {
|
||||
potential_contain_node = potential_contain_node->parent();
|
||||
}
|
||||
|
||||
|
|
@ -1861,7 +1861,7 @@ static void set_user_selection(GC::Ptr<DOM::Node> anchor_node, size_t anchor_off
|
|||
auto target_node = potential_contain_node;
|
||||
potential_contain_node = focus_node;
|
||||
while (
|
||||
(!potential_contain_node->is_element() || potential_contain_node->layout_node()->user_select_used_value() != CSS::UserSelect::Contain) && potential_contain_node->parent() && potential_contain_node != target_node) {
|
||||
(!potential_contain_node->is_element() || !potential_contain_node->layout_node() || potential_contain_node->layout_node()->user_select_used_value() != CSS::UserSelect::Contain) && potential_contain_node->parent() && potential_contain_node != target_node) {
|
||||
potential_contain_node = potential_contain_node->parent();
|
||||
}
|
||||
if (
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
selection includes alpha: true
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="include.js"></script>
|
||||
<body>
|
||||
<div style="display: contents">
|
||||
<p>alpha</p>
|
||||
<p>bravo</p>
|
||||
</div>
|
||||
<script>
|
||||
test(() => {
|
||||
document.body.offsetWidth;
|
||||
|
||||
const paragraphs = document.querySelectorAll("p");
|
||||
const first = paragraphs[0].getBoundingClientRect();
|
||||
const second = paragraphs[1].getBoundingClientRect();
|
||||
|
||||
// Drag a selection from the first paragraph into the second. Both paragraphs are children of a display:contents
|
||||
// element, which has no layout box. So, the user-select:contain containment walk steps onto an element whose
|
||||
// layout_node() is null, and must not dereference it.
|
||||
internals.mouseDown(first.left + 1, first.top + first.height / 2);
|
||||
internals.mouseMove(second.right - 1, second.top + second.height / 2);
|
||||
internals.mouseUp(second.right - 1, second.top + second.height / 2);
|
||||
|
||||
println(`selection includes alpha: ${getSelection().toString().includes("alpha")}`);
|
||||
});
|
||||
</script>
|
||||
Loading…
Reference in a new issue