[SCM] WebKit Debian packaging branch, webkit-1.2, updated. upstream/1.1.90-6072-g9a69373

tkent at chromium.org tkent at chromium.org
Thu Apr 8 00:25:46 UTC 2010


The following commit has been merged in the webkit-1.2 branch:
commit a65e5433a20878e5bd15bcaaae17f6d39f0b684c
Author: tkent at chromium.org <tkent at chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Tue Dec 8 02:26:53 2009 +0000

    2009-12-07  Kent Tamura  <tkent at chromium.org>
    
            Reviewed by Darin Adler.
    
            Add tests for HTMLInputElement::stepUp() and stepDown().
            https://bugs.webkit.org/show_bug.cgi?id=27451
    
            * fast/forms/input-step-number-expected.txt: Added.
            * fast/forms/input-step-number.html: Added.
            * fast/forms/input-step-range-expected.txt: Added.
            * fast/forms/input-step-range.html: Added.
            * fast/forms/input-step-unsupported-expected.txt: Added.
            * fast/forms/input-step-unsupported.html: Added.
            * fast/forms/script-tests/input-step-number.js: Added.
            * fast/forms/script-tests/input-step-range.js: Added.
            * fast/forms/script-tests/input-step-unsupported.js: Added.
    
    2009-12-07  Kent Tamura  <tkent at chromium.org>
    
            Reviewed by Darin Adler.
    
            Add support for HTMLInputElement::stepUp() and stepDown() for
            type=number and type=range.
            https://bugs.webkit.org/show_bug.cgi?id=27451
    
            Our implementation of stepUp() and stepDown() rounds the resultant
            value to conform to the step value.
            Change the number-string conversion method for RenderSlider to be
            consistent with type=number.
    
            Tests: fast/forms/input-step-number.html
                   fast/forms/input-step-range.html
                   fast/forms/input-step-unsupported.html
    
            * html/HTMLInputElement.cpp:
            (WebCore::HTMLInputElement::rangeUnderflow): Unify the code for NUMBER and RANGE.
            (WebCore::HTMLInputElement::rangeOverflow): Unify the code for NUMBER and RANGE.
            (WebCore::HTMLInputElement::minimum): Renamed from rangeMinimum(), and support for NUMBER.
            (WebCore::HTMLInputElement::maximum): Renamed from rangeMaximum(), and support for NUMBER.
            (WebCore::HTMLInputElement::stepBase):
            (WebCore::HTMLInputElement::stepMismatch): Use stepBase().
            (WebCore::HTMLInputElement::applyStepForNumberOrRange):
            (WebCore::HTMLInputElement::stepUp):
            (WebCore::HTMLInputElement::stepDown):
            (WebCore::HTMLInputElement::formStringFromDouble):
            * html/HTMLInputElement.h:
            (WebCore::HTMLInputElement::stepUp):
            (WebCore::HTMLInputElement::stepDown):
            * html/HTMLInputElement.idl: Add stepUp() and stepDown().
            * rendering/RenderSlider.cpp:
            (WebCore::SliderRange::SliderRange): Sync with rangeMinimum()/rangeMaximum() renaming.
            (WebCore::RenderSlider::updateFromElement): Use formStringFromDouble().
            (WebCore::RenderSlider::setValueForPosition): Use formStringFromDouble().
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@51822 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 9f49b0e..ded83bb 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,20 @@
+2009-12-07  Kent Tamura  <tkent at chromium.org>
+
+        Reviewed by Darin Adler.
+
+        Add tests for HTMLInputElement::stepUp() and stepDown().
+        https://bugs.webkit.org/show_bug.cgi?id=27451
+
+        * fast/forms/input-step-number-expected.txt: Added.
+        * fast/forms/input-step-number.html: Added.
+        * fast/forms/input-step-range-expected.txt: Added.
+        * fast/forms/input-step-range.html: Added.
+        * fast/forms/input-step-unsupported-expected.txt: Added.
+        * fast/forms/input-step-unsupported.html: Added.
+        * fast/forms/script-tests/input-step-number.js: Added.
+        * fast/forms/script-tests/input-step-range.js: Added.
+        * fast/forms/script-tests/input-step-unsupported.js: Added.
+
 2009-12-07  Enrica Casucci  <enrica at apple.com>
 
         Reviewed by Darin Adler.
