1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-03 05:32:13 +00:00

LibWeb: Add Page abstraction between PageView and main Frame

* A PageView is a view onto a Page object.
* A Page always has a main Frame (root of Frame tree.)
* Page has a PageClient. PageView is a PageClient.

The goal here is to allow building another kind of view onto
a Page while keeping the rest of LibWeb intact.
This commit is contained in:
Andreas Kling 2020-06-08 20:31:49 +02:00
parent 5072d4e02d
commit 92392398a2
16 changed files with 351 additions and 179 deletions

View file

@ -55,24 +55,8 @@
namespace Web {
PageView::PageView()
: m_main_frame(Web::Frame::create(*this))
: m_page(make<Page>(*this))
{
main_frame().on_set_document = [this](auto* document) {
if (on_set_document)
on_set_document(document);
layout_and_sync_size();
scroll_to_top();
update();
};
main_frame().on_title_change = [this](auto& title) {
if (on_title_change)
on_title_change(title);
};
main_frame().on_load_start = [this](auto& url) {
if (on_load_start)
on_load_start(url);
};
set_should_hide_unnecessary_scrollbars(true);
set_background_role(ColorRole::Base);
}
@ -81,6 +65,86 @@ PageView::~PageView()
{
}
void PageView::page_did_change_title(const String& title)
{
if (on_title_change)
on_title_change(title);
}
void PageView::page_did_set_document_in_main_frame(Document* document)
{
if (on_set_document)
on_set_document(document);
layout_and_sync_size();
scroll_to_top();
update();
}
void PageView::page_did_start_loading(const URL& url)
{
if (on_load_start)
on_load_start(url);
}
void PageView::page_did_change_selection()
{
update();
}
void PageView::page_did_request_cursor_change(GUI::StandardCursor cursor)
{
if (window())
window()->set_override_cursor(cursor);
}
void PageView::page_did_request_link_context_menu(const Gfx::Point& content_position, const String& href, [[maybe_unused]] const String& target, [[maybe_unused]] unsigned modifiers)
{
if (on_link_context_menu_request)
on_link_context_menu_request(href, screen_relative_rect().location().translated(to_widget_position(content_position)));
}
void PageView::page_did_click_link(const String& href, const String& target, unsigned modifiers)
{
if (on_link_click)
on_link_click(href, target, modifiers);
}
void PageView::page_did_middle_click_link(const String& href, [[maybe_unused]] const String& target, [[maybe_unused]] unsigned modifiers)
{
if (on_link_middle_click)
on_link_middle_click(href);
}
void PageView::page_did_enter_tooltip_area(const Gfx::Point& content_position, const String& title)
{
GUI::Application::the().show_tooltip(title, screen_relative_rect().location().translated(to_widget_position(content_position)));
}
void PageView::page_did_leave_tooltip_area()
{
GUI::Application::the().hide_tooltip();
}
void PageView::page_did_hover_link(const URL& url)
{
if (on_link_hover)
on_link_hover(url.to_string());
}
void PageView::page_did_unhover_link()
{
}
void PageView::page_did_request_scroll_to_anchor(const String& fragment)
{
scroll_to_anchor(fragment);
}
void PageView::page_did_invalidate(const Gfx::Rect&)
{
update();
}
void PageView::layout_and_sync_size()
{
if (!document())
@ -89,19 +153,19 @@ void PageView::layout_and_sync_size()
bool had_vertical_scrollbar = vertical_scrollbar().is_visible();
bool had_horizontal_scrollbar = horizontal_scrollbar().is_visible();
main_frame().set_size(available_size());
page().main_frame().set_size(available_size());
document()->layout();
set_content_size(enclosing_int_rect(layout_root()->rect()).size());
// NOTE: If layout caused us to gain or lose scrollbars, we have to lay out again
// since the scrollbars now take up some of the available space.
if (had_vertical_scrollbar != vertical_scrollbar().is_visible() || had_horizontal_scrollbar != horizontal_scrollbar().is_visible()) {
main_frame().set_size(available_size());
page().main_frame().set_size(available_size());
document()->layout();
set_content_size(enclosing_int_rect(layout_root()->rect()).size());
}
main_frame().set_viewport_rect(viewport_rect_in_content_coordinates());
page().main_frame().set_viewport_rect(viewport_rect_in_content_coordinates());
#ifdef HTML_DEBUG
dbgprintf("\033[33;1mLayout tree after layout:\033[0m\n");
@ -145,28 +209,19 @@ void PageView::paint_event(GUI::PaintEvent& event)
void PageView::mousemove_event(GUI::MouseEvent& event)
{
if (main_frame().event_handler().handle_mousemove(to_content_position(event.position()), event.buttons(), event.modifiers())) {
event.accept();
return;
}
page().handle_mousemove(to_content_position(event.position()), event.buttons(), event.modifiers());
GUI::ScrollableWidget::mousemove_event(event);
}
void PageView::mousedown_event(GUI::MouseEvent& event)
{
if (main_frame().event_handler().handle_mousedown(to_content_position(event.position()), event.button(), event.modifiers())) {
event.accept();
return;
}
page().handle_mousedown(to_content_position(event.position()), event.button(), event.modifiers());
GUI::ScrollableWidget::mousedown_event(event);
}
void PageView::mouseup_event(GUI::MouseEvent& event)
{
if (main_frame().event_handler().handle_mouseup(to_content_position(event.position()), event.button(), event.modifiers())) {
event.accept();
return;
}
page().handle_mouseup(to_content_position(event.position()), event.button(), event.modifiers());
GUI::ScrollableWidget::mouseup_event(event);
}
@ -208,7 +263,7 @@ void PageView::keydown_event(GUI::KeyEvent& event)
void PageView::reload()
{
load(main_frame().document()->url());
load(page().main_frame().document()->url());
}
bool PageView::load(const URL& url)
@ -216,7 +271,7 @@ bool PageView::load(const URL& url)
if (window())
window()->set_override_cursor(GUI::StandardCursor::None);
return main_frame().loader().load(url);
return page().main_frame().loader().load(url);
}
const LayoutDocument* PageView::layout_root() const
@ -263,33 +318,33 @@ void PageView::scroll_to_anchor(const StringView& name)
void PageView::set_use_old_parser(bool use_old_parser)
{
main_frame().loader().set_use_old_parser(use_old_parser);
page().main_frame().loader().set_use_old_parser(use_old_parser);
}
void PageView::load_empty_document()
{
main_frame().set_document(nullptr);
page().main_frame().set_document(nullptr);
}
Document* PageView::document()
{
return main_frame().document();
return page().main_frame().document();
}
const Document* PageView::document() const
{
return main_frame().document();
return page().main_frame().document();
}
void PageView::set_document(Document* document)
{
main_frame().set_document(document);
page().main_frame().set_document(document);
}
void PageView::did_scroll()
{
main_frame().set_viewport_rect(viewport_rect_in_content_coordinates());
main_frame().did_scroll({});
page().main_frame().set_viewport_rect(viewport_rect_in_content_coordinates());
page().main_frame().did_scroll({});
}
void PageView::drop_event(GUI::DropEvent& event)
@ -303,77 +358,4 @@ void PageView::drop_event(GUI::DropEvent& event)
ScrollableWidget::drop_event(event);
}
void PageView::notify_link_click(Badge<EventHandler>, Web::Frame&, const String& href, const String& target, unsigned modifiers)
{
if (on_link_click)
on_link_click(href, target, modifiers);
}
void PageView::notify_link_middle_click(Badge<EventHandler>, Web::Frame&, const String& href, const String&, unsigned)
{
if (on_link_middle_click)
on_link_middle_click(href);
}
Gfx::Point PageView::to_screen_position(const Web::Frame& frame, const Gfx::Point& frame_position) const
{
Gfx::Point offset;
for (auto* f = &frame; f; f = f->parent()) {
if (f->is_main_frame())
break;
auto f_position = f->host_element()->layout_node()->box_type_agnostic_position().to_int_point();
offset.move_by(f_position);
}
return screen_relative_rect().location().translated(offset).translated(frame_position);
}
Gfx::Rect PageView::to_widget_rect(const Web::Frame& frame, const Gfx::Rect& frame_rect) const
{
Gfx::Point offset;
for (auto* f = &frame; f; f = f->parent()) {
if (f->is_main_frame())
break;
if (!f->host_element())
return {};
if (!f->host_element()->layout_node())
return {};
auto f_position = f->host_element()->layout_node()->box_type_agnostic_position().to_int_point();
offset.move_by(f_position);
}
auto content_position = frame_rect.location().translated(offset);
return { to_widget_position(content_position), frame_rect.size() };
}
void PageView::notify_link_context_menu_request(Badge<EventHandler>, Web::Frame& frame, const Gfx::Point& content_position, const String& href, const String&, unsigned)
{
if (on_link_context_menu_request)
on_link_context_menu_request(href, to_screen_position(frame, content_position));
}
void PageView::notify_link_hover(Badge<EventHandler>, Web::Frame&, const String& href)
{
if (on_link_hover)
on_link_hover(href);
}
void PageView::notify_tooltip_area_enter(Badge<EventHandler>, Web::Frame& frame, const Gfx::Point& content_position, const String& title)
{
GUI::Application::the().show_tooltip(title, to_screen_position(frame, content_position));
}
void PageView::notify_tooltip_area_leave(Badge<EventHandler>, Web::Frame&)
{
GUI::Application::the().hide_tooltip();
}
void PageView::notify_needs_display(Badge<Web::Frame>, Web::Frame& frame, const Gfx::Rect& rect)
{
update(to_widget_rect(frame, rect));
// FIXME: This is a total hack that forces a full repaint every time.
// We shouldn't have to do this, but until the ICB is actually viewport-sized, we have no choice.
update();
}
}