test_dynamic_change_causing_reflow.html 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. <!DOCTYPE HTML>
  2. <html>
  3. <!--
  4. https://bugzilla.mozilla.org/show_bug.cgi?id=1131371
  5. -->
  6. <head>
  7. <meta charset="utf-8">
  8. <title>Test for Bug 1131371</title>
  9. <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
  10. <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
  11. </head>
  12. <body>
  13. <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1131371">Mozilla Bug 1131371</a>
  14. <div id="display">
  15. <div id="content">
  16. </div>
  17. </div>
  18. <pre id="test">
  19. <script type="application/javascript;version=1.7">
  20. "use strict";
  21. /** Test for Bug 1131371 **/
  22. /**
  23. * This test verifies that certain style changes do or don't cause reflow
  24. * and/or frame construction. We do this by checking the framesReflowed &
  25. * framesConstructed counts, before & after a style-change, and verifying
  26. * that any change to these counts is in line with our expectations.
  27. *
  28. * Each entry in gTestcases contains these member-values:
  29. * - beforeStyle (optional): initial value to use for "style" attribute.
  30. * - afterStyle: value to change the "style" attribute to.
  31. *
  32. * Testcases may also include two optional member-values to express that reflow
  33. * and/or frame construction *are* in fact expected:
  34. * - expectConstruction (optional): if set to something truthy, then we expect
  35. * frame construction to occur when afterStyle is set. Otherwise, we
  36. * expect that frame construction should *not* occur.
  37. * - expectReflow (optional): if set to something truthy, then we expect
  38. * reflow to occur when afterStyle is set. Otherwise, we expect that
  39. * reflow should *not* occur.
  40. */
  41. const gTestcases = [
  42. // Things that shouldn't cause reflow:
  43. // -----------------------------------
  44. // * Adding an outline (e.g. for focus ring).
  45. {
  46. afterStyle: "outline: 1px dotted black",
  47. },
  48. // * Changing between completely different outlines.
  49. {
  50. beforeStyle: "outline: 2px solid black",
  51. afterStyle: "outline: 6px dashed yellow",
  52. },
  53. // * Adding a box-shadow.
  54. {
  55. afterStyle: "box-shadow: inset 3px 3px gray",
  56. },
  57. {
  58. afterStyle: "box-shadow: 0px 0px 10px 30px blue"
  59. },
  60. // * Changing between completely different box-shadow values,
  61. // e.g. from an upper-left shadow to a bottom-right shadow:
  62. {
  63. beforeStyle: "box-shadow: -15px -20px teal",
  64. afterStyle: "box-shadow: 30px 40px yellow",
  65. },
  66. // * Adding a text-shadow.
  67. {
  68. afterStyle: "text-shadow: 3px 3px gray",
  69. },
  70. {
  71. afterStyle: "text-shadow: 0px 0px 10px blue"
  72. },
  73. // * Changing between completely different text-shadow values,
  74. // e.g. from an upper-left shadow to a bottom-right shadow:
  75. {
  76. beforeStyle: "text-shadow: -15px -20px teal",
  77. afterStyle: "text-shadow: 30px 40px yellow",
  78. },
  79. // Things that *should* cause reflow:
  80. // ----------------------------------
  81. // (e.g. to make sure our counts are actually measuring something)
  82. // * Changing 'height' should cause reflow, but not frame construction.
  83. {
  84. beforeStyle: "height: 10px",
  85. afterStyle: "height: 15px",
  86. expectReflow: true,
  87. },
  88. // * Changing 'overflow' on <body> should cause reflow,
  89. // but not frame reconstruction
  90. {
  91. elem: document.body,
  92. /* beforeStyle: implicitly 'overflow:visible' */
  93. afterStyle: "overflow: hidden",
  94. expectConstruction: false,
  95. expectReflow: true,
  96. },
  97. {
  98. elem: document.body,
  99. /* beforeStyle: implicitly 'overflow:visible' */
  100. afterStyle: "overflow: scroll",
  101. expectConstruction: false,
  102. expectReflow: true,
  103. },
  104. {
  105. elem: document.body,
  106. beforeStyle: "overflow: hidden",
  107. afterStyle: "overflow: auto",
  108. expectConstruction: false,
  109. expectReflow: true,
  110. },
  111. {
  112. elem: document.body,
  113. beforeStyle: "overflow: hidden",
  114. afterStyle: "overflow: scroll",
  115. expectConstruction: false,
  116. expectReflow: true,
  117. },
  118. {
  119. elem: document.body,
  120. beforeStyle: "overflow: hidden",
  121. afterStyle: "overflow: visible",
  122. expectConstruction: false,
  123. expectReflow: true,
  124. },
  125. {
  126. elem: document.body,
  127. beforeStyle: "overflow: auto",
  128. afterStyle: "overflow: hidden",
  129. expectConstruction: false,
  130. expectReflow: true,
  131. },
  132. {
  133. elem: document.body,
  134. beforeStyle: "overflow: visible",
  135. afterStyle: "overflow: hidden",
  136. expectConstruction: false,
  137. expectReflow: true,
  138. },
  139. // * Changing 'overflow' on <html> should cause reflow,
  140. // but not frame reconstruction
  141. {
  142. elem: document.documentElement,
  143. /* beforeStyle: implicitly 'overflow:visible' */
  144. afterStyle: "overflow: auto",
  145. expectConstruction: false,
  146. expectReflow: true,
  147. },
  148. {
  149. elem: document.documentElement,
  150. beforeStyle: "overflow: visible",
  151. afterStyle: "overflow: auto",
  152. expectConstruction: false,
  153. expectReflow: true,
  154. },
  155. // * Setting 'overflow' on arbitrary node should cause reflow as well as
  156. // frame reconstruction
  157. {
  158. /* beforeStyle: implicitly 'overflow:visible' */
  159. afterStyle: "overflow: auto",
  160. expectConstruction: true,
  161. expectReflow: true,
  162. },
  163. {
  164. beforeStyle: "overflow: auto",
  165. afterStyle: "overflow: visible",
  166. expectConstruction: true,
  167. expectReflow: true,
  168. },
  169. // * Changing 'display' should cause frame construction and reflow.
  170. {
  171. beforeStyle: "display: inline",
  172. afterStyle: "display: table",
  173. expectConstruction: true,
  174. expectReflow: true,
  175. },
  176. ];
  177. // Helper function to let us call either "is" or "isnot" & assemble
  178. // the failure message, based on the provided parameters.
  179. function checkFinalCount(aFinalCount, aExpectedCount,
  180. aExpectChange, aMsgPrefix, aCountDescription)
  181. {
  182. let compareFunc;
  183. let msg = aMsgPrefix;
  184. if (aExpectChange) {
  185. compareFunc = isnot;
  186. msg += "should cause " + aCountDescription;
  187. } else {
  188. compareFunc = is;
  189. msg += "should not cause " + aCountDescription;
  190. }
  191. compareFunc(aFinalCount, aExpectedCount, msg);
  192. }
  193. // Vars used in runOneTest that we really only have to look up once:
  194. const gUtils = SpecialPowers.getDOMWindowUtils(window);
  195. const gElem = document.getElementById("content");
  196. function runOneTest(aTestcase)
  197. {
  198. // sanity-check that we have the one main thing we need:
  199. if (!aTestcase.afterStyle) {
  200. ok(false, "testcase is missing an 'afterStyle' to change to");
  201. return;
  202. }
  203. // Figure out which element we'll be tweaking (defaulting to gElem)
  204. let elem = aTestcase.elem ?
  205. aTestcase.elem : gElem;
  206. // Verify that 'style' attribute is unset (avoid causing ourselves trouble):
  207. if (elem.hasAttribute("style")) {
  208. ok(false,
  209. "test element has 'style' attribute already set! We're going to stomp " +
  210. "on whatever's there when we clean up...");
  211. }
  212. // Set the "before" style, and compose the first part of the message
  213. // to be used in our "is"/"isnot" invocations:
  214. let msgPrefix = "Changing style ";
  215. if (aTestcase.beforeStyle) {
  216. elem.setAttribute("style", aTestcase.beforeStyle);
  217. msgPrefix += "from '" + aTestcase.beforeStyle + "' ";
  218. }
  219. msgPrefix += "on " + elem.nodeName + " ";
  220. // Establish initial counts:
  221. let unusedVal = elem.offsetHeight; // flush layout
  222. let origFramesConstructed = gUtils.framesConstructed;
  223. let origFramesReflowed = gUtils.framesReflowed;
  224. // Make the change and flush:
  225. elem.setAttribute("style", aTestcase.afterStyle);
  226. unusedVal = elem.offsetHeight; // flush layout
  227. // Make our is/isnot assertions about whether things should have changed:
  228. checkFinalCount(gUtils.framesConstructed, origFramesConstructed,
  229. aTestcase.expectConstruction, msgPrefix,
  230. "frame construction");
  231. checkFinalCount(gUtils.framesReflowed, origFramesReflowed,
  232. aTestcase.expectReflow, msgPrefix,
  233. "reflow");
  234. // Clean up!
  235. elem.removeAttribute("style");
  236. }
  237. gTestcases.forEach(runOneTest);
  238. </script>
  239. </pre>
  240. </body>
  241. </html>