From 8b3ebb7ea8d65bdf5f532de5fcd7a28062274bd9 Mon Sep 17 00:00:00 2001 From: Aliaksandr Kalenik Date: Tue, 6 Aug 2024 15:32:31 +0300 Subject: [PATCH] LibWeb: Unify scroll handling between viewport and scrollable boxes This change causes the viewport to be treated as a "scroll frame," similar to how it already works for boxes with "overflow: scroll." This means that, instead of encoding the viewport translation into a display list, the items will be assigned the scroll frame id of the viewport and then shifted by the scroll offset before execution. In the future it will allow us to reuse a display list for repainting if only scroll offset has changed. As a side effect, it also removes the need for special handling of "position: fixed" because compensating for the viewport offset while painting or hit-testing is no longer necessary. Instead, anything contained within a "position: fixed" element is simply not assigned a scroll frame id, which means it is not shifted by the scroll offset. (cherry picked from commit dd8c6937254045251d910951c6b3ad49e27f0626) --- Userland/Libraries/LibWeb/HTML/Navigable.cpp | 5 +++- .../Libraries/LibWeb/Page/EventHandler.cpp | 12 ++++------ .../LibWeb/Painting/PaintableBox.cpp | 10 -------- .../LibWeb/Painting/StackingContext.cpp | 5 ---- .../LibWeb/Painting/ViewportPaintable.cpp | 23 ++++++++++++++----- 5 files changed, 25 insertions(+), 30 deletions(-) diff --git a/Userland/Libraries/LibWeb/HTML/Navigable.cpp b/Userland/Libraries/LibWeb/HTML/Navigable.cpp index a8c3d12b88b9eb..099aba571b9921 100644 --- a/Userland/Libraries/LibWeb/HTML/Navigable.cpp +++ b/Userland/Libraries/LibWeb/HTML/Navigable.cpp @@ -2012,8 +2012,11 @@ void Navigable::perform_scroll_of_viewport(CSSPixelPoint new_position) scroll_offset_did_change(); set_needs_display(); - if (auto document = active_document()) + if (auto document = active_document()) { + document->set_needs_to_refresh_scroll_state(true); + document->set_needs_to_refresh_clip_state(true); document->inform_all_viewport_clients_about_the_current_viewport_rect(); + } } // Schedule the HTML event loop to ensure that a `resize` event gets fired. diff --git a/Userland/Libraries/LibWeb/Page/EventHandler.cpp b/Userland/Libraries/LibWeb/Page/EventHandler.cpp index 214402e2cf0653..811e24b2d480a7 100644 --- a/Userland/Libraries/LibWeb/Page/EventHandler.cpp +++ b/Userland/Libraries/LibWeb/Page/EventHandler.cpp @@ -174,8 +174,7 @@ EventResult EventHandler::handle_mousewheel(CSSPixelPoint viewport_position, CSS if (!m_navigable->active_document()->is_fully_active()) return EventResult::Dropped; - auto scroll_offset = m_navigable->active_document()->navigable()->viewport_scroll_offset(); - auto position = viewport_position.translated(scroll_offset); + auto position = viewport_position; m_navigable->active_document()->update_layout(); @@ -244,8 +243,7 @@ EventResult EventHandler::handle_mouseup(CSSPixelPoint viewport_position, CSSPix if (!m_navigable->active_document()->is_fully_active()) return EventResult::Dropped; - auto scroll_offset = m_navigable->active_document()->navigable()->viewport_scroll_offset(); - auto position = viewport_position.translated(scroll_offset); + auto position = viewport_position; m_navigable->active_document()->update_layout(); @@ -375,8 +373,7 @@ EventResult EventHandler::handle_mousedown(CSSPixelPoint viewport_position, CSSP if (!m_navigable->active_document()->is_fully_active()) return EventResult::Dropped; - auto scroll_offset = m_navigable->active_document()->navigable()->viewport_scroll_offset(); - auto position = viewport_position.translated(scroll_offset); + auto position = viewport_position; m_navigable->active_document()->update_layout(); @@ -488,8 +485,7 @@ EventResult EventHandler::handle_mousemove(CSSPixelPoint viewport_position, CSSP if (!m_navigable->active_document()->is_fully_active()) return EventResult::Dropped; - auto scroll_offset = m_navigable->active_document()->navigable()->viewport_scroll_offset(); - auto position = viewport_position.translated(scroll_offset); + auto position = viewport_position; m_navigable->active_document()->update_layout(); diff --git a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp index de41eef6ed99e5..662219cfac4e63 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp +++ b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp @@ -296,9 +296,6 @@ Optional PaintableBox::scroll_thumb_rect(ScrollDirection direction }; } - if (is_viewport()) - thumb_rect.translate_by(this->scroll_offset()); - return thumb_rect; } @@ -796,14 +793,10 @@ Paintable::DispatchEventOfSameName PaintableBox::handle_mousedown(Badge(*navigable()).event_handler().set_mouse_event_tracking_paintable(this); } else if (horizontal_scroll_thumb_rect.has_value() && horizontal_scroll_thumb_rect.value().contains(position)) { - if (is_viewport()) - position.translate_by(-scroll_offset()); m_last_mouse_tracking_position = position; m_scroll_thumb_dragging_direction = ScrollDirection::Horizontal; const_cast(*navigable()).event_handler().set_mouse_event_tracking_paintable(this); @@ -824,9 +817,6 @@ Paintable::DispatchEventOfSameName PaintableBox::handle_mouseup(Badge, CSSPixelPoint position, unsigned, unsigned) { if (m_last_mouse_tracking_position.has_value()) { - if (is_viewport()) - position.translate_by(-scroll_offset()); - 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()); diff --git a/Userland/Libraries/LibWeb/Painting/StackingContext.cpp b/Userland/Libraries/LibWeb/Painting/StackingContext.cpp index 6aa591d1553c90..1e0b0197b02bc8 100644 --- a/Userland/Libraries/LibWeb/Painting/StackingContext.cpp +++ b/Userland/Libraries/LibWeb/Painting/StackingContext.cpp @@ -340,11 +340,6 @@ TraversalDecision StackingContext::hit_test(CSSPixelPoint position, HitTestType }; auto transformed_position = affine_transform_matrix().inverse().value_or({}).map(offset_position).to_type() + transform_origin; - if (paintable().is_fixed_position()) { - auto scroll_offset = paintable().document().navigable()->viewport_scroll_offset(); - transformed_position.translate_by(-scroll_offset); - } - // NOTE: Hit testing basically happens in reverse painting order. // https://www.w3.org/TR/CSS22/visuren.html#z-index diff --git a/Userland/Libraries/LibWeb/Painting/ViewportPaintable.cpp b/Userland/Libraries/LibWeb/Painting/ViewportPaintable.cpp index a3423ec034fb3f..8d0dc13aaf18f0 100644 --- a/Userland/Libraries/LibWeb/Painting/ViewportPaintable.cpp +++ b/Userland/Libraries/LibWeb/Painting/ViewportPaintable.cpp @@ -61,13 +61,16 @@ void ViewportPaintable::build_stacking_context_tree() void ViewportPaintable::paint_all_phases(PaintContext& context) { build_stacking_context_tree_if_needed(); - context.display_list_recorder().translate(-context.device_viewport_rect().location().to_type()); stacking_context()->paint(context); } void ViewportPaintable::assign_scroll_frames() { - int next_id = 0; + auto viewport_scroll_frame = adopt_ref(*new ScrollFrame()); + viewport_scroll_frame->id = 0; + scroll_state.set(this, move(viewport_scroll_frame)); + + int next_id = 1; for_each_in_subtree_of_type([&](auto const& paintable_box) { if (paintable_box.has_scrollable_overflow()) { auto scroll_frame = adopt_ref(*new ScrollFrame()); @@ -78,7 +81,10 @@ void ViewportPaintable::assign_scroll_frames() }); for_each_in_subtree([&](auto const& paintable) { - for (auto block = paintable.containing_block(); !block->is_viewport(); block = block->containing_block()) { + if (paintable.is_fixed_position()) { + return TraversalDecision::Continue; + } + for (auto block = paintable.containing_block(); block; block = block->containing_block()) { if (auto scroll_frame = scroll_state.get(block); scroll_frame.has_value()) { if (paintable.is_paintable_box()) { auto const& paintable_box = static_cast(paintable); @@ -87,10 +93,13 @@ void ViewportPaintable::assign_scroll_frames() auto const& inline_paintable = static_cast(paintable); const_cast(inline_paintable).set_enclosing_scroll_frame(scroll_frame.value()); } - break; + return TraversalDecision::Continue; + } + if (block->is_fixed_position()) { + return TraversalDecision::Continue; } } - return TraversalDecision::Continue; + VERIFY_NOT_REACHED(); }); } @@ -134,9 +143,11 @@ void ViewportPaintable::refresh_scroll_state() auto const& paintable_box = *it.key; auto& scroll_frame = *it.value; CSSPixelPoint offset; - for (auto const* block = &paintable_box.layout_box(); !block->is_viewport(); block = block->containing_block()) { + for (auto const* block = &paintable_box.layout_box(); block; block = block->containing_block()) { auto const& block_paintable_box = *block->paintable_box(); offset.translate_by(block_paintable_box.scroll_offset()); + if (block->is_fixed_position()) + break; } scroll_frame.offset = -offset; }