mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 635499 (2/2) - <input type='number'> can suffer from a range overflow when @max is set. r=sicking
--HG-- extra : rebase_source : 8d5a589b3ab4018de422fb92ab436afc5a083fb7
This commit is contained in:
parent
cfbdaec5a7
commit
ccff7a0918
@ -90,6 +90,8 @@
|
||||
|
||||
#include "nsIIDNService.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
@ -811,6 +813,8 @@ nsHTMLInputElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
|
||||
UpdatePatternMismatchValidityState();
|
||||
} else if (aName == nsGkAtoms::multiple) {
|
||||
UpdateTypeMismatchValidityState();
|
||||
} else if (aName == nsGkAtoms::max) {
|
||||
UpdateRangeOverflowValidityState();
|
||||
}
|
||||
|
||||
UpdateState(aNotify);
|
||||
@ -975,6 +979,20 @@ nsHTMLInputElement::IsValueEmpty() const
|
||||
return value.IsEmpty();
|
||||
}
|
||||
|
||||
double
|
||||
nsHTMLInputElement::GetValueAsDouble() const
|
||||
{
|
||||
double doubleValue;
|
||||
nsAutoString stringValue;
|
||||
PRInt32 ec;
|
||||
|
||||
GetValueInternal(stringValue);
|
||||
doubleValue = stringValue.ToDouble(&ec);
|
||||
|
||||
return NS_FAILED(ec) ? std::numeric_limits<double>::quiet_NaN()
|
||||
: doubleValue;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLInputElement::SetValue(const nsAString& aValue)
|
||||
{
|
||||
@ -3593,6 +3611,42 @@ nsHTMLInputElement::DoesPatternApply() const
|
||||
return IsSingleLineTextControl(false);
|
||||
}
|
||||
|
||||
bool
|
||||
nsHTMLInputElement::DoesMinMaxApply() const
|
||||
{
|
||||
switch (mType)
|
||||
{
|
||||
case NS_FORM_INPUT_NUMBER:
|
||||
// TODO:
|
||||
// case NS_FORM_INPUT_RANGE:
|
||||
// All date/time types.
|
||||
return true;
|
||||
#ifdef DEBUG
|
||||
case NS_FORM_INPUT_RESET:
|
||||
case NS_FORM_INPUT_SUBMIT:
|
||||
case NS_FORM_INPUT_IMAGE:
|
||||
case NS_FORM_INPUT_BUTTON:
|
||||
case NS_FORM_INPUT_HIDDEN:
|
||||
case NS_FORM_INPUT_RADIO:
|
||||
case NS_FORM_INPUT_CHECKBOX:
|
||||
case NS_FORM_INPUT_FILE:
|
||||
case NS_FORM_INPUT_TEXT:
|
||||
case NS_FORM_INPUT_PASSWORD:
|
||||
case NS_FORM_INPUT_SEARCH:
|
||||
case NS_FORM_INPUT_TEL:
|
||||
case NS_FORM_INPUT_EMAIL:
|
||||
case NS_FORM_INPUT_URL:
|
||||
return false;
|
||||
default:
|
||||
NS_NOTYETIMPLEMENTED("Unexpected input type in DoesRequiredApply()");
|
||||
return false;
|
||||
#else // DEBUG
|
||||
default:
|
||||
return false;
|
||||
#endif // DEBUG
|
||||
}
|
||||
}
|
||||
|
||||
// nsIConstraintValidation
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -3721,6 +3775,30 @@ nsHTMLInputElement::HasPatternMismatch() const
|
||||
return !nsContentUtils::IsPatternMatching(value, pattern, doc);
|
||||
}
|
||||
|
||||
bool
|
||||
nsHTMLInputElement::IsRangeOverflow() const
|
||||
{
|
||||
nsAutoString maxStr;
|
||||
if (!DoesMinMaxApply() ||
|
||||
!GetAttr(kNameSpaceID_None, nsGkAtoms::max, maxStr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PRInt32 ec;
|
||||
double max = maxStr.ToDouble(&ec);
|
||||
if (NS_FAILED(ec)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
double value = GetValueAsDouble();
|
||||
// value can be NaN when value="".
|
||||
if (value != value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return value > max;
|
||||
}
|
||||
|
||||
void
|
||||
nsHTMLInputElement::UpdateTooLongValidityState()
|
||||
{
|
||||
@ -3799,6 +3877,12 @@ nsHTMLInputElement::UpdatePatternMismatchValidityState()
|
||||
SetValidityState(VALIDITY_STATE_PATTERN_MISMATCH, HasPatternMismatch());
|
||||
}
|
||||
|
||||
void
|
||||
nsHTMLInputElement::UpdateRangeOverflowValidityState()
|
||||
{
|
||||
SetValidityState(VALIDITY_STATE_RANGE_OVERFLOW, IsRangeOverflow());
|
||||
}
|
||||
|
||||
void
|
||||
nsHTMLInputElement::UpdateAllValidityStates(bool aNotify)
|
||||
{
|
||||
@ -3807,6 +3891,7 @@ nsHTMLInputElement::UpdateAllValidityStates(bool aNotify)
|
||||
UpdateValueMissingValidityState();
|
||||
UpdateTypeMismatchValidityState();
|
||||
UpdatePatternMismatchValidityState();
|
||||
UpdateRangeOverflowValidityState();
|
||||
|
||||
if (validBefore != IsValid()) {
|
||||
UpdateState(aNotify);
|
||||
@ -3914,6 +3999,26 @@ nsHTMLInputElement::GetValidationMessage(nsAString& aValidationMessage,
|
||||
aValidationMessage = message;
|
||||
break;
|
||||
}
|
||||
case VALIDITY_STATE_RANGE_OVERFLOW:
|
||||
{
|
||||
nsXPIDLString message;
|
||||
nsAutoString maxStr;
|
||||
GetAttr(kNameSpaceID_None, nsGkAtoms::max, maxStr);
|
||||
|
||||
// We want to show the double as parsed so we parse it and change maxStr.
|
||||
PRInt32 ec;
|
||||
double max = maxStr.ToDouble(&ec);
|
||||
NS_ASSERTION(NS_SUCCEEDED(ec), "max must be a number at this point!");
|
||||
maxStr.Truncate();
|
||||
maxStr.AppendFloat(max);
|
||||
|
||||
const PRUnichar* params[] = { maxStr.get() };
|
||||
rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
|
||||
"FormValidationRangeOverflow",
|
||||
params, message);
|
||||
aValidationMessage = message;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
rv = nsIConstraintValidation::GetValidationMessage(aValidationMessage, aType);
|
||||
}
|
||||
|
@ -216,10 +216,12 @@ public:
|
||||
bool IsValueMissing() const;
|
||||
bool HasTypeMismatch() const;
|
||||
bool HasPatternMismatch() const;
|
||||
bool IsRangeOverflow() const;
|
||||
void UpdateTooLongValidityState();
|
||||
void UpdateValueMissingValidityState();
|
||||
void UpdateTypeMismatchValidityState();
|
||||
void UpdatePatternMismatchValidityState();
|
||||
void UpdateRangeOverflowValidityState();
|
||||
void UpdateAllValidityStates(bool aNotify);
|
||||
void UpdateBarredFromConstraintValidation();
|
||||
nsresult GetValidationMessage(nsAString& aValidationMessage,
|
||||
@ -463,6 +465,11 @@ protected:
|
||||
*/
|
||||
bool DoesPatternApply() const;
|
||||
|
||||
/**
|
||||
* Returns if the min and max attributes apply for the current type.
|
||||
*/
|
||||
bool DoesMinMaxApply() const;
|
||||
|
||||
/**
|
||||
* Returns if the maxlength attribute applies for the current type.
|
||||
*/
|
||||
@ -533,6 +540,14 @@ protected:
|
||||
*/
|
||||
nsIRadioGroupContainer* GetRadioGroupContainer() const;
|
||||
|
||||
/**
|
||||
* Returns the input element's value as a double-precision float.
|
||||
* Returns NaN if the current element's value is not a floating point number.
|
||||
*
|
||||
* @return the input element's value as a double-precision float.
|
||||
*/
|
||||
double GetValueAsDouble() const;
|
||||
|
||||
nsCOMPtr<nsIControllers> mControllers;
|
||||
|
||||
/*
|
||||
|
@ -72,6 +72,8 @@ nsIConstraintValidation::GetValidationMessage(nsAString& aValidationMessage)
|
||||
GetValidationMessage(aValidationMessage, VALIDITY_STATE_TYPE_MISMATCH);
|
||||
} else if (GetValidityState(VALIDITY_STATE_PATTERN_MISMATCH)) {
|
||||
GetValidationMessage(aValidationMessage, VALIDITY_STATE_PATTERN_MISMATCH);
|
||||
} else if (GetValidityState(VALIDITY_STATE_RANGE_OVERFLOW)) {
|
||||
GetValidationMessage(aValidationMessage, VALIDITY_STATE_RANGE_OVERFLOW);
|
||||
} else {
|
||||
// TODO: The other messages have not been written
|
||||
// because related constraint validation are not implemented yet.
|
||||
|
@ -42,6 +42,7 @@ _TEST_FILES = \
|
||||
test_option_disabled.html \
|
||||
test_meter_element.html \
|
||||
test_meter_pseudo-classes.html \
|
||||
test_max_attribute.html \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_TEST_FILES)
|
||||
|
152
content/html/content/test/forms/test_max_attribute.html
Normal file
152
content/html/content/test/forms/test_max_attribute.html
Normal file
@ -0,0 +1,152 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=635499
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 635499</title>
|
||||
<script type="application/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=635499">Mozilla Bug 635499</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 635499 **/
|
||||
|
||||
var types = [
|
||||
[ 'hidden', false ],
|
||||
[ 'text', false ],
|
||||
[ 'search', false ],
|
||||
[ 'tel', false ],
|
||||
[ 'url', false ],
|
||||
[ 'email', false ],
|
||||
[ 'password', false ],
|
||||
[ 'datetime', true, true ],
|
||||
[ 'date', true, true ],
|
||||
[ 'month', true, true ],
|
||||
[ 'week', true, true ],
|
||||
[ 'time', true, true ],
|
||||
[ 'datetime-local', true, true ],
|
||||
[ 'number', true ],
|
||||
[ 'range', true, true ],
|
||||
[ 'color', false, true ],
|
||||
[ 'checkbox', false ],
|
||||
[ 'radio', false ],
|
||||
[ 'file', false ],
|
||||
[ 'submit', false ],
|
||||
[ 'image', false ],
|
||||
[ 'reset', false ],
|
||||
[ 'button', false ],
|
||||
];
|
||||
|
||||
var input = document.createElement("input");
|
||||
document.getElementById('content').appendChild(input);
|
||||
|
||||
function checkValidity(aElement, aValidity)
|
||||
{
|
||||
is(aElement.validity.valid, aValidity,
|
||||
"element validity should be " + aValidity);
|
||||
is(aElement.validity.rangeOverflow, !aValidity,
|
||||
"element overflow status should be " + !aValidity);
|
||||
is(aElement.validationMessage, aValidity
|
||||
? "" : "Please select a value that is lower than " + aElement.max + ".",
|
||||
"validation message");
|
||||
|
||||
is(aElement.mozMatchesSelector(":valid"), aElement.willValidate && aValidity,
|
||||
(aElement.willValidate && aValidity) ? ":valid should apply" : "valid shouldn't apply");
|
||||
is(aElement.mozMatchesSelector(":invalid"), aElement.willValidate && !aValidity,
|
||||
(aElement.wil && aValidity) ? ":invalid shouldn't apply" : "valid should apply");
|
||||
|
||||
// TODO: Add tests for out-of-range / in-range selectors, see bug 635554.
|
||||
}
|
||||
|
||||
for each (var data in types) {
|
||||
input.type = data[0];
|
||||
var apply = data[1];
|
||||
|
||||
if (data[2]) {
|
||||
todo_is(input.type, data[0], data[0] + " isn't implemented yet");
|
||||
continue;
|
||||
}
|
||||
|
||||
checkValidity(input, true);
|
||||
|
||||
input.max = '2';
|
||||
checkValidity(input, true);
|
||||
|
||||
if (input.type == 'url') {
|
||||
input.value = 'http://mozilla.org';
|
||||
checkValidity(input, true);
|
||||
} else if (input.type == 'email') {
|
||||
input.value = 'foo@bar.com';
|
||||
checkValidity(input, true);
|
||||
} else if (input.type == 'file') {
|
||||
// Need privileges to set a filename with .value.
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
|
||||
var dirSvc = Components.classes["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Components.interfaces.nsIProperties);
|
||||
var file = dirSvc.get("ProfD", Components.interfaces.nsIFile);
|
||||
file.append('635499_file');
|
||||
var outStream = Components.
|
||||
classes["@mozilla.org/network/file-output-stream;1"].
|
||||
createInstance(Components.interfaces.nsIFileOutputStream);
|
||||
outStream.init(file, 0x02 | 0x08 | 0x20, // write, create, truncate
|
||||
0666, 0);
|
||||
outStream.write("foo", 3);
|
||||
outStream.close();
|
||||
|
||||
input.value = file.path;
|
||||
checkValidity(input, true);
|
||||
|
||||
file.remove(false);
|
||||
} else {
|
||||
input.value = '1';
|
||||
checkValidity(input, true);
|
||||
|
||||
input.value = '2';
|
||||
checkValidity(input, true);
|
||||
|
||||
input.value = 'foo';
|
||||
checkValidity(input, true);
|
||||
|
||||
input.value = '2.1';
|
||||
checkValidity(input, !apply);
|
||||
|
||||
input.max = '5';
|
||||
checkValidity(input, true);
|
||||
|
||||
input.value = '42';
|
||||
checkValidity(input, !apply);
|
||||
}
|
||||
|
||||
input.max = '';
|
||||
checkValidity(input, true);
|
||||
|
||||
input.max = 'foo';
|
||||
checkValidity(input, true);
|
||||
|
||||
// Check that we correctly convert input.max to a double in validationMessage.
|
||||
if (input.type == 'number') {
|
||||
input.max = "4.333333333333333333333333333333333331";
|
||||
input.value = "5";
|
||||
is(input.validationMessage,
|
||||
"Please select a value that is lower than 4.33333333333333.",
|
||||
"validation message");
|
||||
}
|
||||
|
||||
// Cleaning up,
|
||||
input.removeAttribute('max');
|
||||
input.value = '';
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -40,6 +40,8 @@ FormValidationInvalidURL=Please enter a URL.
|
||||
FormValidationPatternMismatch=Please match the requested format.
|
||||
# LOCALIZATION NOTE (FormValidationPatternMismatchWithTitle): %S is the (possibly truncated) title attribute value.
|
||||
FormValidationPatternMismatchWithTitle=Please match the requested format: %S.
|
||||
# LOCALIZATION NOTE (FormValidationRangeOverflow): %S can be a number or a date.
|
||||
FormValidationRangeOverflow=Please select a value that is lower than %S.
|
||||
GetAttributeNodeWarning=Use of getAttributeNode() is deprecated. Use getAttribute() instead.
|
||||
SetAttributeNodeWarning=Use of setAttributeNode() is deprecated. Use setAttribute() instead.
|
||||
GetAttributeNodeNSWarning=Use of getAttributeNodeNS() is deprecated. Use getAttributeNS() instead.
|
||||
|
Loading…
Reference in New Issue
Block a user