diff --git a/Libraries/LibWeb/Painting/PaintableBox.cpp b/Libraries/LibWeb/Painting/PaintableBox.cpp index b072793c7b8..f618ad3d870 100644 --- a/Libraries/LibWeb/Painting/PaintableBox.cpp +++ b/Libraries/LibWeb/Painting/PaintableBox.cpp @@ -916,24 +916,15 @@ Paintable::DispatchEventOfSameName PaintableBox::handle_mousedown(Badgethumb_rect.contains(position)) { - m_last_mouse_tracking_position = position; - m_scroll_thumb_dragging_direction = direction; - - navigable()->event_handler().set_mouse_event_tracking_paintable(this); - return true; - } - if (scrollbar_data->gutter_rect.contains(position)) { - m_last_mouse_tracking_position = scrollbar_data->thumb_rect.center(); m_scroll_thumb_dragging_direction = direction; navigable()->event_handler().set_mouse_event_tracking_paintable(this); - scroll_to_mouse_postion(position); + scroll_to_mouse_position(position); return true; } @@ -950,10 +941,10 @@ Paintable::DispatchEventOfSameName PaintableBox::handle_mousedown(Badge, CSSPixelPoint, unsigned, unsigned) { - if (m_last_mouse_tracking_position.has_value()) { - m_last_mouse_tracking_position.clear(); + if (m_scroll_thumb_grab_position.has_value()) { + m_scroll_thumb_grab_position.clear(); m_scroll_thumb_dragging_direction.clear(); - const_cast(*navigable()).event_handler().set_mouse_event_tracking_paintable(nullptr); + navigable()->event_handler().set_mouse_event_tracking_paintable(nullptr); } return Paintable::DispatchEventOfSameName::Yes; } @@ -962,8 +953,8 @@ Paintable::DispatchEventOfSameName PaintableBox::handle_mousemove(Badgegutter_rect.contains(position); } -void PaintableBox::scroll_to_mouse_postion(CSSPixelPoint position) +void PaintableBox::scroll_to_mouse_position(CSSPixelPoint position) { - VERIFY(m_last_mouse_tracking_position.has_value()); VERIFY(m_scroll_thumb_dragging_direction.has_value()); - Gfx::Point scroll_delta; - if (m_scroll_thumb_dragging_direction == ScrollDirection::Horizontal) - scroll_delta.set_x((position.x() - m_last_mouse_tracking_position->x()).to_double()); - else - scroll_delta.set_y((position.y() - m_last_mouse_tracking_position->y()).to_double()); + auto scrollbar_data = compute_scrollbar_data(m_scroll_thumb_dragging_direction.value(), AdjustThumbRectForScrollOffset::Yes); + VERIFY(scrollbar_data.has_value()); - auto padding_rect = absolute_padding_box_rect(); - auto scrollable_overflow_rect = this->scrollable_overflow_rect().value(); - auto scroll_overflow_size = m_scroll_thumb_dragging_direction == ScrollDirection::Horizontal ? scrollable_overflow_rect.width() : scrollable_overflow_rect.height(); - auto scrollport_size = m_scroll_thumb_dragging_direction == ScrollDirection::Horizontal ? padding_rect.width() : padding_rect.height(); - auto scroll_px_per_mouse_position_delta_px = scroll_overflow_size.to_double() / scrollport_size.to_double(); - scroll_delta *= scroll_px_per_mouse_position_delta_px; + auto orientation = m_scroll_thumb_dragging_direction == ScrollDirection::Horizontal ? Orientation::Horizontal : Orientation::Vertical; + auto offset_relative_to_gutter = (position - scrollbar_data->gutter_rect.location()).primary_offset_for_orientation(orientation); + auto gutter_size = scrollbar_data->gutter_rect.primary_size_for_orientation(orientation); + auto thumb_size = scrollbar_data->thumb_rect.primary_size_for_orientation(orientation); + + // Set the thumb grab position, if we haven't got one already. + if (!m_scroll_thumb_grab_position.has_value()) { + m_scroll_thumb_grab_position = scrollbar_data->thumb_rect.contains(position) + ? (position - scrollbar_data->thumb_rect.location()).primary_offset_for_orientation(orientation) + : max(min(offset_relative_to_gutter, thumb_size / 2), offset_relative_to_gutter - gutter_size + thumb_size); + } + + // Calculate the relative scroll position (0..1) based on the position of the mouse cursor. We only move the thumb + // if we are interacting with the grab point on the thumb. E.g. if the thumb is all the way to its minimum position + // and the position is beyond the grab point, we should do nothing. + auto constrained_offset = AK::clamp(offset_relative_to_gutter - m_scroll_thumb_grab_position.value(), 0, gutter_size - thumb_size); + auto scroll_position = constrained_offset.to_double() / (gutter_size - thumb_size).to_double(); + + // Calculate the scroll offset we need to apply to the viewport or element. + auto scrollable_overflow_size = scrollable_overflow_rect()->primary_size_for_orientation(orientation); + auto padding_size = absolute_padding_box_rect().primary_size_for_orientation(orientation); + auto scroll_position_in_pixels = CSSPixels::nearest_value_for(scroll_position * (scrollable_overflow_size - padding_size)); + + // Set the new scroll offset. + auto new_scroll_offset = is_viewport() ? document().navigable()->viewport_scroll_offset() : scroll_offset(); + new_scroll_offset.set_primary_offset_for_orientation(orientation, scroll_position_in_pixels); if (is_viewport()) - document().window()->scroll_by(scroll_delta.x(), scroll_delta.y()); + document().navigable()->perform_scroll_of_viewport(new_scroll_offset); else - scroll_by(scroll_delta.x(), scroll_delta.y()); - - m_last_mouse_tracking_position = position; + set_scroll_offset(new_scroll_offset); } bool PaintableBox::handle_mousewheel(Badge, CSSPixelPoint, unsigned, unsigned, int wheel_delta_x, int wheel_delta_y) diff --git a/Libraries/LibWeb/Painting/PaintableBox.h b/Libraries/LibWeb/Painting/PaintableBox.h index 04770c9ddbe..c6a3e2e3f80 100644 --- a/Libraries/LibWeb/Painting/PaintableBox.h +++ b/Libraries/LibWeb/Painting/PaintableBox.h @@ -279,7 +279,7 @@ private: virtual DispatchEventOfSameName handle_mousemove(Badge, CSSPixelPoint, unsigned buttons, unsigned modifiers) override; bool scrollbar_contains_mouse_position(ScrollDirection, CSSPixelPoint); - void scroll_to_mouse_postion(CSSPixelPoint); + void scroll_to_mouse_position(CSSPixelPoint); OwnPtr m_stacking_context; @@ -305,7 +305,7 @@ private: Optional m_outline_data; CSSPixels m_outline_offset { 0 }; - Optional m_last_mouse_tracking_position; + Optional m_scroll_thumb_grab_position; Optional m_scroll_thumb_dragging_direction; bool m_draw_enlarged_horizontal_scrollbar { false }; bool m_draw_enlarged_vertical_scrollbar { false };