mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-09-02 15:46:33 +00:00
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:
parent
1b2f35c3af
commit
ea8d0304e9
Notes:
github-actions[bot]
2024-08-10 08:40:33 +00:00
Author: https://github.com/kalenikaliaksandr
Commit: ea8d0304e9
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/1011
15 changed files with 156 additions and 46 deletions
|
@ -5,6 +5,7 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibWeb/CSS/SystemColor.h>
|
||||
#include <LibWeb/Crypto/Crypto.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/DOM/DocumentLoading.h>
|
||||
|
@ -2082,11 +2083,18 @@ void Navigable::inform_the_navigation_api_about_aborting_navigation()
|
|||
}));
|
||||
}
|
||||
|
||||
void Navigable::record_display_list(Painting::DisplayListRecorder& display_list_recorder, PaintConfig config)
|
||||
RefPtr<Painting::DisplayList> Navigable::record_display_list(PaintConfig config)
|
||||
{
|
||||
auto document = active_document();
|
||||
if (!document)
|
||||
return;
|
||||
return {};
|
||||
|
||||
auto display_list = Painting::DisplayList::create();
|
||||
Painting::DisplayListRecorder display_list_recorder(display_list);
|
||||
|
||||
if (config.canvas_fill_rect.has_value()) {
|
||||
display_list_recorder.fill_rect(config.canvas_fill_rect.value(), CSS::SystemColor::canvas());
|
||||
}
|
||||
|
||||
auto const& page = traversable_navigable()->page();
|
||||
auto viewport_rect = page.css_to_device_rect(this->viewport_rect());
|
||||
|
@ -2109,27 +2117,22 @@ void Navigable::record_display_list(Painting::DisplayListRecorder& display_list_
|
|||
|
||||
auto& viewport_paintable = *document->paintable();
|
||||
|
||||
// NOTE: We only need to refresh the scroll state for traversables because they are responsible
|
||||
// for tracking the state of all nested navigables.
|
||||
if (is_traversable()) {
|
||||
viewport_paintable.refresh_scroll_state();
|
||||
viewport_paintable.refresh_clip_state();
|
||||
}
|
||||
viewport_paintable.refresh_scroll_state();
|
||||
viewport_paintable.refresh_clip_state();
|
||||
|
||||
viewport_paintable.paint_all_phases(context);
|
||||
|
||||
// FIXME: Support scrollable frames inside iframes.
|
||||
if (is_traversable()) {
|
||||
Vector<Gfx::IntPoint> scroll_offsets_by_frame_id;
|
||||
scroll_offsets_by_frame_id.resize(viewport_paintable.scroll_state.size());
|
||||
for (auto [_, scrollable_frame] : viewport_paintable.scroll_state) {
|
||||
auto scroll_offset = context.rounded_device_point(scrollable_frame->offset).to_type<int>();
|
||||
scroll_offsets_by_frame_id[scrollable_frame->id] = scroll_offset;
|
||||
}
|
||||
display_list_recorder.display_list().apply_scroll_offsets(scroll_offsets_by_frame_id);
|
||||
Vector<Gfx::IntPoint> scroll_offsets_by_frame_id;
|
||||
scroll_offsets_by_frame_id.resize(viewport_paintable.scroll_state.size());
|
||||
for (auto [_, scrollable_frame] : viewport_paintable.scroll_state) {
|
||||
auto scroll_offset = context.rounded_device_point(scrollable_frame->offset).to_type<int>();
|
||||
scroll_offsets_by_frame_id[scrollable_frame->id] = scroll_offset;
|
||||
}
|
||||
display_list_recorder.display_list().apply_scroll_offsets(scroll_offsets_by_frame_id);
|
||||
|
||||
m_needs_repaint = false;
|
||||
|
||||
return display_list;
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/browsing-the-web.html#event-uni
|
||||
|
|
|
@ -185,8 +185,9 @@ public:
|
|||
bool paint_overlay { false };
|
||||
bool should_show_line_box_borders { false };
|
||||
bool has_focus { false };
|
||||
Optional<Gfx::IntRect> canvas_fill_rect {};
|
||||
};
|
||||
void record_display_list(Painting::DisplayListRecorder& display_list_recorder, PaintConfig);
|
||||
RefPtr<Painting::DisplayList> record_display_list(PaintConfig);
|
||||
|
||||
Page& page() { return m_page; }
|
||||
Page const& page() const { return m_page; }
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue