<!DOCTYPE HTML> <html> <!-- https://bugzilla.mozilla.org/show_bug.cgi?id=1131371 --> <head> <meta charset="utf-8"> <title>Test for Bug 1131371</title> <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> </head> <body> <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1131371">Mozilla Bug 1131371</a> <div id="display"> <div id="content"> </div> </div> <pre id="test"> <script type="application/javascript;version=1.7"> "use strict"; /** Test for Bug 1131371 **/ /** * This test verifies that certain style changes do or don't cause reflow * and/or frame construction. We do this by checking the framesReflowed & * framesConstructed counts, before & after a style-change, and verifying * that any change to these counts is in line with our expectations. * * Each entry in gTestcases contains these member-values: * - beforeStyle (optional): initial value to use for "style" attribute. * - afterStyle: value to change the "style" attribute to. * * Testcases may also include two optional member-values to express that reflow * and/or frame construction *are* in fact expected: * - expectConstruction (optional): if set to something truthy, then we expect * frame construction to occur when afterStyle is set. Otherwise, we * expect that frame construction should *not* occur. * - expectReflow (optional): if set to something truthy, then we expect * reflow to occur when afterStyle is set. Otherwise, we expect that * reflow should *not* occur. */ const gTestcases = [ // Things that shouldn't cause reflow: // ----------------------------------- // * Adding an outline (e.g. for focus ring). { afterStyle: "outline: 1px dotted black", }, // * Changing between completely different outlines. { beforeStyle: "outline: 2px solid black", afterStyle: "outline: 6px dashed yellow", }, // * Adding a box-shadow. { afterStyle: "box-shadow: inset 3px 3px gray", }, { afterStyle: "box-shadow: 0px 0px 10px 30px blue" }, // * Changing between completely different box-shadow values, // e.g. from an upper-left shadow to a bottom-right shadow: { beforeStyle: "box-shadow: -15px -20px teal", afterStyle: "box-shadow: 30px 40px yellow", }, // * Adding a text-shadow. { afterStyle: "text-shadow: 3px 3px gray", }, { afterStyle: "text-shadow: 0px 0px 10px blue" }, // * Changing between completely different text-shadow values, // e.g. from an upper-left shadow to a bottom-right shadow: { beforeStyle: "text-shadow: -15px -20px teal", afterStyle: "text-shadow: 30px 40px yellow", }, // Things that *should* cause reflow: // ---------------------------------- // (e.g. to make sure our counts are actually measuring something) // * Changing 'height' should cause reflow, but not frame construction. { beforeStyle: "height: 10px", afterStyle: "height: 15px", expectReflow: true, }, // * Changing 'overflow' on <body> should cause reflow, // but not frame reconstruction { elem: document.body, /* beforeStyle: implicitly 'overflow:visible' */ afterStyle: "overflow: hidden", expectConstruction: false, expectReflow: true, }, { elem: document.body, /* beforeStyle: implicitly 'overflow:visible' */ afterStyle: "overflow: scroll", expectConstruction: false, expectReflow: true, }, { elem: document.body, beforeStyle: "overflow: hidden", afterStyle: "overflow: auto", expectConstruction: false, expectReflow: true, }, { elem: document.body, beforeStyle: "overflow: hidden", afterStyle: "overflow: scroll", expectConstruction: false, expectReflow: true, }, { elem: document.body, beforeStyle: "overflow: hidden", afterStyle: "overflow: visible", expectConstruction: false, expectReflow: true, }, { elem: document.body, beforeStyle: "overflow: auto", afterStyle: "overflow: hidden", expectConstruction: false, expectReflow: true, }, { elem: document.body, beforeStyle: "overflow: visible", afterStyle: "overflow: hidden", expectConstruction: false, expectReflow: true, }, // * Changing 'overflow' on <html> should cause reflow, // but not frame reconstruction { elem: document.documentElement, /* beforeStyle: implicitly 'overflow:visible' */ afterStyle: "overflow: auto", expectConstruction: false, expectReflow: true, }, { elem: document.documentElement, beforeStyle: "overflow: visible", afterStyle: "overflow: auto", expectConstruction: false, expectReflow: true, }, // * Setting 'overflow' on arbitrary node should cause reflow as well as // frame reconstruction { /* beforeStyle: implicitly 'overflow:visible' */ afterStyle: "overflow: auto", expectConstruction: true, expectReflow: true, }, { beforeStyle: "overflow: auto", afterStyle: "overflow: visible", expectConstruction: true, expectReflow: true, }, // * Changing 'display' should cause frame construction and reflow. { beforeStyle: "display: inline", afterStyle: "display: table", expectConstruction: true, expectReflow: true, }, ]; // Helper function to let us call either "is" or "isnot" & assemble // the failure message, based on the provided parameters. function checkFinalCount(aFinalCount, aExpectedCount, aExpectChange, aMsgPrefix, aCountDescription) { let compareFunc; let msg = aMsgPrefix; if (aExpectChange) { compareFunc = isnot; msg += "should cause " + aCountDescription; } else { compareFunc = is; msg += "should not cause " + aCountDescription; } compareFunc(aFinalCount, aExpectedCount, msg); } // Vars used in runOneTest that we really only have to look up once: const gUtils = SpecialPowers.getDOMWindowUtils(window); const gElem = document.getElementById("content"); function runOneTest(aTestcase) { // sanity-check that we have the one main thing we need: if (!aTestcase.afterStyle) { ok(false, "testcase is missing an 'afterStyle' to change to"); return; } // Figure out which element we'll be tweaking (defaulting to gElem) let elem = aTestcase.elem ? aTestcase.elem : gElem; // Verify that 'style' attribute is unset (avoid causing ourselves trouble): if (elem.hasAttribute("style")) { ok(false, "test element has 'style' attribute already set! We're going to stomp " + "on whatever's there when we clean up..."); } // Set the "before" style, and compose the first part of the message // to be used in our "is"/"isnot" invocations: let msgPrefix = "Changing style "; if (aTestcase.beforeStyle) { elem.setAttribute("style", aTestcase.beforeStyle); msgPrefix += "from '" + aTestcase.beforeStyle + "' "; } msgPrefix += "on " + elem.nodeName + " "; // Establish initial counts: let unusedVal = elem.offsetHeight; // flush layout let origFramesConstructed = gUtils.framesConstructed; let origFramesReflowed = gUtils.framesReflowed; // Make the change and flush: elem.setAttribute("style", aTestcase.afterStyle); unusedVal = elem.offsetHeight; // flush layout // Make our is/isnot assertions about whether things should have changed: checkFinalCount(gUtils.framesConstructed, origFramesConstructed, aTestcase.expectConstruction, msgPrefix, "frame construction"); checkFinalCount(gUtils.framesReflowed, origFramesReflowed, aTestcase.expectReflow, msgPrefix, "reflow"); // Clean up! elem.removeAttribute("style"); } gTestcases.forEach(runOneTest); </script> </pre> </body> </html>