test_rule_insertion.html (9081B)
1 <!DOCTYPE HTML> 2 <html> 3 <!-- 4 https://bugzilla.mozilla.org/show_bug.cgi?id=816720 5 --> 6 <head> 7 <title>Test for Bug 816720</title> 8 <script src="/tests/SimpleTest/SimpleTest.js"></script> 9 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> 10 <style type="text/css" id="style"></style> 11 </head> 12 <body> 13 14 <pre id="test"></pre> 15 16 <p><span id=control-serif>........</span></p> 17 <p><span id=control-monospace>........</span></p> 18 <p><span id=test-font>........</span></p> 19 20 <style id=other-styles> 21 #test { font-size: 16px; animation: test 1s both } 22 #control-serif { font: 16px serif } 23 #test-font { font: 16px UnlikelyFontName, serif } 24 </style> 25 26 <p><span id=control-decimal></span></p> 27 <p><span id=control-cjk-decimal></span></p> 28 <p><span id=test-counter-style></span></p> 29 30 <style> 31 #control-decimal::before { content: counter(a, decimal); } 32 #control-cjk-decimal::before { content: counter(a, cjk-decimal); } 33 #test-counter-style::before { content: counter(a, unlikely-counter-style); } 34 </style> 35 36 <script type="application/javascript"> 37 38 // Monospace fonts available on all the platforms we're testing on. 39 // 40 // XXX Once bug 817220 is fixed we could instead use the value of 41 // font.name.monospace.x-western as the monospace font to use. 42 var MONOSPACE_FONTS = [ 43 "Courier", 44 "Courier New", 45 "Monaco", 46 "DejaVu Sans Mono", 47 "Droid Sans Mono" 48 ]; 49 50 var test = document.getElementById("test"); 51 var controlSerif = document.getElementById("control-serif"); 52 var controlMonospace = document.getElementById("control-monospace"); 53 var testFont = document.getElementById("test-font"); 54 var otherStyles = document.getElementById("other-styles"); 55 56 otherStyles.sheet.insertRule("#control-monospace { font: 16px " + 57 MONOSPACE_FONTS + ", serif }", 0); 58 59 var monospaceWidth = controlMonospace.getBoundingClientRect().width; 60 var serifWidth = controlSerif.getBoundingClientRect().width; 61 62 var controlDecimal = document.getElementById("control-decimal"); 63 var controlCJKDecimal = document.getElementById("control-cjk-decimal"); 64 var testCounterStyle = document.getElementById("test-counter-style"); 65 66 var decimalWidth = controlDecimal.getBoundingClientRect().width; 67 var cjkDecimalWidth = controlCJKDecimal.getBoundingClientRect().width; 68 69 // [at-rule type, passing condition, failing condition] 70 var outerRuleInfo = [ 71 ["@media", "all", "not all"], 72 ["@supports", "(color: green)", "(unknown: unknown)"] 73 ]; 74 75 // [rule, function to test whether the rule was successfully inserted and applied] 76 var innerRuleInfo = [ 77 ["#test { text-decoration: underline; }", 78 function(aApplied, aParent, aException) { 79 return !aException && 80 window.getComputedStyle(test).textDecorationLine == 81 (aApplied ? "underline" : "none"); 82 }], 83 ["@page { margin: 4cm; }", 84 function(aApplied, aParent, aException) { 85 // just test whether it threw 86 return !aException; 87 }], 88 ["@keyframes test { from { font-size: 100px; } to { font-size: 100px; } }", 89 function(aApplied, aParent, aException) { 90 return !aException && 91 window.getComputedStyle(test).fontSize == 92 (aApplied ? "100px" : "16px") 93 }], 94 ["@font-face { font-family: UnlikelyFontName; src: " + 95 MONOSPACE_FONTS.map(function(s) { return "local('" + s + "')" }).join(", ") + "; }", 96 function(aApplied, aParent, aException) { 97 var width = testFont.getBoundingClientRect().width; 98 if (aException) { 99 return false; 100 } 101 if (navigator.oscpu.match(/Linux/) || 102 navigator.oscpu.match(/Android/) || 103 SpecialPowers.Services.appinfo.name == "B2G") { 104 return true; 105 } 106 return Math.abs(width - (aApplied ? monospaceWidth : serifWidth)) <= 1; // bug 769194 prevents local() 107 // fonts working on Android 108 }], 109 ["@import url(nothing.css);", 110 function(aApplied, aParent, aException) { 111 // just test whether it threw 112 return aParent instanceof CSSRule ? aException : !aException; 113 }], 114 ["@namespace test url(http://example.org);", 115 function(aApplied, aParent, aException) { 116 // just test whether it threw 117 return aParent instanceof CSSRule ? aException : !aException; 118 }], 119 ["@counter-style unlikely-counter-style { system: extends cjk-decimal; }", 120 function (aApplied, aParent, aException) { 121 var width = testCounterStyle.getBoundingClientRect().width; 122 if (aException) { 123 return false; 124 } 125 return width == (aApplied ? cjkDecimalWidth : decimalWidth); 126 }], 127 ]; 128 129 function runTest() 130 { 131 // First, assert that our assumed available fonts are indeed available 132 // and have expected metrics. 133 ok(monospaceWidth > 0, "monospace text has width"); 134 ok(serifWidth > 0, "serif text has width"); 135 ok(Math.abs(monospaceWidth - serifWidth) > 1, "monospace and serif text have sufficiently different widths"); 136 137 // And that the #test-font element starts off using the "serif" font. 138 var initialFontTestWidth = testFont.getBoundingClientRect().width; 139 is(initialFontTestWidth, serifWidth); 140 141 ok(decimalWidth > 0, "decimal counter has width"); 142 ok(cjkDecimalWidth > 0, "cjk-decimal counter has width"); 143 ok(decimalWidth != cjkDecimalWidth, "decimal and cjk-decimal counter have different width") 144 145 var initialCounterStyleWidth = testCounterStyle.getBoundingClientRect().width; 146 is(initialCounterStyleWidth, decimalWidth, "initial counter style is decimal"); 147 148 // We construct a style sheet with zero, one or two levels of conditional 149 // grouping rules (taken from outerRuleInfo), with one of the inner rules 150 // at the deepest level. 151 var style = document.getElementById("style"); 152 153 // For each of the outer rule types... 154 for (var outerRule1 = 0; outerRule1 < outerRuleInfo.length; outerRule1++) { 155 // For each of { 0 = don't create an outer rule, 156 // 1 = create an outer rule with a passing condition, 157 // 2 = create an outer rule with a failing condition }... 158 for (var outerRuleCondition1 = 0; outerRuleCondition1 <= 2; outerRuleCondition1++) { 159 160 // For each of the outer rule types again... 161 for (var outerRule2 = 0; outerRule2 < outerRuleInfo.length; outerRule2++) { 162 // For each of { 0 = don't create an outer rule, 163 // 1 = create an outer rule with a passing condition, 164 // 2 = create an outer rule with a failing condition } again... 165 for (var outerRuleCondition2 = 0; outerRuleCondition2 <= 2; outerRuleCondition2++) { 166 167 // For each of the inner rule types... 168 for (var innerRule = 0; innerRule < innerRuleInfo.length; innerRule++) { 169 170 // Clear rules 171 var object = style.sheet; 172 while (object.cssRules.length) { 173 object.deleteRule(0); 174 } 175 176 // We'll record whether the inner rule should have been applied, 177 // according to whether we put passing or failing conditional 178 // grouping rules around it. 179 var applied = true; 180 181 if (outerRuleCondition1) { 182 // Create an outer conditional rule. 183 object.insertRule([outerRuleInfo[outerRule1][0], 184 outerRuleInfo[outerRule1][outerRuleCondition1], 185 "{}"].join(" "), 0); 186 object = object.cssRules[0]; 187 188 if (outerRuleCondition1 == 2) { 189 // If we used a failing condition, we don't expect the inner 190 // rule to be applied. 191 applied = false; 192 } 193 } 194 195 if (outerRuleCondition2) { 196 // Create another outer conditional rule as a child of the first 197 // outer conditional rule (or the style sheet, if we didn't create 198 // a first outer conditional rule). 199 object.insertRule([outerRuleInfo[outerRule2][0], 200 outerRuleInfo[outerRule2][outerRuleCondition2], 201 "{}"].join(" "), 0); 202 object = object.cssRules[0]; 203 204 if (outerRuleCondition2 == 2) { 205 // If we used a failing condition, we don't expect the inner 206 // rule to be applied. 207 applied = false; 208 } 209 } 210 211 var outer = object instanceof CSSRule ? object.cssText : "style sheet"; 212 var inner = innerRuleInfo[innerRule][0]; 213 214 // Insert the inner rule. 215 var exception = null; 216 try { 217 object.insertRule(inner, 0); 218 } catch (e) { 219 exception = e; 220 } 221 222 ok(innerRuleInfo[innerRule][1](applied, object, exception), 223 "<" + [outerRule1, outerRuleCondition1, outerRule2, 224 outerRuleCondition2, innerRule].join(",") + "> " + 225 "inserting " + inner + " into " + outer.replace(/ *\n */g, ' ')); 226 } 227 } 228 } 229 } 230 } 231 232 SimpleTest.finish(); 233 } 234 235 SimpleTest.waitForExplicitFinish(); 236 237 runTest(); 238 </script> 239 </body> 240 </html>