Changeset 56242 in webkit


Ignore:
Timestamp:
Mar 19, 2010 9:16:16 AM (14 years ago)
Author:
Joseph Pecoraro
Message:

2010-03-19 Joseph Pecoraro <Joseph Pecoraro>

Reviewed by David Kilzer.

<input type=range> does not validate correctly without a renderer and the tests are incorrect
https://bugs.webkit.org/show_bug.cgi?id=36259

Setting value attribute on an <input type=range> to an out-of-range value fires oninput
https://bugs.webkit.org/show_bug.cgi?id=16990

Part 2 of 2: When setting the range element's value, overflows and underflows
are automatically sanitized to valid values. Moved the general case
sanitization code out of the Renderer into HTMLInputElement::sanitizeValue.

  • html/HTMLInputElement.cpp: (WebCore::HTMLInputElement::value): when getting a default value on reset() ensure the defaultValue is provided (WebCore::HTMLInputElement::sanitizeValue): clamp the value within the max/min/step range constraints
  • html/StepRange.cpp: (WebCore::StepRange::StepRange): allow const element in the constructor (WebCore::StepRange::clampValue): clamp from a String value
  • html/StepRange.h: (WebCore::StepRange::defaultValue): easy calculation of the default value for max/min/step range constraints
  • rendering/RenderSlider.cpp: (WebCore::RenderSlider::updateFromElement): no longer handle the general case sanitization in the renderer

2010-03-19 Joseph Pecoraro <Joseph Pecoraro>

Reviewed by David Kilzer.

<input type=range> does not validate correctly without a renderer and the tests are incorrect
https://bugs.webkit.org/show_bug.cgi?id=36259

Setting value attribute on an <input type=range> to an out-of-range value fires oninput
https://bugs.webkit.org/show_bug.cgi?id=16990

When setting the range element's value, overflows and underflows are
automatically sanitized to valid values. Fixed the behavior and removed
tests that were testing for improper behavior.

  • fast/forms/ValidityState-rangeOverflow-expected.txt:
  • fast/forms/ValidityState-rangeUnderflow-expected.txt:
  • fast/forms/input-stepup-stepdown-expected.txt:
  • fast/forms/script-tests/ValidityState-rangeOverflow.js:
  • fast/forms/script-tests/ValidityState-rangeUnderflow.js:
  • fast/forms/script-tests/input-stepup-stepdown.js:
  • fast/forms/script-tests/validationMessage.js:
  • fast/forms/validationMessage-expected.txt:

Added test verifying that bug 16990 was fixed as well.

  • fast/forms/range-input-dynamic-oninput-expected.txt: Added.
  • fast/forms/range-input-dynamic-oninput.html Added.

Improved test because handling of this case changed.

  • fast/forms/range-reset-expected.txt:
  • fast/forms/range-reset.html:
