Flexbox.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  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 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/TestsShell.h"
  29. #include <RmlUi/Core/Context.h>
  30. #include <RmlUi/Core/Element.h>
  31. #include <RmlUi/Core/ElementDocument.h>
  32. #include <RmlUi/Core/Types.h>
  33. #include <doctest.h>
  34. #include <nanobench.h>
  35. using namespace ankerl;
  36. using namespace Rml;
  37. static const String rml_flexbox_basic_document = R"(
  38. <rml>
  39. <head>
  40. <title>Flex 01 - Basic flexbox (slow, content-based sizing)</title>
  41. <link type="text/rcss" href="/../Tests/Data/style.rcss"/>
  42. <style>
  43. header, article { display: block; }
  44. h1 { font-size: 1.5em; }
  45. h2 { font-size: 1.3em; }
  46. header {
  47. background-color: #9777d9;
  48. border: 5dp #666;
  49. }
  50. h1 {
  51. text-align: center;
  52. color: white;
  53. line-height: 100dp;
  54. }
  55. section {
  56. display: flex;
  57. background: #666;
  58. border: 5dp #666;
  59. }
  60. article {
  61. padding: 10dp;
  62. margin: 0 5dp;
  63. background-color: #edd3c0;
  64. }
  65. h2 {
  66. text-align: center;
  67. background-color: #eb6e14;
  68. margin: -10dp -10dp 0;
  69. padding: 10dp 0;
  70. }
  71. </style>
  72. </head>
  73. <body>
  74. </body>
  75. </rml>
  76. )";
  77. static const String rml_flexbox_basic_document_fast = R"(
  78. <rml>
  79. <head>
  80. <title>Flex 01 - Basic flexbox (fast, not content based)</title>
  81. <link type="text/rcss" href="/../Tests/Data/style.rcss"/>
  82. <style>
  83. header, article { display: block; }
  84. h1 { font-size: 1.5em; }
  85. h2 { font-size: 1.3em; }
  86. header {
  87. background-color: #9777d9;
  88. border: 5dp #666;
  89. }
  90. h1 {
  91. text-align: center;
  92. color: white;
  93. line-height: 100dp;
  94. }
  95. section {
  96. display: flex;
  97. background: #666;
  98. border: 5dp #666;
  99. height: 650px;
  100. }
  101. article {
  102. padding: 10dp;
  103. margin: 0 5dp;
  104. background-color: #edd3c0;
  105. flex: 1;
  106. box-sizing: border-box;
  107. height: 100%;
  108. }
  109. h2 {
  110. text-align: center;
  111. background-color: #eb6e14;
  112. margin: -10dp -10dp 0;
  113. padding: 10dp 0;
  114. }
  115. </style>
  116. </head>
  117. <body>
  118. </body>
  119. </rml>
  120. )";
  121. static const String rml_flexbox_basic_document_float_reference = R"(
  122. <rml>
  123. <head>
  124. <title>Flex 01 - Basic flexbox (float comparison)</title>
  125. <link type="text/rcss" href="/../Tests/Data/style.rcss"/>
  126. <style>
  127. header, article { display: block; }
  128. h1 { font-size: 1.5em; }
  129. h2 { font-size: 1.3em; }
  130. header {
  131. background-color: #9777d9;
  132. border: 5dp #666;
  133. }
  134. h1 {
  135. text-align: center;
  136. color: white;
  137. line-height: 100dp;
  138. }
  139. section {
  140. display: block;
  141. background: #666;
  142. border: 5dp #666;
  143. }
  144. article {
  145. padding: 10dp;
  146. margin: 0 5dp;
  147. background-color: #edd3c0;
  148. float: left;
  149. width: 30%;
  150. box-sizing: border-box;
  151. }
  152. h2 {
  153. text-align: center;
  154. background-color: #eb6e14;
  155. margin: -10dp -10dp 0;
  156. padding: 10dp 0;
  157. }
  158. </style>
  159. </head>
  160. <body>
  161. </body>
  162. </rml>
  163. )";
  164. static const String rml_flexbox_basic_body = R"(
  165. <header>
  166. <h1>Header</h1>
  167. </header>
  168. <section>
  169. <article>
  170. <h2>First article</h2>
  171. <p>Etiam libero lorem, lacinia non augue lobortis, tincidunt consequat justo. Sed id enim tempor, feugiat tortor id, rhoncus enim. Quisque pretium neque eu felis tincidunt fringilla. Mauris laoreet enim neque, iaculis cursus lorem mollis sed. Nulla pretium euismod nulla sed convallis. Curabitur in tempus sem. Phasellus suscipit vitae nulla nec ultricies.</p>
  172. </article>
  173. <article>
  174. <h2>Second article</h2>
  175. <p>Ut volutpat, odio et facilisis molestie, lacus elit euismod enim, et tempor lacus sapien finibus ipsum. Aliquam erat volutpat. Nullam risus turpis, hendrerit ac fermentum in, dapibus non risus.</p>
  176. </article>
  177. <article>
  178. <h2>Third article</h2>
  179. <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed aliquet commodo nisi, id cursus enim eleifend vitae. Praesent turpis lorem, commodo id tempus sit amet, faucibus et libero. Aliquam malesuada ultrices leo, ut molestie tortor posuere sit amet. Proin vitae tortor a sem consequat gravida. Maecenas sed egestas dolor.</p>
  180. <p>In gravida ligula in turpis molestie varius. Ut sed velit id tellus aliquet aliquet. Nulla et leo tellus. Ut a convallis dolor, eu rutrum enim. Nam vitae ultrices dui. Aliquam semper eros ut ultrices rutrum.</p>
  181. </article>
  182. </section>
  183. )";
  184. static const String rml_flexbox_mixed_document = R"(
  185. <rml>
  186. <head>
  187. <title>Flex 02 - Various features</title>
  188. <link type="text/rcss" href="/../Tests/Data/style.rcss"/>
  189. <style>
  190. .flex-container {
  191. display: flex;
  192. margin: 10px 20px;
  193. background-color: #333;
  194. max-height: 210px;
  195. flex-wrap: wrap-reverse;
  196. }
  197. .flex-item {
  198. width: 50px;
  199. margin: 20px;
  200. background-color: #eee;
  201. height: 50px;
  202. text-align: center;
  203. }
  204. .flex-direction-row {
  205. flex-direction: row;
  206. }
  207. .flex-direction-row-reverse {
  208. flex-direction: row-reverse;
  209. }
  210. .flex-direction-column {
  211. flex-direction: column;
  212. }
  213. .flex-direction-column-reverse {
  214. flex-direction: column-reverse;
  215. }
  216. .absolute {
  217. margin: 0;
  218. position: absolute;
  219. right: 0;
  220. bottom: 10px;
  221. }
  222. </style>
  223. </head>
  224. <body>
  225. </body>
  226. </rml>
  227. )";
  228. static const String rml_flexbox_mixed_body = R"(
  229. <div class="flex-container flex-direction-row" style="position: relative">
  230. <div class="flex-item absolute">Abs</div>
  231. <div class="flex-item" style="margin: 50px;">1</div>
  232. <div class="flex-item" style="margin-top: auto">2</div>
  233. <div class="flex-item" style="margin: auto">3</div>
  234. </div>
  235. <div class="flex-container flex-direction-row-reverse" style="height: 200px; justify-content: space-around;">
  236. <div class="flex-item">1</div>
  237. <div class="flex-item" style="margin-bottom: auto;">2</div>
  238. <div class="flex-item" style="margin-right: 40px;">3</div>
  239. </div>
  240. <div class="flex-container flex-direction-column">
  241. <div class="flex-item" id="test" style="margin-right: auto">1</div>
  242. <div class="flex-item">2</div>
  243. <div class="flex-item">3</div>
  244. </div>
  245. <div class="flex-container flex-direction-column-reverse">
  246. <div class="flex-item">1</div>
  247. <div class="flex-item">2 LONG_OVERFLOWING_WORD</div>
  248. <div class="flex-item">3</div>
  249. </div>
  250. )";
  251. static const String rml_flexbox_scroll_document = R"(
  252. <rml>
  253. <head>
  254. <title>Flex 03 - Scrolling container</title>
  255. <link type="text/rcss" href="/../Tests/Data/style.rcss"/>
  256. <style>
  257. .flex {
  258. display: flex;
  259. background-color: #555;
  260. margin: 5dp 20dp 15dp;
  261. border: 2dp #333;
  262. justify-content: space-between;
  263. color: #d44fff;
  264. }
  265. .auto {
  266. overflow: auto;
  267. }
  268. .scroll {
  269. overflow: scroll;
  270. }
  271. .flex div {
  272. flex: 0 1 auto;
  273. width: 50dp;
  274. height: 50dp;
  275. margin: 20dp;
  276. background-color: #eee;
  277. line-height: 50dp;
  278. text-align: center;
  279. }
  280. .flex div.tall {
  281. height: 80dp;
  282. width: 15dp;
  283. margin: 0;
  284. border: 2dp #d44fff;
  285. }
  286. </style>
  287. </head>
  288. <body>
  289. </body>
  290. </rml>
  291. )";
  292. static const String rml_flexbox_scroll_body = R"(
  293. overflow: scroll
  294. <div class="flex scroll" id="scroll">
  295. <div>Hello<div class="tall"/></div>
  296. <div>big world!</div>
  297. <div>LOOOOOOOOOOOOOOOOOOOOONG</div>
  298. </div>
  299. overflow: auto
  300. <div class="flex auto" id="auto">
  301. <div>Hello<div class="tall"/></div>
  302. <div>big world!</div>
  303. <div>LOOOOOOOOOOOOOOOOOOOOONG</div>
  304. </div>
  305. overflow: auto - only vertical overflow
  306. <div class="flex auto" id="vertical">
  307. <div>Hello<div class="tall"/></div>
  308. <div>big world!</div>
  309. <div>LONG</div>
  310. </div>
  311. overflow: auto - only horizontal overflow
  312. <div class="flex auto" id="horizontal">
  313. <div>Hello</div>
  314. <div>big</div>
  315. <div>LOOOOOOOOOOOOOOOOOOOOONG</div>
  316. </div>
  317. overflow: visible
  318. <div class="flex" id="visible">
  319. <div>Hello<div class="tall"/></div>
  320. <div>big world!</div>
  321. <div>LOOOOOOOOOOOOOOOOOOOOONG</div>
  322. </div>
  323. )";
  324. TEST_CASE("flexbox")
  325. {
  326. Context* context = TestsShell::GetContext();
  327. REQUIRE(context);
  328. {
  329. nanobench::Bench bench;
  330. bench.title("Flexbox basic layout");
  331. bench.relative(true);
  332. // Construct the flexbox layout document.
  333. ElementDocument* document = context->LoadDocumentFromMemory(rml_flexbox_basic_document);
  334. REQUIRE(document);
  335. document->Show();
  336. document->SetInnerRML(rml_flexbox_basic_body);
  337. context->Update();
  338. context->Render();
  339. TestsShell::RenderLoop();
  340. // Compare to an almost equivalent fast flexbox layout where we try to eliminate any content-based sizing. Uses the same body rml.
  341. ElementDocument* document_fast = context->LoadDocumentFromMemory(rml_flexbox_basic_document_fast);
  342. REQUIRE(document_fast);
  343. document_fast->Show();
  344. document_fast->SetInnerRML(rml_flexbox_basic_body);
  345. context->Update();
  346. context->Render();
  347. TestsShell::RenderLoop();
  348. // Finally, add a reference document based on layout with float boxes instead of flexbox. Uses the same body rml.
  349. ElementDocument* document_float_reference = context->LoadDocumentFromMemory(rml_flexbox_basic_document_float_reference);
  350. REQUIRE(document_float_reference);
  351. document_float_reference->Show();
  352. document_float_reference->SetInnerRML(rml_flexbox_basic_body);
  353. context->Update();
  354. context->Render();
  355. TestsShell::RenderLoop();
  356. bench.run("Update (unmodified)", [&] { context->Update(); });
  357. bench.run("Render", [&] { context->Render(); });
  358. bench.run("SetInnerRML", [&] { document->SetInnerRML(rml_flexbox_scroll_body); });
  359. bench.run("SetInnerRML + Update (float reference)", [&] {
  360. document_float_reference->SetInnerRML(rml_flexbox_basic_body);
  361. context->Update();
  362. });
  363. bench.run("SetInnerRML + Update (fast version)", [&] {
  364. document_fast->SetInnerRML(rml_flexbox_basic_body);
  365. context->Update();
  366. });
  367. bench.run("SetInnerRML + Update", [&] {
  368. document->SetInnerRML(rml_flexbox_basic_body);
  369. context->Update();
  370. });
  371. bench.run("SetInnerRML + Update + Render (float reference)", [&] {
  372. document_float_reference->SetInnerRML(rml_flexbox_basic_body);
  373. context->Update();
  374. context->Render();
  375. });
  376. bench.run("SetInnerRML + Update + Render (fast version)", [&] {
  377. document_fast->SetInnerRML(rml_flexbox_basic_body);
  378. context->Update();
  379. context->Render();
  380. });
  381. bench.run("SetInnerRML + Update + Render", [&] {
  382. document->SetInnerRML(rml_flexbox_basic_body);
  383. context->Update();
  384. context->Render();
  385. });
  386. document->Close();
  387. document_fast->Close();
  388. document_float_reference->Close();
  389. }
  390. {
  391. nanobench::Bench bench;
  392. bench.title("Flexbox mixed");
  393. bench.relative(true);
  394. ElementDocument* document = context->LoadDocumentFromMemory(rml_flexbox_mixed_document);
  395. REQUIRE(document);
  396. document->Show();
  397. document->SetInnerRML(rml_flexbox_mixed_body);
  398. context->Update();
  399. context->Render();
  400. TestsShell::RenderLoop();
  401. bench.run("Update (unmodified)", [&] { context->Update(); });
  402. bench.run("Render", [&] { context->Render(); });
  403. bench.run("SetInnerRML", [&] { document->SetInnerRML(rml_flexbox_scroll_body); });
  404. bench.run("SetInnerRML + Update", [&] {
  405. document->SetInnerRML(rml_flexbox_mixed_body);
  406. context->Update();
  407. });
  408. bench.run("SetInnerRML + Update + Render", [&] {
  409. document->SetInnerRML(rml_flexbox_mixed_body);
  410. context->Update();
  411. context->Render();
  412. });
  413. document->Close();
  414. }
  415. {
  416. nanobench::Bench bench;
  417. bench.title("Flexbox scroll");
  418. bench.relative(true);
  419. ElementDocument* document = context->LoadDocumentFromMemory(rml_flexbox_scroll_document);
  420. REQUIRE(document);
  421. document->Show();
  422. document->SetInnerRML(rml_flexbox_scroll_body);
  423. context->Update();
  424. context->Render();
  425. TestsShell::RenderLoop();
  426. bench.run("Update (unmodified)", [&] { context->Update(); });
  427. bench.run("Render", [&] { context->Render(); });
  428. bench.run("SetInnerRML", [&] { document->SetInnerRML(rml_flexbox_scroll_body); });
  429. bench.run("SetInnerRML + Update", [&] {
  430. document->SetInnerRML(rml_flexbox_scroll_body);
  431. context->Update();
  432. });
  433. bench.run("SetInnerRML + Update + Render", [&] {
  434. document->SetInnerRML(rml_flexbox_scroll_body);
  435. context->Update();
  436. context->Render();
  437. });
  438. document->Close();
  439. }
  440. }