Changeset 119948 in webkit


Ignore:
Timestamp:
Jun 10, 2012 7:30:39 PM (12 years ago)
Author:
yosin@chromium.org
Message:

[Forms] Introduce Decimal behind the InputNumber type
https://bugs.webkit.org/show_bug.cgi?id=88383

Reviewed by Kent Tamura.

Source/WebCore:

This patch introduces decimal arithmetic for steppable input types,
e.g. date, datetime, number, range, and so on, to avoid rounding error
caused by base 2 floating point representation, e.g. C/C++ double type.

Most of decimal arithmetic calculations are implemented in StepRange
class, replacing "double" with "Decimal", InputType::applyStep, and
InputType::stepFromRenderer.

Changes introduced by this patch are still intermediate state.
Following patch will replace InputNumber type to Decimal type for
completion of introducing decimal arithmetic.

Test: fast/forms/range/range-value-rounding.html

  • html/BaseDateAndTimeInputType.cpp:

(WebCore::BaseDateAndTimeInputType::serialize): Changed for Decimal type.
(WebCore::BaseDateAndTimeInputType::serializeWithComponents): ditto.

  • html/DateInputType.cpp:

(WebCore::DateInputType::createStepRange): Replaced NumberWithDecimalPlaces to InputNumber.

  • html/DateTimeInputType.cpp:

(WebCore::DateTimeInputType::createStepRange): Replaced NumberWithDecimalPlaces to InputNumber.

  • html/DateTimeLocalInputType.cpp:

(WebCore::DateTimeLocalInputType::createStepRange): Replaced NumberWithDecimalPlaces to InputNumber.

  • html/InputType.cpp:

(WebCore::InputType::rangeUnderflow): Changed for Decimal type.
(WebCore::InputType::rangeOverflow): Changed for Decimal type.
(WebCore::InputType::minimum): Changed for Decimal type.
(WebCore::InputType::maximum): ditto.
(WebCore::InputType::isInRange): ditto.
(WebCore::InputType::isOutOfRange): ditto.
(WebCore::InputType::stepMismatch): ditto.
(WebCore::InputType::validationMessage): ditto.
(WebCore::InputType::parseToNumberOrNaN): ditto.
(WebCore::InputType::applyStep): ditto.
(WebCore::InputType::stepUpFromRenderer): ditto.

  • html/InputType.h:

(InputType): Removed parseToNumberWIthDecimaplPlaces.

  • html/MonthInputType.cpp:

(WebCore::MonthInputType::createStepRange): Changed for Decimal type.

  • html/NumberInputType.cpp:

(WebCore::RealNumberRenderSize): Added for calculateRenderSize.
(WebCore::calculateRenderSize): Added. This function replacess lengthBeforeDecimalPoint.
(WebCore::NumberInputType::createStepRange): Changed for Decimal type.
(WebCore::NumberInputType::sizeShouldIncludeDecoration): Changed to use calculateRenderSize.
(WebCore::NumberInputType::parseToNumber): Changed for Decimal type.
(WebCore::NumberInputType::serialize): ditto.

  • html/NumberInputType.h:

(NumberInputType): Removed parseToNumberWIthDecimaplPlaces.

  • html/RangeInputType.cpp:

(WebCore::RangeInputType::createStepRange): Changed for Decimal type.
(WebCore::RangeInputType::handleKeydownEvent): ditto.
(WebCore::RangeInputType::parseToNumber): ditto.
(WebCore::RangeInputType::serialize): ditto.

  • html/StepRange.cpp:

(WebCore::StepRange::StepRange): Removed decimal places and changed for Decimal type.
(WebCore::StepRange::acceptableError): Changed for Decimal type.
(WebCore::StepRange::alignValueForStep): ditto.
(WebCore::StepRange::clampValue): Changed for Decimal type and std::min/max.
(WebCore::StepRange::parseStep): Changed for Decimal type and removed NumberWithDecimalPlaces.
(WebCore::StepRange::stepMismatch): Changed for Decimal type.
(WebCore::convertDoubleToInputNumber): Changed to real implementation.
(WebCore::convertInputNumberToDouble): Changed to real implementation.

  • html/StepRange.h:

(InputNumber): Replacement of NumberWithDecimalPlaces.
(WebCore::StepRange::InputNumber::InputNumber):

  • html/TimeInputType.cpp:

(WebCore::TimeInputType::createStepRange): Changed for Decimal type.

  • html/WeekInputType.cpp:

(WebCore::WeekInputType::createStepRange): Changed for Decimal type.

  • html/parser/HTMLParserIdioms.cpp:

(WebCore::serializeForNumberType): Added Decimal version.
(WebCore::parseToDecimalForNumberType): Added.

  • html/parser/HTMLParserIdioms.h: Updated comments for parseToDoubleForNumberType.
  • html/shadow/SliderThumbElement.cpp:

(WebCore::sliderPosition): Changed for Decimal type.

LayoutTests:

  • fast/forms/range/range-value-rounding-expected.txt: Added.
  • fast/forms/range/range-value-rounding.html: Added.