Location:
trunk
Files:
2 added
16 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r56240 r56242  
     12010-03-19  Joseph Pecoraro  <joepeck@webkit.org>
     2
     3        Reviewed by David Kilzer.
     4
     5        <input type=range> does not validate correctly without a renderer and the tests are incorrect
     6        https://bugs.webkit.org/show_bug.cgi?id=36259
     7
     8        Setting value attribute on an <input type=range> to an out-of-range value fires oninput
     9        https://bugs.webkit.org/show_bug.cgi?id=16990
     10
     11        When setting the range element's value, overflows and underflows are
     12        automatically sanitized to valid values. Fixed the behavior and removed
     13        tests that were testing for improper behavior.
     14
     15        * fast/forms/ValidityState-rangeOverflow-expected.txt:
     16        * fast/forms/ValidityState-rangeUnderflow-expected.txt:
     17        * fast/forms/input-stepup-stepdown-expected.txt:
     18        * fast/forms/script-tests/ValidityState-rangeOverflow.js:
     19        * fast/forms/script-tests/ValidityState-rangeUnderflow.js:
     20        * fast/forms/script-tests/input-stepup-stepdown.js:
     21        * fast/forms/script-tests/validationMessage.js:
     22        * fast/forms/validationMessage-expected.txt:
     23
     24          Added test verifying that bug 16990 was fixed as well.
     25
     26        * fast/forms/range-input-dynamic-oninput-expected.txt: Added.
     27        * fast/forms/range-input-dynamic-oninput.html Added.
     28
     29          Improved test because handling of this case changed.
     30
     31        * fast/forms/range-reset-expected.txt:
     32        * fast/forms/range-reset.html:
     33
    1342010-03-19  Darin Fisher  <darin@chromium.org>
    235
  • trunk/LayoutTests/fast/forms/ValidityState-rangeOverflow-expected.txt

    r54271 r56242  
    7474PASS The value "101" overflows the maximum value "100".
    7575
    76 Type=range
    77 PASS The value "99" doesn't overflow the maximum value "100".
    78 PASS The value "-101" doesn't overflow the maximum value "-100".
    79 PASS The value "99" doesn't overflow the maximum value "1E+2".
    80 PASS The value "0.99" doesn't overflow the maximum value "1.00".
    81 PASS The value "abc" doesn't overflow the maximum value "100".
    82 PASS The value "" doesn't overflow the maximum value "-1".
    83 PASS The value "0.999999999999999999999999999999999999999999" doesn't overflow the maximum value "0.999999999999999999999999999999999999999998".
    84 PASS The value "101" doesn't overflow the maximum value "100".
    85 PASS The value "101" overflows the maximum value "100".
    86 PASS The value "-99" overflows the maximum value "-100".
    87 PASS The value "101" overflows the maximum value "1E+2".
    88 PASS The value "101" overflows the maximum value "".
    89 PASS The value "101" overflows the maximum value "xxx".
    90 
    9176Type=time
    9277PASS The value "13:16" doesn't overflow the maximum value "".
  • trunk/LayoutTests/fast/forms/ValidityState-rangeUnderflow-expected.txt

    r54271 r56242  
    7474PASS The value "101" undeflows the minimum value "200".
    7575
    76 Type=range
    77 PASS The value "101" doesn't underflow the minimum value "100".
    78 PASS The value "-99" doesn't underflow the minimum value "-100".
    79 PASS The value "101" doesn't underflow the minimum value "1E+2".
    80 PASS The value "1.01" doesn't underflow the minimum value "1.00".
    81 PASS The value "abc" doesn't underflow the minimum value "100".
    82 PASS The value "" doesn't underflow the minimum value "1".
    83 PASS The value "0.999999999999999999999999999999999999999998" doesn't underflow the minimum value "0.999999999999999999999999999999999999999999".
    84 PASS The value "101" doesn't underflow the minimum value "100".
    85 PASS The value "99" undeflows the minimum value "100".
    86 PASS The value "-101" undeflows the minimum value "-100".
    87 PASS The value "99" undeflows the minimum value "1E+2".
    88 PASS The value "-1" undeflows the minimum value "".
    89 PASS The value "-1" undeflows the minimum value "xxx".
    90 
    9176Type=time
    9277PASS The value "13:16" doesn't underflow the minimum value "".
  • trunk/LayoutTests/fast/forms/input-stepup-stepdown-expected.txt

    r55423 r56242  
    168168
    169169Range type
    170 Invalid value
    171 PASS stepUp("", null, null) threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
    172 PASS stepDown("", null, null) threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
    173 Non-number arguments
    174 PASS stepUp("0", null, null, "0") is "0"
    175 PASS stepDown("0", null, null, "0") is "0"
    176 PASS stepUp("0", null, null, "foo") is "0"
    177 PASS stepDown("0", null, null, "foo") is "0"
    178 PASS stepUp("0", null, null, null) is "0"
    179 PASS stepDown("0", null, null, null) is "0"
    180 Normal cases
    181 PASS stepUp("0", null, null) is "1"
    182 PASS stepUp("1", null, null, 2) is "3"
    183 PASS stepUp("3", null, null, -1) is "2"
    184 PASS stepDown("2", null, "-100") is "1"
    185 PASS stepDown("1", null, "-100", 2) is "-1"
    186 PASS stepDown("-1", null, "-100", -1) is "0"
     170function arguments are (min, max, step, value, [stepCount])
     171Using the default values
     172PASS stepUpExplicitBounds(null, null, null, "") is "51"
     173PASS stepDownExplicitBounds(null, null, null, "") is "49"
     174Non-number arguments (stepCount)
     175PASS stepUpExplicitBounds(null, null, null, "0", "0") is "0"
     176PASS stepDownExplicitBounds(null, null, null, "0", "0") is "0"
     177PASS stepUpExplicitBounds(null, null, null, "0", "foo") is "0"
     178PASS stepDownExplicitBounds(null, null, null, "0", "foo") is "0"
     179PASS stepUpExplicitBounds(null, null, null, "0", null) is "0"
     180PASS stepDownExplicitBounds(null, null, null, "0", null) is "0"
     181Normal cases
     182PASS stepUpExplicitBounds(null, null, null, "0") is "1"
     183PASS stepUpExplicitBounds(null, null, null, "1", 2) is "3"
     184PASS stepUpExplicitBounds(null, null, null, "3", -1) is "2"
     185PASS stepDownExplicitBounds("-100", null, null, "2") is "1"
     186PASS stepDownExplicitBounds("-100", null, null, "1", 2) is "-1"
     187PASS stepDownExplicitBounds("-100", null, null, "-1", -1) is "0"
    187188Extra arguments
    188 PASS input.value = "0"; input.min = null; input.step = null; input.stepUp(1, 2); input.value is "1"
    189 PASS input.value = "1"; input.stepDown(1, 3); input.value is "0"
     189PASS setInputAttributes(null, null, null, "0"); input.stepUp(1,2); input.value is "1"
     190PASS setInputAttributes(null, null, null, "1"); input.stepDown(1,3); input.value is "0"
    190191Invalid step value
    191 PASS stepUp("0", "foo", null) is "1"
    192 PASS stepUp("1", "0", null) is "2"
    193 PASS stepUp("2", "-1", null) is "3"
    194 Step=any
    195 PASS stepUp("0", "any", null) threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
    196 PASS stepDown("0", "any", null) threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
    197 Overflow/underflow
    198 PASS stepDown("1", "1", "0") is "0"
    199 PASS stepDown("0", "1", "0") threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
    200 PASS stepDown("1", "1", "0", 2) threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
     192PASS stepUpExplicitBounds(null, null, "foo", "0") is "1"
     193PASS stepUpExplicitBounds(null, null, "0", "1") is "2"
     194PASS stepUpExplicitBounds(null, null, "-1", "2") is "3"
     195PASS stepDownExplicitBounds(null, null, "foo", "1") is "0"
     196PASS stepDownExplicitBounds(null, null, "0", "2") is "1"
     197PASS stepDownExplicitBounds(null, null, "-1", "3") is "2"
     198Step=any
     199PASS stepUpExplicitBounds(null, null, "any", "1") threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
     200PASS stepDownExplicitBounds(null, null, "any", "1") threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
     201Overflow/underflow
     202PASS stepUpExplicitBounds(null, "100", "1", "99") is "100"
     203PASS stepUpExplicitBounds(null, "100", "1", "100") threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
     204PASS input.value is "100"
     205PASS stepUpExplicitBounds(null, "100", "1", "99", "2") threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
     206PASS input.value is "99"
     207PASS stepDownExplicitBounds("0", null, "1", "1") is "0"
     208PASS stepDownExplicitBounds("0", null, "1", "0") threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
     209PASS input.value is "0"
     210PASS stepDownExplicitBounds("0", null, "1", "1", "2") threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
    201211PASS input.value is "1"
    202 PASS stepDown("1", "1.7976931348623156e+308", "", 2) threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
    203 PASS input.min = "-100"; stepUp("-1", "1", "0") is "0"
    204 PASS stepUp("0", "1", "0") threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
    205 PASS input.min = "-100"; stepUp("-1", "1", "0", 2) threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
     212PASS stepDownExplicitBounds(null, null, "1.7976931348623156e+308", "1", "2") threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
     213PASS stepUpExplicitBounds(-100, 0, 1, -1) is "0"
     214PASS stepUpExplicitBounds(null, 0, 1, 0) threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
     215PASS stepUpExplicitBounds(-100, 0, 1, -1, 2) threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
    206216PASS input.value is "-1"
    207 PASS stepUp("1", "1.7976931348623156e+308", "", 2) threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
     217PASS stepUpExplicitBounds(null, null, "1.7976931348623156e+308", "1", "2") threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
    208218stepDown()/stepUp() for stepMismatch values
    209 PASS stepUp("1", "2", "") is "4"
     219PASS stepUpExplicitBounds(null, null, 2, 1) is "4"
    210220PASS input.stepDown(); input.value is "2"
    211 PASS input.min = "0"; stepUp("9", "10", "", 9) is "100"
    212 PASS stepDown("19", "10", "0") is "10"
    213 PASS stepUp("89", "10", "99") threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
     221PASS stepUpExplicitBounds(0, null, 10, 9, 9) is "100"
     222PASS stepDownExplicitBounds(0, null, 10, 19) is "10"
     223value + step is <= max, but rounded result would be > max.
     224PASS stepUpExplicitBounds(null, 99, 10, 89) threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
    214225Huge value and small step
    215 PASS input.min = "0"; stepUp("1e+308", "1", "1e+308", 999999) is "1e+308"
    216 PASS input.max = "1e+308"; input.min = "0"; input.step = "1"; input.value = "1e+308"; input.stepDown(999999); input.value is "1e+308"
     226PASS stepUpExplicitBounds(0, 1e308, 1, 1e308, 999999) is "1e+308"
     227PASS stepDownExplicitBounds(0, 1e308, 1, 1e308, 999999) is "1e+308"
    217228Fractional numbers
    218 PASS input.min = ""; stepUp("0", "0.33333333333333333", "", 3) is "1"
    219 PASS stepUp("1", "0.1", "", 10) is "2"
     229PASS stepUpExplicitBounds(null, null, 0.33333333333333333, 0, 3) is "1"
     230PASS stepUpExplicitBounds(null, null, 0.1, 1) is "1.1"
     231PASS stepUpExplicitBounds(null, null, 0.1, 1, 8) is "1.8"
     232PASS stepUpExplicitBounds(null, null, 0.1, 1, 10) is "2"
    220233PASS input.stepUp(); input.stepUp(); input.stepUp(); input.stepUp(); input.stepUp(); input.stepUp(); input.stepUp(); input.stepUp(); input.stepUp(); input.stepUp(); input.value is "3"
    221 PASS input.min = "0"; stepUp("0", "0.003921568627450980", "1", 255) is "1"
     234PASS stepUpExplicitBounds(0, 1, 0.003921568627450980, 0, 255) is "1"
    222235PASS for (var i = 0; i < 255; i++) { input.stepDown(); }; input.value is "0"
     236PASS stepDownExplicitBounds(null, null, 0.1, 1, 8) is "0.2"
     237PASS stepDownExplicitBounds(null, null, 0.1, 1) is "0.9"
    223238
    224239Time type
  • trunk/LayoutTests/fast/forms/range-reset-expected.txt

    r25701 r56242  
    44
    55
    6 
     6 
     7Slider with explicit limits
    78Current value is: "30"
    89PASS slider.value is "80"
    910Resetting form
    1011PASS slider.value is "30"
     12
     13Slider with default limits, and no explicit value
     14Current value is: "50"
     15PASS slider.value is "80"
     16Resetting form
     17PASS slider.value is "50"
     18
     19Slider with default limits, and a step value
     20Current value is: "60"
     21PASS slider.value is "80"
     22Resetting form
     23PASS slider.value is "60"
     24
    1125PASS successfullyParsed is true
    1226
  • trunk/LayoutTests/fast/forms/range-reset.html

    r25701 r56242  
    77<form>
    88<input id="slider" type="range" min="0" max="100" value="30">
     9<input id="defaults" type="range">
     10<input id="step" type="range" step="20">
    911</form>
    1012<div id="console"></div>
     
    1719}
    1820
    19 var slider = document.getElementById("slider");
     21var slider; // Global needed for eval in shouldBe calls.
     22function testSliderReset(id)
     23{
     24    slider = document.getElementById(id);
     25    var originalValue = quoteNumber(slider.value);
     26    debug("Current value is: " + originalValue);
    2027
    21 var originalValue = quoteNumber(slider.value);
    22 debug("Current value is: " + originalValue);
     28    slider.value = 80;
     29    shouldBe("slider.value", quoteNumber(80));
    2330
    24 slider.value = 80;
    25 shouldBe("slider.value", quoteNumber(80));
     31    debug("Resetting form");
     32    document.forms[0].reset();
     33    shouldBe("slider.value", originalValue);
    2634
    27 debug("Resetting form");
    28 document.forms[0].reset();
    29 shouldBe("slider.value", originalValue);
     35    debug("");
     36}
     37
     38debug("Slider with explicit limits");
     39testSliderReset("slider");
     40
     41debug("Slider with default limits, and no explicit value");
     42testSliderReset("defaults");
     43
     44debug("Slider with default limits, and a step value");
     45testSliderReset("step");
    3046
    3147var successfullyParsed = true;
  • trunk/LayoutTests/fast/forms/script-tests/ValidityState-rangeOverflow.js

    r54271 r56242  
    145145// ----------------------------------------------------------------
    146146debug('');
    147 debug('Type=range');
    148 input.type = 'range';
    149 input.min = '';
    150 checkNotOverflow('99', '100');  // Very normal case.
    151 checkNotOverflow('-101', '-100');
    152 checkNotOverflow('99', '1E+2');
    153 checkNotOverflow('0.99', '1.00');
    154 checkNotOverflow('abc', '100');  // Invalid value.
    155 checkNotOverflow('', '-1');  // No value.
    156 // The following case should be rangeOverflow==true ideally.  But the "double" type doesn't have enough precision.
    157 checkNotOverflow('0.999999999999999999999999999999999999999999', '0.999999999999999999999999999999999999999998');
    158 input.min = '200';  // If min > max, max is reset to min.
    159 checkNotOverflow('101', '100');
    160 input.min = '';
    161 
    162 // Overflow cases
    163 checkOverflow('101', '100');
    164 input.min = '-200';
    165 checkOverflow('-99', '-100');
    166 input.min = '';
    167 checkOverflow('101', '1E+2');
    168 checkOverflow('101', '');  // No max.
    169 checkOverflow('101', 'xxx');  // Invalid max.
    170 
    171 // ----------------------------------------------------------------
    172 debug('');
    173147debug('Type=time');
    174148input.type = 'time';
  • trunk/LayoutTests/fast/forms/script-tests/ValidityState-rangeUnderflow.js

    r54271 r56242  
    155155// ----------------------------------------------------------------
    156156debug('');
    157 debug('Type=range');
    158 input.type = 'range';
    159 input.max = '';
    160 // No underflow cases
    161 checkNotUnderflow('101', '100');  // Very normal case.
    162 checkNotUnderflow('-99', '-100');
    163 checkNotUnderflow('101', '1E+2');
    164 checkNotUnderflow('1.01', '1.00');
    165 checkNotUnderflow('abc', '100');  // Invalid value.
    166 checkNotUnderflow('', '1');  // No value.
    167 // The following case should be rangeUnderflow==true ideally.  But the "double" type doesn't have enough precision.
    168 checkNotUnderflow('0.999999999999999999999999999999999999999998', '0.999999999999999999999999999999999999999999');
    169 input.max = '0';  // If min > max, max is reset to min and min is not changed.
    170 checkNotUnderflow('101', '100');
    171 input.max = '';
    172 
    173 // Underflow cases
    174 checkUnderflow('99', '100');
    175 checkUnderflow('-101', '-100');
    176 checkUnderflow('99', '1E+2');
    177 checkUnderflow('-1', '');  // No min.
    178 checkUnderflow('-1', 'xxx');  // Invalid min.
    179 
    180 // ----------------------------------------------------------------
    181 debug('');
    182157debug('Type=time');
    183158input.type = 'time';
  • trunk/LayoutTests/fast/forms/script-tests/input-stepup-stepdown.js

    r55423 r56242  
    44var invalidStateErr = '"Error: INVALID_STATE_ERR: DOM Exception 11"';
    55
     6function setInputAttributes(min, max, step, value) {
     7    input.min = min;
     8    input.max = max;
     9    input.step = step;
     10    input.value = value;
     11}
     12
    613function stepUp(value, step, max, optionalStepCount) {
    7     input.value = value;
    8     input.step = step;
    9     input.min = null;
    10     input.max = max;
     14    setInputAttributes(null, max, step, value);
    1115    if (typeof optionalStepCount != "undefined")
    1216        input.stepUp(optionalStepCount);
     
    1721
    1822function stepDown(value, step, min, optionalStepCount) {
    19     input.value = value;
    20     input.step = step;
    21     input.min = min;
    22     input.max = null;
     23    setInputAttributes(min, null, step, value);
    2324    if (typeof optionalStepCount != "undefined")
    2425        input.stepDown(optionalStepCount);
     26    else
     27        input.stepDown();
     28    return input.value;
     29}
     30
     31// Range value gets automatically shifted based on bounds,
     32// So always set the min and max first to get expected behavior
     33
     34function stepUpExplicitBounds(min, max, step, value, stepCount) {
     35    setInputAttributes(min, max, step, value);
     36    if (typeof stepCount !== 'undefined')
     37        input.stepUp(stepCount);
     38    else
     39        input.stepUp();
     40    return input.value;
     41}
     42
     43function stepDownExplicitBounds(min, max, step, value, stepCount) {
     44    setInputAttributes(min, max, step, value);
     45    if (typeof stepCount !== 'undefined')
     46        input.stepDown(stepCount);
    2547    else
    2648        input.stepDown();
     
    204226debug('Range type');
    205227input.type = 'range';
    206 debug('Invalid value');
    207 shouldThrow('stepUp("", null, null)', invalidStateErr);
    208 shouldThrow('stepDown("", null, null)', invalidStateErr);
    209 debug('Non-number arguments');
    210 shouldBe('stepUp("0", null, null, "0")', '"0"');
    211 shouldBe('stepDown("0", null, null, "0")', '"0"');
    212 shouldBe('stepUp("0", null, null, "foo")', '"0"');
    213 shouldBe('stepDown("0", null, null, "foo")', '"0"');
    214 shouldBe('stepUp("0", null, null, null)', '"0"');
    215 shouldBe('stepDown("0", null, null, null)', '"0"');
    216 debug('Normal cases');
    217 shouldBe('stepUp("0", null, null)', '"1"');
    218 shouldBe('stepUp("1", null, null, 2)', '"3"');
    219 shouldBe('stepUp("3", null, null, -1)', '"2"');
    220 shouldBe('stepDown("2", null, "-100")', '"1"');
    221 shouldBe('stepDown("1", null, "-100", 2)', '"-1"');
    222 shouldBe('stepDown("-1", null, "-100", -1)', '"0"');
     228debug('function arguments are (min, max, step, value, [stepCount])');
     229debug('Using the default values');
     230shouldBe('stepUpExplicitBounds(null, null, null, "")', '"51"');
     231shouldBe('stepDownExplicitBounds(null, null, null, "")', '"49"');
     232debug('Non-number arguments (stepCount)');
     233shouldBe('stepUpExplicitBounds(null, null, null, "0", "0")', '"0"');
     234shouldBe('stepDownExplicitBounds(null, null, null, "0", "0")', '"0"');
     235shouldBe('stepUpExplicitBounds(null, null, null, "0", "foo")', '"0"');
     236shouldBe('stepDownExplicitBounds(null, null, null, "0", "foo")', '"0"');
     237shouldBe('stepUpExplicitBounds(null, null, null, "0", null)', '"0"');
     238shouldBe('stepDownExplicitBounds(null, null, null, "0", null)', '"0"');
     239debug('Normal cases');
     240shouldBe('stepUpExplicitBounds(null, null, null, "0")', '"1"');
     241shouldBe('stepUpExplicitBounds(null, null, null, "1", 2)', '"3"');
     242shouldBe('stepUpExplicitBounds(null, null, null, "3", -1)', '"2"');
     243shouldBe('stepDownExplicitBounds("-100", null, null, "2")', '"1"');
     244shouldBe('stepDownExplicitBounds("-100", null, null, "1", 2)', '"-1"');
     245shouldBe('stepDownExplicitBounds("-100", null, null, "-1", -1)', '"0"');
    223246debug('Extra arguments');
    224 shouldBe('input.value = "0"; input.min = null; input.step = null; input.stepUp(1, 2); input.value', '"1"');
    225 shouldBe('input.value = "1"; input.stepDown(1, 3); input.value', '"0"');
     247shouldBe('setInputAttributes(null, null, null, "0"); input.stepUp(1,2); input.value', '"1"');
     248shouldBe('setInputAttributes(null, null, null, "1"); input.stepDown(1,3); input.value', '"0"');
    226249debug('Invalid step value');
    227 shouldBe('stepUp("0", "foo", null)', '"1"');
    228 shouldBe('stepUp("1", "0", null)', '"2"');
    229 shouldBe('stepUp("2", "-1", null)', '"3"');
    230 debug('Step=any');
    231 shouldThrow('stepUp("0", "any", null)', invalidStateErr);
    232 shouldThrow('stepDown("0", "any", null)', invalidStateErr);
    233 debug('Overflow/underflow');
    234 shouldBe('stepDown("1", "1", "0")', '"0"');
    235 shouldThrow('stepDown("0", "1", "0")', invalidStateErr);
    236 shouldThrow('stepDown("1", "1", "0", 2)', invalidStateErr);
     250shouldBe('stepUpExplicitBounds(null, null, "foo", "0")', '"1"');
     251shouldBe('stepUpExplicitBounds(null, null, "0", "1")', '"2"');
     252shouldBe('stepUpExplicitBounds(null, null, "-1", "2")', '"3"');
     253shouldBe('stepDownExplicitBounds(null, null, "foo", "1")', '"0"');
     254shouldBe('stepDownExplicitBounds(null, null, "0", "2")', '"1"');
     255shouldBe('stepDownExplicitBounds(null, null, "-1", "3")', '"2"');
     256debug('Step=any');
     257shouldThrow('stepUpExplicitBounds(null, null, "any", "1")', invalidStateErr);
     258shouldThrow('stepDownExplicitBounds(null, null, "any", "1")', invalidStateErr);
     259debug('Overflow/underflow');
     260shouldBe('stepUpExplicitBounds(null, "100", "1", "99")', '"100"');
     261shouldThrow('stepUpExplicitBounds(null, "100", "1", "100")', invalidStateErr);
     262shouldBe('input.value', '"100"');
     263shouldThrow('stepUpExplicitBounds(null, "100", "1", "99", "2")', invalidStateErr);
     264shouldBe('input.value', '"99"');
     265shouldBe('stepDownExplicitBounds("0", null, "1", "1")', '"0"');
     266shouldThrow('stepDownExplicitBounds("0", null, "1", "0")', invalidStateErr);
     267shouldBe('input.value', '"0"');
     268shouldThrow('stepDownExplicitBounds("0", null, "1", "1", "2")', invalidStateErr);
    237269shouldBe('input.value', '"1"');
    238 shouldThrow('stepDown("1", "1.7976931348623156e+308", "", 2)', invalidStateErr);
    239 shouldBe('input.min = "-100"; stepUp("-1", "1", "0")', '"0"');
    240 shouldThrow('stepUp("0", "1", "0")', invalidStateErr);
    241 shouldThrow('input.min = "-100"; stepUp("-1", "1", "0", 2)', invalidStateErr);
     270shouldThrow('stepDownExplicitBounds(null, null, "1.7976931348623156e+308", "1", "2")', invalidStateErr);
     271shouldBe('stepUpExplicitBounds(-100, 0, 1, -1)', '"0"');
     272shouldThrow('stepUpExplicitBounds(null, 0, 1, 0)', invalidStateErr);
     273shouldThrow('stepUpExplicitBounds(-100, 0, 1, -1, 2)', invalidStateErr);
    242274shouldBe('input.value', '"-1"');
    243 shouldThrow('stepUp("1", "1.7976931348623156e+308", "", 2)', invalidStateErr);
     275shouldThrow('stepUpExplicitBounds(null, null, "1.7976931348623156e+308", "1", "2")', invalidStateErr);
    244276debug('stepDown()/stepUp() for stepMismatch values');
    245 shouldBe('stepUp("1", "2", "")', '"4"');
     277shouldBe('stepUpExplicitBounds(null, null, 2, 1)', '"4"');
    246278shouldBe('input.stepDown(); input.value', '"2"');
    247 shouldBe('input.min = "0"; stepUp("9", "10", "", 9)', '"100"');
    248 shouldBe('stepDown("19", "10", "0")', '"10"');
    249 // value + step is <= max, but rounded result would be > max.
    250 shouldThrow('stepUp("89", "10", "99")', invalidStateErr);
     279shouldBe('stepUpExplicitBounds(0, null, 10, 9, 9)', '"100"');
     280shouldBe('stepDownExplicitBounds(0, null, 10, 19)', '"10"');
     281debug('value + step is <= max, but rounded result would be > max.');
     282shouldThrow('stepUpExplicitBounds(null, 99, 10, 89)', invalidStateErr);
    251283debug('Huge value and small step');
    252 shouldBe('input.min = "0"; stepUp("1e+308", "1", "1e+308", 999999)', '"1e+308"');
    253 shouldBe('input.max = "1e+308"; input.min = "0"; input.step = "1"; input.value = "1e+308"; input.stepDown(999999); input.value', '"1e+308"');
     284shouldBe('stepUpExplicitBounds(0, 1e308, 1, 1e308, 999999)', '"1e+308"');
     285shouldBe('stepDownExplicitBounds(0, 1e308, 1, 1e308, 999999)', '"1e+308"');
    254286debug('Fractional numbers');
    255 shouldBe('input.min = ""; stepUp("0", "0.33333333333333333", "", 3)', '"1"');
    256 shouldBe('stepUp("1", "0.1", "", 10)', '"2"');
     287shouldBe('stepUpExplicitBounds(null, null, 0.33333333333333333, 0, 3)', '"1"');
     288shouldBe('stepUpExplicitBounds(null, null, 0.1, 1)', '"1.1"');
     289shouldBe('stepUpExplicitBounds(null, null, 0.1, 1, 8)', '"1.8"');
     290shouldBe('stepUpExplicitBounds(null, null, 0.1, 1, 10)', '"2"');
    257291shouldBe('input.stepUp(); input.stepUp(); input.stepUp(); input.stepUp(); input.stepUp(); input.stepUp(); input.stepUp(); input.stepUp(); input.stepUp(); input.stepUp(); input.value', '"3"');
    258 shouldBe('input.min = "0"; stepUp("0", "0.003921568627450980", "1", 255)', '"1"');
     292shouldBe('stepUpExplicitBounds(0, 1, 0.003921568627450980, 0, 255)', '"1"');
    259293shouldBe('for (var i = 0; i < 255; i++) { input.stepDown(); }; input.value', '"0"');
     294shouldBe('stepDownExplicitBounds(null, null, 0.1, 1, 8)', '"0.2"');
     295shouldBe('stepDownExplicitBounds(null, null, 0.1, 1)', '"0.9"');
    260296
    261297debug('');
  • trunk/LayoutTests/fast/forms/script-tests/validationMessage.js

    r51172 r56242  
    3333shouldBe("emailInput.validationMessage", "'type mismatch'");
    3434
    35 // A "ranged" input for "range underflow" flag
    36 var underInput = document.createElement("input");
    37 underInput.name = "underInput";
    38 underInput.type = "range";
    39 underInput.min = "2";
    40 underInput.value = "1";
    41 form.appendChild(underInput);
    42 shouldBe("underInput.validationMessage", "'range underflow'");
    43 
    44 // A "ranged" input for "range overflow" flag
    45 var overInput = document.createElement("input");
    46 overInput.name = "overInput";
    47 overInput.type = "range";
    48 overInput.max = "2";
    49 overInput.value = "3";
    50 form.appendChild(overInput);
    51 shouldBe("overInput.validationMessage", "'range overflow'");
    52 
    5335// A button can't be valited and, thus, has a blank validationMessage
    5436var but = document.createElement("button");
  • trunk/LayoutTests/fast/forms/validationMessage-expected.txt

    r51172 r56242  
    88PASS requiredTextArea.validationMessage is 'value missing'
    99PASS emailInput.validationMessage is 'type mismatch'
    10 PASS underInput.validationMessage is 'range underflow'
    11 PASS overInput.validationMessage is 'range overflow'
    1210PASS but.validationMessage is ''
    1311PASS anoninput.validationMessage is ''
  • trunk/WebCore/ChangeLog

    r56241 r56242  
     12010-03-19  Joseph Pecoraro  <joepeck@webkit.org>
     2
     3        Reviewed by David Kilzer.
     4
     5        <input type=range> does not validate correctly without a renderer and the tests are incorrect
     6        https://bugs.webkit.org/show_bug.cgi?id=36259
     7
     8        Setting value attribute on an <input type=range> to an out-of-range value fires oninput
     9        https://bugs.webkit.org/show_bug.cgi?id=16990
     10
     11        Part 2 of 2: When setting the range element's value, overflows and underflows
     12        are automatically sanitized to valid values. Moved the general case
     13        sanitization code out of the Renderer into HTMLInputElement::sanitizeValue.
     14
     15        * html/HTMLInputElement.cpp:
     16        (WebCore::HTMLInputElement::value): when getting a default value on reset() ensure the defaultValue is provided
     17        (WebCore::HTMLInputElement::sanitizeValue): clamp the value within the max/min/step range constraints
     18        * html/StepRange.cpp:
     19        (WebCore::StepRange::StepRange): allow const element in the constructor
     20        (WebCore::StepRange::clampValue): clamp from a String value
     21        * html/StepRange.h:
     22        (WebCore::StepRange::defaultValue): easy calculation of the default value for max/min/step range constraints
     23        * rendering/RenderSlider.cpp:
     24        (WebCore::RenderSlider::updateFromElement): no longer handle the general case sanitization in the renderer
     25
    1262010-03-19  Joseph Pecoraro  <joepeck@webkit.org>
    227
  • trunk/WebCore/html/HTMLInputElement.cpp

    r56174 r56242  
    33 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
    44 *           (C) 2001 Dirk Mueller (mueller@kde.org)
    5  * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
     5 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
    66 *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
    77 * Copyright (C) 2007 Samuel Weinig (sam@webkit.org)
     
    6161#include "RenderTextControlSingleLine.h"
    6262#include "RenderTheme.h"
     63#include "StepRange.h"
    6364#include "StringHash.h"
    6465#include "TextEvent.h"
     
    310311    case MONTH:
    311312    case NUMBER:
    312     case RANGE:
    313313    case TIME:
    314314    case WEEK: {
     
    316316        return isfinite(doubleValue) && doubleValue < minimum();
    317317    }
     318    case RANGE: // Guaranteed by sanitization.
     319        ASSERT(parseToDouble(value(), nan) >= minimum());
    318320    case BUTTON:
    319321    case CHECKBOX:
     
    346348    case MONTH:
    347349    case NUMBER:
    348     case RANGE:
    349350    case TIME:
    350351    case WEEK: {
    351352        double doubleValue = parseToDouble(value(), nan);
    352         return isfinite(doubleValue) && doubleValue >  maximum();
    353     }
     353        return isfinite(doubleValue) && doubleValue > maximum();
     354    }
     355    case RANGE: // Guaranteed by sanitization.
     356        ASSERT(parseToDouble(value(), nan) <= maximum());
    354357    case BUTTON:
    355358    case CHECKBOX:
     
    504507    case RANGE:
    505508        // stepMismatch doesn't occur for RANGE. RenderSlider guarantees the
    506         // value matches to step.
     509        // value matches to step on user input, and sanitation takes care
     510        // of the general case.
    507511        return false;
    508512    case NUMBER: {
     
    14831487    if (value.isNull()) {
    14841488        value = sanitizeValue(getAttribute(valueAttr));
    1485 
    1486         // If no attribute exists, then just use "on" or "" based off the checked() state of the control.
    1487         if (value.isNull() && (inputType() == CHECKBOX || inputType() == RADIO))
    1488             return checked() ? "on" : "";
     1489       
     1490        // If no attribute exists, extra handling may be necessary.
     1491        // For Checkbox Types just use "on" or "" based off the checked() state of the control.
     1492        // For a Range Input use the calculated default value.
     1493        if (value.isNull()) {
     1494            if (inputType() == CHECKBOX || inputType() == RADIO)
     1495                return checked() ? "on" : "";
     1496            else if (inputType() == RANGE)
     1497                return serializeForNumberType(StepRange(this).defaultValue());
     1498        }
    14891499    }
    14901500
     
    24932503    if (isTextField())
    24942504        return InputElement::sanitizeValue(this, proposedValue);
     2505
     2506    // If the proposedValue is null than this is a reset scenario and we
     2507    // want the range input's value attribute to take priority over the
     2508    // calculated default (middle) value.
     2509    if (inputType() == RANGE && !proposedValue.isNull())
     2510        return serializeForNumberType(StepRange(this).clampValue(proposedValue));
     2511
    24952512    return proposedValue;
    24962513}
  • trunk/WebCore/html/StepRange.cpp

    r56241 r56242  
    2424#include "HTMLInputElement.h"
    2525#include "HTMLNames.h"
     26#include "PlatformString.h"
    2627#include <wtf/MathExtras.h>
    2728
     
    3233using namespace HTMLNames;
    3334
    34 StepRange::StepRange(HTMLInputElement* element)
     35StepRange::StepRange(const HTMLInputElement* element)
    3536{
    3637    if (element->hasAttribute(precisionAttr)) {
     
    5859}
    5960
     61double StepRange::clampValue(const String& stringValue)
     62{
     63    double value;
     64    bool parseSuccess = HTMLInputElement::parseToDoubleForNumberType(stringValue, &value);
     65    if (!parseSuccess)
     66        value = (minimum + maximum) / 2;
     67    return clampValue(value);
     68}
     69
    6070double StepRange::valueFromElement(HTMLInputElement* element, bool* wasClamped)
    6171{
  • trunk/WebCore/html/StepRange.h

    r56241 r56242  
    2727
    2828class HTMLInputElement;
     29class String;
    2930
    3031class StepRange : public Noncopyable {
     
    3536    double maximum; // maximum must be >= minimum.
    3637
    37     explicit StepRange(HTMLInputElement*);
     38    explicit StepRange(const HTMLInputElement*);
    3839    double clampValue(double value);
     40    double clampValue(const String& stringValue);
     41
     42    // Clamp the middle value according to the step
     43    double defaultValue()
     44    {
     45        return clampValue((minimum + maximum) / 2);
     46    }
    3947
    4048    // Map value into 0-1 range
  • trunk/WebCore/rendering/RenderSlider.cpp

    r56241 r56242  
    304304void RenderSlider::updateFromElement()
    305305{
    306     HTMLInputElement* element = static_cast<HTMLInputElement*>(node());
    307 
    308     // Send the value back to the element if the range changes it.
    309     StepRange range(element);
    310     bool clamped;
    311     double value = range.valueFromElement(element, &clamped);
    312     if (clamped)
    313         element->setValueFromRenderer(HTMLInputElement::serializeForNumberType(value));
    314 
    315306    // Layout will take care of the thumb's size and position.
    316307    if (!m_thumb) {
Note: See TracChangeset for help on using the changeset viewer.