mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-04-26 01:35:08 +02:00
LibWeb: Do not scroll cursor into view on programmatic selection changes
We were mimicking Firefox' behavior that whenever a programmatic change to an <input>'s or <textarea>'s selection happened, the new selection focus is brought into view by scrolling. Currently we run a layout update synchronously for that to make sure we have the fragment's correct dimensions, which caused a significant performance regression in Speedometer. Since this is non-standard behavior, let's mimic Chromium instead which does not scroll at all - only for direct user initiated input such as typing. Relevant issues: * https://github.com/whatwg/html/issues/6217 * https://bugzilla.mozilla.org/show_bug.cgi?id=232405 * https://issues.chromium.org/issues/41081857
This commit is contained in:
committed by
Andreas Kling
parent
fa04c8db83
commit
ded42e649b
Notes:
github-actions[bot]
2026-02-17 09:25:08 +00:00
Author: https://github.com/gmta Commit: https://github.com/LadybirdBrowser/ladybird/commit/ded42e649b2 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/7982
@@ -841,7 +841,7 @@ void FormAssociatedTextControlElement::set_the_selection_range(Optional<WebIDL::
|
||||
});
|
||||
}
|
||||
|
||||
selection_was_changed();
|
||||
selection_was_changed(source);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -872,6 +872,7 @@ void FormAssociatedTextControlElement::handle_insert(FlyString const& input_type
|
||||
data_for_input_event = data_for_insertion;
|
||||
|
||||
did_edit_text_node(input_type, data_for_input_event);
|
||||
scroll_cursor_into_view();
|
||||
}
|
||||
|
||||
void FormAssociatedTextControlElement::handle_delete(FlyString const& input_type)
|
||||
@@ -897,6 +898,7 @@ void FormAssociatedTextControlElement::handle_delete(FlyString const& input_type
|
||||
|
||||
text_node->invalidate_style(DOM::StyleInvalidationReason::EditingDeletion);
|
||||
did_edit_text_node(input_type, {});
|
||||
scroll_cursor_into_view();
|
||||
}
|
||||
|
||||
Optional<Utf16String> FormAssociatedTextControlElement::selected_text_for_stringifier() const
|
||||
@@ -920,7 +922,7 @@ void FormAssociatedTextControlElement::collapse_selection_to_offset(size_t posit
|
||||
void FormAssociatedTextControlElement::scroll_cursor_into_view()
|
||||
{
|
||||
auto& element = form_associated_element_to_html_element();
|
||||
element.document().update_layout(DOM::UpdateLayoutReason::ScrollFocusIntoView);
|
||||
element.document().update_layout(DOM::UpdateLayoutReason::ScrollCursorIntoView);
|
||||
|
||||
auto text_node = form_associated_element_to_text_node();
|
||||
if (!text_node)
|
||||
@@ -933,7 +935,7 @@ void FormAssociatedTextControlElement::scroll_cursor_into_view()
|
||||
paintable->scroll_ancestor_to_offset_into_view(m_selection_end);
|
||||
}
|
||||
|
||||
void FormAssociatedTextControlElement::selection_was_changed()
|
||||
void FormAssociatedTextControlElement::selection_was_changed(SelectionSource source)
|
||||
{
|
||||
auto& element = form_associated_element_to_html_element();
|
||||
if (auto* input_element = as_if<HTMLInputElement>(element)) {
|
||||
@@ -959,10 +961,14 @@ void FormAssociatedTextControlElement::selection_was_changed()
|
||||
}
|
||||
text_paintable->set_needs_display();
|
||||
|
||||
// AD-HOC: Skip scroll-into-view during mouse selection, since the user controls the viewport.
|
||||
auto navigable = element.document().cached_navigable();
|
||||
if (!(navigable && navigable->event_handler().is_handling_mouse_selection()))
|
||||
scroll_cursor_into_view();
|
||||
// AD-HOC: Only scroll the cursor into view for UI-driven selection changes (like keyboard input). Programmatic
|
||||
// changes (input.value, setSelectionRange) do not cause the cursor to scroll into view. This matches the
|
||||
// behavior of other browsers.
|
||||
if (source == SelectionSource::UI) {
|
||||
auto navigable = element.document().navigable();
|
||||
if (navigable && !navigable->event_handler().is_handling_mouse_selection())
|
||||
scroll_cursor_into_view();
|
||||
}
|
||||
}
|
||||
|
||||
void FormAssociatedTextControlElement::select_all()
|
||||
@@ -971,7 +977,7 @@ void FormAssociatedTextControlElement::select_all()
|
||||
if (!text_node)
|
||||
return;
|
||||
set_the_selection_range(0, text_node->length());
|
||||
selection_was_changed();
|
||||
selection_was_changed(SelectionSource::UI);
|
||||
}
|
||||
|
||||
void FormAssociatedTextControlElement::set_selection_anchor(GC::Ref<DOM::Node> anchor_node, size_t anchor_offset)
|
||||
@@ -982,7 +988,7 @@ void FormAssociatedTextControlElement::set_selection_anchor(GC::Ref<DOM::Node> a
|
||||
if (!text_node || anchor_node != text_node)
|
||||
return;
|
||||
collapse_selection_to_offset(anchor_offset);
|
||||
selection_was_changed();
|
||||
selection_was_changed(SelectionSource::UI);
|
||||
}
|
||||
|
||||
void FormAssociatedTextControlElement::set_selection_focus(GC::Ref<DOM::Node> focus_node, size_t focus_offset)
|
||||
@@ -993,7 +999,7 @@ void FormAssociatedTextControlElement::set_selection_focus(GC::Ref<DOM::Node> fo
|
||||
if (!text_node || focus_node != text_node)
|
||||
return;
|
||||
m_selection_end = focus_offset;
|
||||
selection_was_changed();
|
||||
selection_was_changed(SelectionSource::UI);
|
||||
}
|
||||
|
||||
void FormAssociatedTextControlElement::move_cursor_to_start(CollapseSelection collapse)
|
||||
@@ -1006,7 +1012,7 @@ void FormAssociatedTextControlElement::move_cursor_to_start(CollapseSelection co
|
||||
} else {
|
||||
m_selection_end = 0;
|
||||
}
|
||||
selection_was_changed();
|
||||
selection_was_changed(SelectionSource::UI);
|
||||
}
|
||||
|
||||
void FormAssociatedTextControlElement::move_cursor_to_end(CollapseSelection collapse)
|
||||
@@ -1019,7 +1025,7 @@ void FormAssociatedTextControlElement::move_cursor_to_end(CollapseSelection coll
|
||||
} else {
|
||||
m_selection_end = text_node->length();
|
||||
}
|
||||
selection_was_changed();
|
||||
selection_was_changed(SelectionSource::UI);
|
||||
}
|
||||
|
||||
void FormAssociatedTextControlElement::increment_cursor_position_offset(CollapseSelection collapse)
|
||||
@@ -1034,7 +1040,7 @@ void FormAssociatedTextControlElement::increment_cursor_position_offset(Collapse
|
||||
m_selection_end = *offset;
|
||||
}
|
||||
}
|
||||
selection_was_changed();
|
||||
selection_was_changed(SelectionSource::UI);
|
||||
}
|
||||
|
||||
void FormAssociatedTextControlElement::decrement_cursor_position_offset(CollapseSelection collapse)
|
||||
@@ -1049,7 +1055,7 @@ void FormAssociatedTextControlElement::decrement_cursor_position_offset(Collapse
|
||||
m_selection_end = *offset;
|
||||
}
|
||||
}
|
||||
selection_was_changed();
|
||||
selection_was_changed(SelectionSource::UI);
|
||||
}
|
||||
|
||||
void FormAssociatedTextControlElement::increment_cursor_position_to_next_word(CollapseSelection collapse)
|
||||
@@ -1072,7 +1078,7 @@ void FormAssociatedTextControlElement::increment_cursor_position_to_next_word(Co
|
||||
break;
|
||||
}
|
||||
|
||||
selection_was_changed();
|
||||
selection_was_changed(SelectionSource::UI);
|
||||
}
|
||||
|
||||
void FormAssociatedTextControlElement::decrement_cursor_position_to_previous_word(CollapseSelection collapse)
|
||||
@@ -1095,7 +1101,7 @@ void FormAssociatedTextControlElement::decrement_cursor_position_to_previous_wor
|
||||
break;
|
||||
}
|
||||
|
||||
selection_was_changed();
|
||||
selection_was_changed(SelectionSource::UI);
|
||||
}
|
||||
|
||||
void FormAssociatedTextControlElement::increment_cursor_position_to_next_line(CollapseSelection collapse)
|
||||
@@ -1113,7 +1119,7 @@ void FormAssociatedTextControlElement::increment_cursor_position_to_next_line(Co
|
||||
else
|
||||
m_selection_end = *new_offset;
|
||||
|
||||
selection_was_changed();
|
||||
selection_was_changed(SelectionSource::UI);
|
||||
}
|
||||
|
||||
void FormAssociatedTextControlElement::decrement_cursor_position_to_previous_line(CollapseSelection collapse)
|
||||
@@ -1131,7 +1137,7 @@ void FormAssociatedTextControlElement::decrement_cursor_position_to_previous_lin
|
||||
else
|
||||
m_selection_end = *new_offset;
|
||||
|
||||
selection_was_changed();
|
||||
selection_was_changed(SelectionSource::UI);
|
||||
}
|
||||
|
||||
GC::Ptr<DOM::Position> FormAssociatedTextControlElement::cursor_position() const
|
||||
|
||||
Reference in New Issue
Block a user