Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(932)

Unified Diff: Source/core/html/forms/InputType.cpp

Issue 136783006: Upgrade stepUp()/stepDown() implementation to match spec. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: applyStep(): add missing EventQueueScope Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/core/html/forms/InputType.h ('k') | Source/core/html/forms/StepRange.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/core/html/forms/InputType.cpp
diff --git a/Source/core/html/forms/InputType.cpp b/Source/core/html/forms/InputType.cpp
index 238c38bb47055497971a10feca8e49da300a8989..e56509a3b7d903afb0a840024e54d14cd1dc38b2 100644
--- a/Source/core/html/forms/InputType.cpp
+++ b/Source/core/html/forms/InputType.cpp
@@ -794,7 +794,7 @@ unsigned InputType::width() const
return 0;
}
-void InputType::applyStep(int count, AnyStepHandling anyStepHandling, TextFieldEventBehavior eventBehavior, ExceptionState& exceptionState)
+void InputType::applyStep(const Decimal& current, int count, AnyStepHandling anyStepHandling, TextFieldEventBehavior eventBehavior, ExceptionState& exceptionState)
{
StepRange stepRange(createStepRange(anyStepHandling));
if (!stepRange.hasStep()) {
@@ -802,38 +802,56 @@ void InputType::applyStep(int count, AnyStepHandling anyStepHandling, TextFieldE
return;
}
- const Decimal current = parseToNumberOrNaN(element().value());
- if (!current.isFinite()) {
- exceptionState.throwDOMException(InvalidStateError, ExceptionMessages::notAFiniteNumber(current, "form element's current value"));
- return;
- }
- Decimal newValue = current + stepRange.step() * count;
- if (!newValue.isFinite()) {
- exceptionState.throwDOMException(InvalidStateError, ExceptionMessages::notAFiniteNumber(newValue, "form element's new value"));
- return;
- }
-
- const Decimal acceptableErrorValue = stepRange.acceptableError();
- if (newValue - stepRange.minimum() < -acceptableErrorValue) {
- exceptionState.throwDOMException(InvalidStateError, "The form element's new value (" + newValue.toString() + ") would be lower than the minimum (" + stepRange.minimum().toString() + "), and snapping to the minimum would exceed the amount of acceptible error.");
- return;
- }
- if (newValue < stepRange.minimum())
- newValue = stepRange.minimum();
+ EventQueueScope scope;
+ const Decimal step = stepRange.step();
const AtomicString& stepString = element().fastGetAttribute(stepAttr);
- if (!equalIgnoringCase(stepString, "any"))
- newValue = stepRange.alignValueForStep(current, newValue);
+ if (!equalIgnoringCase(stepString, "any") && stepRange.stepMismatch(current)) {
+ // Snap-to-step / clamping steps
+ // If the current value is not matched to step value:
+ // - The value should be the larger matched value nearest to 0 if count > 0
+ // e.g. <input type=number value=3 min=-100 step=3> -> 5
+ // - The value should be the smaller matched value nearest to 0 if count < 0
+ // e.g. <input type=number value=3 min=-100 step=3> -> 2
+ //
+
+ ASSERT(!step.isZero());
+ Decimal newValue;
+ const Decimal base = stepRange.stepBase();
+ if (count < 0)
+ newValue = base + ((current - base) / step).floor() * step;
+ else if (count > 0)
+ newValue = base + ((current - base) / step).ceiling() * step;
+ else
+ newValue = current;
+
+ if (newValue < stepRange.minimum())
+ newValue = stepRange.minimum();
+ if (newValue > stepRange.maximum())
+ newValue = stepRange.maximum();
+
+ setValueAsDecimal(newValue, count == 1 || count == -1 ? DispatchChangeEvent : DispatchNoEvent, IGNORE_EXCEPTION);
+ if (count > 1) {
+ applyStep(newValue, count - 1, AnyIsDefaultStep, DispatchChangeEvent, IGNORE_EXCEPTION);
+ return;
+ }
+ if (count < -1) {
+ applyStep(newValue, count + 1, AnyIsDefaultStep, DispatchChangeEvent, IGNORE_EXCEPTION);
+ return;
+ }
+ } else {
+ Decimal newValue = current + stepRange.step() * count;
- if (newValue - stepRange.maximum() > acceptableErrorValue) {
- exceptionState.throwDOMException(InvalidStateError, "The form element's new value (" + newValue.toString() + ") would be higher than the maximum (" + stepRange.maximum().toString() + "), and snapping to the maximum would exceed the amount of acceptible error.");
- return;
- }
- if (newValue > stepRange.maximum())
- newValue = stepRange.maximum();
+ if (!equalIgnoringCase(stepString, "any"))
+ newValue = stepRange.alignValueForStep(current, newValue);
- setValueAsDecimal(newValue, eventBehavior, exceptionState);
+ if (newValue > stepRange.maximum())
+ newValue = newValue - stepRange.step();
+ else if (newValue < stepRange.minimum())
+ newValue = newValue + stepRange.step();
+ setValueAsDecimal(newValue, eventBehavior, exceptionState);
+ }
if (AXObjectCache* cache = element().document().existingAXObjectCache())
cache->postNotification(&element(), AXObjectCache::AXValueChanged, true);
}
@@ -857,14 +875,15 @@ void InputType::stepUp(int n, ExceptionState& exceptionState)
exceptionState.throwDOMException(InvalidStateError, "This form element is not steppable.");
return;
}
- applyStep(n, RejectAny, DispatchNoEvent, exceptionState);
+ const Decimal current = parseToNumber(element().value(), 0);
+ applyStep(current, n, RejectAny, DispatchNoEvent, exceptionState);
}
void InputType::stepUpFromRenderer(int n)
{
- // The differences from stepUp()/stepDown():
+ // The only difference from stepUp()/stepDown() is the extra treatment
+ // of the current value before applying the step:
//
- // Difference 1: the current value
// If the current value is not a number, including empty, the current value is assumed as 0.
// * If 0 is in-range, and matches to step value
// - The value should be the +step if n > 0
@@ -888,13 +907,6 @@ void InputType::stepUpFromRenderer(int n)
// - The value should be the maximum value if n < 0
// - Nothing should happen if n > 0
//
- // Difference 2: clamping steps
- // If the current value is not matched to step value:
- // - The value should be the larger matched value nearest to 0 if n > 0
- // e.g. <input type=number value=3 min=-100 step=3> -> 5
- // - The value should be the smaler matched value nearest to 0 if n < 0
- // e.g. <input type=number value=3 min=-100 step=3> -> 2
- //
// n is assumed as -n if step < 0.
ASSERT(isSteppable());
@@ -922,8 +934,7 @@ void InputType::stepUpFromRenderer(int n)
else
sign = 0;
- String currentStringValue = element().value();
- Decimal current = parseToNumberOrNaN(currentStringValue);
+ Decimal current = parseToNumberOrNaN(element().value());
if (!current.isFinite()) {
current = defaultValueForStepUp();
const Decimal nextDiff = step * n;
@@ -935,32 +946,9 @@ void InputType::stepUpFromRenderer(int n)
}
if ((sign > 0 && current < stepRange.minimum()) || (sign < 0 && current > stepRange.maximum())) {
setValueAsDecimal(sign > 0 ? stepRange.minimum() : stepRange.maximum(), DispatchChangeEvent, IGNORE_EXCEPTION);
- } else {
- if (stepMismatch(element().value())) {
- ASSERT(!step.isZero());
- const Decimal base = stepRange.stepBase();
- Decimal newValue;
- if (sign < 0)
- newValue = base + ((current - base) / step).floor() * step;
- else if (sign > 0)
- newValue = base + ((current - base) / step).ceiling() * step;
- else
- newValue = current;
-
- if (newValue < stepRange.minimum())
- newValue = stepRange.minimum();
- if (newValue > stepRange.maximum())
- newValue = stepRange.maximum();
-
- setValueAsDecimal(newValue, n == 1 || n == -1 ? DispatchChangeEvent : DispatchNoEvent, IGNORE_EXCEPTION);
- if (n > 1)
- applyStep(n - 1, AnyIsDefaultStep, DispatchChangeEvent, IGNORE_EXCEPTION);
- else if (n < -1)
- applyStep(n + 1, AnyIsDefaultStep, DispatchChangeEvent, IGNORE_EXCEPTION);
- } else {
- applyStep(n, AnyIsDefaultStep, DispatchChangeEvent, IGNORE_EXCEPTION);
- }
+ return;
}
+ applyStep(current, n, AnyIsDefaultStep, DispatchChangeEvent, IGNORE_EXCEPTION);
}
void InputType::countUsageIfVisible(UseCounter::Feature feature) const
« no previous file with comments | « Source/core/html/forms/InputType.h ('k') | Source/core/html/forms/StepRange.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698