Issue #1384 - Match standard for colSpan/rowSpan

HTML standardizes proper behavior of colSpan and rowSpan:

The main thing is that getting the .rowSpan and .colSpan IDL properties will now return the actual clamped value that we use.
This commit is contained in:
win7-7 2020-02-03 16:59:23 +02:00 • committed by Roy Tam
commit 51f5cb3576
6 changed files with 59 additions and 19 deletions

View file

@ -1526,6 +1526,40 @@ nsAttrValue::ParseIntWithFallback(const nsAString& aString, int32_t aDefault,
SetIntValueAndType(val, eInteger, nonStrict ? &aString : nullptr); SetIntValueAndType(val, eInteger, nonStrict ? &aString : nullptr);
} }
void
nsAttrValue::ParseClampedNonNegativeInt(const nsAString& aString,
int32_t aDefault, int32_t aMin,
int32_t aMax)
{
ResetIfSet();
nsContentUtils::ParseHTMLIntegerResultFlags result;
int32_t val = nsContentUtils::ParseHTMLInteger(aString, &result);
bool nonStrict = (result & nsContentUtils::eParseHTMLInteger_IsPercent) ||
(result & nsContentUtils::eParseHTMLInteger_NonStandard) ||
(result & nsContentUtils::eParseHTMLInteger_DidNotConsumeAllInput);
if (result & nsContentUtils::eParseHTMLInteger_ErrorOverflow) {
if (result & nsContentUtils::eParseHTMLInteger_Negative) {
val = aDefault;
} else {
val = aMax;
}
nonStrict = true;
} else if ((result & nsContentUtils::eParseHTMLInteger_Error) || val < 0) {
val = aDefault;
nonStrict = true;
} else if (val < aMin) {
val = aMin;
nonStrict = true;
} else if (val > aMax) {
val = aMax;
nonStrict = true;
}
SetIntValueAndType(val, eInteger, nonStrict ? &aString : nullptr);
}
bool bool
nsAttrValue::ParseNonNegativeIntValue(const nsAString& aString) nsAttrValue::ParseNonNegativeIntValue(const nsAString& aString)
{ {

View file

@ -362,6 +362,19 @@ public:
*/ */
bool ParseNonNegativeIntValue(const nsAString& aString); bool ParseNonNegativeIntValue(const nsAString& aString);
/**
* Parse a string value into a clamped non-negative integer.
* This method follows the rules for parsing non-negative integer from:
* https://html.spec.whatwg.org/multipage/infrastructure.html#clamped-to-the-range
*
* @param aString the string to parse
* @param aDefault value to return for negative or invalid values
* @param aMin minimum value
* @param aMax maximum value
*/
void ParseClampedNonNegativeInt(const nsAString& aString, int32_t aDefault,
int32_t aMin, int32_t aMax);
/** /**
* Parse a string value into a positive integer. * Parse a string value into a positive integer.
* This method follows the rules for parsing non-negative integer from: * This method follows the rules for parsing non-negative integer from:

View file

@ -1088,6 +1088,7 @@ nsContentUtils::ParseHTMLInteger(const nsAString& aValue,
int sign = 1; int sign = 1;
if (*iter == char16_t('-')) { if (*iter == char16_t('-')) {
sign = -1; sign = -1;
result |= eParseHTMLInteger_Negative;
++iter; ++iter;
} else if (*iter == char16_t('+')) { } else if (*iter == char16_t('+')) {
result |= eParseHTMLInteger_NonStandard; result |= eParseHTMLInteger_NonStandard;

View file

@ -445,7 +445,9 @@ public:
// Set if one or more error flags were set. // Set if one or more error flags were set.
eParseHTMLInteger_Error = 1 << 3, eParseHTMLInteger_Error = 1 << 3,
eParseHTMLInteger_ErrorNoValue = 1 << 4, eParseHTMLInteger_ErrorNoValue = 1 << 4,
eParseHTMLInteger_ErrorOverflow = 1 << 5 eParseHTMLInteger_ErrorOverflow = 1 << 5,
// Use this flag to detect the difference between overflow and underflow
eParseHTMLInteger_Negative = 1 << 6,
}; };
static int32_t ParseHTMLInteger(const nsAString& aValue, static int32_t ParseHTMLInteger(const nsAString& aValue,
ParseHTMLIntegerResultFlags *aResult); ParseHTMLIntegerResultFlags *aResult);

View file

@ -390,26 +390,16 @@ HTMLTableCellElement::ParseAttribute(int32_t aNamespaceID,
return aResult.ParseIntWithBounds(aValue, 0); return aResult.ParseIntWithBounds(aValue, 0);
} }
if (aAttribute == nsGkAtoms::colspan) { if (aAttribute == nsGkAtoms::colspan) {
bool res = aResult.ParseIntWithBounds(aValue, -1); aResult.ParseClampedNonNegativeInt(aValue, 1, 1, MAX_COLSPAN);
if (res) { return true;
int32_t val = aResult.GetIntegerValue();
// reset large colspan values as IE and opera do
if (val > MAX_COLSPAN || val <= 0) {
aResult.SetTo(1, &aValue);
}
}
return res;
} }
if (aAttribute == nsGkAtoms::rowspan) { if (aAttribute == nsGkAtoms::rowspan) {
bool res = aResult.ParseIntWithBounds(aValue, -1, MAX_ROWSPAN); aResult.ParseClampedNonNegativeInt(aValue, 1, 0, MAX_ROWSPAN);
if (res) { // quirks mode does not honor the special html 4 value of 0
int32_t val = aResult.GetIntegerValue(); if (aResult.GetIntegerValue() == 0 && InNavQuirksMode(OwnerDoc())) {
// quirks mode does not honor the special html 4 value of 0
if (val < 0 || (0 == val && InNavQuirksMode(OwnerDoc()))) {
aResult.SetTo(1, &aValue); aResult.SetTo(1, &aValue);
}
} }
return res; return true;
} }
if (aAttribute == nsGkAtoms::height) { if (aAttribute == nsGkAtoms::height) {
return aResult.ParseSpecialIntValue(aValue); return aResult.ParseSpecialIntValue(aValue);

View file

@ -37,7 +37,7 @@ public:
} }
void SetColSpan(uint32_t aColSpan, ErrorResult& aError) void SetColSpan(uint32_t aColSpan, ErrorResult& aError)
{ {
SetHTMLIntAttr(nsGkAtoms::colspan, aColSpan, aError); SetUnsignedIntAttr(nsGkAtoms::colspan, aColSpan, 1, aError);
} }
uint32_t RowSpan() const uint32_t RowSpan() const
{ {
@ -45,7 +45,7 @@ public:
} }
void SetRowSpan(uint32_t aRowSpan, ErrorResult& aError) void SetRowSpan(uint32_t aRowSpan, ErrorResult& aError)
{ {
SetHTMLIntAttr(nsGkAtoms::rowspan, aRowSpan, aError); SetUnsignedIntAttr(nsGkAtoms::rowspan, aRowSpan, 1, aError);
} }
//already_AddRefed<nsDOMTokenList> Headers() const; //already_AddRefed<nsDOMTokenList> Headers() const;
void GetHeaders(DOMString& aHeaders) void GetHeaders(DOMString& aHeaders)