Fix parsing of 'none' values in 'list-style' shorthand. (Bug 474135) r+sr=bzbarsky

This commit is contained in:
L. David Baron 2009-01-22 17:28:13 -08:00
Родитель 2c8b4e0b19
Коммит e5173ca99c
5 изменённых файлов: 83 добавлений и 108 удалений

Просмотреть файл

@ -4684,6 +4684,10 @@ CSSParserImpl::ParseChoice(nsCSSValue aValues[],
if ((found & bit) == 0) {
if (ParseSingleValueProperty(aValues[index], aPropIDs[index])) {
found |= bit;
// It's more efficient to break since it will reset |hadFound|
// to |found|. Furthermore, ParseListStyle depends on our going
// through the properties in order for each value..
break;
}
}
}
@ -5690,6 +5694,8 @@ CSSParserImpl::ParseSingleValueProperty(nsCSSValue& aValue,
nsCSSProps::kWordwrapKTable);
case eCSSProperty_z_index:
return ParseVariant(aValue, VARIANT_AHI, nsnull);
case eCSSPropertyExtra_x_none_value:
return ParseVariant(aValue, VARIANT_NONE | VARIANT_INHERIT, nsnull);
}
// explicitly do NOT have a default case to let the compiler
// help find missing properties
@ -7367,32 +7373,56 @@ CSSParserImpl::ParseFontRanges(nsCSSValue& aValue)
PRBool
CSSParserImpl::ParseListStyle()
{
const PRInt32 numProps = 3;
// 'list-style' can accept 'none' for two different subproperties,
// 'list-style-type' and 'list-style-position'. In order to accept
// 'none' as the value of either but still allow another value for
// either, we need to ensure that the first 'none' we find gets
// allocated to a dummy property instead.
static const nsCSSProperty listStyleIDs[] = {
eCSSPropertyExtra_x_none_value,
eCSSProperty_list_style_type,
eCSSProperty_list_style_position,
eCSSProperty_list_style_image
};
nsCSSValue values[numProps];
PRInt32 index;
PRInt32 found = ParseChoice(values, listStyleIDs, numProps);
if ((found < 1) || (PR_FALSE == ExpectEndProperty())) {
nsCSSValue values[NS_ARRAY_LENGTH(listStyleIDs)];
PRInt32 found =
ParseChoice(values, listStyleIDs, NS_ARRAY_LENGTH(listStyleIDs));
if (found < 1 || !ExpectEndProperty()) {
return PR_FALSE;
}
// Provide default values
if ((found & 1) == 0) {
values[0].SetIntValue(NS_STYLE_LIST_STYLE_DISC, eCSSUnit_Enumerated);
}
if ((found & 2) == 0) {
values[1].SetIntValue(NS_STYLE_LIST_STYLE_POSITION_OUTSIDE, eCSSUnit_Enumerated);
}
if ((found & 4) == 0) {
values[2].SetNoneValue();
if ((found & (1|2|8)) == (1|2|8)) {
if (values[0].GetUnit() == eCSSUnit_None) {
// We found a 'none' plus another value for both of
// 'list-style-type' and 'list-style-image'. This is a parse
// error, since the 'none' has to count for at least one of them.
return PR_FALSE;
} else {
NS_ASSERTION(found == (1|2|4|8) && values[0] == values[1] &&
values[0] == values[2] && values[0] == values[3],
"should be a special value");
}
}
for (index = 0; index < numProps; index++) {
// Provide default values
if ((found & 2) == 0) {
if (found & 1) {
values[1].SetNoneValue();
} else {
values[1].SetIntValue(NS_STYLE_LIST_STYLE_DISC, eCSSUnit_Enumerated);
}
}
if ((found & 4) == 0) {
values[2].SetIntValue(NS_STYLE_LIST_STYLE_POSITION_OUTSIDE,
eCSSUnit_Enumerated);
}
if ((found & 8) == 0) {
values[3].SetNoneValue();
}
// Start at 1 to avoid appending fake value.
for (PRUint32 index = 1; index < NS_ARRAY_LENGTH(listStyleIDs); ++index) {
AppendValue(listStyleIDs[index], values[index]);
}
return PR_TRUE;

Просмотреть файл

@ -62,7 +62,10 @@ enum nsCSSProperty {
#include "nsCSSPropList.h"
#undef CSS_PROP_SHORTHAND
eCSSProperty_COUNT
eCSSProperty_COUNT,
// Extra dummy values for nsCSSParser internal use.
eCSSPropertyExtra_x_none_value
};
// The types of values that can be in the nsCSS*/nsRuleData* structs.

Просмотреть файл

@ -1126,9 +1126,21 @@ var gCSSProperties = {
inherited: true,
type: CSS_TYPE_TRUE_SHORTHAND,
subproperties: [ "list-style-type", "list-style-position", "list-style-image" ],
initial_values: [ "outside", "disc", "none disc outside" ],
other_values: [ "inside none", "none inside", "none none inside", "none outside none", "square", 'url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==")', "none" ],
invalid_values: []
initial_values: [ "outside", "disc", "disc outside", "outside disc", "disc none", "none disc", "none disc outside", "none outside disc", "disc none outside", "disc outside none", "outside none disc", "outside disc none" ],
other_values: [ "inside none", "none inside", "none none inside", "square", "none", "none none", "outside none none", "none outside none", "none none outside", "none outside", "outside none",
'url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==")',
'none url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==")',
'url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==") none',
'url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==") outside',
'outside url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==")',
'outside none url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==")',
'outside url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==") none',
'none url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==") outside',
'none outside url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==")',
'url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==") outside none',
'url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==") none outside'
],
invalid_values: [ "outside outside", "disc disc", "unknown value", "none none none", "none disc url(404.png)", "none url(404.png) disc", "disc none url(404.png)", "disc url(404.png) none", "url(404.png) none disc", "url(404.png) disc none", "none disc outside url(404.png)" ]
},
"list-style-image": {
domProp: "listStyleImage",

Просмотреть файл

@ -35,10 +35,6 @@
/** Test for computation of values in property database **/
var gNotAccepted = {
"list-style": [ "none disc outside" ],
};
var gBadComputed = {
// The 'medium' keyword should be computing to '3px', not 'medium'.
"outline-width": [ "3px" ],
@ -75,10 +71,6 @@ var gBadComputedNoFrame = {
};
function xfail_value(property, value, is_initial, has_frame) {
if ((property in gNotAccepted) &&
gNotAccepted[property].indexOf(value) != -1)
return true;
if ((property in gBadComputed) &&
gBadComputed[property].indexOf(value) != -1)
return true;

Просмотреть файл

@ -46,10 +46,6 @@
* cserialize.
*/
var gNotAccepted = {
"list-style": [ "none disc outside" ],
};
var gSystemFont = {
"caption": true,
"icon": true,
@ -64,49 +60,6 @@ var gBadCompute = {
"-moz-box-ordinal-group": [ "-1", "-1000" ],
};
function xfail_accepted(property, value)
{
if (property in gNotAccepted &&
gNotAccepted[property].indexOf(value) != -1)
return true;
return false;
}
function xfail_accepted_split(property, subprop, value)
{
if (property in gNotAccepted &&
gNotAccepted[property].indexOf(value) != -1)
return true;
return false;
}
function xfail_idparseser(property, value)
{
if (property != "font" && xfail_accepted(property, value))
// We already failed the first test, which will make us always pass this
// one.
return false;
return false;
}
function xfail_idserparse_compute(property, value)
{
return false;
}
function xfail_idsersplitparse_compute(property, subprop, value, step1subcomp)
{
return false;
}
function xfail_idparsesplitser(property, value)
{
return false;
}
function xfail_compute(property, value)
{
if (property in gBadCompute &&
@ -116,11 +69,6 @@ function xfail_compute(property, value)
return false;
}
function xfail_split_compute(property, value)
{
return false;
}
var gElement = document.getElementById("testnode");
var gDeclaration = gElement.style;
var gComputedStyle = window.getComputedStyle(gElement, "");
@ -134,7 +82,7 @@ function test_property(property)
function test_value(value) {
gDeclaration.setProperty(property, value, "");
var idx, func;
var idx;
var step1val = gDeclaration.getPropertyValue(property);
var step1vals = [];
@ -150,15 +98,12 @@ function test_property(property)
for (idx in info.subproperties)
step1comps.push(gComputedStyle.getPropertyValue(info.subproperties[idx]));
func = xfail_accepted(property, value) ? todo_isnot : isnot;
func(step1val, "", "setting '" + value + "' on '" + property + "'");
isnot(step1val, "", "setting '" + value + "' on '" + property + "'");
if ("subproperties" in info)
for (idx in info.subproperties) {
var subprop = info.subproperties[idx];
func = xfail_accepted_split(property, subprop, value)
? todo_isnot : isnot;
func(gDeclaration.getPropertyValue(subprop), "",
"setting '" + value + "' on '" + property + "'");
isnot(gDeclaration.getPropertyValue(subprop), "",
"setting '" + value + "' on '" + property + "'");
}
// We don't care particularly about the whitespace or the placement of
@ -172,15 +117,13 @@ function test_property(property)
gDeclaration.removeProperty(property);
gDeclaration.setProperty(property, step1val, "");
func = xfail_idparseser(property, value) ? todo_is : is;
func(gDeclaration.getPropertyValue(property), step1val,
"parse+serialize should be idempotent for '" +
is(gDeclaration.getPropertyValue(property), step1val,
"parse+serialize should be idempotent for '" +
property + ": " + value + "'");
if (test_computed && info.type != CSS_TYPE_TRUE_SHORTHAND) {
func = xfail_idserparse_compute(property, value) ? todo_is : is;
func(gComputedStyle.getPropertyValue(property), step1comp,
"serialize+parse should be identity transform for '" +
property + ": " + value + "'");
is(gComputedStyle.getPropertyValue(property), step1comp,
"serialize+parse should be identity transform for '" +
property + ": " + value + "'");
}
if ("subproperties" in info &&
@ -199,24 +142,20 @@ function test_property(property)
for (idx in info.subproperties) {
var subprop = info.subproperties[idx];
if (test_computed && !("backend_only" in gCSSProperties[subprop])) {
func =
xfail_idsersplitparse_compute(property, subprop, value, step1comps[idx])
? todo_is : is;
func(gComputedStyle.getPropertyValue(subprop), step1comps[idx],
"serialize(" + subprop + ")+parse should be the identity " +
"transform for '" + property + ": " + value + "'");
is(gComputedStyle.getPropertyValue(subprop), step1comps[idx],
"serialize(" + subprop + ")+parse should be the identity " +
"transform for '" + property + ": " + value + "'");
}
}
func = xfail_idparsesplitser(property, value) ? todo_is : is;
func(gDeclaration.getPropertyValue(property), step1val,
"parse+split+serialize should be idempotent for '" +
property + ": " + value + "'");
is(gDeclaration.getPropertyValue(property), step1val,
"parse+split+serialize should be idempotent for '" +
property + ": " + value + "'");
}
if (test_computed && info.type != CSS_TYPE_TRUE_SHORTHAND) {
gDeclaration.removeProperty(property);
gDeclaration.setProperty(property, step1comp, "");
func = xfail_compute(property, value) ? todo_is : is;
var func = xfail_compute(property, value) ? todo_is : is;
func(gComputedStyle.getPropertyValue(property), step1comp,
"parse+compute+serialize should be idempotent for '" +
property + ": " + value + "'");
@ -233,14 +172,13 @@ function test_property(property)
// Now that all the subprops are set, check their values. Note that we
// need this in a separate loop, in case parts of the shorthand affect
// the computed values of other parts.
func = xfail_split_compute(property, value) ? todo_is : is;
for (idx in info.subproperties) {
var subprop = info.subproperties[idx];
if ("backend_only" in gCSSProperties[subprop])
continue;
func(gComputedStyle.getPropertyValue(subprop), step1comps[idx],
"parse+compute+serialize(" + subprop + ") should be idempotent for '" +
property + ": " + value + "'");
is(gComputedStyle.getPropertyValue(subprop), step1comps[idx],
"parse+compute+serialize(" + subprop + ") should be idempotent for '" +
property + ": " + value + "'");
}
}