BackingStoreManager.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. /*
  2. * Copyright (c) 2024, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibCore/Timer.h>
  7. #include <LibWeb/HTML/TraversableNavigable.h>
  8. #include <WebContent/BackingStoreManager.h>
  9. #include <WebContent/PageClient.h>
  10. #ifdef AK_OS_MACOS
  11. # include <LibCore/IOSurface.h>
  12. # include <LibCore/MachPort.h>
  13. # include <LibCore/Platform/MachMessageTypes.h>
  14. #endif
  15. namespace WebContent {
  16. #ifdef AK_OS_MACOS
  17. static Optional<Core::MachPort> s_browser_mach_port;
  18. void BackingStoreManager::set_browser_mach_port(Core::MachPort&& port)
  19. {
  20. s_browser_mach_port = move(port);
  21. }
  22. #endif
  23. BackingStoreManager::BackingStoreManager(PageClient& page_client)
  24. : m_page_client(page_client)
  25. {
  26. m_backing_store_shrink_timer = Core::Timer::create_single_shot(3000, [this] {
  27. resize_backing_stores_if_needed(WindowResizingInProgress::No);
  28. });
  29. }
  30. void BackingStoreManager::restart_resize_timer()
  31. {
  32. m_backing_store_shrink_timer->restart();
  33. }
  34. void BackingStoreManager::reallocate_backing_stores(Gfx::IntSize size)
  35. {
  36. #ifdef AK_OS_MACOS
  37. if (s_browser_mach_port.has_value()) {
  38. auto back_iosurface = Core::IOSurfaceHandle::create(size.width(), size.height());
  39. auto back_iosurface_port = back_iosurface.create_mach_port();
  40. auto front_iosurface = Core::IOSurfaceHandle::create(size.width(), size.height());
  41. auto front_iosurface_port = front_iosurface.create_mach_port();
  42. m_front_bitmap_id = m_next_bitmap_id++;
  43. m_back_bitmap_id = m_next_bitmap_id++;
  44. m_front_bitmap = Gfx::Bitmap::create_wrapper(Gfx::BitmapFormat::BGRA8888, size, size.width() * front_iosurface.bytes_per_element(), front_iosurface.data(), [handle = move(front_iosurface)] {}).release_value();
  45. m_back_bitmap = Gfx::Bitmap::create_wrapper(Gfx::BitmapFormat::BGRA8888, size, size.width() * back_iosurface.bytes_per_element(), back_iosurface.data(), [handle = move(back_iosurface)] {}).release_value();
  46. Core::Platform::BackingStoreMetadata metadata;
  47. metadata.page_id = m_page_client.m_id;
  48. metadata.front_backing_store_id = m_front_bitmap_id;
  49. metadata.back_backing_store_id = m_back_bitmap_id;
  50. Core::Platform::MessageWithBackingStores message;
  51. message.header.msgh_remote_port = s_browser_mach_port->port();
  52. message.header.msgh_local_port = MACH_PORT_NULL;
  53. message.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0) | MACH_MSGH_BITS_COMPLEX;
  54. message.header.msgh_size = sizeof(message);
  55. message.header.msgh_id = Core::Platform::BACKING_STORE_IOSURFACES_MESSAGE_ID;
  56. message.body.msgh_descriptor_count = 2;
  57. message.front_descriptor.name = front_iosurface_port.release();
  58. message.front_descriptor.disposition = MACH_MSG_TYPE_MOVE_SEND;
  59. message.front_descriptor.type = MACH_MSG_PORT_DESCRIPTOR;
  60. message.back_descriptor.name = back_iosurface_port.release();
  61. message.back_descriptor.disposition = MACH_MSG_TYPE_MOVE_SEND;
  62. message.back_descriptor.type = MACH_MSG_PORT_DESCRIPTOR;
  63. message.metadata = metadata;
  64. mach_msg_timeout_t const timeout = 100; // milliseconds
  65. auto const send_result = mach_msg(&message.header, MACH_SEND_MSG | MACH_SEND_TIMEOUT, message.header.msgh_size, 0, MACH_PORT_NULL, timeout, MACH_PORT_NULL);
  66. if (send_result != KERN_SUCCESS) {
  67. dbgln("Failed to send message to server: {}", mach_error_string(send_result));
  68. VERIFY_NOT_REACHED();
  69. }
  70. return;
  71. }
  72. #endif
  73. m_front_bitmap_id = m_next_bitmap_id++;
  74. m_back_bitmap_id = m_next_bitmap_id++;
  75. m_front_bitmap = Gfx::Bitmap::create_shareable(Gfx::BitmapFormat::BGRA8888, size).release_value();
  76. m_back_bitmap = Gfx::Bitmap::create_shareable(Gfx::BitmapFormat::BGRA8888, size).release_value();
  77. m_page_client.page_did_allocate_backing_stores(m_front_bitmap_id, m_front_bitmap->to_shareable_bitmap(), m_back_bitmap_id, m_back_bitmap->to_shareable_bitmap());
  78. }
  79. void BackingStoreManager::resize_backing_stores_if_needed(WindowResizingInProgress window_resize_in_progress)
  80. {
  81. auto css_pixels_viewpor_rect = m_page_client.page().top_level_traversable()->viewport_rect();
  82. auto viewport_size = m_page_client.page().css_to_device_rect(css_pixels_viewpor_rect).size();
  83. if (viewport_size.is_empty())
  84. return;
  85. Web::DevicePixelSize minimum_needed_size;
  86. if (window_resize_in_progress == WindowResizingInProgress::Yes) {
  87. // Pad the minimum needed size so that we don't have to keep reallocating backing stores while the window is being resized.
  88. minimum_needed_size = { viewport_size.width() + 256, viewport_size.height() + 256 };
  89. } else {
  90. // If we're not in the middle of a resize, we can shrink the backing store size to match the viewport size.
  91. minimum_needed_size = viewport_size;
  92. m_front_bitmap.clear();
  93. m_back_bitmap.clear();
  94. }
  95. if (!m_front_bitmap || !m_back_bitmap || !m_front_bitmap->size().contains(minimum_needed_size.to_type<int>())) {
  96. reallocate_backing_stores(minimum_needed_size.to_type<int>());
  97. }
  98. }
  99. void BackingStoreManager::swap_back_and_front()
  100. {
  101. swap(m_front_bitmap, m_back_bitmap);
  102. swap(m_front_bitmap_id, m_back_bitmap_id);
  103. }
  104. }