test_value_computation.html (10069B)
1 <!DOCTYPE HTML> 2 <html> 3 <!-- 4 --> 5 <head> 6 <title>Test for computation of values in property database</title> 7 <script src="/tests/SimpleTest/SimpleTest.js"></script> 8 <script type="text/javascript" src="property_database.js"></script> 9 <style type="text/css" id="stylesheet"></style> 10 <style type="text/css"> 11 /* For 'width', 'height', etc., need a constant size container. */ 12 #display { width: 500px; height: 200px } 13 </style> 14 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> 15 <script type="text/javascript"> 16 SimpleTest.waitForExplicitFinish(); 17 SimpleTest.requestLongerTimeout(2); 18 19 var load_count = 0; 20 function load_done() { 21 if (++load_count == 3) 22 run_tests(); 23 } 24 </script> 25 </head> 26 <body> 27 <iframe id="unstyledn" src="unstyled.xml" height="10" width="10" onload="load_done()"></iframe> 28 <iframe id="unstyledf" src="unstyled-frame.xml" height="10" width="10" onload="load_done()"></iframe> 29 <p id="display"><span><span id="elementf"></span></span></p> 30 <div id="content" style="display: none"> 31 32 <div><span id="elementn"></span></div> 33 34 35 </div> 36 <pre id="test"> 37 <script class="testbody" type="text/javascript"> 38 39 /** Test for computation of values in property database */ 40 41 var gBadComputedNoFrame = { 42 // These are probably bogus tests... 43 "-moz-margin-end": [ "0%", "calc(0% + 0px)" ], 44 "-moz-margin-start": [ "0%", "calc(0% + 0px)" ], 45 "-moz-padding-end": [ "0%", "calc(0% + 0px)", "calc(-1%)" ], 46 "-moz-padding-start": [ "0%", "calc(0% + 0px)", "calc(-1%)" ], 47 "margin": [ "0% 0px 0em 0pt" ], 48 "margin-block-end": [ "0%", "calc(0% + 0px)" ], 49 "margin-block-start": [ "0%", "calc(0% + 0px)" ], 50 "margin-bottom": [ "0%", "calc(0% + 0px)" ], 51 "margin-inline-end": [ "0%", "calc(0% + 0px)" ], 52 "margin-inline-start": [ "0%", "calc(0% + 0px)" ], 53 "margin-left": [ "0%", "calc(0% + 0px)" ], 54 "margin-right": [ "0%", "calc(0% + 0px)" ], 55 "margin-top": [ "0%", "calc(0% + 0px)" ], 56 "padding": [ "0% 0px 0em 0pt", "calc(0px) calc(0em) calc(-2px) calc(-1%)" ], 57 "padding-block-end": [ "0%", "calc(0% + 0px)", "calc(-1%)" ], 58 "padding-block-start": [ "0%", "calc(0% + 0px)", "calc(-1%)" ], 59 "padding-bottom": [ "0%", "calc(0% + 0px)", "calc(-1%)" ], 60 "padding-inline-end": [ "0%", "calc(0% + 0px)", "calc(-1%)" ], 61 "padding-inline-start": [ "0%", "calc(0% + 0px)", "calc(-1%)" ], 62 "padding-left": [ "0%", "calc(0% + 0px)", "calc(-1%)" ], 63 "padding-right": [ "0%", "calc(0% + 0px)", "calc(-1%)" ], 64 "padding-top": [ "0%", "calc(0% + 0px)", "calc(-1%)" ], 65 }; 66 67 function xfail_value(property, value, is_initial, has_frame) { 68 if (!has_frame && (property in gBadComputedNoFrame) && 69 gBadComputedNoFrame[property].includes(value)) 70 return true; 71 72 return false; 73 } 74 75 var gSwapInitialWhenHaveFrame = { 76 // For the inline axis ('width' by default): when there's a frame, 77 // 'stretch' and its prefixed aliases work out to the same as 'auto', 78 // given the prerequisites of only 'display: block'. 79 "width": [ "-moz-available", "-webkit-fill-available", "stretch" ], 80 81 // For the block axis ('height' by default): when there's a frame, these 82 // keywords work out to the same as the initial value, i.e. `auto`, given 83 // the prerequisites of only 'display: block'. (Notably, 'stretch' and 84 // its '-webkit-fill-available' alias *do not behave like auto* in the 85 // block axis, so they're not listed among the keywords here.) 86 "height": [ "-moz-max-content", "-moz-min-content", "-moz-fit-content", 87 "-moz-available", // TODO(dholbert): remove in bug 527285. 88 "max-content", "min-content", "fit-content", 89 "fit-content(100px)", "fit-content(10%)", 90 "fit-content(calc(3*25px + 50%))" ], 91 }; 92 // Use the same lists for logical versions of width/height properties: 93 gSwapInitialWhenHaveFrame["inline-size"] = gSwapInitialWhenHaveFrame.width; 94 gSwapInitialWhenHaveFrame["block-size"] = gSwapInitialWhenHaveFrame.height; 95 96 function swap_when_frame(property, value) { 97 return (property in gSwapInitialWhenHaveFrame) && 98 gSwapInitialWhenHaveFrame[property].includes(value); 99 } 100 101 var gDisplayTree = document.getElementById("display"); 102 var gElementN = document.getElementById("elementn"); 103 var gElementF = document.getElementById("elementf"); 104 var gStyleSheet = document.getElementById("stylesheet").sheet; 105 var gRule1 = gStyleSheet.cssRules[gStyleSheet.insertRule("#elementn, #elementf {}", gStyleSheet.cssRules.length)]; 106 var gRule2 = gStyleSheet.cssRules[gStyleSheet.insertRule("#elementn, #elementf {}", gStyleSheet.cssRules.length)]; 107 108 var gInitialValuesN; 109 var gInitialValuesF; 110 var gInitialPrereqsRuleN; 111 var gInitialPrereqsRuleF; 112 113 function setup_initial_values(id, ivalprop, prereqprop) { 114 var iframe = document.getElementById(id); 115 window[ivalprop] = iframe.contentWindow.getComputedStyle( 116 iframe.contentDocument.documentElement.firstChild); 117 var sheet = iframe.contentDocument.styleSheets[0]; 118 // For 'width', 'height', etc., need a constant size container. 119 sheet.insertRule(":root { height: 200px; width: 500px }", sheet.cssRules.length); 120 121 window[prereqprop] = sheet.cssRules[sheet.insertRule(":root > * {}", sheet.cssRules.length)]; 122 } 123 124 function test_value(property, val, is_initial) 125 { 126 var info = gCSSProperties[property]; 127 128 if ("prerequisites" in info) { 129 var prereqs = info.prerequisites; 130 for (var prereq in prereqs) { 131 gRule1.style.setProperty(prereq, prereqs[prereq], ""); 132 gInitialPrereqsRuleN.style.setProperty(prereq, prereqs[prereq], ""); 133 gInitialPrereqsRuleF.style.setProperty(prereq, prereqs[prereq], ""); 134 } 135 } 136 if (info.inherited && is_initial) { 137 gElementN.parentNode.style.setProperty(property, info.other_values[0], ""); 138 gElementF.parentNode.style.setProperty(property, info.other_values[0], ""); 139 } 140 141 var initial_computed_n = get_computed_value(gInitialValuesN, property); 142 var initial_computed_f = get_computed_value(gInitialValuesF, property); 143 if (is_initial) { 144 gRule1.style.setProperty(property, info.other_values[0], ""); 145 var other_computed_n = get_computed_value(getComputedStyle(gElementN, ""), property); 146 var other_computed_f = get_computed_value(getComputedStyle(gElementF, ""), property); 147 isnot(other_computed_n, initial_computed_n, 148 "should be testing with values that compute to different things " + 149 "for '" + property + "'"); 150 isnot(other_computed_f, initial_computed_f, 151 "should be testing with values that compute to different things " + 152 "for '" + property + "'"); 153 } 154 // It used to be important for values that are supposed to compute to the 155 // initial value (given the design of the old rule tree, nsRuleNode) that 156 // we're modifying the most specific rule that matches the element, and 157 // that we've already requested style while that rule was empty. This 158 // means we'd have a cached aStartStruct from the parent in the rule 159 // tree (caching the "other" value), so we'd make sure we don't get the 160 // initial value from the luck of default-initialization. This means 161 // that it would've been important that we set the prereqs on 162 // gRule1.style rather than on gElement.style. 163 // 164 // However, the rule tree no longer stores cached structs, and we only 165 // temporarily cache reset structs during a single restyle. So the 166 // particular failure mode this was designed to test for isn't as 167 // likely to eventuate. 168 gRule2.style.setProperty(property, val, ""); 169 var val_computed_n = get_computed_value(getComputedStyle(gElementN, ""), property); 170 var val_computed_f = get_computed_value(getComputedStyle(gElementF, ""), property); 171 isnot(val_computed_n, "", 172 "should not get empty value for '" + property + ":" + val + "'"); 173 isnot(val_computed_f, "", 174 "should not get empty value for '" + property + ":" + val + "'"); 175 if (is_initial) { 176 (xfail_value(property, val, is_initial, false) ? todo_is : is)( 177 val_computed_n, initial_computed_n, 178 "should get initial value for '" + property + ":" + val + "'"); 179 (xfail_value(property, val, is_initial, true) ? todo_is : is)( 180 val_computed_f, initial_computed_f, 181 "should get initial value for '" + property + ":" + val + "'"); 182 } else { 183 (xfail_value(property, val, is_initial, false) ? todo_isnot : isnot)( 184 val_computed_n, initial_computed_n, 185 "should not get initial value for '" + property + ":" + val + "' on elementn."); 186 var swap = swap_when_frame(property, val); 187 (xfail_value(property, val, is_initial, true) ? todo_isnot : (swap ? is : isnot))( 188 val_computed_f, initial_computed_f, 189 "should " + (swap ? "" : "not ") + 190 "get initial value for '" + property + ":" + val + "' on elementf."); 191 } 192 if (is_initial) 193 gRule1.style.removeProperty(property); 194 gRule2.style.removeProperty(property); 195 196 if ("prerequisites" in info) { 197 var prereqs = info.prerequisites; 198 for (var prereq in prereqs) { 199 gRule1.style.removeProperty(prereq); 200 gInitialPrereqsRuleN.style.removeProperty(prereq); 201 gInitialPrereqsRuleF.style.removeProperty(prereq); 202 } 203 } 204 if (info.inherited && is_initial) { 205 gElementN.parentNode.style.removeProperty(property); 206 gElementF.parentNode.style.removeProperty(property); 207 } 208 } 209 210 function test_property(prop) { 211 var info = gCSSProperties[prop]; 212 for (var idx in info.initial_values) 213 test_value(prop, info.initial_values[idx], true); 214 for (var idx in info.other_values) 215 test_value(prop, info.other_values[idx], false); 216 } 217 218 function run_tests() { 219 setup_initial_values("unstyledn", "gInitialValuesN", "gInitialPrereqsRuleN"); 220 setup_initial_values("unstyledf", "gInitialValuesF", "gInitialPrereqsRuleF"); 221 var props = []; 222 for (var prop in gCSSProperties) 223 props.push(prop); 224 props = props.reverse(); 225 function do_one() { 226 if (props.length == 0) { 227 SimpleTest.finish(); 228 return; 229 } 230 test_property(props.pop()); 231 SimpleTest.executeSoon(do_one); 232 } 233 SimpleTest.executeSoon(do_one); 234 } 235 236 load_done(); 237 238 </script> 239 </pre> 240 </body> 241 </html>