Serenity Operating System
at master 386 lines 12 kB view raw
1/* 2 * Copyright (c) 2020-2023, Andreas Kling <kling@serenityos.org> 3 * Copyright (c) 2021-2022, Linus Groh <linusg@serenityos.org> 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#include "PageHost.h" 9#include "ConnectionFromClient.h" 10#include <LibGfx/Painter.h> 11#include <LibGfx/ShareableBitmap.h> 12#include <LibGfx/SystemTheme.h> 13#include <LibWeb/Cookie/ParsedCookie.h> 14#include <LibWeb/HTML/BrowsingContext.h> 15#include <LibWeb/Layout/Viewport.h> 16#include <LibWeb/Painting/PaintableBox.h> 17#include <LibWeb/Platform/Timer.h> 18#include <WebContent/WebContentClientEndpoint.h> 19#include <WebContent/WebDriverConnection.h> 20 21namespace WebContent { 22 23PageHost::PageHost(ConnectionFromClient& client) 24 : m_client(client) 25 , m_page(make<Web::Page>(*this)) 26{ 27 setup_palette(); 28 m_invalidation_coalescing_timer = Web::Platform::Timer::create_single_shot(0, [this] { 29 m_client.async_did_invalidate_content_rect({ m_invalidation_rect.x().value(), m_invalidation_rect.y().value(), m_invalidation_rect.width().value(), m_invalidation_rect.height().value() }); 30 m_invalidation_rect = {}; 31 }); 32} 33 34PageHost::~PageHost() = default; 35 36void PageHost::set_has_focus(bool has_focus) 37{ 38 m_has_focus = has_focus; 39} 40 41void PageHost::setup_palette() 42{ 43 // FIXME: Get the proper palette from our peer somehow 44 auto buffer_or_error = Core::AnonymousBuffer::create_with_size(sizeof(Gfx::SystemTheme)); 45 VERIFY(!buffer_or_error.is_error()); 46 auto buffer = buffer_or_error.release_value(); 47 auto* theme = buffer.data<Gfx::SystemTheme>(); 48 theme->color[(int)Gfx::ColorRole::Window] = Color::Magenta; 49 theme->color[(int)Gfx::ColorRole::WindowText] = Color::Cyan; 50 m_palette_impl = Gfx::PaletteImpl::create_with_anonymous_buffer(buffer); 51} 52 53bool PageHost::is_connection_open() const 54{ 55 return m_client.is_open(); 56} 57 58Gfx::Palette PageHost::palette() const 59{ 60 return Gfx::Palette(*m_palette_impl); 61} 62 63void PageHost::set_palette_impl(Gfx::PaletteImpl& impl) 64{ 65 m_palette_impl = impl; 66 if (auto* document = page().top_level_browsing_context().active_document()) 67 document->invalidate_style(); 68} 69 70void PageHost::set_preferred_color_scheme(Web::CSS::PreferredColorScheme color_scheme) 71{ 72 m_preferred_color_scheme = color_scheme; 73 if (auto* document = page().top_level_browsing_context().active_document()) 74 document->invalidate_style(); 75} 76 77void PageHost::set_is_scripting_enabled(bool is_scripting_enabled) 78{ 79 page().set_is_scripting_enabled(is_scripting_enabled); 80} 81 82void PageHost::set_window_position(Web::DevicePixelPoint position) 83{ 84 page().set_window_position(position); 85} 86 87void PageHost::set_window_size(Web::DevicePixelSize size) 88{ 89 page().set_window_size(size); 90} 91 92ErrorOr<void> PageHost::connect_to_webdriver(DeprecatedString const& webdriver_ipc_path) 93{ 94 VERIFY(!m_webdriver); 95 m_webdriver = TRY(WebDriverConnection::connect(*this, webdriver_ipc_path)); 96 return {}; 97} 98 99Web::Layout::Viewport* PageHost::layout_root() 100{ 101 auto* document = page().top_level_browsing_context().active_document(); 102 if (!document) 103 return nullptr; 104 return document->layout_node(); 105} 106 107void PageHost::paint(Web::DevicePixelRect const& content_rect, Gfx::Bitmap& target) 108{ 109 Gfx::Painter painter(target); 110 Gfx::IntRect bitmap_rect { {}, content_rect.size().to_type<int>() }; 111 112 if (auto* document = page().top_level_browsing_context().active_document()) 113 document->update_layout(); 114 115 auto* layout_root = this->layout_root(); 116 if (!layout_root) { 117 painter.fill_rect(bitmap_rect, palette().base()); 118 return; 119 } 120 121 Web::PaintContext context(painter, palette(), device_pixels_per_css_pixel()); 122 context.set_should_show_line_box_borders(m_should_show_line_box_borders); 123 context.set_device_viewport_rect(content_rect); 124 context.set_has_focus(m_has_focus); 125 layout_root->paint_all_phases(context); 126} 127 128void PageHost::set_viewport_rect(Web::DevicePixelRect const& rect) 129{ 130 page().top_level_browsing_context().set_viewport_rect(page().device_to_css_rect(rect)); 131} 132 133void PageHost::page_did_invalidate(Web::CSSPixelRect const& content_rect) 134{ 135 m_invalidation_rect = m_invalidation_rect.united(page().enclosing_device_rect(content_rect)); 136 if (!m_invalidation_coalescing_timer->is_active()) 137 m_invalidation_coalescing_timer->start(); 138} 139 140void PageHost::page_did_change_selection() 141{ 142 m_client.async_did_change_selection(); 143} 144 145void PageHost::page_did_request_cursor_change(Gfx::StandardCursor cursor) 146{ 147 m_client.async_did_request_cursor_change((u32)cursor); 148} 149 150void PageHost::page_did_layout() 151{ 152 auto* layout_root = this->layout_root(); 153 VERIFY(layout_root); 154 if (layout_root->paint_box()->has_overflow()) 155 m_content_size = page().enclosing_device_rect(layout_root->paint_box()->scrollable_overflow_rect().value()).size(); 156 else 157 m_content_size = page().enclosing_device_rect(layout_root->paint_box()->absolute_rect()).size(); 158 m_client.async_did_layout(m_content_size.to_type<int>()); 159} 160 161void PageHost::page_did_change_title(DeprecatedString const& title) 162{ 163 m_client.async_did_change_title(title); 164} 165 166void PageHost::page_did_request_navigate_back() 167{ 168 m_client.async_did_request_navigate_back(); 169} 170 171void PageHost::page_did_request_navigate_forward() 172{ 173 m_client.async_did_request_navigate_forward(); 174} 175 176void PageHost::page_did_request_refresh() 177{ 178 m_client.async_did_request_refresh(); 179} 180 181Gfx::IntSize PageHost::page_did_request_resize_window(Gfx::IntSize size) 182{ 183 return m_client.did_request_resize_window(size); 184} 185 186Gfx::IntPoint PageHost::page_did_request_reposition_window(Gfx::IntPoint position) 187{ 188 return m_client.did_request_reposition_window(position); 189} 190 191void PageHost::page_did_request_restore_window() 192{ 193 m_client.async_did_request_restore_window(); 194} 195 196Gfx::IntRect PageHost::page_did_request_maximize_window() 197{ 198 return m_client.did_request_maximize_window(); 199} 200 201Gfx::IntRect PageHost::page_did_request_minimize_window() 202{ 203 return m_client.did_request_minimize_window(); 204} 205 206Gfx::IntRect PageHost::page_did_request_fullscreen_window() 207{ 208 return m_client.did_request_fullscreen_window(); 209} 210 211void PageHost::page_did_request_scroll(i32 x_delta, i32 y_delta) 212{ 213 m_client.async_did_request_scroll(x_delta, y_delta); 214} 215 216void PageHost::page_did_request_scroll_to(Web::CSSPixelPoint scroll_position) 217{ 218 m_client.async_did_request_scroll_to({ scroll_position.x().value(), scroll_position.y().value() }); 219} 220 221void PageHost::page_did_request_scroll_into_view(Web::CSSPixelRect const& rect) 222{ 223 auto device_pixel_rect = page().enclosing_device_rect(rect); 224 m_client.async_did_request_scroll_into_view({ device_pixel_rect.x().value(), 225 device_pixel_rect.y().value(), 226 device_pixel_rect.width().value(), 227 device_pixel_rect.height().value() }); 228} 229 230void PageHost::page_did_enter_tooltip_area(Web::CSSPixelPoint content_position, DeprecatedString const& title) 231{ 232 m_client.async_did_enter_tooltip_area({ content_position.x().value(), content_position.y().value() }, title); 233} 234 235void PageHost::page_did_leave_tooltip_area() 236{ 237 m_client.async_did_leave_tooltip_area(); 238} 239 240void PageHost::page_did_hover_link(const URL& url) 241{ 242 m_client.async_did_hover_link(url); 243} 244 245void PageHost::page_did_unhover_link() 246{ 247 m_client.async_did_unhover_link(); 248} 249 250void PageHost::page_did_click_link(const URL& url, DeprecatedString const& target, unsigned modifiers) 251{ 252 m_client.async_did_click_link(url, target, modifiers); 253} 254 255void PageHost::page_did_middle_click_link(const URL& url, [[maybe_unused]] DeprecatedString const& target, [[maybe_unused]] unsigned modifiers) 256{ 257 m_client.async_did_middle_click_link(url, target, modifiers); 258} 259 260void PageHost::page_did_start_loading(const URL& url, bool is_redirect) 261{ 262 m_client.async_did_start_loading(url, is_redirect); 263} 264 265void PageHost::page_did_create_main_document() 266{ 267 m_client.initialize_js_console({}); 268} 269 270void PageHost::page_did_finish_loading(const URL& url) 271{ 272 m_client.async_did_finish_loading(url); 273} 274 275void PageHost::page_did_request_context_menu(Web::CSSPixelPoint content_position) 276{ 277 m_client.async_did_request_context_menu(page().css_to_device_point(content_position).to_type<int>()); 278} 279 280void PageHost::page_did_request_link_context_menu(Web::CSSPixelPoint content_position, URL const& url, DeprecatedString const& target, unsigned modifiers) 281{ 282 m_client.async_did_request_link_context_menu(page().css_to_device_point(content_position).to_type<int>(), url, target, modifiers); 283} 284 285void PageHost::page_did_request_alert(DeprecatedString const& message) 286{ 287 m_client.async_did_request_alert(message); 288} 289 290void PageHost::alert_closed() 291{ 292 page().alert_closed(); 293} 294 295void PageHost::page_did_request_confirm(DeprecatedString const& message) 296{ 297 m_client.async_did_request_confirm(message); 298} 299 300void PageHost::confirm_closed(bool accepted) 301{ 302 page().confirm_closed(accepted); 303} 304 305void PageHost::page_did_request_prompt(DeprecatedString const& message, DeprecatedString const& default_) 306{ 307 m_client.async_did_request_prompt(message, default_); 308} 309 310void PageHost::page_did_request_set_prompt_text(DeprecatedString const& text) 311{ 312 m_client.async_did_request_set_prompt_text(text); 313} 314 315void PageHost::prompt_closed(DeprecatedString response) 316{ 317 page().prompt_closed(move(response)); 318} 319 320void PageHost::page_did_request_accept_dialog() 321{ 322 m_client.async_did_request_accept_dialog(); 323} 324 325void PageHost::page_did_request_dismiss_dialog() 326{ 327 m_client.async_did_request_dismiss_dialog(); 328} 329 330void PageHost::page_did_change_favicon(Gfx::Bitmap const& favicon) 331{ 332 m_client.async_did_change_favicon(favicon.to_shareable_bitmap()); 333} 334 335void PageHost::page_did_request_image_context_menu(Web::CSSPixelPoint content_position, URL const& url, DeprecatedString const& target, unsigned modifiers, Gfx::Bitmap const* bitmap_pointer) 336{ 337 auto bitmap = bitmap_pointer ? bitmap_pointer->to_shareable_bitmap() : Gfx::ShareableBitmap(); 338 m_client.async_did_request_image_context_menu({ content_position.x().value(), content_position.y().value() }, url, target, modifiers, bitmap); 339} 340 341Vector<Web::Cookie::Cookie> PageHost::page_did_request_all_cookies(URL const& url) 342{ 343 return m_client.did_request_all_cookies(url); 344} 345 346Optional<Web::Cookie::Cookie> PageHost::page_did_request_named_cookie(URL const& url, DeprecatedString const& name) 347{ 348 return m_client.did_request_named_cookie(url, name); 349} 350 351DeprecatedString PageHost::page_did_request_cookie(const URL& url, Web::Cookie::Source source) 352{ 353 auto response = m_client.send_sync_but_allow_failure<Messages::WebContentClient::DidRequestCookie>(move(url), static_cast<u8>(source)); 354 if (!response) { 355 dbgln("WebContent client disconnected during DidRequestCookie. Exiting peacefully."); 356 exit(0); 357 } 358 return response->take_cookie(); 359} 360 361void PageHost::page_did_set_cookie(const URL& url, Web::Cookie::ParsedCookie const& cookie, Web::Cookie::Source source) 362{ 363 m_client.async_did_set_cookie(url, cookie, static_cast<u8>(source)); 364} 365 366void PageHost::page_did_update_cookie(Web::Cookie::Cookie cookie) 367{ 368 m_client.async_did_update_cookie(move(cookie)); 369} 370 371void PageHost::page_did_update_resource_count(i32 count_waiting) 372{ 373 m_client.async_did_update_resource_count(count_waiting); 374} 375 376void PageHost::page_did_close_browsing_context(Web::HTML::BrowsingContext const&) 377{ 378 m_client.async_did_close_browsing_context(); 379} 380 381void PageHost::request_file(Web::FileRequest file_request) 382{ 383 m_client.request_file(move(file_request)); 384} 385 386}