diff --git a/LayoutTests/fast/forms/input-step-number-expected.txt b/LayoutTests/fast/forms/input-step-number-expected.txt
new file mode 100644
index 0000000..ebee207
--- /dev/null
+++ b/LayoutTests/fast/forms/input-step-number-expected.txt
@@ -0,0 +1,89 @@
+Tests stepDown()/stepUp() for type=number.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Tests for an invalid current value:
+PASS input.stepDown() threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
+PASS input.stepUp() threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
+stepDown("foo") with value=0:
+PASS input.value is "0"
+stepUp("foo") with value=0:
+PASS input.value is "0"
+stepDown(null) with value=0:
+PASS input.value is "0"
+stepUp(null) with value=0:
+PASS input.value is "0"
+stepDown(undefined) with value=0:
+PASS input.value is "0"
+stepUp(undefined) with value=0:
+PASS input.value is "0"
+stepUp() with value=0:
+PASS input.value is "1"
+stepUp(2) with value=1:
+PASS input.value is "3"
+stepUp(-1) with value=3:
+PASS input.value is "2"
+stepDown(-1) with value=2:
+PASS input.value is "1"
+stepDown(2) with value=1:
+PASS input.value is "-1"
+stepDown(-1) with value=-1:
+PASS input.value is "0"
+stepUp(1, 2) with value=0:
+PASS input.value is "1"
+stepUp(1, 3) with value=1:
+PASS input.value is "0"
+stepUp() with value=0 step=foo:
+PASS input.value is "1"
+stepUp() with value=1 step=0:
+PASS input.value is "2"
+stepUp() with value=2 step=-1:
+PASS input.value is "3"
+stepDown() and stepUp() with value=0 step=any:
+PASS input.stepDown() threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
+PASS input.stepUp() threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
+stepDown() with value=1 min=0 step=1:
+PASS input.value is "0"
+stepDown() with value=0 min=0 step=1:
+PASS input.stepDown() threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
+stepDown(2) with value=1 min=0 step=1:
+PASS input.stepDown(2) threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
+PASS input.value is "1"
+stepDown(2) with value=1 step=DBL_MAX:
+PASS input.stepDown(2) threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
+stepUp() with value=-1 max=0 step=1:
+PASS input.value is "0"
+stepUp() with value=0 max=0 step=1:
+PASS input.stepUp() threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
+stepUp(2) with value=-1 max=0 step=1:
+PASS input.stepUp(2) threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
+PASS input.value is "-1"
+stepUp(2) with value=1 step=DBL_MAX:
+PASS input.stepUp(2) threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
+stepUp() with value=0 min=-1 step=2:
+PASS input.value is "3"
+PASS input.value is "1"
+stepUp(9) with value=9 min=0 step=10:
+PASS input.value is "100"
+stepDown() with value=19 min=0 step=10:
+PASS input.value is "10"
+stepUp() with value=89 min=0 max=99 step=10:
+PASS input.stepUp() threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
+stepUp(999999) with value=1e+308 step=1:
+PASS input.value is "1e+308"
+PASS input.value is "1e+308"
+stepUp(3) with value=0 step=0.33333333333333333:
+PASS input.value is "1"
+stepUp(10) with value=1 step=0.1:
+PASS input.value is "2"
+stepUp() x10 with value=2 step=0.1:
+PASS input.value is "3"
+stepUp(255) with value=0 min=0 max=1 step=0.003921568627450980:
+PASS input.value is "1"
+stepDown() x255 with value=1 min=0 max=1 step=0.003921568627450980:
+PASS input.value is "0"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/forms/input-step-number.html b/LayoutTests/fast/forms/input-step-number.html
new file mode 100644
index 0000000..eb80ca6
--- /dev/null
+++ b/LayoutTests/fast/forms/input-step-number.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<link rel="stylesheet" href="../../fast/js/resources/js-test-style.css">
+<script src="../../fast/js/resources/js-test-pre.js"></script>
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<script src="script-tests/input-step-number.js"></script>
+<script src="../../fast/js/resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/forms/input-step-range-expected.txt b/LayoutTests/fast/forms/input-step-range-expected.txt
new file mode 100644
index 0000000..abff94c
--- /dev/null
+++ b/LayoutTests/fast/forms/input-step-range-expected.txt
@@ -0,0 +1,89 @@
+Tests stepDown()/stepUp() for type=range.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Tests for an invalid current value:
+PASS input.stepDown() threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
+PASS input.stepUp() threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
+stepDown("foo") with value=0:
+PASS input.value is "0"
+stepUp("foo") with value=0:
+PASS input.value is "0"
+stepDown(null) with value=0:
+PASS input.value is "0"
+stepUp(null) with value=0:
+PASS input.value is "0"
+stepDown(undefined) with value=0:
+PASS input.value is "0"
+stepUp(undefined) with value=0:
+PASS input.value is "0"
+stepUp() with value=0 min=-100:
+PASS input.value is "1"
+stepUp(2) with value=1:
+PASS input.value is "3"
+stepUp(-1) with value=3:
+PASS input.value is "2"
+stepDown(-1) with value=2:
+PASS input.value is "1"
+stepDown(2) with value=1:
+PASS input.value is "-1"
+stepDown(-1) with value=-1:
+PASS input.value is "0"
+stepUp(1, 2) with value=0:
+PASS input.value is "1"
+stepUp(1, 3) with value=1:
+PASS input.value is "0"
+stepUp() with value=0 step=foo:
+PASS input.value is "1"
+stepUp() with value=1 step=0:
+PASS input.value is "2"
+stepUp() with value=2 step=-1:
+PASS input.value is "3"
+stepDown() and stepUp() with value=0 step=any:
+PASS input.stepDown() threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
+PASS input.stepUp() threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
+stepDown() with value=1 min=0 step=1:
+PASS input.value is "0"
+stepDown() with value=0 min=0 step=1:
+PASS input.stepDown() threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
+stepDown(2) with value=1 min=0 step=1:
+PASS input.stepDown(2) threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
+PASS input.value is "1"
+stepDown(2) with value=1 step=DBL_MAX:
+PASS input.stepDown(2) threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
+stepUp() with value=-1 min=-100 max=0 step=1:
+PASS input.value is "0"
+stepUp() with value=0 min=-100 max=0 step=1:
+PASS input.stepUp() threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
+stepUp(2) with value=-1 min=-100 max=0 step=1:
+PASS input.stepUp(2) threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
+PASS input.value is "-1"
+stepUp(2) with value=1 step=DBL_MAX:
+PASS input.stepUp(2) threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
+stepUp() with value=0 min=-1 step=2:
+PASS input.value is "3"
+PASS input.value is "1"
+stepUp(9) with value=9 min=0 step=10:
+PASS input.value is "100"
+stepDown() with value=19 min=0 step=10:
+PASS input.value is "10"
+stepUp() with value=89 min=0 max=99 step=10:
+PASS input.stepUp() threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
+stepUp(999999) with value=1e+308 min=0 max=1.1e+308 step=1:
+PASS input.value is "1e+308"
+PASS input.value is "1e+308"
+stepUp(3) with value=0 step=0.33333333333333333:
+PASS input.value is "1"
+stepUp(10) with value=1 step=0.1:
+PASS input.value is "2"
+stepUp() x10 with value=2 step=0.1:
+PASS input.value is "3"
+stepUp(255) with value=0 min=0 max=1 step=0.003921568627450980:
+PASS input.value is "1"
+stepDown() x255 with value=1 min=0 max=1 step=0.003921568627450980:
+PASS input.value is "0"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/forms/input-step-range.html b/LayoutTests/fast/forms/input-step-range.html
new file mode 100644
index 0000000..776b374
--- /dev/null
+++ b/LayoutTests/fast/forms/input-step-range.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<link rel="stylesheet" href="../../fast/js/resources/js-test-style.css">
+<script src="../../fast/js/resources/js-test-pre.js"></script>
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<script src="script-tests/input-step-range.js"></script>
+<script src="../../fast/js/resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/forms/input-step-unsupported-expected.txt b/LayoutTests/fast/forms/input-step-unsupported-expected.txt
new file mode 100644
index 0000000..df4a6ea
--- /dev/null
+++ b/LayoutTests/fast/forms/input-step-unsupported-expected.txt
@@ -0,0 +1,13 @@
+Tests stepDown()/stepUp() for unsupported types
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS input.stepDown() threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
+PASS input.stepDown(0) threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
+PASS input.stepUp() threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
+PASS input.stepUp(0) threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/forms/input-step-unsupported.html b/LayoutTests/fast/forms/input-step-unsupported.html
new file mode 100644
index 0000000..663caad
--- /dev/null
+++ b/LayoutTests/fast/forms/input-step-unsupported.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<link rel="stylesheet" href="../../fast/js/resources/js-test-style.css">
+<script src="../../fast/js/resources/js-test-pre.js"></script>
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<script src="script-tests/input-step-unsupported.js"></script>
+<script src="../../fast/js/resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/forms/script-tests/input-step-number.js b/LayoutTests/fast/forms/script-tests/input-step-number.js
new file mode 100644
index 0000000..80b489f
--- /dev/null
+++ b/LayoutTests/fast/forms/script-tests/input-step-number.js
@@ -0,0 +1,212 @@
+description('Tests stepDown()/stepUp() for type=number.');
+
+var input = document.createElement('input');
+input.type = 'number';
+var invalidStateErr = '"Error: INVALID_STATE_ERR: DOM Exception 11"';
+
+debug('Tests for an invalid current value:');
+input.value = '';
+shouldThrow('input.stepDown()', invalidStateErr);
+shouldThrow('input.stepUp()', invalidStateErr);
+
+// Non-number argument
+debug('stepDown("foo") with value=0:');
+input.value = '0';
+input.stepDown("foo");
+shouldBe('input.value', '"0"');
+
+debug('stepUp("foo") with value=0:');
+input.stepUp("foo");
+shouldBe('input.value', '"0"');
+
+debug('stepDown(null) with value=0:');
+input.stepDown(null);
+shouldBe('input.value', '"0"');
+
+debug('stepUp(null) with value=0:');
+input.stepUp(null);
+shouldBe('input.value', '"0"');
+
+debug('stepDown(undefined) with value=0:');
+input.stepDown(undefined);
+shouldBe('input.value', '"0"');
+
+debug('stepUp(undefined) with value=0:');
+input.stepUp(undefined);
+shouldBe('input.value', '"0"');
+
+// Default step value for type=number is 1.
+debug('stepUp() with value=0:');
+input.value = '0';
+input.stepUp();
+shouldBe('input.value', '"1"');
+
+debug('stepUp(2) with value=1:');
+input.stepUp(2);
+shouldBe('input.value', '"3"');
+
+debug('stepUp(-1) with value=3:');
+input.stepUp(-1);
+shouldBe('input.value', '"2"');
+
+debug('stepDown(-1) with value=2:');
+input.stepDown();
+shouldBe('input.value', '"1"');
+
+debug('stepDown(2) with value=1:');
+input.stepDown(2);
+shouldBe('input.value', '"-1"');
+
+debug('stepDown(-1) with value=-1:');
+input.stepDown(-1);
+shouldBe('input.value', '"0"');
+
+// Extra arguments are ignored.
+debug('stepUp(1, 2) with value=0:');
+input.stepUp(1, 2);
+shouldBe('input.value', '"1"');
+
+debug('stepUp(1, 3) with value=1:');
+input.stepDown(1, 3);
+shouldBe('input.value', '"0"');
+
+// The default value is used for invalid step values.
+debug('stepUp() with value=0 step=foo:');
+input.value = '0';
+input.step = 'foo';
+input.stepUp();
+shouldBe('input.value', '"1"');
+
+debug('stepUp() with value=1 step=0:');
+input.step = '0';
+input.stepUp();
+shouldBe('input.value', '"2"');
+
+debug('stepUp() with value=2 step=-1:');
+input.step = '-1';
+input.stepUp();
+shouldBe('input.value', '"3"');
+
+// No step value
+debug('stepDown() and stepUp() with value=0 step=any:');
+input.value = '0';
+input.step = 'any';
+shouldThrow('input.stepDown()', invalidStateErr);
+shouldThrow('input.stepUp()', invalidStateErr);
+
+// Minimum limit
+debug('stepDown() with value=1 min=0 step=1:');
+input.min = '0';
+input.step = '1';
+input.value = '1';
+input.stepDown();
+shouldBe('input.value', '"0"');
+debug('stepDown() with value=0 min=0 step=1:');
+shouldThrow('input.stepDown()', invalidStateErr);
+
+debug('stepDown(2) with value=1 min=0 step=1:');
+input.value = '1';
+shouldThrow('input.stepDown(2)', invalidStateErr);
+shouldBe('input.value', '"1"');
+
+// Should not be -Infinity.
+debug('stepDown(2) with value=1 step=DBL_MAX:');
+input.value = '1';
+input.min = '';
+input.step = '1.7976931348623156e+308';
+shouldThrow('input.stepDown(2)', invalidStateErr);
+
+// Maximum limit
+debug('stepUp() with value=-1 max=0 step=1:');
+input.value = '-1';
+input.min = '';
+input.max = '0';
+input.step = '1';
+input.stepUp();
+shouldBe('input.value', '"0"');
+debug('stepUp() with value=0 max=0 step=1:');
+shouldThrow('input.stepUp()', invalidStateErr);
+
+debug('stepUp(2) with value=-1 max=0 step=1:');
+input.value = '-1';
+shouldThrow('input.stepUp(2)', invalidStateErr);
+shouldBe('input.value', '"-1"');
+
+// Should not be Infinity.
+debug('stepUp(2) with value=1 step=DBL_MAX:');
+input.value = '1';
+input.max = '';
+input.step = '1.7976931348623156e+308';
+shouldThrow('input.stepUp(2)', invalidStateErr);
+
+// stepDown()/stepUp() for stepMismatch values
+debug('stepUp() with value=0 min=-1 step=2:');
+input.value = '0';
+input.min = '-1';
+input.step = '2';
+input.stepUp();
+shouldBe('input.value', '"3"');
+input.stepDown();
+shouldBe('input.value', '"1"');
+
+debug('stepUp(9) with value=9 min=0 step=10:');
+input.value = '9';
+input.min = '0';
+input.max = '';
+input.step = '10';
+input.stepUp(9);
+shouldBe('input.value', '"100"');
+
+debug('stepDown() with value=19 min=0 step=10:');
+input.value = '19';
+input.stepDown();
+shouldBe('input.value', '"10"');
+
+// value + step is <= max, but rounded result would be > max.
+debug('stepUp() with value=89 min=0 max=99 step=10:');
+input.value = '89';
+input.max = '99';
+shouldThrow('input.stepUp()', invalidStateErr);
+
+// Huge value and small step
+debug('stepUp(999999) with value=1e+308 step=1:');
+input.value = '1e+308';
+input.min = '';
+input.max = '';
+input.step = '1';
+input.stepUp(999999);
+shouldBe('input.value', '"1e+308"');
+input.stepDown(999999);
+shouldBe('input.value', '"1e+308"');
+
+// Fractional numbers
+debug('stepUp(3) with value=0 step=0.33333333333333333:');
+input.value = '0';
+input.min = '';
+input.max = '';
+input.step = '0.33333333333333333';
+input.stepUp(3);
+shouldBe('input.value', '"1"');
+
+debug('stepUp(10) with value=1 step=0.1:');
+input.step = '0.1';
+input.stepUp(10);
+shouldBe('input.value', '"2"');
+debug('stepUp() x10 with value=2 step=0.1:');
+for (var i = 0; i < 10; i++)
+    input.stepUp();
+shouldBe('input.value', '"3"');
+
+debug('stepUp(255) with value=0 min=0 max=1 step=0.003921568627450980:');
+input.value = '0';
+input.min = '0';
+input.max = '1';
+input.step = '0.003921568627450980';
+input.stepUp(255);
+shouldBe('input.value', '"1"');
+debug('stepDown() x255 with value=1 min=0 max=1 step=0.003921568627450980:');
+for (var i = 0; i < 255; i++)
+    input.stepDown();
+shouldBe('input.value', '"0"');
+
+var successfullyParsed = true;
diff --git a/LayoutTests/fast/forms/script-tests/input-step-range.js b/LayoutTests/fast/forms/script-tests/input-step-range.js
new file mode 100644
index 0000000..d8745c1
--- /dev/null
+++ b/LayoutTests/fast/forms/script-tests/input-step-range.js
@@ -0,0 +1,213 @@
+description('Tests stepDown()/stepUp() for type=range.');
+
+var input = document.createElement('input');
+input.type = 'range';
+var invalidStateErr = '"Error: INVALID_STATE_ERR: DOM Exception 11"';
+
+debug('Tests for an invalid current value:');
+input.value = '';
+shouldThrow('input.stepDown()', invalidStateErr);
+shouldThrow('input.stepUp()', invalidStateErr);
+
+// Non-number argument
+debug('stepDown("foo") with value=0:');
+input.value = '0';
+input.stepDown("foo");
+shouldBe('input.value', '"0"');
+
+debug('stepUp("foo") with value=0:');
+input.stepUp("foo");
+shouldBe('input.value', '"0"');
+
+debug('stepDown(null) with value=0:');
+input.stepDown(null);
+shouldBe('input.value', '"0"');
+
+debug('stepUp(null) with value=0:');
+input.stepUp(null);
+shouldBe('input.value', '"0"');
+
+debug('stepDown(undefined) with value=0:');
+input.stepDown(undefined);
+shouldBe('input.value', '"0"');
+
+debug('stepUp(undefined) with value=0:');
+input.stepUp(undefined);
+shouldBe('input.value', '"0"');
+
+// Default step value for type=range is 1.
+debug('stepUp() with value=0 min=-100:');
+input.value = '0';
+input.min = '-100';
+input.stepUp();
+shouldBe('input.value', '"1"');
+
+debug('stepUp(2) with value=1:');
+input.stepUp(2);
+shouldBe('input.value', '"3"');
+
+debug('stepUp(-1) with value=3:');
+input.stepUp(-1);
+shouldBe('input.value', '"2"');
+
+debug('stepDown(-1) with value=2:');
+input.stepDown();
+shouldBe('input.value', '"1"');
+
+debug('stepDown(2) with value=1:');
+input.stepDown(2);
+shouldBe('input.value', '"-1"');
+
+debug('stepDown(-1) with value=-1:');
+input.stepDown(-1);
+shouldBe('input.value', '"0"');
+
+// Extra arguments are ignored.
+debug('stepUp(1, 2) with value=0:');
+input.stepUp(1, 2);
+shouldBe('input.value', '"1"');
+
+debug('stepUp(1, 3) with value=1:');
+input.stepDown(1, 3);
+shouldBe('input.value', '"0"');
+
+// The default value is used for invalid step values.
+debug('stepUp() with value=0 step=foo:');
+input.value = '0';
+input.step = 'foo';
+input.stepUp();
+shouldBe('input.value', '"1"');
+
+debug('stepUp() with value=1 step=0:');
+input.step = '0';
+input.stepUp();
+shouldBe('input.value', '"2"');
+
+debug('stepUp() with value=2 step=-1:');
+input.step = '-1';
+input.stepUp();
+shouldBe('input.value', '"3"');
+
+// No step value
+debug('stepDown() and stepUp() with value=0 step=any:');
+input.value = '0';
+input.step = 'any';
+shouldThrow('input.stepDown()', invalidStateErr);
+shouldThrow('input.stepUp()', invalidStateErr);
+
+// Minimum limit
+debug('stepDown() with value=1 min=0 step=1:');
+input.min = '0';
+input.step = '1';
+input.value = '1';
+input.stepDown();
+shouldBe('input.value', '"0"');
+debug('stepDown() with value=0 min=0 step=1:');
+shouldThrow('input.stepDown()', invalidStateErr);
+
+debug('stepDown(2) with value=1 min=0 step=1:');
+input.value = '1';
+shouldThrow('input.stepDown(2)', invalidStateErr);
+shouldBe('input.value', '"1"');
+
+// Implicit minimum.
+debug('stepDown(2) with value=1 step=DBL_MAX:');
+input.value = '1';
+input.min = '';
+input.step = '1.7976931348623156e+308';
+shouldThrow('input.stepDown(2)', invalidStateErr);
+
+// Maximum limit
+debug('stepUp() with value=-1 min=-100 max=0 step=1:');
+input.value = '-1';
+input.min = '-100';
+input.max = '0';
+input.step = '1';
+input.stepUp();
+shouldBe('input.value', '"0"');
+debug('stepUp() with value=0 min=-100 max=0 step=1:');
+shouldThrow('input.stepUp()', invalidStateErr);
+
+debug('stepUp(2) with value=-1 min=-100 max=0 step=1:');
+input.value = '-1';
+shouldThrow('input.stepUp(2)', invalidStateErr);
+shouldBe('input.value', '"-1"');
+
+// Implicit maximum
+debug('stepUp(2) with value=1 step=DBL_MAX:');
+input.value = '1';
+input.max = '';
+input.step = '1.7976931348623156e+308';
+shouldThrow('input.stepUp(2)', invalidStateErr);
+
+// stepDown()/stepUp() for stepMismatch values
+debug('stepUp() with value=0 min=-1 step=2:');
+input.value = '0';
+input.min = '-1';
+input.step = '2';
+input.stepUp();
+shouldBe('input.value', '"3"');
+input.stepDown();
+shouldBe('input.value', '"1"');
+
+debug('stepUp(9) with value=9 min=0 step=10:');
+input.value = '9';
+input.min = '0';
+input.max = '';
+input.step = '10';
+input.stepUp(9);
+shouldBe('input.value', '"100"');
+
+debug('stepDown() with value=19 min=0 step=10:');
+input.value = '19';
+input.stepDown();
+shouldBe('input.value', '"10"');
+
+// value + step is <= max, but rounded result would be > max.
+debug('stepUp() with value=89 min=0 max=99 step=10:');
+input.value = '89';
+input.max = '99';
+shouldThrow('input.stepUp()', invalidStateErr);
+
+// Huge value and small step
+debug('stepUp(999999) with value=1e+308 min=0 max=1.1e+308 step=1:');
+input.value = '1e+308';
+input.min = '0';
+input.max = '1.1e+308';
+input.step = '1';
+input.stepUp(999999);
+shouldBe('input.value', '"1e+308"');
+input.stepDown(999999);
+shouldBe('input.value', '"1e+308"');
+
+// Fractional numbers
+debug('stepUp(3) with value=0 step=0.33333333333333333:');
+input.value = '0';
+input.min = '';
+input.max = '';
+input.step = '0.33333333333333333';
+input.stepUp(3);
+shouldBe('input.value', '"1"');
+
+debug('stepUp(10) with value=1 step=0.1:');
+input.step = '0.1';
+input.stepUp(10);
+shouldBe('input.value', '"2"');
+debug('stepUp() x10 with value=2 step=0.1:');
+for (var i = 0; i < 10; i++)
+    input.stepUp();
+shouldBe('input.value', '"3"');
+
+debug('stepUp(255) with value=0 min=0 max=1 step=0.003921568627450980:');
+input.value = '0';
+input.min = '0';
+input.max = '1';
+input.step = '0.003921568627450980';
+input.stepUp(255);
+shouldBe('input.value', '"1"');
+debug('stepDown() x255 with value=1 min=0 max=1 step=0.003921568627450980:');
+for (var i = 0; i < 255; i++)
+    input.stepDown();
+shouldBe('input.value', '"0"');
+
+var successfullyParsed = true;
diff --git a/LayoutTests/fast/forms/script-tests/input-step-unsupported.js b/LayoutTests/fast/forms/script-tests/input-step-unsupported.js
new file mode 100644
index 0000000..9ccaf19
--- /dev/null
+++ b/LayoutTests/fast/forms/script-tests/input-step-unsupported.js
@@ -0,0 +1,12 @@
+description('Tests stepDown()/stepUp() for unsupported types');
+
+var input = document.createElement('input');
+input.type = 'text';
+input.step = '3';
+input.value = '2';
+shouldThrow('input.stepDown()', '"Error: INVALID_STATE_ERR: DOM Exception 11"');
+shouldThrow('input.stepDown(0)', '"Error: INVALID_STATE_ERR: DOM Exception 11"');
+shouldThrow('input.stepUp()', '"Error: INVALID_STATE_ERR: DOM Exception 11"');
+shouldThrow('input.stepUp(0)', '"Error: INVALID_STATE_ERR: DOM Exception 11"');
+
+var successfullyParsed = true;
diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 6261e9d..4e6a570 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,40 @@
+2009-12-07  Kent Tamura  <tkent at chromium.org>
+
+        Reviewed by Darin Adler.
+
+        Add support for HTMLInputElement::stepUp() and stepDown() for
+        type=number and type=range.
+        https://bugs.webkit.org/show_bug.cgi?id=27451
+
+        Our implementation of stepUp() and stepDown() rounds the resultant
+        value to conform to the step value.
+        Change the number-string conversion method for RenderSlider to be
+        consistent with type=number.
+
+        Tests: fast/forms/input-step-number.html
+               fast/forms/input-step-range.html
+               fast/forms/input-step-unsupported.html
+
+        * html/HTMLInputElement.cpp:
+        (WebCore::HTMLInputElement::rangeUnderflow): Unify the code for NUMBER and RANGE.
+        (WebCore::HTMLInputElement::rangeOverflow): Unify the code for NUMBER and RANGE.
+        (WebCore::HTMLInputElement::minimum): Renamed from rangeMinimum(), and support for NUMBER.
+        (WebCore::HTMLInputElement::maximum): Renamed from rangeMaximum(), and support for NUMBER.
+        (WebCore::HTMLInputElement::stepBase):
+        (WebCore::HTMLInputElement::stepMismatch): Use stepBase().
+        (WebCore::HTMLInputElement::applyStepForNumberOrRange):
+        (WebCore::HTMLInputElement::stepUp):
+        (WebCore::HTMLInputElement::stepDown):
+        (WebCore::HTMLInputElement::formStringFromDouble):
+        * html/HTMLInputElement.h:
+        (WebCore::HTMLInputElement::stepUp):
+        (WebCore::HTMLInputElement::stepDown):
+        * html/HTMLInputElement.idl: Add stepUp() and stepDown().
+        * rendering/RenderSlider.cpp:
+        (WebCore::SliderRange::SliderRange): Sync with rangeMinimum()/rangeMaximum() renaming.
+        (WebCore::RenderSlider::updateFromElement): Use formStringFromDouble().
+        (WebCore::RenderSlider::setValueForPosition): Use formStringFromDouble().
+
 2009-12-07  Albert J. Wong  <ajwong at chromium.org>
 
         Not reviewed: Chromium build fix try 2 (dumb error).
