ElementBackgroundBorder.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. /*
  2. * This source file is part of RmlUi, the HTML/CSS Interface Middleware
  3. *
  4. * For the latest information, see http://github.com/mikke89/RmlUi
  5. *
  6. * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
  7. * Copyright (c) 2019-2024 The RmlUi Team, and contributors
  8. *
  9. * Permission is hereby granted, free of charge, to any person obtaining a copy
  10. * of this software and associated documentation files (the "Software"), to deal
  11. * in the Software without restriction, including without limitation the rights
  12. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. * copies of the Software, and to permit persons to whom the Software is
  14. * furnished to do so, subject to the following conditions:
  15. *
  16. * The above copyright notice and this permission notice shall be included in
  17. * all copies or substantial portions of the Software.
  18. *
  19. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25. * THE SOFTWARE.
  26. *
  27. */
  28. #include "../Common/TestsInterface.h"
  29. #include "../Common/TestsShell.h"
  30. #include <RmlUi/Core/Context.h>
  31. #include <RmlUi/Core/Element.h>
  32. #include <RmlUi/Core/ElementDocument.h>
  33. #include <RmlUi/Core/Types.h>
  34. #include <doctest.h>
  35. #include <float.h>
  36. using namespace Rml;
  37. static String GenerateRowsRml(int num_rows, String row_rml)
  38. {
  39. String rml;
  40. rml.reserve(num_rows * row_rml.size());
  41. for (int i = 0; i < num_rows; i++)
  42. rml += row_rml;
  43. return rml;
  44. }
  45. static const String document_basic_rml = R"(
  46. <rml>
  47. <head>
  48. <title>Demo</title>
  49. <link type="text/rcss" href="/assets/rml.rcss" />
  50. <link type="text/rcss" href="/../Tests/Data/style.rcss" />
  51. <style>
  52. body {
  53. width: 800px;
  54. height: 800px;
  55. }
  56. #wrapper {
  57. height: 300.3px;
  58. overflow-y: scroll;
  59. background-color: #333;
  60. }
  61. #wrapper > div {
  62. height: 100.25px;
  63. background-color: #c33;
  64. margin: 5.333px 0;
  65. position: relative;
  66. }
  67. </style>
  68. </head>
  69. <body>
  70. <div id="wrapper">
  71. </div>
  72. </body>
  73. </rml>
  74. )";
  75. TEST_CASE("ElementBackgroundBorder.render_stats")
  76. {
  77. Context* context = TestsShell::GetContext();
  78. REQUIRE(context);
  79. ElementDocument* document = context->LoadDocumentFromMemory(document_basic_rml);
  80. REQUIRE(document);
  81. document->Show();
  82. constexpr int num_rows = 10;
  83. const String row_rml = "<div/>";
  84. const String inner_rml = GenerateRowsRml(num_rows, row_rml);
  85. Element* wrapper = document->GetElementById("wrapper");
  86. REQUIRE(wrapper);
  87. wrapper->SetInnerRML(inner_rml);
  88. context->Update();
  89. context->Render();
  90. TestsShell::RenderLoop();
  91. TestsRenderInterface* render_interface = TestsShell::GetTestsRenderInterface();
  92. if (!render_interface)
  93. return;
  94. MESSAGE(TestsShell::GetRenderStats());
  95. render_interface->Reset();
  96. for (int i = 1; i < 50; i++)
  97. {
  98. wrapper->SetScrollTop(1.3333f * float(i));
  99. context->Update();
  100. context->Render();
  101. }
  102. wrapper->SetScrollTop(FLT_MAX);
  103. context->Update();
  104. context->Render();
  105. // Ensure that we have no unnecessary compile geometry commands. The geometry for the background-border should not
  106. // change in size as long as scrolling occurs in integer increments.
  107. CHECK(render_interface->GetCounters().compile_geometry == 0);
  108. document->Close();
  109. TestsShell::ShutdownShell();
  110. }
  111. static const String document_relative_offset_rml = R"(
  112. <rml>
  113. <head>
  114. <title>Demo</title>
  115. <link type="text/rcss" href="/assets/rml.rcss" />
  116. <link type="text/rcss" href="/../Tests/Data/style.rcss" />
  117. <style>
  118. body {
  119. width: 800px;
  120. height: 800px;
  121. }
  122. #wrapper {
  123. height: 600px;
  124. background-color: #333;
  125. }
  126. #wrapper > div {
  127. height: 10.333px;
  128. background-color: #c33;
  129. position: relative;
  130. }
  131. </style>
  132. </head>
  133. <body>
  134. <div id="wrapper">
  135. </div>
  136. </body>
  137. </rml>
  138. )";
  139. TEST_CASE("ElementBackgroundBorder.background_edges_line_up_with_relative_offset")
  140. {
  141. Context* context = TestsShell::GetContext();
  142. REQUIRE(context);
  143. ElementDocument* document = context->LoadDocumentFromMemory(document_relative_offset_rml);
  144. REQUIRE(document);
  145. document->Show();
  146. constexpr int num_children = 10;
  147. const String row_rml = "<div/>";
  148. const String inner_rml = GenerateRowsRml(num_children, row_rml);
  149. Element* wrapper = document->GetElementById("wrapper");
  150. REQUIRE(wrapper);
  151. wrapper->SetInnerRML(inner_rml);
  152. context->Update();
  153. context->Render();
  154. TestsShell::RenderLoop();
  155. TestsRenderInterface* render_interface = TestsShell::GetTestsRenderInterface();
  156. if (!render_interface)
  157. return;
  158. MESSAGE(TestsShell::GetRenderStats());
  159. render_interface->Reset();
  160. for (int i = 1; i < 100; i++)
  161. {
  162. for (int child_index = 0; child_index < num_children; child_index++)
  163. {
  164. Element* child = wrapper->GetChild(child_index);
  165. child->SetProperty(PropertyId::Top, Property(1.3333f * float(i), Unit::PX));
  166. }
  167. context->Update();
  168. context->Render();
  169. for (int child_index = 0; child_index < num_children - 1; child_index++)
  170. {
  171. Element* current_child = wrapper->GetChild(child_index);
  172. Element* next_child = wrapper->GetChild(child_index + 1);
  173. Vector2f current_bottom_right = current_child->GetAbsoluteOffset(BoxArea::Border).Round() + current_child->GetRenderBox().GetFillSize();
  174. Vector2f next_top_left = next_child->GetAbsoluteOffset(BoxArea::Border).Round();
  175. CHECK(current_bottom_right.y == next_top_left.y);
  176. }
  177. }
  178. // When changing the position using fractional increments we expect the size of the backgrounds to change, resulting
  179. // in new geometry. This is done to ensure that the top and bottom of each background lines up with the one for the
  180. // next element, thereby avoiding any gaps.
  181. CHECK(render_interface->GetCounters().compile_geometry > 0);
  182. MESSAGE("Compile geometry after movement: ", render_interface->GetCounters().compile_geometry);
  183. document->Close();
  184. TestsShell::ShutdownShell();
  185. }