Location:
trunk
Files:
2 added
19 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r119947 r119948  
     12012-06-10  Yoshifumi Inoue  <yosin@chromium.org>
     2
     3        [Forms] Introduce Decimal behind the InputNumber type
     4        https://bugs.webkit.org/show_bug.cgi?id=88383
     5
     6        Reviewed by Kent Tamura.
     7
     8        * fast/forms/range/range-value-rounding-expected.txt: Added.
     9        * fast/forms/range/range-value-rounding.html: Added.
     10
    1112012-06-10  Jason Liu  <jason.liu@torchmobile.com.cn>
    212
  • trunk/Source/WebCore/ChangeLog

    r119947 r119948  
     12012-06-10  Yoshifumi Inoue  <yosin@chromium.org>
     2
     3        [Forms] Introduce Decimal behind the InputNumber type
     4        https://bugs.webkit.org/show_bug.cgi?id=88383
     5
     6        Reviewed by Kent Tamura.
     7
     8        This patch introduces decimal arithmetic for steppable input types,
     9        e.g. date, datetime, number, range, and so on, to avoid rounding error
     10        caused by base 2 floating point representation, e.g. C/C++ double type.
     11
     12        Most of decimal arithmetic calculations are implemented in StepRange
     13        class, replacing "double" with "Decimal", InputType::applyStep, and
     14        InputType::stepFromRenderer.
     15
     16        Changes introduced by this patch are still intermediate state.
     17        Following patch will replace InputNumber type to Decimal type for
     18        completion of introducing decimal arithmetic.
     19
     20        Test: fast/forms/range/range-value-rounding.html
     21
     22        * html/BaseDateAndTimeInputType.cpp:
     23        (WebCore::BaseDateAndTimeInputType::serialize): Changed for Decimal type.
     24        (WebCore::BaseDateAndTimeInputType::serializeWithComponents): ditto.
     25        * html/DateInputType.cpp:
     26        (WebCore::DateInputType::createStepRange): Replaced NumberWithDecimalPlaces to InputNumber.
     27        * html/DateTimeInputType.cpp:
     28        (WebCore::DateTimeInputType::createStepRange): Replaced NumberWithDecimalPlaces to InputNumber.
     29        * html/DateTimeLocalInputType.cpp:
     30        (WebCore::DateTimeLocalInputType::createStepRange): Replaced NumberWithDecimalPlaces to InputNumber.
     31        * html/InputType.cpp:
     32        (WebCore::InputType::rangeUnderflow): Changed for Decimal type.
     33        (WebCore::InputType::rangeOverflow): Changed for Decimal type.
     34        (WebCore::InputType::minimum): Changed for Decimal type.
     35        (WebCore::InputType::maximum): ditto.
     36        (WebCore::InputType::isInRange): ditto.
     37        (WebCore::InputType::isOutOfRange): ditto.
     38        (WebCore::InputType::stepMismatch): ditto.
     39        (WebCore::InputType::validationMessage): ditto.
     40        (WebCore::InputType::parseToNumberOrNaN): ditto.
     41        (WebCore::InputType::applyStep): ditto.
     42        (WebCore::InputType::stepUpFromRenderer): ditto.
     43        * html/InputType.h:
     44        (InputType): Removed parseToNumberWIthDecimaplPlaces.
     45        * html/MonthInputType.cpp:
     46        (WebCore::MonthInputType::createStepRange): Changed for Decimal type.
     47        * html/NumberInputType.cpp:
     48        (WebCore::RealNumberRenderSize): Added for calculateRenderSize.
     49        (WebCore::calculateRenderSize): Added. This function replacess lengthBeforeDecimalPoint.
     50        (WebCore::NumberInputType::createStepRange): Changed for Decimal type.
     51        (WebCore::NumberInputType::sizeShouldIncludeDecoration): Changed to use calculateRenderSize.
     52        (WebCore::NumberInputType::parseToNumber): Changed for Decimal type.
     53        (WebCore::NumberInputType::serialize): ditto.
     54        * html/NumberInputType.h:
     55        (NumberInputType): Removed parseToNumberWIthDecimaplPlaces.
     56        * html/RangeInputType.cpp:
     57        (WebCore::RangeInputType::createStepRange): Changed for Decimal type.
     58        (WebCore::RangeInputType::handleKeydownEvent): ditto.
     59        (WebCore::RangeInputType::parseToNumber): ditto.
     60        (WebCore::RangeInputType::serialize): ditto.
     61        * html/StepRange.cpp:
     62        (WebCore::StepRange::StepRange): Removed decimal places and changed for Decimal type.
     63        (WebCore::StepRange::acceptableError): Changed for Decimal type.
     64        (WebCore::StepRange::alignValueForStep): ditto.
     65        (WebCore::StepRange::clampValue): Changed for Decimal type and std::min/max.
     66        (WebCore::StepRange::parseStep): Changed for Decimal type and removed NumberWithDecimalPlaces.
     67        (WebCore::StepRange::stepMismatch): Changed for Decimal type.
     68        (WebCore::convertDoubleToInputNumber): Changed to real implementation.
     69        (WebCore::convertInputNumberToDouble):  Changed to real implementation.
     70        * html/StepRange.h:
     71        (InputNumber): Replacement of NumberWithDecimalPlaces.
     72        (WebCore::StepRange::InputNumber::InputNumber):
     73        * html/TimeInputType.cpp:
     74        (WebCore::TimeInputType::createStepRange): Changed for Decimal type.
     75        * html/WeekInputType.cpp:
     76        (WebCore::WeekInputType::createStepRange): Changed for Decimal type.
     77        * html/parser/HTMLParserIdioms.cpp:
     78        (WebCore::serializeForNumberType): Added Decimal version.
     79        (WebCore::parseToDecimalForNumberType): Added.
     80        * html/parser/HTMLParserIdioms.h: Updated comments for parseToDoubleForNumberType.
     81        * html/shadow/SliderThumbElement.cpp:
     82        (WebCore::sliderPosition): Changed for Decimal type.
     83
    1842012-06-10  Jason Liu  <jason.liu@torchmobile.com.cn>
    285
  • trunk/Source/WebCore/html/BaseDateAndTimeInputType.cpp

    r119580 r119948  
    137137String BaseDateAndTimeInputType::serialize(const InputNumber& value) const
    138138{
    139     if (!isfinite(value))
     139    if (!value.isFinite())
    140140        return String();
    141141    DateComponents date;
     
    150150    if (!element()->getAllowedValueStep(&step))
    151151        return date.toString();
    152     if (!fmod(step, msecPerMinute))
     152    if (step.remainder(msecPerMinute).isZero())
    153153        return date.toString(DateComponents::None);
    154     if (!fmod(step, msecPerSecond))
     154    if (step.remainder(msecPerSecond).isZero())
    155155        return date.toString(DateComponents::Second);
    156156    return date.toString(DateComponents::Millisecond);
  • trunk/Source/WebCore/html/DateInputType.cpp

    r119809 r119948  
    7777    const InputNumber minimum = parseToNumber(element()->fastGetAttribute(minAttr), convertDoubleToInputNumber(DateComponents::minimumDate()));
    7878    const InputNumber maximum = parseToNumber(element()->fastGetAttribute(maxAttr), convertDoubleToInputNumber(DateComponents::maximumDate()));
    79     const StepRange::NumberWithDecimalPlaces step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
     79    const InputNumber step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
    8080    return StepRange(stepBase, minimum, maximum, step, stepDescription);
    8181}
  • trunk/Source/WebCore/html/DateTimeInputType.cpp

    r119809 r119948  
    7575    const InputNumber minimum = parseToNumber(element()->fastGetAttribute(minAttr), convertDoubleToInputNumber(DateComponents::minimumDateTime()));
    7676    const InputNumber maximum = parseToNumber(element()->fastGetAttribute(maxAttr), convertDoubleToInputNumber(DateComponents::maximumDateTime()));
    77     const StepRange::NumberWithDecimalPlaces step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
     77    const InputNumber step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
    7878    return StepRange(stepBase, minimum, maximum, step, stepDescription);
    7979}
  • trunk/Source/WebCore/html/DateTimeLocalInputType.cpp

    r119809 r119948  
    8181    const InputNumber minimum = parseToNumber(element()->fastGetAttribute(minAttr), convertDoubleToInputNumber(DateComponents::minimumDateTime()));
    8282    const InputNumber maximum = parseToNumber(element()->fastGetAttribute(maxAttr), convertDoubleToInputNumber(DateComponents::maximumDateTime()));
    83     const StepRange::NumberWithDecimalPlaces step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
     83    const InputNumber step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
    8484    return StepRange(stepBase, minimum, maximum, step, stepDescription);
    8585}
  • trunk/Source/WebCore/html/InputType.cpp

    r119580 r119948  
    258258
    259259    const InputNumber numericValue = parseToNumberOrNaN(value);
    260     if (isnan(numericValue))
     260    if (!numericValue.isFinite())
    261261        return false;
    262262
     
    270270
    271271    const InputNumber numericValue = parseToNumberOrNaN(value);
    272     if (isnan(numericValue))
     272    if (!numericValue.isFinite())
    273273        return false;
    274274
     
    303303
    304304    const InputNumber numericValue = parseToNumberOrNaN(value);
    305     if (isnan(numericValue))
     305    if (!numericValue.isFinite())
    306306        return true;
    307307
     
    316316
    317317    const InputNumber numericValue = parseToNumberOrNaN(value);
    318     if (isnan(numericValue))
     318    if (!numericValue.isFinite())
    319319        return true;
    320320
     
    329329
    330330    const InputNumber numericValue = parseToNumberOrNaN(value);
    331     if (isnan(numericValue))
     331    if (!numericValue.isFinite())
    332332        return false;
    333333
     
    367367
    368368    const InputNumber numericValue = parseToNumberOrNaN(value);
    369     if (isnan(numericValue))
     369    if (!numericValue.isFinite())
    370370        return emptyString();
    371371
     
    467467InputNumber InputType::parseToNumberOrNaN(const String& string) const
    468468{
    469     return parseToNumber(string, numeric_limits<InputNumber>::quiet_NaN());
    470 }
    471 
    472 InputNumber InputType::parseToNumberWithDecimalPlaces(const String& src, const InputNumber& defaultValue, unsigned *decimalPlaces) const
    473 {
    474     if (decimalPlaces)
    475         *decimalPlaces = 0;
    476     return parseToNumber(src, defaultValue);
     469    return parseToNumber(string, Decimal::nan());
    477470}
    478471
     
    887880    }
    888881
    889     const double nan = numeric_limits<double>::quiet_NaN();
    890     unsigned currentDecimalPlaces;
    891     const InputNumber current = parseToNumberWithDecimalPlaces(element()->value(), nan, &currentDecimalPlaces);
    892     if (!isfinite(current)) {
     882    const InputNumber current = parseToNumberOrNaN(element()->value());
     883    if (!current.isFinite()) {
    893884        ec = INVALID_STATE_ERR;
    894885        return;
    895886    }
    896887    InputNumber newValue = current + stepRange.step() * count;
    897     if (isinf(newValue)) {
     888    if (!newValue.isFinite()) {
    898889        ec = INVALID_STATE_ERR;
    899890        return;
     
    910901    const AtomicString& stepString = element()->fastGetAttribute(stepAttr);
    911902    if (!equalIgnoringCase(stepString, "any"))
    912         newValue = stepRange.alignValueForStep(current, currentDecimalPlaces, newValue);
     903        newValue = stepRange.alignValueForStep(current, newValue);
    913904
    914905    if (newValue - stepRange.maximum() > acceptableErrorValue) {
     
    10101001    String currentStringValue = element()->value();
    10111002    InputNumber current = parseToNumberOrNaN(currentStringValue);
    1012     if (!isfinite(current)) {
     1003    if (!current.isFinite()) {
    10131004        ExceptionCode ec;
    10141005        current = defaultValueForStepUp();
     
    10261017        ExceptionCode ec;
    10271018        if (stepMismatch(element()->value())) {
    1028             ASSERT(step);
    1029             const InputNumber scale = pow(10.0, static_cast<InputNumber>(max(stepRange.stepDecimalPlaces(), stepRange.stepBaseDecimalPlaces())));
    1030             const InputNumber base = stepRange.stepBase();
    1031 
    1032             InputNumber newValue;
     1019            ASSERT(!step.isZero());
     1020            const Decimal base = stepRange.stepBase();
     1021            Decimal newValue;
    10331022            if (sign < 0)
    1034                 newValue = round((base + floor((current - base) / step) * step) * scale) / scale;
     1023                newValue = base + ((current - base) / step).floor() * step;
    10351024            else if (sign > 0)
    1036                 newValue = round((base + ceil((current - base) / step) * step) * scale) / scale;
     1025                newValue = base + ((current - base) / step).ceiling() * step;
    10371026            else
    10381027                newValue = current;
  • trunk/Source/WebCore/html/InputType.h

    r119540 r119948  
    267267    virtual InputNumber parseToNumber(const String&, const InputNumber& defaultValue) const;
    268268
    269     // Parses the specified string for the type as parseToNumber() does.
    270     // In addition, it stores the number of digits after the decimal point
    271     // into *decimalPlaces.
    272     virtual InputNumber parseToNumberWithDecimalPlaces(const String&, const InputNumber& defaultValue, unsigned* decimalPlaces) const;
    273 
    274269    // Parses the specified string for this InputType, and returns true if it
    275270    // is successfully parsed. An instance pointed by the DateComponents*
  • trunk/Source/WebCore/html/MonthInputType.cpp

    r119809 r119948  
    105105    const InputNumber minimum = parseToNumber(element()->fastGetAttribute(minAttr), convertDoubleToInputNumber(DateComponents::minimumMonth()));
    106106    const InputNumber maximum = parseToNumber(element()->fastGetAttribute(maxAttr), convertDoubleToInputNumber(DateComponents::maximumMonth()));
    107     const StepRange::NumberWithDecimalPlaces step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
     107    const InputNumber step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
    108108    return StepRange(stepBase, minimum, maximum, step, stepDescription);
    109109}
  • trunk/Source/WebCore/html/NumberInputType.cpp

    r119809 r119948  
    5555static const int numberStepScaleFactor = 1;
    5656
    57 static unsigned lengthBeforeDecimalPoint(double value)
    58 {
    59     // If value is negative, '-' should be counted.
    60 
    61     double absoluteValue = fabs(value);
    62     if (absoluteValue < 1)
    63         return value < 0 ? 2 : 1;
    64 
    65     unsigned length = static_cast<unsigned>(log10(floor(absoluteValue))) + 1;
    66     if (value < 0)
    67         length += 1;
    68 
    69     return length;
     57struct RealNumberRenderSize
     58{
     59    unsigned sizeBeforeDecimalPoint;
     60    unsigned sizeAfteDecimalPoint;
     61
     62    RealNumberRenderSize(unsigned before, unsigned after)
     63        : sizeBeforeDecimalPoint(before)
     64        , sizeAfteDecimalPoint(after)
     65    {
     66    }
     67
     68    RealNumberRenderSize max(const RealNumberRenderSize& other) const
     69    {
     70        return RealNumberRenderSize(
     71            std::max(sizeBeforeDecimalPoint, other.sizeBeforeDecimalPoint),
     72            std::max(sizeAfteDecimalPoint, other.sizeAfteDecimalPoint));
     73    }
     74};
     75
     76static RealNumberRenderSize calculateRenderSize(const Decimal& value)
     77{
     78    ASSERT(value.isFinite());
     79    const unsigned sizeOfDigits = String::number(value.value().coefficient()).length();
     80    const unsigned sizeOfSign = value.isNegative() ? 1 : 0;
     81    const int exponent = value.exponent();
     82    if (exponent >= 0)
     83        return RealNumberRenderSize(sizeOfSign + sizeOfDigits, 0);
     84
     85    const int sizeBeforeDecimalPoint = exponent + sizeOfDigits;
     86    if (sizeBeforeDecimalPoint > 0) {
     87        // In case of "123.456"
     88        return RealNumberRenderSize(sizeOfSign + sizeBeforeDecimalPoint, sizeOfDigits - sizeBeforeDecimalPoint);
     89    }
     90
     91    // In case of "0.00012345"
     92    const unsigned sizeOfZero = 1;
     93    const unsigned numberOfZeroAfterDecimalPoint = -sizeBeforeDecimalPoint;
     94    return RealNumberRenderSize(sizeOfSign + sizeOfZero , numberOfZeroAfterDecimalPoint + sizeOfDigits);
    7095}
    7196
     
    129154{
    130155    DEFINE_STATIC_LOCAL(const StepRange::StepDescription, stepDescription, (numberDefaultStep, numberDefaultStepBase, numberStepScaleFactor));
    131 
    132     unsigned stepBaseDecimalPlaces;
    133     const InputNumber stepBaseValue = parseToNumberWithDecimalPlaces(element()->fastGetAttribute(minAttr), numberDefaultStepBase, &stepBaseDecimalPlaces);
    134     StepRange::NumberWithDecimalPlaces stepBase(stepBaseValue, min(stepBaseDecimalPlaces, 16u));
    135 
     156    const InputNumber stepBase = parseToDecimalForNumberType(element()->fastGetAttribute(minAttr), numberDefaultStepBase);
    136157    // FIXME: We should use numeric_limits<double>::max for number input type.
    137158    const InputNumber floatMax = convertDoubleToInputNumber(numeric_limits<float>::max());
    138159    const InputNumber minimum = parseToNumber(element()->fastGetAttribute(minAttr), -floatMax);
    139160    const InputNumber maximum = parseToNumber(element()->fastGetAttribute(maxAttr), floatMax);
    140     const StepRange::NumberWithDecimalPlaces step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
     161    const InputNumber step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
    141162    return StepRange(stepBase, minimum, maximum, step, stepDescription);
    142163}
     
    146167    preferredSize = defaultSize;
    147168
    148     unsigned minValueDecimalPlaces;
    149     String minValue = element()->fastGetAttribute(minAttr);
    150     double minValueDouble = parseToDoubleForNumberTypeWithDecimalPlaces(minValue, &minValueDecimalPlaces);
    151     if (!isfinite(minValueDouble))
     169    const String stepString = element()->fastGetAttribute(stepAttr);
     170    if (equalIgnoringCase(stepString, "any"))
    152171        return false;
    153172
    154     unsigned maxValueDecimalPlaces;
    155     String maxValue = element()->fastGetAttribute(maxAttr);
    156     double maxValueDouble = parseToDoubleForNumberTypeWithDecimalPlaces(maxValue, &maxValueDecimalPlaces);
    157     if (!isfinite(maxValueDouble))
     173    const Decimal minimum = parseToDecimalForNumberType(element()->fastGetAttribute(minAttr));
     174    if (!minimum.isFinite())
    158175        return false;
    159176
    160     if (maxValueDouble < minValueDouble) {
    161         maxValueDouble = minValueDouble;
    162         maxValueDecimalPlaces = minValueDecimalPlaces;
    163     }
    164 
    165     String stepValue = element()->fastGetAttribute(stepAttr);
    166     if (equalIgnoringCase(stepValue, "any"))
     177    const Decimal maximum = parseToDecimalForNumberType(element()->fastGetAttribute(maxAttr));
     178    if (!maximum.isFinite())
    167179        return false;
    168     unsigned stepValueDecimalPlaces;
    169     double stepValueDouble = parseToDoubleForNumberTypeWithDecimalPlaces(stepValue, &stepValueDecimalPlaces);
    170     if (!isfinite(stepValueDouble)) {
    171         stepValueDouble = 1;
    172         stepValueDecimalPlaces = 0;
    173     }
    174 
    175     unsigned length = lengthBeforeDecimalPoint(minValueDouble);
    176     length = max(length, lengthBeforeDecimalPoint(maxValueDouble));
    177     length = max(length, lengthBeforeDecimalPoint(stepValueDouble));
    178 
    179     unsigned lengthAfterDecimalPoint = minValueDecimalPlaces;
    180     lengthAfterDecimalPoint = max(lengthAfterDecimalPoint, maxValueDecimalPlaces);
    181     lengthAfterDecimalPoint = max(lengthAfterDecimalPoint, stepValueDecimalPlaces);
    182 
    183     // '.' should be counted if the value has decimal places.
    184     if (lengthAfterDecimalPoint > 0)
    185         length += lengthAfterDecimalPoint + 1;
    186 
    187     preferredSize = length;
     180
     181    const Decimal step = parseToDecimalForNumberType(stepString, 1);
     182    ASSERT(step.isFinite());
     183
     184    RealNumberRenderSize size = calculateRenderSize(minimum).max(calculateRenderSize(maximum).max(calculateRenderSize(step)));
     185
     186    preferredSize = size.sizeBeforeDecimalPoint + size.sizeAfteDecimalPoint + (size.sizeAfteDecimalPoint ? 1 : 0);
     187
    188188    return true;
    189189}
     
    208208InputNumber NumberInputType::parseToNumber(const String& src, const InputNumber& defaultValue) const
    209209{
    210     return convertDoubleToInputNumber(parseToDoubleForNumberType(src, defaultValue));
    211 }
    212 
    213 InputNumber NumberInputType::parseToNumberWithDecimalPlaces(const String& src, const InputNumber& defaultValue, unsigned *decimalPlaces) const
    214 {
    215     return convertDoubleToInputNumber(parseToDoubleForNumberTypeWithDecimalPlaces(src, decimalPlaces, defaultValue));
     210    return parseToDecimalForNumberType(src, defaultValue);
    216211}
    217212
    218213String NumberInputType::serialize(const InputNumber& value) const
    219214{
    220     if (!isfinite(value))
     215    if (!value.isFinite())
    221216        return String();
    222217    return serializeForNumberType(value);
  • trunk/Source/WebCore/html/NumberInputType.h

    r119540 r119948  
    5454    virtual void handleWheelEvent(WheelEvent*) OVERRIDE;
    5555    virtual InputNumber parseToNumber(const String&, const InputNumber&) const OVERRIDE;
    56     virtual InputNumber parseToNumberWithDecimalPlaces(const String&, const InputNumber&, unsigned*) const OVERRIDE;
    5756    virtual String serialize(const InputNumber&) const OVERRIDE;
    5857    virtual void handleBlurEvent() OVERRIDE;
  • trunk/Source/WebCore/html/RangeInputType.cpp

    r119809 r119948  
    105105    const AtomicString& precisionValue = element()->fastGetAttribute(precisionAttr);
    106106    if (!precisionValue.isNull()) {
    107         const StepRange::NumberWithDecimalPlaces step(equalIgnoringCase(precisionValue, "float") ? std::numeric_limits<double>::quiet_NaN() : 1);
     107        const InputNumber step = equalIgnoringCase(precisionValue, "float") ? Decimal::nan() : 1;
    108108        return StepRange(minimum, minimum, maximum, step, stepDescription);
    109109    }
    110110
    111     const StepRange::NumberWithDecimalPlaces step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
     111    const InputNumber step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
    112112    return StepRange(minimum, minimum, maximum, step, stepDescription);
    113113}
     
    143143
    144144    const InputNumber current = parseToNumberOrNaN(element()->value());
    145     ASSERT(isfinite(current));
     145    ASSERT(current.isFinite());
    146146
    147147    StepRange stepRange(createStepRange(RejectAny));
     
    216216InputNumber RangeInputType::parseToNumber(const String& src, const InputNumber& defaultValue) const
    217217{
    218     return convertDoubleToInputNumber(parseToDoubleForNumberType(src, defaultValue));
     218    return parseToDecimalForNumberType(src, defaultValue);
    219219}
    220220
    221221String RangeInputType::serialize(const InputNumber& value) const
    222222{
    223     if (!isfinite(value))
     223    if (!value.isFinite())
    224224        return String();
    225225    return serializeForNumberType(value);
  • trunk/Source/WebCore/html/StepRange.cpp

    r119809 r119948  
    3838    , m_step(1)
    3939    , m_stepBase(0)
    40     , m_stepBaseDecimalPlaces(0)
    41     , m_stepDecimalPlaces(0)
    4240    , m_hasStep(false)
    4341{
     
    5048    , m_stepBase(stepRange.m_stepBase)
    5149    , m_stepDescription(stepRange.m_stepDescription)
    52     , m_stepBaseDecimalPlaces(stepRange.m_stepBaseDecimalPlaces)
    53     , m_stepDecimalPlaces(stepRange.m_stepDecimalPlaces)
    5450    , m_hasStep(stepRange.m_hasStep)
    5551{
    5652}
    5753
    58 StepRange::StepRange(const NumberWithDecimalPlaces& stepBase, const InputNumber& minimum, const InputNumber& maximum, const NumberWithDecimalPlaces& step, const StepDescription& stepDescription)
     54StepRange::StepRange(const InputNumber& stepBase, const InputNumber& minimum, const InputNumber& maximum, const InputNumber& step, const StepDescription& stepDescription)
    5955    : m_maximum(maximum)
    6056    , m_minimum(minimum)
    61     , m_step(isfinite(step.value) ? step.value : 1)
    62     , m_stepBase(isfinite(stepBase.value) ? stepBase.value : 1)
     57    , m_step(step.isFinite() ? step : 1)
     58    , m_stepBase(stepBase.isFinite() ? stepBase : 1)
    6359    , m_stepDescription(stepDescription)
    64     , m_stepBaseDecimalPlaces(stepBase.decimalPlaces)
    65     , m_stepDecimalPlaces(step.decimalPlaces)
    66     , m_hasStep(isfinite(step.value))
     60    , m_hasStep(step.isFinite())
    6761{
    68     ASSERT(isfinite(m_maximum));
    69     ASSERT(isfinite(m_minimum));
    70     ASSERT(isfinite(m_step));
    71     ASSERT(isfinite(m_stepBase));
     62    ASSERT(m_maximum.isFinite());
     63    ASSERT(m_minimum.isFinite());
     64    ASSERT(m_step.isFinite());
     65    ASSERT(m_stepBase.isFinite());
    7266}
    7367
    7468InputNumber StepRange::acceptableError() const
    7569{
    76     return m_step / pow(2.0, FLT_MANT_DIG);
     70    // FIXME: We should use DBL_MANT_DIG instead of FLT_MANT_DIG regarding to HTML5 specification.
     71    DEFINE_STATIC_LOCAL(const Decimal, twoPowerOfFloatMantissaBits, (Decimal::Positive, 0, UINT64_C(1) << FLT_MANT_DIG));
     72    return m_step / twoPowerOfFloatMantissaBits;
    7773}
    7874
    79 InputNumber StepRange::alignValueForStep(const InputNumber& currentValue, unsigned currentDecimalPlaces, const InputNumber& proposedValue) const
     75InputNumber StepRange::alignValueForStep(const InputNumber& currentValue, const InputNumber& newValue) const
    8076{
    81     if (proposedValue >= pow(10.0, 21.0))
    82         return proposedValue;
     77    DEFINE_STATIC_LOCAL(const Decimal, tenPowerOf21, (Decimal::Positive, 21, 1));
     78    if (newValue >= tenPowerOf21)
     79        return newValue;
    8380
    84     InputNumber newValue = proposedValue;
    85     if (stepMismatch(currentValue)) {
    86         const InputNumber scale = pow(10.0, static_cast<InputNumber>(max(m_stepDecimalPlaces, currentDecimalPlaces)));
    87         newValue = round(newValue * scale) / scale;
    88     } else {
    89         const InputNumber scale = pow(10.0, static_cast<InputNumber>(max(m_stepDecimalPlaces, m_stepBaseDecimalPlaces)));
    90         newValue = round(roundByStep(newValue, m_stepBase) * scale) / scale;
    91     }
    92 
    93     return newValue;
     81    return stepMismatch(currentValue) ? newValue : roundByStep(newValue, m_stepBase);
    9482}
    9583
     
    10795}
    10896
    109 StepRange::NumberWithDecimalPlaces StepRange::parseStep(AnyStepHandling anyStepHandling, const StepDescription& stepDescription, const String& stepString)
     97InputNumber StepRange::parseStep(AnyStepHandling anyStepHandling, const StepDescription& stepDescription, const String& stepString)
    11098{
    11199    if (stepString.isEmpty())
    112         return NumberWithDecimalPlaces(stepDescription.defaultValue());
     100        return stepDescription.defaultValue();
    113101
    114102    if (equalIgnoringCase(stepString, "any")) {
    115103        switch (anyStepHandling) {
    116104        case RejectAny:
    117             return NumberWithDecimalPlaces(std::numeric_limits<double>::quiet_NaN());
     105            return Decimal::nan();
    118106        case AnyIsDefaultStep:
    119             return NumberWithDecimalPlaces(stepDescription.defaultValue());
     107            return stepDescription.defaultValue();
    120108        default:
    121109            ASSERT_NOT_REACHED();
     
    123111    }
    124112
    125     NumberWithDecimalPlaces step(0);
    126     step.value = parseToDoubleForNumberTypeWithDecimalPlaces(stepString, &step.decimalPlaces);
    127     if (!isfinite(step.value) || step.value <= 0.0)
    128         return NumberWithDecimalPlaces(stepDescription.defaultValue());
     113    Decimal step = parseToDecimalForNumberType(stepString);
     114    if (!step.isFinite() || step <= 0)
     115        return stepDescription.defaultValue();
    129116
    130117    switch (stepDescription.stepValueShouldBe) {
    131118    case StepValueShouldBeReal:
    132         step.value *= stepDescription.stepScaleFactor;
     119        step *= stepDescription.stepScaleFactor;
    133120        break;
    134121    case ParsedStepValueShouldBeInteger:
    135122        // For date, month, and week, the parsed value should be an integer for some types.
    136         step.value = max(round(step.value), 1.0);
    137         step.value *= stepDescription.stepScaleFactor;
     123        step = max(step.round(), Decimal(1));
     124        step *= stepDescription.stepScaleFactor;
    138125        break;
    139126    case ScaledStepValueShouldBeInteger:
    140127        // For datetime, datetime-local, time, the result should be an integer.
    141         step.value *= stepDescription.stepScaleFactor;
    142         step.value = max(round(step.value), 1.0);
     128        step *= stepDescription.stepScaleFactor;
     129        step = max(step.round(), Decimal(1));
    143130        break;
    144131    default:
     
    146133    }
    147134
    148     ASSERT(step.value > 0);
     135    ASSERT(step > 0);
    149136    return step;
    150137}
     
    152139InputNumber StepRange::roundByStep(const InputNumber& value, const InputNumber& base) const
    153140{
    154     return base + round((value - base) / m_step) * m_step;
     141    return base + ((value - base) / m_step).round() * m_step;
    155142}
    156143
     
    159146    if (!m_hasStep)
    160147        return false;
    161     if (!isfinite(valueForCheck))
     148    if (!valueForCheck.isFinite())
    162149        return false;
    163     const InputNumber value = fabs(valueForCheck - m_stepBase);
    164     if (isinf(value))
     150    const InputNumber value = (valueForCheck - m_stepBase).abs();
     151    if (!value.isFinite())
    165152        return false;
    166153    // InputNumber's fractional part size is DBL_MAN_DIG-bit. If the current value
    167154    // is greater than step*2^DBL_MANT_DIG, the following computation for
    168155    // remainder makes no sense.
    169     if (value / pow(2.0, DBL_MANT_DIG) > m_step)
     156    DEFINE_STATIC_LOCAL(const Decimal, twoPowerOfDoubleMantissaBits, (Decimal::Positive, 0, UINT64_C(1) << DBL_MANT_DIG));
     157    if (value / twoPowerOfDoubleMantissaBits > m_step)
    170158        return false;
    171159    // The computation follows HTML5 4.10.7.2.10 `The step attribute' :
    172160    // ... that number subtracted from the step base is not an integral multiple
    173161    // of the allowed value step, the element is suffering from a step mismatch.
    174     const InputNumber remainder = fabs(value - m_step * round(value / m_step));
     162    const InputNumber remainder = (value - m_step * (value / m_step).round()).abs();
    175163    // Accepts erros in lower fractional part which IEEE 754 single-precision
    176164    // can't represent.
  • trunk/Source/WebCore/html/StepRange.h

    r119809 r119948  
    2222#define StepRange_h
    2323
     24#include "Decimal.h"
    2425#include <wtf/Forward.h>
    2526#include <wtf/Noncopyable.h>
     
    3132enum AnyStepHandling { RejectAny, AnyIsDefaultStep };
    3233
    33 // FIXME: The type InputNumber will be replaced with Decimal.
    34 typedef double InputNumber;
     34// FIXME: We should rename InputNumber to Decimal in all places.
     35typedef Decimal InputNumber;
    3536
    3637inline InputNumber convertDoubleToInputNumber(double doubleValue)
    3738{
    38     return doubleValue;
     39    return Decimal::fromDouble(doubleValue);
    3940}
    4041
    4142inline double convertInputNumberToDouble(const InputNumber& numericValue)
    4243{
    43     return numericValue;
     44    return numericValue.toDouble();
    4445}
    4546
    4647class StepRange {
    4748public:
    48     struct NumberWithDecimalPlaces {
    49         unsigned decimalPlaces;
    50         InputNumber value;
    51 
    52         NumberWithDecimalPlaces(InputNumber value = 0, unsigned decimalPlaces = 0)
    53             : decimalPlaces(decimalPlaces)
    54             , value(value)
    55         {
    56         }
    57     };
    58 
    5949    enum StepValueShouldBe {
    6050        StepValueShouldBeReal,
     
    9383    StepRange();
    9484    StepRange(const StepRange&);
    95     StepRange(const NumberWithDecimalPlaces& stepBase, const InputNumber& minimum, const InputNumber& maximum, const NumberWithDecimalPlaces& step, const StepDescription&);
     85    StepRange(const InputNumber& stepBase, const InputNumber& minimum, const InputNumber& maximum, const InputNumber& step, const StepDescription&);
    9686    InputNumber acceptableError() const;
    97     InputNumber alignValueForStep(const InputNumber& currentValue, unsigned currentDecimalPlaces, const InputNumber& newValue) const;
     87    InputNumber alignValueForStep(const InputNumber& currentValue, const InputNumber& newValue) const;
    9888    InputNumber clampValue(const InputNumber& value) const;
    9989    bool hasStep() const { return m_hasStep; }
    10090    InputNumber maximum() const { return m_maximum; }
    10191    InputNumber minimum() const { return m_minimum; }
    102     static NumberWithDecimalPlaces parseStep(AnyStepHandling, const StepDescription&, const String&);
     92    static InputNumber parseStep(AnyStepHandling, const StepDescription&, const String&);
    10393    InputNumber step() const { return m_step; }
    10494    InputNumber stepBase() const { return m_stepBase; }
    105     unsigned stepBaseDecimalPlaces() const { return m_stepBaseDecimalPlaces; }
    106     unsigned stepDecimalPlaces() const { return m_stepDecimalPlaces; }
    10795    int stepScaleFactor() const { return m_stepDescription.stepScaleFactor; }
    10896    bool stepMismatch(const InputNumber&) const;
     
    138126    const InputNumber m_stepBase;
    139127    const StepDescription m_stepDescription;
    140     const unsigned m_stepBaseDecimalPlaces;
    141     const unsigned m_stepDecimalPlaces;
    142128    const bool m_hasStep;
    143129};
  • trunk/Source/WebCore/html/TimeInputType.cpp

    r119809 r119948  
    8787    const InputNumber minimum = parseToNumber(element()->fastGetAttribute(minAttr), convertDoubleToInputNumber(DateComponents::minimumTime()));
    8888    const InputNumber maximum = parseToNumber(element()->fastGetAttribute(maxAttr), convertDoubleToInputNumber(DateComponents::maximumTime()));
    89     const StepRange::NumberWithDecimalPlaces step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
     89    const InputNumber step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
    9090    return StepRange(stepBase, minimum, maximum, step, stepDescription);
    9191}
  • trunk/Source/WebCore/html/WeekInputType.cpp

    r119809 r119948  
    6969    const InputNumber minimum = parseToNumber(element()->fastGetAttribute(minAttr), convertDoubleToInputNumber(DateComponents::minimumWeek()));
    7070    const InputNumber maximum = parseToNumber(element()->fastGetAttribute(maxAttr), convertDoubleToInputNumber(DateComponents::maximumWeek()));
    71     const StepRange::NumberWithDecimalPlaces step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
     71    const InputNumber step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
    7272    return StepRange(stepBase, minimum, maximum, step, stepDescription);
    7373}
  • trunk/Source/WebCore/html/parser/HTMLParserIdioms.cpp

    r117929 r119948  
    2626#include "HTMLParserIdioms.h"
    2727
     28#include "Decimal.h"
    2829#include <limits>
    2930#include <wtf/MathExtras.h>
     
    5960}
    6061
     62String serializeForNumberType(const Decimal& number)
     63{
     64    if (number.isZero()) {
     65        // Decimal::toString appends exponent, e.g. "0e-18"
     66        return number.isNegative() ? "-0" : "0";
     67    }
     68    return number.toString();
     69}
     70
    6171String serializeForNumberType(double number)
    6272{
     
    6575    NumberToStringBuffer buffer;
    6676    return String(numberToString(number, buffer));
     77}
     78
     79Decimal parseToDecimalForNumberType(const String& string, const Decimal& fallbackValue)
     80{
     81    // See HTML5 2.5.4.3 `Real numbers.' and parseToDoubleForNumberType
     82
     83    // String::toDouble() accepts leading + and whitespace characters, which are not valid here.
     84    const UChar firstCharacter = string[0];
     85    if (firstCharacter != '-' && firstCharacter != '.' && !isASCIIDigit(firstCharacter))
     86        return fallbackValue;
     87
     88    const Decimal value = Decimal::fromString(string);
     89    if (!value.isFinite())
     90        return fallbackValue;
     91
     92    // Numbers are considered finite IEEE 754 single-precision floating point values.
     93    // See HTML5 2.5.4.3 `Real numbers.'
     94    // FIXME: We should use numeric_limits<double>::max for number input type.
     95    const Decimal floatMax = Decimal::fromDouble(std::numeric_limits<float>::max());
     96    if (value < -floatMax || value > floatMax)
     97        return fallbackValue;
     98
     99    // We return +0 for -0 case.
     100    return value.isZero() ? Decimal(0) : value;
     101}
     102
     103Decimal parseToDecimalForNumberType(const String& string)
     104{
     105    return parseToDecimalForNumberType(string, Decimal::nan());
    67106}
    68107
  • trunk/Source/WebCore/html/parser/HTMLParserIdioms.h

    r117929 r119948  
    3131namespace WebCore {
    3232
     33class Decimal;
     34
    3335// Space characters as defined by the HTML specification.
    3436bool isHTMLSpace(UChar);
     
    4042
    4143// An implementation of the HTML specification's algorithm to convert a number to a string for number and range types.
     44String serializeForNumberType(const Decimal&);
    4245String serializeForNumberType(double);
    4346
    44 // Convert the specified string to a double. If the conversion fails, the return value is false.
     47// Convert the specified string to a decimal/double. If the conversion fails, the return value is fallback value or NaN if not specified.
    4548// Leading or trailing illegal characters cause failure, as does passing an empty string.
    4649// The double* parameter may be 0 to check if the string can be parsed without getting the result.
     50Decimal parseToDecimalForNumberType(const String&);
     51Decimal parseToDecimalForNumberType(const String&, const Decimal& fallbackValue);
    4752double parseToDoubleForNumberType(const String&);
    4853double parseToDoubleForNumberType(const String&, double fallbackValue);
  • trunk/Source/WebCore/html/shadow/SliderThumbElement.cpp

    r119547 r119948  
    5555{
    5656    const StepRange stepRange(element->createStepRange(RejectAny));
    57     const double oldValue = parseToDoubleForNumberType(element->value(), stepRange.defaultValue());
     57    const InputNumber oldValue = parseToDecimalForNumberType(element->value(), stepRange.defaultValue());
    5858    return stepRange.proportionFromValue(stepRange.clampValue(oldValue));
    5959}
Note: See TracChangeset for help on using the changeset viewer.