LibWeb: Create clip and scroll frame trees separately for each navigable

While introducing clip and scroll frame trees, I made a mistake by
assuming that the paintable tree includes boxes from nested navigables.
Therefore, this comment in the code was incorrect, and clip/scroll
frames were simply not assigned for iframes:
// NOTE: We only need to refresh the scroll state for traversables
//       because they are responsible for tracking the state of all
//       nested navigables.

As a result, anything with "overflow: scroll" is currently not
scrollable inside an iframe

This change fixes that by ensuring clip and scroll frames are assigned
and refreshed for each navigable. To achieve this, I had to modify the
display list building process to record a separate display list for each
navigable. This is necessary because scroll frame ids are local to a
navigable, making it impossible to call
`DisplayList::apply_scroll_offsets()` on a display list that contains
ids from multiple navigables.
This commit is contained in:
Aliaksandr Kalenik 2024-08-08 14:17:54 +03:00 committed by Andreas Kling
commit ea8d0304e9
Notes: github-actions[bot] 2024-08-10 08:40:33 +00:00
15 changed files with 156 additions and 46 deletions

View file

@ -6,7 +6,6 @@
#include <AK/QuickSort.h>
#include <LibWeb/Bindings/MainThreadVM.h>
#include <LibWeb/CSS/SystemColor.h>
#include <LibWeb/DOM/Document.h>
#include <LibWeb/HTML/BrowsingContextGroup.h>
#include <LibWeb/HTML/DocumentState.h>
@ -1190,17 +1189,15 @@ JS::GCPtr<DOM::Node> TraversableNavigable::currently_focused_area()
void TraversableNavigable::paint(DevicePixelRect const& content_rect, Painting::BackingStore& target, PaintOptions paint_options)
{
auto display_list = Painting::DisplayList::create();
Painting::DisplayListRecorder display_list_recorder(display_list);
Gfx::IntRect bitmap_rect { {}, content_rect.size().to_type<int>() };
display_list_recorder.fill_rect(bitmap_rect, CSS::SystemColor::canvas());
HTML::Navigable::PaintConfig paint_config;
paint_config.paint_overlay = paint_options.paint_overlay == PaintOptions::PaintOverlay::Yes;
paint_config.should_show_line_box_borders = paint_options.should_show_line_box_borders;
paint_config.has_focus = paint_options.has_focus;
record_display_list(display_list_recorder, paint_config);
paint_config.canvas_fill_rect = Gfx::IntRect { {}, content_rect.size() };
auto display_list = record_display_list(paint_config);
if (!display_list) {
return;
}
switch (page().client().display_list_player_type()) {
case DisplayListPlayerType::SkiaGPUIfAvailable: {
@ -1209,7 +1206,7 @@ void TraversableNavigable::paint(DevicePixelRect const& content_rect, Painting::
auto& iosurface_backing_store = static_cast<Painting::IOSurfaceBackingStore&>(target);
auto texture = m_metal_context->create_texture_from_iosurface(iosurface_backing_store.iosurface_handle());
Painting::DisplayListPlayerSkia player(*m_skia_backend_context, *texture);
player.execute(display_list);
player.execute(*display_list);
return;
}
#endif
@ -1217,19 +1214,19 @@ void TraversableNavigable::paint(DevicePixelRect const& content_rect, Painting::
#ifdef USE_VULKAN
if (m_skia_backend_context) {
Painting::DisplayListPlayerSkia player(*m_skia_backend_context, target.bitmap());
player.execute(display_list);
player.execute(*display_list);
return;
}
#endif
// Fallback to CPU backend if GPU is not available
Painting::DisplayListPlayerSkia player(target.bitmap());
player.execute(display_list);
player.execute(*display_list);
break;
}
case DisplayListPlayerType::SkiaCPU: {
Painting::DisplayListPlayerSkia player(target.bitmap());
player.execute(display_list);
player.execute(*display_list);
break;
}
default: