Changeset 71622 in webkit


Ignore:
Timestamp:
Nov 9, 2010 4:26:45 AM (13 years ago)
Author:
commit-queue@webkit.org
Message:

2010-11-09 Dai Mikurube <dmikurube@google.com>

Reviewed by Kent Tamura.

Too precise serialization from floating point number to string for "number" input elements
https://bugs.webkit.org/show_bug.cgi?id=48308

  • fast/forms/input-stepup-stepdown-expected.txt:
  • fast/forms/script-tests/input-stepup-stepdown.js:

2010-11-09 Dai Mikurube <dmikurube@google.com>

Reviewed by Kent Tamura.

Too precise serialization from floating point number to string for "number" input elements
https://bugs.webkit.org/show_bug.cgi?id=48308

Modified to consider decimal places when handling step and base in applyStep().

  • html/HTMLInputElement.cpp: Considering decimal places of the given "step" attribtue. (WebCore::HTMLInputElement::getAllowedValueStep): (WebCore::HTMLInputElement::getAllowedValueStepWithDecimalPlaces): (WebCore::HTMLInputElement::applyStep):
  • html/HTMLInputElement.h:
  • html/InputType.cpp: Added virtual functions for decimal places and an acceptable error. (WebCore::InputType::stepBaseWithDecimalPlaces): (WebCore::InputType::acceptableError): (WebCore::InputType::parseToDoubleWithDecimalPlaces):
  • html/InputType.h:
  • html/NumberInputType.cpp: (WebCore::NumberInputType::stepMismatch): Using the virtual function acceptableError(). (WebCore::NumberInputType::stepBaseWithDecimalPlaces): Considering decimal places of the given "base" attribute. (WebCore::NumberInputType::parseToDoubleWithDecimalPlaces): (WebCore::NumberInputType::acceptableError): Concrete acceptableError() for the number type.
  • html/NumberInputType.h:
  • html/parser/HTMLParserIdioms.cpp: (WebCore::parseToDoubleForNumberTypeWithDecimalPlaces): Parsing numbers with decimal places.
  • html/parser/HTMLParserIdioms.h:
