WebViewHints.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. /*
  2. * Copyright (c) 2024, Andrew Kaster <akaster@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibIPC/Decoder.h>
  7. #include <LibIPC/Encoder.h>
  8. #include <LibWeb/HTML/Numbers.h>
  9. #include <LibWeb/HTML/WebViewHints.h>
  10. #include <LibWeb/Page/Page.h>
  11. #include <LibWeb/PixelUnits.h>
  12. namespace Web::HTML {
  13. static void set_up_browsing_context_features(WebViewHints& target, TokenizedFeature::Map const& tokenized_features, Page const& page);
  14. WebViewHints WebViewHints::from_tokenised_features(TokenizedFeature::Map const& tokenized_features, Page const& page)
  15. {
  16. WebViewHints hints;
  17. hints.popup = check_if_a_popup_window_is_requested(tokenized_features) == TokenizedFeature::Popup::Yes;
  18. set_up_browsing_context_features(hints, tokenized_features, page);
  19. return hints;
  20. }
  21. // https://drafts.csswg.org/cssom-view/#set-up-browsing-context-features
  22. static void set_up_browsing_context_features(WebViewHints& target, TokenizedFeature::Map const& tokenized_features, Page const& page)
  23. {
  24. // 1. Let x be null.
  25. Optional<CSSPixels> x;
  26. // 2. Let y be null.
  27. Optional<CSSPixels> y;
  28. // 3. Let width be null.
  29. Optional<CSSPixels> width;
  30. // 4. Let height be null.
  31. Optional<CSSPixels> height;
  32. auto screen_rect = page.web_exposed_screen_area();
  33. // 5. If tokenizedFeatures["left"] exists:
  34. if (auto left = tokenized_features.get("left"sv); left.has_value()) {
  35. // 1. Set x to the result of invoking the rules for parsing integers on tokenizedFeatures["left"].
  36. // 2. If x is an error, set x to 0.
  37. x = parse_integer(*left).value_or(0);
  38. // 3. Optionally, clamp x in a user-agent-defined manner so that the window does not move outside the Web-exposed available screen area.
  39. x = min(*x, screen_rect.x());
  40. // 4. Optionally, move target’s window such that the window’s left edge is at the horizontal coordinate x relative
  41. // to the left edge of the Web-exposed screen area, measured in CSS pixels of target. The positive axis is rightward.
  42. // Note: Handled in the UI process when creating the traversable navigable.
  43. }
  44. // 6. If tokenizedFeatures["top"] exists:
  45. if (auto top = tokenized_features.get("top"sv); top.has_value()) {
  46. // 1. Set y to the result of invoking the rules for parsing integers on tokenizedFeatures["top"].
  47. // 2. If y is an error, set y to 0.
  48. y = parse_integer(*top).value_or(0);
  49. // 3. Optionally, clamp y in a user-agent-defined manner so that the window does not move outside the Web-exposed available screen area.
  50. y = min(*y, screen_rect.y());
  51. // 4. Optionally, move target’s window such that the window’s top edge is at the vertical coordinate y relative
  52. // to the top edge of the Web-exposed screen area, measured in CSS pixels of target. The positive axis is downward.
  53. // Note: Handled in the UI process when creating the traversable navigable.
  54. }
  55. // 7. If tokenizedFeatures["width"] exists:
  56. if (auto width_token = tokenized_features.get("width"sv); width_token.has_value()) {
  57. // 1. Set width to the result of invoking the rules for parsing integers on tokenizedFeatures["width"].
  58. // 2. If width is an error, set width to 0.
  59. width = parse_integer(*width_token).value_or(0);
  60. // 3. If width is not 0:
  61. if (width != 0) {
  62. // 1. Optionally, clamp width in a user-agent-defined manner so that the window does not get too small or bigger than the Web-exposed available screen area.
  63. width = clamp(*width, 100, screen_rect.width());
  64. // 2. Optionally, size target’s window by moving its right edge such that the distance between the left and right edges of the viewport are width CSS pixels of target.
  65. // 3. Optionally, move target’s window in a user-agent-defined manner so that it does not grow outside the Web-exposed available screen area.
  66. // Note: Handled in the UI process when creating the traversable navigable.
  67. }
  68. }
  69. // 8. If tokenizedFeatures["height"] exists:
  70. if (auto height_token = tokenized_features.get("height"sv); height_token.has_value()) {
  71. // 1. Set height to the result of invoking the rules for parsing integers on tokenizedFeatures["height"].
  72. // 2. If height is an error, set height to 0.
  73. height = parse_integer(*height_token).value_or(0);
  74. // 3. If height is not 0:
  75. if (height != 0) {
  76. // 1. Optionally, clamp height in a user-agent-defined manner so that the window does not get too small or bigger than the Web-exposed available screen area.
  77. height = clamp(*height, 100, screen_rect.height());
  78. // 2. Optionally, size target’s window by moving its bottom edge such that the distance between the top and bottom edges of the viewport are height CSS pixels of target.
  79. // 3. Optionally, move target’s window in a user-agent-defined manner so that it does not grow outside the Web-exposed available screen area.
  80. // Note: Handled in the UI process when creating the traversable navigable.
  81. }
  82. }
  83. auto scale = page.client().device_pixels_per_css_pixel();
  84. if (x.has_value()) {
  85. // Make sure we don't fly off the screen to the right
  86. if (x.value() + width.value_or(0) > screen_rect.width())
  87. x = screen_rect.width() - width.value_or(0);
  88. target.screen_x = x.value() / scale;
  89. }
  90. if (y.has_value()) {
  91. // Make sure we don't fly off the screen to the bottom
  92. if (y.value() + height.value_or(0) > screen_rect.height())
  93. y = screen_rect.height() - height.value_or(0);
  94. target.screen_y = y.value() / scale;
  95. }
  96. if (width.has_value()) {
  97. target.width = width.value() / scale;
  98. }
  99. if (height.has_value()) {
  100. target.height = height.value() / scale;
  101. }
  102. }
  103. }
  104. namespace IPC {
  105. template<>
  106. ErrorOr<void> encode(Encoder& encoder, ::Web::HTML::WebViewHints const& data_holder)
  107. {
  108. TRY(encoder.encode(data_holder.popup));
  109. TRY(encoder.encode(data_holder.width));
  110. TRY(encoder.encode(data_holder.height));
  111. TRY(encoder.encode(data_holder.screen_x));
  112. TRY(encoder.encode(data_holder.screen_y));
  113. return {};
  114. }
  115. template<>
  116. ErrorOr<::Web::HTML::WebViewHints> decode(Decoder& decoder)
  117. {
  118. auto popup = TRY(decoder.decode<bool>());
  119. auto width = TRY(decoder.decode<Optional<Web::DevicePixels>>());
  120. auto height = TRY(decoder.decode<Optional<Web::DevicePixels>>());
  121. auto screen_x = TRY(decoder.decode<Optional<Web::DevicePixels>>());
  122. auto screen_y = TRY(decoder.decode<Optional<Web::DevicePixels>>());
  123. return ::Web::HTML::WebViewHints {
  124. .popup = popup,
  125. .width = width,
  126. .height = height,
  127. .screen_x = screen_x,
  128. .screen_y = screen_y,
  129. };
  130. }
  131. }