diff --git a/Libraries/LibWeb/Painting/ViewportPaintable.cpp b/Libraries/LibWeb/Painting/ViewportPaintable.cpp index 547baa09ce6..22b30d0af93 100644 --- a/Libraries/LibWeb/Painting/ViewportPaintable.cpp +++ b/Libraries/LibWeb/Painting/ViewportPaintable.cpp @@ -362,19 +362,23 @@ void ViewportPaintable::recompute_selection_states(DOM::Range& range) // 4. Mark the selection end node as End (if text) or Full (if anything else). if (auto* paintable = end_container->paintable(); paintable && !range.end().node->is_inert()) { - if (is(*end_container) || end_container->is_ancestor_of(start_container)) { + if (is(*end_container)) paintable->set_selection_state(SelectionState::End); - } else { - paintable->for_each_in_inclusive_subtree([&](auto& layout_node) { - if (!layout_node.dom_node() || !layout_node.dom_node()->is_inert()) - layout_node.set_selection_state(SelectionState::Full); - return TraversalDecision::Continue; - }); - } + else + paintable->set_selection_state(SelectionState::Full); } // 5. Mark the nodes between start node and end node (in tree order) as Full. - for (auto* node = start_container->next_in_pre_order(); node && node != end_container; node = node->next_in_pre_order()) { + // NOTE: If the start node is a descendant of the end node, we cannot traverse from it to the end node since the end node is before it in tree order. + // Instead, we need to stop traversal somewhere inside the end node, or right after it. + DOM::Node* stop_at; + if (start_container->is_descendant_of(end_container)) { + stop_at = end_container->child_at_index(range.end_offset()); + } else { + stop_at = end_container; + } + + for (auto* node = start_container->next_in_pre_order(); node && node != stop_at; node = node->next_in_pre_order(end_container)) { if (node->is_inert()) continue; if (auto* paintable = node->paintable()) diff --git a/Tests/LibWeb/Screenshot/expected/selection-start-in-end-node-ref.html b/Tests/LibWeb/Screenshot/expected/selection-start-in-end-node-ref.html new file mode 100644 index 00000000000..d647397b779 --- /dev/null +++ b/Tests/LibWeb/Screenshot/expected/selection-start-in-end-node-ref.html @@ -0,0 +1,7 @@ + + + diff --git a/Tests/LibWeb/Screenshot/images/selection-start-in-end-node-ref.png b/Tests/LibWeb/Screenshot/images/selection-start-in-end-node-ref.png new file mode 100644 index 00000000000..7fc8f2747c6 Binary files /dev/null and b/Tests/LibWeb/Screenshot/images/selection-start-in-end-node-ref.png differ diff --git a/Tests/LibWeb/Screenshot/input/selection-start-in-end-node-2.html b/Tests/LibWeb/Screenshot/input/selection-start-in-end-node-2.html new file mode 100644 index 00000000000..7eee9a3ce94 --- /dev/null +++ b/Tests/LibWeb/Screenshot/input/selection-start-in-end-node-2.html @@ -0,0 +1,10 @@ + + + +End Node Start Node NOT SELECTED + diff --git a/Tests/LibWeb/Screenshot/input/selection-start-in-end-node-3.html b/Tests/LibWeb/Screenshot/input/selection-start-in-end-node-3.html new file mode 100644 index 00000000000..ecbc40c1d2a --- /dev/null +++ b/Tests/LibWeb/Screenshot/input/selection-start-in-end-node-3.html @@ -0,0 +1,10 @@ + + + +End Node Start Node NOT SELECTED + diff --git a/Tests/LibWeb/Screenshot/input/selection-start-in-end-node.html b/Tests/LibWeb/Screenshot/input/selection-start-in-end-node.html new file mode 100644 index 00000000000..56741b36c51 --- /dev/null +++ b/Tests/LibWeb/Screenshot/input/selection-start-in-end-node.html @@ -0,0 +1,10 @@ + + + +End Node Start Node NOT SELECTED +