Location:
trunk
Files:
12 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r71621 r71622  
     12010-11-09  Dai Mikurube  <dmikurube@google.com>
     2
     3        Reviewed by Kent Tamura.
     4
     5        Too precise serialization from floating point number to string for "number" input elements
     6        https://bugs.webkit.org/show_bug.cgi?id=48308
     7
     8        * fast/forms/input-stepup-stepdown-expected.txt:
     9        * fast/forms/script-tests/input-stepup-stepdown.js:
     10
    1112010-11-09  Yuzo Fujishima  <yuzo@google.com>
    212
  • trunk/LayoutTests/fast/forms/input-stepup-stepdown-expected.txt

    r70549 r71622  
    166166PASS input.min = "0"; stepUp("0", "0.003921568627450980", "1", 255) is "1"
    167167PASS for (var i = 0; i < 255; i++) { input.stepDown(); }; input.value is "0"
     168Rounding
     169PASS stepUp("5.005", "0.005", "", 2) is "5.015"
     170PASS stepUp("5.005", "0.005", "", 11) is "5.06"
     171PASS stepUp("5.005", "0.005", "", 12) is "5.065"
     172PASS stepUpExplicitBounds("4", "9", "0.005", "5.005", 2) is "5.015"
     173PASS stepUpExplicitBounds("4", "9", "0.005", "5.005", 11) is "5.06"
     174PASS stepUpExplicitBounds("4", "9", "0.005", "5.005", 12) is "5.065"
    168175
    169176Range type
  • trunk/LayoutTests/fast/forms/script-tests/input-stepup-stepdown.js

    r70549 r71622  
    222222shouldBe('input.min = "0"; stepUp("0", "0.003921568627450980", "1", 255)', '"1"');
    223223shouldBe('for (var i = 0; i < 255; i++) { input.stepDown(); }; input.value', '"0"');
     224debug('Rounding');
     225shouldBe('stepUp("5.005", "0.005", "", 2)', '"5.015"');
     226shouldBe('stepUp("5.005", "0.005", "", 11)', '"5.06"');
     227shouldBe('stepUp("5.005", "0.005", "", 12)', '"5.065"');
     228shouldBe('stepUpExplicitBounds("4", "9", "0.005", "5.005", 2)', '"5.015"');
     229shouldBe('stepUpExplicitBounds("4", "9", "0.005", "5.005", 11)', '"5.06"');
     230shouldBe('stepUpExplicitBounds("4", "9", "0.005", "5.005", 12)', '"5.065"');
    224231
    225232debug('');
  • trunk/WebCore/ChangeLog

    r71621 r71622  
     12010-11-09  Dai Mikurube  <dmikurube@google.com>
     2
     3        Reviewed by Kent Tamura.
     4
     5        Too precise serialization from floating point number to string for "number" input elements
     6        https://bugs.webkit.org/show_bug.cgi?id=48308
     7
     8        Modified to consider decimal places when handling step and base in applyStep().
     9
     10        * html/HTMLInputElement.cpp: Considering decimal places of the given "step" attribtue.
     11        (WebCore::HTMLInputElement::getAllowedValueStep):
     12        (WebCore::HTMLInputElement::getAllowedValueStepWithDecimalPlaces):
     13        (WebCore::HTMLInputElement::applyStep):
     14        * html/HTMLInputElement.h:
     15        * html/InputType.cpp: Added virtual functions for decimal places and an acceptable error.
     16        (WebCore::InputType::stepBaseWithDecimalPlaces):
     17        (WebCore::InputType::acceptableError):
     18        (WebCore::InputType::parseToDoubleWithDecimalPlaces):
     19        * html/InputType.h:
     20        * html/NumberInputType.cpp:
     21        (WebCore::NumberInputType::stepMismatch): Using the virtual function acceptableError().
     22        (WebCore::NumberInputType::stepBaseWithDecimalPlaces): Considering decimal places of the given "base" attribute.
     23        (WebCore::NumberInputType::parseToDoubleWithDecimalPlaces):
     24        (WebCore::NumberInputType::acceptableError): Concrete acceptableError() for the number type.
     25        * html/NumberInputType.h:
     26        * html/parser/HTMLParserIdioms.cpp:
     27        (WebCore::parseToDoubleForNumberTypeWithDecimalPlaces): Parsing numbers with decimal places.
     28        * html/parser/HTMLParserIdioms.h:
     29
    1302010-11-09  Yuzo Fujishima  <yuzo@google.com>
    231
  • trunk/WebCore/html/HTMLInputElement.cpp

    r71479 r71622  
    254254bool HTMLInputElement::getAllowedValueStep(double* step) const
    255255{
     256    return getAllowedValueStepWithDecimalPlaces(step, 0);
     257}
     258
     259bool HTMLInputElement::getAllowedValueStepWithDecimalPlaces(double* step, unsigned* decimalPlaces) const
     260{
    256261    ASSERT(step);
    257262    double defaultStep = m_inputType->defaultStep();
     
    262267    if (stepString.isEmpty()) {
    263268        *step = defaultStep * stepScaleFactor;
     269        if (decimalPlaces)
     270            *decimalPlaces = 0;
    264271        return true;
    265272    }
     
    267274        return false;
    268275    double parsed;
    269     if (!parseToDoubleForNumberType(stepString, &parsed) || parsed <= 0.0) {
    270         *step = defaultStep * stepScaleFactor;
    271         return true;
     276    if (!decimalPlaces) {
     277        if (!parseToDoubleForNumberType(stepString, &parsed) || parsed <= 0.0) {
     278            *step = defaultStep * stepScaleFactor;
     279            return true;
     280        }
     281    } else {
     282        if (!parseToDoubleForNumberTypeWithDecimalPlaces(stepString, &parsed, decimalPlaces) || parsed <= 0.0) {
     283            *step = defaultStep * stepScaleFactor;
     284            *decimalPlaces = 0;
     285            return true;
     286        }
    272287    }
    273288    // For date, month, week, the parsed value should be an integer for some types.
     
    286301{
    287302    double step;
    288     if (!getAllowedValueStep(&step)) {
     303    unsigned stepDecimalPlaces;
     304    if (!getAllowedValueStepWithDecimalPlaces(&step, &stepDecimalPlaces)) {
    289305        ec = INVALID_STATE_ERR;
    290306        return;
     
    301317        return;
    302318    }
    303     if (newValue < m_inputType->minimum()) {
     319    double acceptableError = m_inputType->acceptableError(step);
     320    if (newValue - m_inputType->minimum() < -acceptableError) {
    304321        ec = INVALID_STATE_ERR;
    305322        return;
    306323    }
    307     double base = m_inputType->stepBase();
    308     newValue = base + round((newValue - base) / step) * step;
    309     if (newValue > m_inputType->maximum()) {
     324    if (newValue < m_inputType->minimum())
     325        newValue = m_inputType->minimum();
     326    unsigned baseDecimalPlaces;
     327    double base = m_inputType->stepBaseWithDecimalPlaces(&baseDecimalPlaces);
     328    baseDecimalPlaces = min(baseDecimalPlaces, 16u);
     329    if (newValue < pow(10.0, 21.0)) {
     330        double scale = pow(10.0, static_cast<double>(max(stepDecimalPlaces, baseDecimalPlaces)));
     331        newValue = round((base + round((newValue - base) / step) * step) * scale) / scale;
     332    }
     333    if (newValue - m_inputType->maximum() > acceptableError) {
    310334        ec = INVALID_STATE_ERR;
    311335        return;
    312336    }
     337    if (newValue > m_inputType->maximum())
     338        newValue = m_inputType->maximum();
    313339    setValueAsNumber(newValue, ec);
    314340}
  • trunk/WebCore/html/HTMLInputElement.h

    r70511 r71622  
    6666    // Returns false if there is no "allowed value step."
    6767    bool getAllowedValueStep(double*) const;
     68    bool getAllowedValueStepWithDecimalPlaces(double*, unsigned*) const;
    6869    // For ValidityState.
    6970    bool stepMismatch(const String&) const;
  • trunk/WebCore/html/InputType.cpp

    r70511 r71622  
    238238}
    239239
     240double InputType::stepBaseWithDecimalPlaces(unsigned* decimalPlaces) const
     241{
     242    if (decimalPlaces)
     243        *decimalPlaces = 0;
     244    return stepBase();
     245}
     246
    240247double InputType::defaultStep() const
    241248{
     
    258265}
    259266
     267double InputType::acceptableError(double) const
     268{
     269    return 0;
     270}
     271
    260272RenderObject* InputType::createRenderer(RenderArena*, RenderStyle* style) const
    261273{
     
    266278{
    267279    return defaultValue;
     280}
     281
     282double InputType::parseToDoubleWithDecimalPlaces(const String& src, double defaultValue, unsigned *decimalPlaces) const
     283{
     284    if (decimalPlaces)
     285        *decimalPlaces = 0;
     286    return parseToDouble(src, defaultValue);
    268287}
    269288
  • trunk/WebCore/html/InputType.h

    r70511 r71622  
    9191    virtual bool stepMismatch(const String&, double) const;
    9292    virtual double stepBase() const;
     93    virtual double stepBaseWithDecimalPlaces(unsigned*) const;
    9394    virtual double defaultStep() const;
    9495    virtual double stepScaleFactor() const;
    9596    virtual bool parsedStepValueShouldBeInteger() const;
    9697    virtual bool scaledStepValeuShouldBeInteger() const;
     98    virtual double acceptableError(double) const;
    9799
    98100    // Miscellaneous functions
     
    105107    // return NaN or Infinity only if defaultValue is NaN or Infinity.
    106108    virtual double parseToDouble(const String&, double defaultValue) const;
     109    // Parses the specified string for the type as parseToDouble() does.
     110    // In addition, it stores the number of digits after the decimal point
     111    // into *decimalPlaces.
     112    virtual double parseToDoubleWithDecimalPlaces(const String& src, double defaultValue, unsigned *decimalPlaces) const;
    107113    // Parses the specified string for this InputType, and returns true if it
    108114    // is successfully parsed. An instance pointed by the DateComponents*
  • trunk/WebCore/html/NumberInputType.cpp

    r70615 r71622  
    132132    // Accepts erros in lower fractional part which IEEE 754 single-precision
    133133    // can't represent.
    134     double acceptableError = step / pow(2.0, FLT_MANT_DIG);
    135     return acceptableError < remainder && remainder < (step - acceptableError);
     134    double computedAcceptableError = acceptableError(step);
     135    return computedAcceptableError < remainder && remainder < (step - computedAcceptableError);
    136136}
    137137
     
    139139{
    140140    return parseToDouble(element()->fastGetAttribute(minAttr), defaultStepBase());
     141}
     142
     143double NumberInputType::stepBaseWithDecimalPlaces(unsigned* decimalPlaces) const
     144{
     145    return parseToDoubleWithDecimalPlaces(element()->fastGetAttribute(minAttr), defaultStepBase(), decimalPlaces);
    141146}
    142147
     
    160165}
    161166
     167double NumberInputType::parseToDoubleWithDecimalPlaces(const String& src, double defaultValue, unsigned *decimalPlaces) const
     168{
     169    double numberValue;
     170    if (!parseToDoubleForNumberTypeWithDecimalPlaces(src, &numberValue, decimalPlaces))
     171        return defaultValue;
     172    ASSERT(isfinite(numberValue));
     173    return numberValue;
     174}
     175
    162176String NumberInputType::serialize(double value) const
    163177{
     
    167181}
    168182
     183double NumberInputType::acceptableError(double step) const
     184{
     185    return step / pow(2.0, FLT_MANT_DIG);
     186}
     187
     188
    169189} // namespace WebCore
  • trunk/WebCore/html/NumberInputType.h

    r69445 r71622  
    5353    virtual bool stepMismatch(const String&, double) const;
    5454    virtual double stepBase() const;
     55    virtual double stepBaseWithDecimalPlaces(unsigned*) const;
    5556    virtual double defaultStep() const;
    5657    virtual double stepScaleFactor() const;
    5758    virtual double parseToDouble(const String&, double) const;
     59    virtual double parseToDoubleWithDecimalPlaces(const String&, double, unsigned*) const;
    5860    virtual String serialize(double) const;
     61    virtual double acceptableError(double) const;
    5962};
    6063
  • trunk/WebCore/html/parser/HTMLParserIdioms.cpp

    r70549 r71622  
    9797}
    9898
     99bool parseToDoubleForNumberTypeWithDecimalPlaces(const String& string, double *result, unsigned *decimalPlaces)
     100{
     101    if (decimalPlaces)
     102        *decimalPlaces = 0;
     103
     104    if (!parseToDoubleForNumberType(string, result))
     105        return false;
     106
     107    if (!decimalPlaces)
     108        return true;
     109
     110    size_t dotIndex = string.find('.');
     111    size_t eIndex = string.find('e');
     112    if (eIndex == notFound)
     113        eIndex = string.find('E');
     114
     115    unsigned baseDecimalPlaces = 0;
     116    if (dotIndex != notFound) {
     117        if (eIndex == notFound)
     118            baseDecimalPlaces = string.length() - dotIndex - 1;
     119        else
     120            baseDecimalPlaces = eIndex - dotIndex - 1;
     121    }
     122
     123    int exponent = 0;
     124    if (eIndex != notFound) {
     125        unsigned cursor = eIndex + 1, cursorSaved;
     126        int digit, exponentSign;
     127        int32_t exponent32;
     128        size_t length = string.length();
     129
     130        // Not using String.toInt() in order to perform the same computation as dtoa() does.
     131        exponentSign = 0;
     132        switch (digit = string[cursor]) {
     133        case '-':
     134            exponentSign = 1;
     135        case '+':
     136            digit = string[++cursor];
     137        }
     138        if (digit >= '0' && digit <= '9') {
     139            while (cursor < length && digit == '0')
     140                digit = string[++cursor];
     141            if (digit > '0' && digit <= '9') {
     142                exponent32 = digit - '0';
     143                cursorSaved = cursor;
     144                while (cursor < length && (digit = string[++cursor]) >= '0' && digit <= '9')
     145                    exponent32 = (10 * exponent32) + digit - '0';
     146                if (cursor - cursorSaved > 8 || exponent32 > 19999)
     147                    /* Avoid confusion from exponents
     148                     * so large that e might overflow.
     149                     */
     150                    exponent = 19999; /* safe for 16 bit ints */
     151                else
     152                    exponent = static_cast<int>(exponent32);
     153                if (exponentSign)
     154                    exponent = -exponent;
     155            } else
     156                exponent = 0;
     157        }
     158    }
     159
     160    int intDecimalPlaces = baseDecimalPlaces - exponent;
     161    if (intDecimalPlaces < 0)
     162        *decimalPlaces = 0;
     163    else if (intDecimalPlaces > 19999)
     164        *decimalPlaces = 19999;
     165    else
     166        *decimalPlaces = static_cast<unsigned>(intDecimalPlaces);
     167
     168    return true;
     169}
     170
    99171// http://www.whatwg.org/specs/web-apps/current-work/#rules-for-parsing-integers
    100172bool parseHTMLInteger(const String& input, int& value)
  • trunk/WebCore/html/parser/HTMLParserIdioms.h

    r69044 r71622  
    4545// The double* parameter may be 0 to check if the string can be parsed without getting the result.
    4646bool parseToDoubleForNumberType(const String&, double*);
     47bool parseToDoubleForNumberTypeWithDecimalPlaces(const String&, double*, unsigned*);
    4748
    4849// http://www.whatwg.org/specs/web-apps/current-work/#rules-for-parsing-integers
Note: See TracChangeset for help on using the changeset viewer.