<!DOCTYPE HTML> <html> <!-- https://bugzilla.mozilla.org/show_bug.cgi?id=816720 --> <head> <title>Test for Bug 816720</title> <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> <style type="text/css" id="style"></style> </head> <body> <pre id="test"></pre> <p><span id=control-serif>........</span></p> <p><span id=control-monospace>........</span></p> <p><span id=test-font>........</span></p> <style id=other-styles> #test { font-size: 16px; animation: test 1s both } #control-serif { font: 16px serif } #test-font { font: 16px UnlikelyFontName, serif } </style> <p><span id=control-decimal></span></p> <p><span id=control-cjk-decimal></span></p> <p><span id=test-counter-style></span></p> <style> #control-decimal::before { content: counter(a, decimal); } #control-cjk-decimal::before { content: counter(a, cjk-decimal); } #test-counter-style::before { content: counter(a, unlikely-counter-style); } </style> <script type="application/javascript"> // Monospace fonts available on all the platforms we're testing on. // // XXX Once bug 817220 is fixed we could instead use the value of // font.name.monospace.x-western as the monospace font to use. var MONOSPACE_FONTS = [ "Courier", "Courier New", "Monaco", "DejaVu Sans Mono", "Droid Sans Mono" ]; var test = document.getElementById("test"); var controlSerif = document.getElementById("control-serif"); var controlMonospace = document.getElementById("control-monospace"); var testFont = document.getElementById("test-font"); var otherStyles = document.getElementById("other-styles"); otherStyles.sheet.insertRule("#control-monospace { font: 16px " + MONOSPACE_FONTS + ", serif }", 0); var monospaceWidth = controlMonospace.getBoundingClientRect().width; var serifWidth = controlSerif.getBoundingClientRect().width; var controlDecimal = document.getElementById("control-decimal"); var controlCJKDecimal = document.getElementById("control-cjk-decimal"); var testCounterStyle = document.getElementById("test-counter-style"); var decimalWidth = controlDecimal.getBoundingClientRect().width; var cjkDecimalWidth = controlCJKDecimal.getBoundingClientRect().width; // [at-rule type, passing condition, failing condition] var outerRuleInfo = [ ["@media", "all", "not all"], ["@-moz-document", "url-prefix('')", "url-prefix('zzz')"], ["@supports", "(color: green)", "(unknown: unknown)"] ]; // [rule, function to test whether the rule was successfully inserted and applied] var innerRuleInfo = [ ["#test { text-decoration: underline; }", function(aApplied, aParent, aException) { return !aException && window.getComputedStyle(test, "").textDecoration == (aApplied ? "underline" : "none"); }], ["@page { margin: 4cm; }", function(aApplied, aParent, aException) { // just test whether it threw return !aException; }], ["@keyframes test { from { font-size: 100px; } to { font-size: 100px; } }", function(aApplied, aParent, aException) { return !aException && window.getComputedStyle(test, "").fontSize == (aApplied ? "100px" : "16px") }], ["@font-face { font-family: UnlikelyFontName; src: " + MONOSPACE_FONTS.map(function(s) { return "local('" + s + "')" }).join(", ") + "; }", function(aApplied, aParent, aException) { var width = testFont.getBoundingClientRect().width; if (aException) { return false; } if (navigator.oscpu.match(/Linux/) || navigator.oscpu.match(/Android/) || SpecialPowers.Services.appinfo.name == "B2G") { return true; } return Math.abs(width - (aApplied ? monospaceWidth : serifWidth)) <= 1; // bug 769194 prevents local() // fonts working on Android }], ["@import url(nothing.css);", function(aApplied, aParent, aException) { // just test whether it threw return aParent instanceof CSSRule ? aException : !aException; }], ["@namespace test url(http://example.org);", function(aApplied, aParent, aException) { // just test whether it threw return aParent instanceof CSSRule ? aException : !aException; }], ["@counter-style unlikely-counter-style { system: extends cjk-decimal; }", function (aApplied, aParent, aException) { var width = testCounterStyle.getBoundingClientRect().width; if (aException) { return false; } return width == (aApplied ? cjkDecimalWidth : decimalWidth); }], ]; function runTest() { // First, assert that our assumed available fonts are indeed available // and have expected metrics. ok(monospaceWidth > 0, "monospace text has width"); ok(serifWidth > 0, "serif text has width"); ok(Math.abs(monospaceWidth - serifWidth) > 1, "monospace and serif text have sufficiently different widths"); // And that the #test-font element starts off using the "serif" font. var initialFontTestWidth = testFont.getBoundingClientRect().width; is(initialFontTestWidth, serifWidth); ok(decimalWidth > 0, "decimal counter has width"); ok(cjkDecimalWidth > 0, "cjk-decimal counter has width"); ok(decimalWidth != cjkDecimalWidth, "decimal and cjk-decimal counter have different width") var initialCounterStyleWidth = testCounterStyle.getBoundingClientRect().width; is(initialCounterStyleWidth, decimalWidth); // We construct a style sheet with zero, one or two levels of conditional // grouping rules (taken from outerRuleInfo), with one of the inner rules // at the deepest level. var style = document.getElementById("style"); // For each of the outer rule types... for (var outerRule1 = 0; outerRule1 < outerRuleInfo.length; outerRule1++) { // For each of { 0 = don't create an outer rule, // 1 = create an outer rule with a passing condition, // 2 = create an outer rule with a failing condition }... for (var outerRuleCondition1 = 0; outerRuleCondition1 <= 2; outerRuleCondition1++) { // For each of the outer rule types again... for (var outerRule2 = 0; outerRule2 < outerRuleInfo.length; outerRule2++) { // For each of { 0 = don't create an outer rule, // 1 = create an outer rule with a passing condition, // 2 = create an outer rule with a failing condition } again... for (var outerRuleCondition2 = 0; outerRuleCondition2 <= 2; outerRuleCondition2++) { // For each of the inner rule types... for (var innerRule = 0; innerRule < innerRuleInfo.length; innerRule++) { // Clear rules var object = style.sheet; while (object.cssRules.length) { object.deleteRule(0); } // We'll record whether the inner rule should have been applied, // according to whether we put passing or failing conditional // grouping rules around it. var applied = true; if (outerRuleCondition1) { // Create an outer conditional rule. object.insertRule([outerRuleInfo[outerRule1][0], outerRuleInfo[outerRule1][outerRuleCondition1], "{}"].join(" "), 0); object = object.cssRules[0]; if (outerRuleCondition1 == 2) { // If we used a failing condition, we don't expect the inner // rule to be applied. applied = false; } } if (outerRuleCondition2) { // Create another outer conditional rule as a child of the first // outer conditional rule (or the style sheet, if we didn't create // a first outer conditional rule). object.insertRule([outerRuleInfo[outerRule2][0], outerRuleInfo[outerRule2][outerRuleCondition2], "{}"].join(" "), 0); object = object.cssRules[0]; if (outerRuleCondition2 == 2) { // If we used a failing condition, we don't expect the inner // rule to be applied. applied = false; } } var outer = object instanceof CSSRule ? object.cssText : "style sheet"; var inner = innerRuleInfo[innerRule][0]; // Insert the inner rule. var exception = null; try { object.insertRule(inner, 0); } catch (e) { exception = e; } ok(innerRuleInfo[innerRule][1](applied, object, exception), "<" + [outerRule1, outerRuleCondition1, outerRule2, outerRuleCondition2, innerRule].join(",") + "> " + "inserting " + inner + " into " + outer.replace(/ *\n */g, ' ')); } } } } } SimpleTest.finish(); } SimpleTest.waitForExplicitFinish(); runTest(); </script> </body> </html>