Skip to content

Commit

Permalink
LibWeb: Unify scroll handling between viewport and scrollable boxes
Browse files Browse the repository at this point in the history
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)
  • Loading branch information
kalenikaliaksandr authored and nico committed Nov 22, 2024
1 parent a73fb69 commit 8b3ebb7
Show file tree
Hide file tree
Showing 5 changed files with 25 additions and 30 deletions.
5 changes: 4 additions & 1 deletion Userland/Libraries/LibWeb/HTML/Navigable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
12 changes: 4 additions & 8 deletions Userland/Libraries/LibWeb/Page/EventHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -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();

Expand Down
10 changes: 0 additions & 10 deletions Userland/Libraries/LibWeb/Painting/PaintableBox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -296,9 +296,6 @@ Optional<CSSPixelRect> PaintableBox::scroll_thumb_rect(ScrollDirection direction
};
}

if (is_viewport())
thumb_rect.translate_by(this->scroll_offset());

return thumb_rect;
}

Expand Down Expand Up @@ -796,14 +793,10 @@ Paintable::DispatchEventOfSameName PaintableBox::handle_mousedown(Badge<EventHan
auto vertical_scroll_thumb_rect = scroll_thumb_rect(ScrollDirection::Vertical);
auto horizontal_scroll_thumb_rect = scroll_thumb_rect(ScrollDirection::Horizontal);
if (vertical_scroll_thumb_rect.has_value() && vertical_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::Vertical;
const_cast<HTML::Navigable&>(*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<HTML::Navigable&>(*navigable()).event_handler().set_mouse_event_tracking_paintable(this);
Expand All @@ -824,9 +817,6 @@ Paintable::DispatchEventOfSameName PaintableBox::handle_mouseup(Badge<EventHandl
Paintable::DispatchEventOfSameName PaintableBox::handle_mousemove(Badge<EventHandler>, CSSPixelPoint position, unsigned, unsigned)
{
if (m_last_mouse_tracking_position.has_value()) {
if (is_viewport())
position.translate_by(-scroll_offset());

Gfx::Point<double> scroll_delta;
if (m_scroll_thumb_dragging_direction == ScrollDirection::Horizontal)
scroll_delta.set_x((position.x() - m_last_mouse_tracking_position->x()).to_double());
Expand Down
5 changes: 0 additions & 5 deletions Userland/Libraries/LibWeb/Painting/StackingContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<CSSPixels>() + 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

Expand Down
23 changes: 17 additions & 6 deletions Userland/Libraries/LibWeb/Painting/ViewportPaintable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<int>());
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<PaintableBox>([&](auto const& paintable_box) {
if (paintable_box.has_scrollable_overflow()) {
auto scroll_frame = adopt_ref(*new ScrollFrame());
Expand All @@ -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<PaintableBox const&>(paintable);
Expand All @@ -87,10 +93,13 @@ void ViewportPaintable::assign_scroll_frames()
auto const& inline_paintable = static_cast<InlinePaintable const&>(paintable);
const_cast<InlinePaintable&>(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();
});
}

Expand Down Expand Up @@ -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;
}
Expand Down

0 comments on commit 8b3ebb7

Please sign in to comment.