Bug 816720 - Allow CSSRule.insertRule to insert non-style rules. r=bz

This commit is contained in:
Cameron McCormack 2012-12-01 15:10:45 +11:00
parent 518b0898c1
commit 5fa2f0edb8
3 changed files with 232 additions and 3 deletions

View File

@ -2142,10 +2142,25 @@ nsCSSStyleSheet::InsertRuleIntoGroup(const nsAString & aRule,
int32_t counter;
css::Rule* rule;
for (counter = 0; counter < rulecount; counter++) {
// Only rulesets are allowed in a group as of CSS2
rule = rules.ObjectAt(counter);
if (rule->GetType() != css::Rule::STYLE_RULE) {
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
switch (rule->GetType()) {
case css::Rule::STYLE_RULE:
case css::Rule::MEDIA_RULE:
case css::Rule::FONT_FACE_RULE:
case css::Rule::PAGE_RULE:
case css::Rule::KEYFRAMES_RULE:
case css::Rule::DOCUMENT_RULE:
case css::Rule::SUPPORTS_RULE:
// these types are OK to insert into a group
break;
case css::Rule::CHARSET_RULE:
case css::Rule::IMPORT_RULE:
case css::Rule::NAMESPACE_RULE:
// these aren't
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
default:
NS_NOTREACHED("unexpected rule type");
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
}
}

View File

@ -127,6 +127,7 @@ MOCHITEST_FILES = test_acid3_test46.html \
test_priority_preservation.html \
test_property_syntax_errors.html \
test_rem_unit.html \
test_rule_insertion.html \
test_rule_serialization.html \
test_rules_out_of_sheets.html \
test_selectors.html \

View File

@ -0,0 +1,213 @@
<!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>
<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;
// [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/)) {
return true;
}
return width == (aApplied ? monospaceWidth : serifWidth) ||
navigator.oscpu.match(/Android/); // bug 769194 prevents local()
// fonts working on Android
}],
["@charset 'UTF-8';",
function(aApplied, aParent, aException) {
// just test whether it threw
return aParent instanceof CSSRule ? aException : !aException;
}],
["@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;
}],
];
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");
isnot(monospaceWidth, serifWidth, "monospace and serif text have different widths");
// And that the #test-font element starts off using the "serif" font.
var initialFontTestWidth = testFont.getBoundingClientRect().width;
is(initialFontTestWidth, serifWidth);
// 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();
SpecialPowers.pushPrefEnv({ "set": [["layout.css.supports-rule.enabled", true]] }, runTest);
</script>
</body>
</html>