LadybirdWebViewBridge.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. /*
  2. * Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <Ladybird/HelperProcess.h>
  7. #include <Ladybird/Types.h>
  8. #include <Ladybird/Utilities.h>
  9. #include <LibGfx/Font/FontDatabase.h>
  10. #include <LibGfx/Rect.h>
  11. #include <LibIPC/File.h>
  12. #include <LibWeb/Crypto/Crypto.h>
  13. #include <UI/LadybirdWebViewBridge.h>
  14. #import <UI/Palette.h>
  15. namespace Ladybird {
  16. template<typename T>
  17. static T scale_for_device(T size, float device_pixel_ratio)
  18. {
  19. return size.template to_type<float>().scaled(device_pixel_ratio).template to_type<int>();
  20. }
  21. ErrorOr<NonnullOwnPtr<WebViewBridge>> WebViewBridge::create(Vector<Gfx::IntRect> screen_rects, float device_pixel_ratio, Optional<StringView> webdriver_content_ipc_path, Web::CSS::PreferredColorScheme preferred_color_scheme)
  22. {
  23. return adopt_nonnull_own_or_enomem(new (nothrow) WebViewBridge(move(screen_rects), device_pixel_ratio, move(webdriver_content_ipc_path), preferred_color_scheme));
  24. }
  25. WebViewBridge::WebViewBridge(Vector<Gfx::IntRect> screen_rects, float device_pixel_ratio, Optional<StringView> webdriver_content_ipc_path, Web::CSS::PreferredColorScheme preferred_color_scheme)
  26. : m_screen_rects(move(screen_rects))
  27. , m_webdriver_content_ipc_path(move(webdriver_content_ipc_path))
  28. , m_preferred_color_scheme(preferred_color_scheme)
  29. {
  30. m_device_pixel_ratio = device_pixel_ratio;
  31. create_client(WebView::EnableCallgrindProfiling::No);
  32. on_scroll_by_delta = [this](auto x_delta, auto y_delta) {
  33. auto position = m_viewport_rect.location();
  34. position.set_x(position.x() + x_delta);
  35. position.set_y(position.y() + y_delta);
  36. if (on_scroll_to_point)
  37. on_scroll_to_point(position);
  38. };
  39. on_scroll_into_view = [this](auto rect) {
  40. if (m_viewport_rect.contains(rect))
  41. return;
  42. auto position = m_viewport_rect.location();
  43. if (rect.top() < m_viewport_rect.top()) {
  44. position.set_y(rect.top());
  45. } else if (rect.top() > m_viewport_rect.top() && rect.bottom() > m_viewport_rect.bottom()) {
  46. position.set_y(rect.bottom() - m_viewport_rect.height());
  47. } else {
  48. return;
  49. }
  50. if (on_scroll_to_point)
  51. on_scroll_to_point(position);
  52. };
  53. on_scroll_to_point = [this](auto position) {
  54. if (on_scroll)
  55. on_scroll(to_widget_position(position));
  56. };
  57. }
  58. WebViewBridge::~WebViewBridge() = default;
  59. void WebViewBridge::set_device_pixel_ratio(float device_pixel_ratio)
  60. {
  61. m_device_pixel_ratio = device_pixel_ratio;
  62. client().async_set_device_pixels_per_css_pixel(m_device_pixel_ratio * m_zoom_level);
  63. }
  64. void WebViewBridge::set_system_visibility_state(bool is_visible)
  65. {
  66. client().async_set_system_visibility_state(is_visible);
  67. }
  68. void WebViewBridge::set_viewport_rect(Gfx::IntRect viewport_rect, ForResize for_resize)
  69. {
  70. viewport_rect.set_size(scale_for_device(viewport_rect.size(), m_device_pixel_ratio));
  71. m_viewport_rect = viewport_rect;
  72. client().async_set_viewport_rect(m_viewport_rect);
  73. request_repaint();
  74. if (for_resize == ForResize::Yes) {
  75. handle_resize();
  76. }
  77. }
  78. void WebViewBridge::update_palette()
  79. {
  80. auto theme = create_system_palette();
  81. client().async_update_system_theme(move(theme));
  82. }
  83. void WebViewBridge::set_preferred_color_scheme(Web::CSS::PreferredColorScheme color_scheme)
  84. {
  85. m_preferred_color_scheme = color_scheme;
  86. client().async_set_preferred_color_scheme(color_scheme);
  87. }
  88. void WebViewBridge::mouse_wheel_event(Gfx::IntPoint position, Gfx::IntPoint screen_position, GUI::MouseButton button, KeyModifier modifiers, int wheel_delta_x, int wheel_delta_y)
  89. {
  90. client().async_mouse_wheel(to_content_position(position), screen_position, to_underlying(button), to_underlying(button), modifiers, wheel_delta_x, wheel_delta_y);
  91. }
  92. void WebViewBridge::mouse_down_event(Gfx::IntPoint position, Gfx::IntPoint screen_position, GUI::MouseButton button, KeyModifier modifiers)
  93. {
  94. client().async_mouse_down(to_content_position(position), screen_position, to_underlying(button), to_underlying(button), modifiers);
  95. }
  96. void WebViewBridge::mouse_up_event(Gfx::IntPoint position, Gfx::IntPoint screen_position, GUI::MouseButton button, KeyModifier modifiers)
  97. {
  98. client().async_mouse_up(to_content_position(position), screen_position, to_underlying(button), to_underlying(button), modifiers);
  99. }
  100. void WebViewBridge::mouse_move_event(Gfx::IntPoint position, Gfx::IntPoint screen_position, GUI::MouseButton button, KeyModifier modifiers)
  101. {
  102. client().async_mouse_move(to_content_position(position), screen_position, 0, to_underlying(button), modifiers);
  103. }
  104. void WebViewBridge::mouse_double_click_event(Gfx::IntPoint position, Gfx::IntPoint screen_position, GUI::MouseButton button, KeyModifier modifiers)
  105. {
  106. client().async_doubleclick(to_content_position(position), screen_position, button, to_underlying(button), modifiers);
  107. }
  108. void WebViewBridge::key_down_event(KeyCode key_code, KeyModifier modifiers, u32 code_point)
  109. {
  110. client().async_key_down(key_code, modifiers, code_point);
  111. }
  112. void WebViewBridge::key_up_event(KeyCode key_code, KeyModifier modifiers, u32 code_point)
  113. {
  114. client().async_key_up(key_code, modifiers, code_point);
  115. }
  116. Optional<WebViewBridge::Paintable> WebViewBridge::paintable()
  117. {
  118. Gfx::Bitmap* bitmap = nullptr;
  119. Gfx::IntSize bitmap_size;
  120. if (m_client_state.has_usable_bitmap) {
  121. bitmap = m_client_state.front_bitmap.bitmap.ptr();
  122. bitmap_size = m_client_state.front_bitmap.last_painted_size;
  123. } else {
  124. bitmap = m_backup_bitmap.ptr();
  125. bitmap_size = m_backup_bitmap_size;
  126. }
  127. if (!bitmap)
  128. return {};
  129. return Paintable { *bitmap, bitmap_size };
  130. }
  131. void WebViewBridge::update_zoom()
  132. {
  133. client().async_set_device_pixels_per_css_pixel(m_device_pixel_ratio * m_zoom_level);
  134. if (on_zoom_level_changed)
  135. on_zoom_level_changed();
  136. }
  137. Gfx::IntRect WebViewBridge::viewport_rect() const
  138. {
  139. return m_viewport_rect;
  140. }
  141. Gfx::IntPoint WebViewBridge::to_content_position(Gfx::IntPoint widget_position) const
  142. {
  143. return scale_for_device(widget_position, m_device_pixel_ratio);
  144. }
  145. Gfx::IntPoint WebViewBridge::to_widget_position(Gfx::IntPoint content_position) const
  146. {
  147. return scale_for_device(content_position, inverse_device_pixel_ratio());
  148. }
  149. void WebViewBridge::create_client(WebView::EnableCallgrindProfiling enable_callgrind_profiling)
  150. {
  151. m_client_state = {};
  152. auto candidate_web_content_paths = MUST(get_paths_for_helper_process("WebContent"sv));
  153. auto new_client = MUST(launch_web_content_process(*this, candidate_web_content_paths, enable_callgrind_profiling, WebView::IsLayoutTestMode::No, Ladybird::UseLagomNetworking::Yes, WebView::EnableGPUPainting::No));
  154. m_client_state.client = new_client;
  155. m_client_state.client->on_web_content_process_crash = [this] {
  156. Core::deferred_invoke([this] {
  157. handle_web_content_process_crash();
  158. });
  159. };
  160. m_client_state.client_handle = MUST(Web::Crypto::generate_random_uuid());
  161. client().async_set_window_handle(m_client_state.client_handle);
  162. client().async_set_device_pixels_per_css_pixel(m_device_pixel_ratio);
  163. client().async_update_system_fonts(Gfx::FontDatabase::default_font_query(), Gfx::FontDatabase::fixed_width_font_query(), Gfx::FontDatabase::window_title_font_query());
  164. client().async_set_preferred_color_scheme(m_preferred_color_scheme);
  165. update_palette();
  166. if (!m_screen_rects.is_empty()) {
  167. // FIXME: Update the screens again if they ever change.
  168. client().async_update_screen_rects(m_screen_rects, 0);
  169. }
  170. if (m_webdriver_content_ipc_path.has_value()) {
  171. client().async_connect_to_webdriver(*m_webdriver_content_ipc_path);
  172. }
  173. }
  174. }