LadybirdWebViewBridge.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  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. namespace Ladybird {
  15. template<typename T>
  16. static T scale_for_device(T size, float device_pixel_ratio)
  17. {
  18. return size.template to_type<float>().scaled(device_pixel_ratio).template to_type<int>();
  19. }
  20. ErrorOr<NonnullOwnPtr<WebViewBridge>> WebViewBridge::create(Vector<Gfx::IntRect> screen_rects, float device_pixel_ratio, Optional<StringView> webdriver_content_ipc_path)
  21. {
  22. return adopt_nonnull_own_or_enomem(new (nothrow) WebViewBridge(move(screen_rects), device_pixel_ratio, move(webdriver_content_ipc_path)));
  23. }
  24. WebViewBridge::WebViewBridge(Vector<Gfx::IntRect> screen_rects, float device_pixel_ratio, Optional<StringView> webdriver_content_ipc_path)
  25. : m_screen_rects(move(screen_rects))
  26. , m_webdriver_content_ipc_path(move(webdriver_content_ipc_path))
  27. {
  28. m_device_pixel_ratio = device_pixel_ratio;
  29. m_inverse_device_pixel_ratio = 1.0 / device_pixel_ratio;
  30. create_client(WebView::EnableCallgrindProfiling::No);
  31. }
  32. WebViewBridge::~WebViewBridge() = default;
  33. void WebViewBridge::set_system_visibility_state(bool is_visible)
  34. {
  35. client().async_set_system_visibility_state(is_visible);
  36. }
  37. void WebViewBridge::set_viewport_rect(Gfx::IntRect viewport_rect, ForResize for_resize)
  38. {
  39. viewport_rect.set_size(scale_for_device(viewport_rect.size(), m_device_pixel_ratio));
  40. m_viewport_rect = viewport_rect;
  41. client().async_set_viewport_rect(m_viewport_rect);
  42. request_repaint();
  43. if (for_resize == ForResize::Yes) {
  44. handle_resize();
  45. }
  46. }
  47. void WebViewBridge::mouse_down_event(Gfx::IntPoint position, GUI::MouseButton button, KeyModifier modifiers)
  48. {
  49. client().async_mouse_down(to_content_position(position), to_underlying(button), to_underlying(button), modifiers);
  50. }
  51. void WebViewBridge::mouse_up_event(Gfx::IntPoint position, GUI::MouseButton button, KeyModifier modifiers)
  52. {
  53. client().async_mouse_up(to_content_position(position), to_underlying(button), to_underlying(button), modifiers);
  54. }
  55. void WebViewBridge::mouse_move_event(Gfx::IntPoint position, GUI::MouseButton button, KeyModifier modifiers)
  56. {
  57. client().async_mouse_move(to_content_position(position), 0, to_underlying(button), modifiers);
  58. }
  59. void WebViewBridge::mouse_double_click_event(Gfx::IntPoint position, GUI::MouseButton button, KeyModifier modifiers)
  60. {
  61. client().async_doubleclick(to_content_position(position), button, to_underlying(button), modifiers);
  62. }
  63. void WebViewBridge::key_down_event(KeyCode key_code, KeyModifier modifiers, u32 code_point)
  64. {
  65. client().async_key_down(key_code, modifiers, code_point);
  66. }
  67. void WebViewBridge::key_up_event(KeyCode key_code, KeyModifier modifiers, u32 code_point)
  68. {
  69. client().async_key_up(key_code, modifiers, code_point);
  70. }
  71. Optional<WebViewBridge::Paintable> WebViewBridge::paintable()
  72. {
  73. Gfx::Bitmap* bitmap = nullptr;
  74. Gfx::IntSize bitmap_size;
  75. if (m_client_state.has_usable_bitmap) {
  76. bitmap = m_client_state.front_bitmap.bitmap.ptr();
  77. bitmap_size = m_client_state.front_bitmap.last_painted_size;
  78. } else {
  79. bitmap = m_backup_bitmap.ptr();
  80. bitmap_size = m_backup_bitmap_size;
  81. }
  82. if (!bitmap)
  83. return {};
  84. return Paintable { *bitmap, bitmap_size };
  85. }
  86. void WebViewBridge::notify_server_did_layout(Badge<WebView::WebContentClient>, Gfx::IntSize content_size)
  87. {
  88. if (on_layout) {
  89. content_size = scale_for_device(content_size, m_inverse_device_pixel_ratio);
  90. on_layout(content_size);
  91. }
  92. }
  93. void WebViewBridge::notify_server_did_invalidate_content_rect(Badge<WebView::WebContentClient>, Gfx::IntRect const&)
  94. {
  95. request_repaint();
  96. }
  97. void WebViewBridge::notify_server_did_change_selection(Badge<WebView::WebContentClient>)
  98. {
  99. request_repaint();
  100. }
  101. void WebViewBridge::notify_server_did_request_cursor_change(Badge<WebView::WebContentClient>, Gfx::StandardCursor cursor)
  102. {
  103. if (on_cursor_change)
  104. on_cursor_change(cursor);
  105. }
  106. void WebViewBridge::notify_server_did_request_scroll(Badge<WebView::WebContentClient>, i32 x_delta, i32 y_delta)
  107. {
  108. // FIXME: This currently isn't reached because we do not yet propagate mouse wheel events to WebContent.
  109. // When that is implemented, make sure our mutations to the viewport position here are correct.
  110. auto position = m_viewport_rect.location();
  111. position.set_x(position.x() + x_delta);
  112. position.set_y(position.y() + y_delta);
  113. if (on_scroll)
  114. on_scroll(position);
  115. }
  116. void WebViewBridge::notify_server_did_request_scroll_to(Badge<WebView::WebContentClient>, Gfx::IntPoint position)
  117. {
  118. if (on_scroll)
  119. on_scroll(position);
  120. }
  121. void WebViewBridge::notify_server_did_request_scroll_into_view(Badge<WebView::WebContentClient>, Gfx::IntRect const& rect)
  122. {
  123. if (m_viewport_rect.contains(rect))
  124. return;
  125. auto position = m_viewport_rect.location();
  126. if (rect.top() < m_viewport_rect.top()) {
  127. position.set_y(rect.top());
  128. } else if (rect.top() > m_viewport_rect.top() && rect.bottom() > m_viewport_rect.bottom()) {
  129. position.set_y(rect.bottom() - m_viewport_rect.height());
  130. } else {
  131. return;
  132. }
  133. if (on_scroll)
  134. on_scroll(position);
  135. }
  136. void WebViewBridge::notify_server_did_enter_tooltip_area(Badge<WebView::WebContentClient>, Gfx::IntPoint, DeprecatedString const& tooltip)
  137. {
  138. if (on_tooltip_entered)
  139. on_tooltip_entered(tooltip);
  140. }
  141. void WebViewBridge::notify_server_did_leave_tooltip_area(Badge<WebView::WebContentClient>)
  142. {
  143. if (on_tooltip_left)
  144. on_tooltip_left();
  145. }
  146. void WebViewBridge::notify_server_did_finish_handling_input_event(bool)
  147. {
  148. }
  149. void WebViewBridge::update_zoom()
  150. {
  151. }
  152. Gfx::IntRect WebViewBridge::viewport_rect() const
  153. {
  154. return m_viewport_rect;
  155. }
  156. Gfx::IntPoint WebViewBridge::to_content_position(Gfx::IntPoint widget_position) const
  157. {
  158. return scale_for_device(widget_position, m_device_pixel_ratio);
  159. }
  160. Gfx::IntPoint WebViewBridge::to_widget_position(Gfx::IntPoint content_position) const
  161. {
  162. return scale_for_device(content_position, m_inverse_device_pixel_ratio);
  163. }
  164. void WebViewBridge::create_client(WebView::EnableCallgrindProfiling enable_callgrind_profiling)
  165. {
  166. m_client_state = {};
  167. auto candidate_web_content_paths = MUST(get_paths_for_helper_process("WebContent"sv));
  168. auto new_client = MUST(launch_web_content_process(*this, candidate_web_content_paths, enable_callgrind_profiling, WebView::IsLayoutTestMode::No, Ladybird::UseLagomNetworking::Yes));
  169. m_client_state.client = new_client;
  170. m_client_state.client->on_web_content_process_crash = [this] {
  171. Core::deferred_invoke([this] {
  172. handle_web_content_process_crash();
  173. });
  174. };
  175. m_client_state.client_handle = MUST(Web::Crypto::generate_random_uuid());
  176. client().async_set_window_handle(m_client_state.client_handle);
  177. client().async_set_device_pixels_per_css_pixel(m_device_pixel_ratio);
  178. client().async_update_system_fonts(Gfx::FontDatabase::default_font_query(), Gfx::FontDatabase::fixed_width_font_query(), Gfx::FontDatabase::window_title_font_query());
  179. update_palette();
  180. if (!m_screen_rects.is_empty()) {
  181. // FIXME: Update the screens again if they ever change.
  182. client().async_update_screen_rects(m_screen_rects, 0);
  183. }
  184. if (m_webdriver_content_ipc_path.has_value()) {
  185. client().async_connect_to_webdriver(*m_webdriver_content_ipc_path);
  186. }
  187. }
  188. void WebViewBridge::update_palette()
  189. {
  190. auto theme = MUST(Gfx::load_system_theme(DeprecatedString::formatted("{}/res/themes/Default.ini", s_serenity_resource_root)));
  191. auto palette_impl = Gfx::PaletteImpl::create_with_anonymous_buffer(theme);
  192. auto palette = Gfx::Palette(move(palette_impl));
  193. client().async_update_system_theme(move(theme));
  194. }
  195. }