diff --git a/WebCore/html/HTMLInputElement.cpp b/WebCore/html/HTMLInputElement.cpp
index 1578c6e..13dbbb0 100644
--- a/WebCore/html/HTMLInputElement.cpp
+++ b/WebCore/html/HTMLInputElement.cpp
@@ -65,6 +65,7 @@
 #include <wtf/HashMap.h>
 #include <wtf/MathExtras.h>
 #include <wtf/StdLibExtras.h>
+#include <wtf/dtoa.h>
 
 using namespace std;
 
@@ -77,6 +78,12 @@ const int maxSavedResults = 256;
 // Constant values for getAllowedValueStep().
 static const double numberDefaultStep = 1.0;
 static const double numberStepScaleFactor = 1.0;
+// Constant values for minimum().
+static const double numberDefaultMinimum = -DBL_MAX;
+static const double rangeDefaultMinimum = 0.0;
+// Constant values for maximum().
+static const double numberDefaultMaximum = DBL_MAX;
+static const double rangeDefaultMaximum = 100.0;
 
 HTMLInputElement::HTMLInputElement(const QualifiedName& tagName, Document* doc, HTMLFormElement* f)
     : HTMLTextFormControlElement(tagName, doc, f)
@@ -259,60 +266,62 @@ bool HTMLInputElement::tooLong() const
 
 bool HTMLInputElement::rangeUnderflow() const
 {
-    if (inputType() == NUMBER) {
-        double min = 0.0;
-        double doubleValue = 0.0;
-        if (formStringToDouble(getAttribute(minAttr), &min) && formStringToDouble(value(), &doubleValue))
-            return doubleValue < min;
-    } else if (inputType() == RANGE) {
+    if (inputType() == NUMBER || inputType() == RANGE) {
         double doubleValue;
         if (formStringToDouble(value(), &doubleValue))
-            return doubleValue < rangeMinimum();
+            return doubleValue < minimum();
     }
     return false;
 }
 
 bool HTMLInputElement::rangeOverflow() const
 {
-    if (inputType() == NUMBER) {
-        double max = 0.0;
-        double doubleValue = 0.0;
-        if (formStringToDouble(getAttribute(maxAttr), &max) && formStringToDouble(value(), &doubleValue))
-            return doubleValue > max;
-    } else if (inputType() == RANGE) {
+    if (inputType() == NUMBER || inputType() == RANGE) {
         double doubleValue;
         if (formStringToDouble(value(), &doubleValue))
-            return doubleValue > rangeMaximum();
+            return doubleValue > maximum();
     }
     return false;
 }
 
-double HTMLInputElement::rangeMinimum() const
+double HTMLInputElement::minimum() const
 {
-    ASSERT(inputType() == RANGE);
-    // The range type's "default minimum" is 0.
-    double min = 0.0;
+    ASSERT(inputType() == NUMBER || inputType() == RANGE);
+    double min = inputType() == RANGE ? rangeDefaultMinimum : numberDefaultMinimum;
     formStringToDouble(getAttribute(minAttr), &min);
     return min;
 }
 
-double HTMLInputElement::rangeMaximum() const
+double HTMLInputElement::maximum() const
 {
-    ASSERT(inputType() == RANGE);
-    // The range type's "default maximum" is 100.
-    static const double defaultMaximum = 100.0;
+    ASSERT(inputType() == NUMBER || inputType() == RANGE);
+    double defaultMaximum = inputType() == RANGE ? rangeDefaultMaximum : numberDefaultMaximum;
     double max = defaultMaximum;
     formStringToDouble(getAttribute(maxAttr), &max);
-    const double min = rangeMinimum();
-
-    if (max < min) {
-        // A remedy for the inconsistent min/max values.
-        // Sets the maxmimum to the default (100.0) or the minimum value.
-        max = min < defaultMaximum ? defaultMaximum : min;
+    if (inputType() == RANGE) {
+        // A remedy for the inconsistent min/max values for RANGE.
+        // Sets the maxmimum to the default or the minimum value.
+        double min = minimum();
+        if (max < min)
+            max = std::max(min, defaultMaximum);
     }
     return max;
 }
 
+double HTMLInputElement::stepBase() const
+{
+    if (inputType() == RANGE)
+        return minimum();
+    if (inputType() == NUMBER) {
+        static const double defaultStepBase = 0.0;
+        double min = defaultStepBase;
+        formStringToDouble(getAttribute(minAttr), &min);
+        return min;
+    }
+    ASSERT_NOT_REACHED();
+    return 0.0;
+}
+
 bool HTMLInputElement::stepMismatch() const
 {
     double step;
@@ -322,9 +331,7 @@ bool HTMLInputElement::stepMismatch() const
         double doubleValue;
         if (!formStringToDouble(value(), &doubleValue))
             return false;
-        double stepBase = 0.0;
-        formStringToDouble(getAttribute(minAttr), &stepBase);
-        doubleValue = fabs(doubleValue - stepBase);
+        doubleValue = fabs(doubleValue - stepBase());
         if (isinf(doubleValue))
             return false;
         // double's fractional part size is DBL_MAN_DIG-bit.  If the current
@@ -404,9 +411,59 @@ bool HTMLInputElement::getAllowedValueStep(double* step) const
         return true;
     }
     *step = parsed * stepScaleFactor;
+    ASSERT(*step > 0);
     return true;
 }
 
+void HTMLInputElement::applyStepForNumberOrRange(double count, ExceptionCode& ec)
+{
+    ASSERT(inputType() == NUMBER || inputType() == RANGE);
+    double step;
+    if (!getAllowedValueStep(&step)) {
+        ec = INVALID_STATE_ERR;
+        return;
+    }
+    double current;
+    if (!formStringToDouble(value(), &current)) {
+        ec = INVALID_STATE_ERR;
+        return;
+    }
+    double newValue = current + step * count;
+    if (isinf(newValue)) {
+        ec = INVALID_STATE_ERR;
+        return;
+    }
+    if (newValue < minimum()) {
+        ec = INVALID_STATE_ERR;
+        return;
+    }
+    double base = stepBase();
+    newValue = base + round((newValue - base) / step) * step;
+    if (newValue > maximum()) {
+        ec = INVALID_STATE_ERR;
+        return;
+    }
+    setValue(formStringFromDouble(newValue));
+}
+
+void HTMLInputElement::stepUp(int n, ExceptionCode& ec)
+{
+    if (inputType() != NUMBER && inputType() != RANGE) {
+        ec = INVALID_STATE_ERR;
+        return;
+    }
+    applyStepForNumberOrRange(n, ec);
+}
+
+void HTMLInputElement::stepDown(int n, ExceptionCode& ec)
+{
+    if (inputType() != NUMBER && inputType() != RANGE) {
+        ec = INVALID_STATE_ERR;
+        return;
+    }
+    applyStepForNumberOrRange(-n, ec);
+}
+
 static inline CheckedRadioButtons& checkedRadioButtons(const HTMLInputElement *element)
 {
     if (HTMLFormElement* form = element->form())
@@ -1997,6 +2054,16 @@ bool HTMLInputElement::willValidate() const
            inputType() != BUTTON && inputType() != RESET;
 }
 
+String HTMLInputElement::formStringFromDouble(double number)
+{
+    // According to HTML5, "the best representation of the number n as a floating
+    // point number" is a string produced by applying ToString() to n.
+    DtoaBuffer buffer;
+    unsigned length;
+    doubleToStringInJavaScriptFormat(number, buffer, &length);
+    return String(buffer, length);
+}
+
 bool HTMLInputElement::formStringToDouble(const String& src, double* out)
 {
     // See HTML5 2.4.4.3 `Real numbers.'
diff --git a/WebCore/html/HTMLInputElement.h b/WebCore/html/HTMLInputElement.h
index 14d12bf..8f00aeb 100644
--- a/WebCore/html/HTMLInputElement.h
+++ b/WebCore/html/HTMLInputElement.h
@@ -106,16 +106,21 @@ public:
     // For ValidityState
     bool rangeUnderflow() const;
     bool rangeOverflow() const;
-    // Returns the minimum value for type=range.  Don't call this for other types.
-    double rangeMinimum() const;
-    // Returns the maximum value for type=range.  Don't call this for other types.
-    // This always returns a value which is <= rangeMinimum().
-    double rangeMaximum() const;
+    // Returns the minimum value for type=number or range.  Don't call this for other types.
+    double minimum() const;
+    // Returns the maximum value for type=number or range.  Don't call this for other types.
+    // This always returns a value which is >= minimum().
+    double maximum() const;
     // Sets the "allowed value step" defined in the HTML spec to the specified double pointer.
     // Returns false if there is no "allowed value step."
     bool getAllowedValueStep(double*) const;
     // For ValidityState.
     bool stepMismatch() const;
+    // Implementations of HTMLInputElement::stepUp() and stepDown().
+    void stepUp(int, ExceptionCode&);
+    void stepDown(int, ExceptionCode&);
+    void stepUp(ExceptionCode& ec) { stepUp(1, ec); }
+    void stepDown(ExceptionCode& ec) { stepDown(1, ec); }
 
     bool isTextButton() const { return m_type == SUBMIT || m_type == RESET || m_type == BUTTON; }
     virtual bool isRadioButton() const { return m_type == RADIO; }
@@ -249,6 +254,9 @@ public:
     // If the conversion fails, the return value is false. Take care that leading or trailing unnecessary characters make failures.  This returns false for an empty string input.
     // The double* parameter may be 0.
     static bool formStringToDouble(const String&, double*);
+    // Converts the specified number to a string. This is an implementation of
+    // HTML5's "algorithm to convert a number to a string" for NUMBER/RANGE types.
+    static String formStringFromDouble(double);
     // Parses the specified string as the InputType, and returns true if it is successfully parsed.
     // An instance pointed by the ISODateTime* parameter will have parsed values and be
     // modified even if the parsing fails.  The ISODateTime* parameter may be 0.
@@ -278,6 +286,11 @@ private:
     PassRefPtr<HTMLFormElement> createTemporaryFormForIsIndex();
     // Helper for getAllowedValueStep();
     bool getStepParameters(double* defaultStep, double* stepScaleFactor) const;
+    // Helper for stepUp()/stepDown().  Adds step value * count to the current number/range value.
+    void applyStepForNumberOrRange(double count, ExceptionCode&);
+    // Helper for applyStepForNumberOrRange().
+    double stepBase() const;
+
 #if ENABLE(DATALIST)
     HTMLDataListElement* dataList() const;
 #endif
diff --git a/WebCore/html/HTMLInputElement.idl b/WebCore/html/HTMLInputElement.idl
index fc03c81..2ac6674 100644
--- a/WebCore/html/HTMLInputElement.idl
+++ b/WebCore/html/HTMLInputElement.idl
@@ -71,6 +71,11 @@ module html {
         readonly attribute HTMLOptionElement selectedOption;
 #endif
 
+        void               stepUp(in [Optional] long n)
+            raises(DOMException);
+        void               stepDown(in [Optional] long n)
+            raises(DOMException);
+
         readonly attribute boolean         willValidate;
         readonly attribute DOMString       validationMessage;
         boolean            checkValidity();
diff --git a/WebCore/rendering/RenderSlider.cpp b/WebCore/rendering/RenderSlider.cpp
index e18b433..b2f5cef 100644
--- a/WebCore/rendering/RenderSlider.cpp
+++ b/WebCore/rendering/RenderSlider.cpp
@@ -82,8 +82,8 @@ SliderRange::SliderRange(HTMLInputElement* element)
     } else
         hasStep = element->getAllowedValueStep(&step);
 
-    maximum = element->rangeMaximum();
-    minimum = element->rangeMinimum();
+    maximum = element->maximum();
+    minimum = element->minimum();
 }
 
 double SliderRange::clampValue(double value)
@@ -379,7 +379,7 @@ void RenderSlider::updateFromElement()
     bool clamped;
     double value = range.valueFromElement(element, &clamped);
     if (clamped)
-        element->setValueFromRenderer(String::number(value));
+        element->setValueFromRenderer(HTMLInputElement::formStringFromDouble(value));
 
     // Layout will take care of the thumb's size and position.
     if (!m_thumb) {
@@ -435,7 +435,7 @@ void RenderSlider::setValueForPosition(int position)
     if (style()->appearance() == SliderVerticalPart || style()->appearance() == MediaVolumeSliderPart)
         fraction = 1 - fraction;
     double value = range.clampValue(range.valueFromProportion(fraction));
-    element->setValueFromRenderer(String::number(value));
+    element->setValueFromRenderer(HTMLInputElement::formStringFromDouble(value));
 
     // Also update the position if appropriate.
     if (position != currentPosition()) {

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list