Changeset 119948 in webkit
- Timestamp:
- Jun 10, 2012 7:30:39 PM (12 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 19 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r119947 r119948 1 2012-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 1 11 2012-06-10 Jason Liu <jason.liu@torchmobile.com.cn> 2 12 -
trunk/Source/WebCore/ChangeLog
r119947 r119948 1 2012-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 1 84 2012-06-10 Jason Liu <jason.liu@torchmobile.com.cn> 2 85 -
trunk/Source/WebCore/html/BaseDateAndTimeInputType.cpp
r119580 r119948 137 137 String BaseDateAndTimeInputType::serialize(const InputNumber& value) const 138 138 { 139 if (! isfinite(value))139 if (!value.isFinite()) 140 140 return String(); 141 141 DateComponents date; … … 150 150 if (!element()->getAllowedValueStep(&step)) 151 151 return date.toString(); 152 if ( !fmod(step, msecPerMinute))152 if (step.remainder(msecPerMinute).isZero()) 153 153 return date.toString(DateComponents::None); 154 if ( !fmod(step, msecPerSecond))154 if (step.remainder(msecPerSecond).isZero()) 155 155 return date.toString(DateComponents::Second); 156 156 return date.toString(DateComponents::Millisecond); -
trunk/Source/WebCore/html/DateInputType.cpp
r119809 r119948 77 77 const InputNumber minimum = parseToNumber(element()->fastGetAttribute(minAttr), convertDoubleToInputNumber(DateComponents::minimumDate())); 78 78 const InputNumber maximum = parseToNumber(element()->fastGetAttribute(maxAttr), convertDoubleToInputNumber(DateComponents::maximumDate())); 79 const StepRange::NumberWithDecimalPlacesstep = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));79 const InputNumber step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr)); 80 80 return StepRange(stepBase, minimum, maximum, step, stepDescription); 81 81 } -
trunk/Source/WebCore/html/DateTimeInputType.cpp
r119809 r119948 75 75 const InputNumber minimum = parseToNumber(element()->fastGetAttribute(minAttr), convertDoubleToInputNumber(DateComponents::minimumDateTime())); 76 76 const InputNumber maximum = parseToNumber(element()->fastGetAttribute(maxAttr), convertDoubleToInputNumber(DateComponents::maximumDateTime())); 77 const StepRange::NumberWithDecimalPlacesstep = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));77 const InputNumber step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr)); 78 78 return StepRange(stepBase, minimum, maximum, step, stepDescription); 79 79 } -
trunk/Source/WebCore/html/DateTimeLocalInputType.cpp
r119809 r119948 81 81 const InputNumber minimum = parseToNumber(element()->fastGetAttribute(minAttr), convertDoubleToInputNumber(DateComponents::minimumDateTime())); 82 82 const InputNumber maximum = parseToNumber(element()->fastGetAttribute(maxAttr), convertDoubleToInputNumber(DateComponents::maximumDateTime())); 83 const StepRange::NumberWithDecimalPlacesstep = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));83 const InputNumber step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr)); 84 84 return StepRange(stepBase, minimum, maximum, step, stepDescription); 85 85 } -
trunk/Source/WebCore/html/InputType.cpp
r119580 r119948 258 258 259 259 const InputNumber numericValue = parseToNumberOrNaN(value); 260 if ( isnan(numericValue))260 if (!numericValue.isFinite()) 261 261 return false; 262 262 … … 270 270 271 271 const InputNumber numericValue = parseToNumberOrNaN(value); 272 if ( isnan(numericValue))272 if (!numericValue.isFinite()) 273 273 return false; 274 274 … … 303 303 304 304 const InputNumber numericValue = parseToNumberOrNaN(value); 305 if ( isnan(numericValue))305 if (!numericValue.isFinite()) 306 306 return true; 307 307 … … 316 316 317 317 const InputNumber numericValue = parseToNumberOrNaN(value); 318 if ( isnan(numericValue))318 if (!numericValue.isFinite()) 319 319 return true; 320 320 … … 329 329 330 330 const InputNumber numericValue = parseToNumberOrNaN(value); 331 if ( isnan(numericValue))331 if (!numericValue.isFinite()) 332 332 return false; 333 333 … … 367 367 368 368 const InputNumber numericValue = parseToNumberOrNaN(value); 369 if ( isnan(numericValue))369 if (!numericValue.isFinite()) 370 370 return emptyString(); 371 371 … … 467 467 InputNumber InputType::parseToNumberOrNaN(const String& string) const 468 468 { 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()); 477 470 } 478 471 … … 887 880 } 888 881 889 const double nan = numeric_limits<double>::quiet_NaN(); 890 unsigned currentDecimalPlaces; 891 const InputNumber current = parseToNumberWithDecimalPlaces(element()->value(), nan, ¤tDecimalPlaces); 892 if (!isfinite(current)) { 882 const InputNumber current = parseToNumberOrNaN(element()->value()); 883 if (!current.isFinite()) { 893 884 ec = INVALID_STATE_ERR; 894 885 return; 895 886 } 896 887 InputNumber newValue = current + stepRange.step() * count; 897 if ( isinf(newValue)) {888 if (!newValue.isFinite()) { 898 889 ec = INVALID_STATE_ERR; 899 890 return; … … 910 901 const AtomicString& stepString = element()->fastGetAttribute(stepAttr); 911 902 if (!equalIgnoringCase(stepString, "any")) 912 newValue = stepRange.alignValueForStep(current, currentDecimalPlaces,newValue);903 newValue = stepRange.alignValueForStep(current, newValue); 913 904 914 905 if (newValue - stepRange.maximum() > acceptableErrorValue) { … … 1010 1001 String currentStringValue = element()->value(); 1011 1002 InputNumber current = parseToNumberOrNaN(currentStringValue); 1012 if (! isfinite(current)) {1003 if (!current.isFinite()) { 1013 1004 ExceptionCode ec; 1014 1005 current = defaultValueForStepUp(); … … 1026 1017 ExceptionCode ec; 1027 1018 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; 1033 1022 if (sign < 0) 1034 newValue = round((base + floor((current - base) / step) * step) * scale) / scale;1023 newValue = base + ((current - base) / step).floor() * step; 1035 1024 else if (sign > 0) 1036 newValue = round((base + ceil((current - base) / step) * step) * scale) / scale;1025 newValue = base + ((current - base) / step).ceiling() * step; 1037 1026 else 1038 1027 newValue = current; -
trunk/Source/WebCore/html/InputType.h
r119540 r119948 267 267 virtual InputNumber parseToNumber(const String&, const InputNumber& defaultValue) const; 268 268 269 // Parses the specified string for the type as parseToNumber() does.270 // In addition, it stores the number of digits after the decimal point271 // into *decimalPlaces.272 virtual InputNumber parseToNumberWithDecimalPlaces(const String&, const InputNumber& defaultValue, unsigned* decimalPlaces) const;273 274 269 // Parses the specified string for this InputType, and returns true if it 275 270 // is successfully parsed. An instance pointed by the DateComponents* -
trunk/Source/WebCore/html/MonthInputType.cpp
r119809 r119948 105 105 const InputNumber minimum = parseToNumber(element()->fastGetAttribute(minAttr), convertDoubleToInputNumber(DateComponents::minimumMonth())); 106 106 const InputNumber maximum = parseToNumber(element()->fastGetAttribute(maxAttr), convertDoubleToInputNumber(DateComponents::maximumMonth())); 107 const StepRange::NumberWithDecimalPlacesstep = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));107 const InputNumber step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr)); 108 108 return StepRange(stepBase, minimum, maximum, step, stepDescription); 109 109 } -
trunk/Source/WebCore/html/NumberInputType.cpp
r119809 r119948 55 55 static const int numberStepScaleFactor = 1; 56 56 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; 57 struct 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 76 static 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); 70 95 } 71 96 … … 129 154 { 130 155 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); 136 157 // FIXME: We should use numeric_limits<double>::max for number input type. 137 158 const InputNumber floatMax = convertDoubleToInputNumber(numeric_limits<float>::max()); 138 159 const InputNumber minimum = parseToNumber(element()->fastGetAttribute(minAttr), -floatMax); 139 160 const InputNumber maximum = parseToNumber(element()->fastGetAttribute(maxAttr), floatMax); 140 const StepRange::NumberWithDecimalPlacesstep = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));161 const InputNumber step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr)); 141 162 return StepRange(stepBase, minimum, maximum, step, stepDescription); 142 163 } … … 146 167 preferredSize = defaultSize; 147 168 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")) 152 171 return false; 153 172 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()) 158 175 return false; 159 176 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()) 167 179 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 188 188 return true; 189 189 } … … 208 208 InputNumber NumberInputType::parseToNumber(const String& src, const InputNumber& defaultValue) const 209 209 { 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); 216 211 } 217 212 218 213 String NumberInputType::serialize(const InputNumber& value) const 219 214 { 220 if (! isfinite(value))215 if (!value.isFinite()) 221 216 return String(); 222 217 return serializeForNumberType(value); -
trunk/Source/WebCore/html/NumberInputType.h
r119540 r119948 54 54 virtual void handleWheelEvent(WheelEvent*) OVERRIDE; 55 55 virtual InputNumber parseToNumber(const String&, const InputNumber&) const OVERRIDE; 56 virtual InputNumber parseToNumberWithDecimalPlaces(const String&, const InputNumber&, unsigned*) const OVERRIDE;57 56 virtual String serialize(const InputNumber&) const OVERRIDE; 58 57 virtual void handleBlurEvent() OVERRIDE; -
trunk/Source/WebCore/html/RangeInputType.cpp
r119809 r119948 105 105 const AtomicString& precisionValue = element()->fastGetAttribute(precisionAttr); 106 106 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; 108 108 return StepRange(minimum, minimum, maximum, step, stepDescription); 109 109 } 110 110 111 const StepRange::NumberWithDecimalPlacesstep = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));111 const InputNumber step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr)); 112 112 return StepRange(minimum, minimum, maximum, step, stepDescription); 113 113 } … … 143 143 144 144 const InputNumber current = parseToNumberOrNaN(element()->value()); 145 ASSERT( isfinite(current));145 ASSERT(current.isFinite()); 146 146 147 147 StepRange stepRange(createStepRange(RejectAny)); … … 216 216 InputNumber RangeInputType::parseToNumber(const String& src, const InputNumber& defaultValue) const 217 217 { 218 return convertDoubleToInputNumber(parseToDoubleForNumberType(src, defaultValue));218 return parseToDecimalForNumberType(src, defaultValue); 219 219 } 220 220 221 221 String RangeInputType::serialize(const InputNumber& value) const 222 222 { 223 if (! isfinite(value))223 if (!value.isFinite()) 224 224 return String(); 225 225 return serializeForNumberType(value); -
trunk/Source/WebCore/html/StepRange.cpp
r119809 r119948 38 38 , m_step(1) 39 39 , m_stepBase(0) 40 , m_stepBaseDecimalPlaces(0)41 , m_stepDecimalPlaces(0)42 40 , m_hasStep(false) 43 41 { … … 50 48 , m_stepBase(stepRange.m_stepBase) 51 49 , m_stepDescription(stepRange.m_stepDescription) 52 , m_stepBaseDecimalPlaces(stepRange.m_stepBaseDecimalPlaces)53 , m_stepDecimalPlaces(stepRange.m_stepDecimalPlaces)54 50 , m_hasStep(stepRange.m_hasStep) 55 51 { 56 52 } 57 53 58 StepRange::StepRange(const NumberWithDecimalPlaces& stepBase, const InputNumber& minimum, const InputNumber& maximum, const NumberWithDecimalPlaces& step, const StepDescription& stepDescription)54 StepRange::StepRange(const InputNumber& stepBase, const InputNumber& minimum, const InputNumber& maximum, const InputNumber& step, const StepDescription& stepDescription) 59 55 : m_maximum(maximum) 60 56 , 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) 63 59 , m_stepDescription(stepDescription) 64 , m_stepBaseDecimalPlaces(stepBase.decimalPlaces) 65 , m_stepDecimalPlaces(step.decimalPlaces) 66 , m_hasStep(isfinite(step.value)) 60 , m_hasStep(step.isFinite()) 67 61 { 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()); 72 66 } 73 67 74 68 InputNumber StepRange::acceptableError() const 75 69 { 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; 77 73 } 78 74 79 InputNumber StepRange::alignValueForStep(const InputNumber& currentValue, unsigned currentDecimalPlaces, const InputNumber& proposedValue) const75 InputNumber StepRange::alignValueForStep(const InputNumber& currentValue, const InputNumber& newValue) const 80 76 { 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; 83 80 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); 94 82 } 95 83 … … 107 95 } 108 96 109 StepRange::NumberWithDecimalPlacesStepRange::parseStep(AnyStepHandling anyStepHandling, const StepDescription& stepDescription, const String& stepString)97 InputNumber StepRange::parseStep(AnyStepHandling anyStepHandling, const StepDescription& stepDescription, const String& stepString) 110 98 { 111 99 if (stepString.isEmpty()) 112 return NumberWithDecimalPlaces(stepDescription.defaultValue());100 return stepDescription.defaultValue(); 113 101 114 102 if (equalIgnoringCase(stepString, "any")) { 115 103 switch (anyStepHandling) { 116 104 case RejectAny: 117 return NumberWithDecimalPlaces(std::numeric_limits<double>::quiet_NaN());105 return Decimal::nan(); 118 106 case AnyIsDefaultStep: 119 return NumberWithDecimalPlaces(stepDescription.defaultValue());107 return stepDescription.defaultValue(); 120 108 default: 121 109 ASSERT_NOT_REACHED(); … … 123 111 } 124 112 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(); 129 116 130 117 switch (stepDescription.stepValueShouldBe) { 131 118 case StepValueShouldBeReal: 132 step .value*= stepDescription.stepScaleFactor;119 step *= stepDescription.stepScaleFactor; 133 120 break; 134 121 case ParsedStepValueShouldBeInteger: 135 122 // 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; 138 125 break; 139 126 case ScaledStepValueShouldBeInteger: 140 127 // 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)); 143 130 break; 144 131 default: … … 146 133 } 147 134 148 ASSERT(step .value> 0);135 ASSERT(step > 0); 149 136 return step; 150 137 } … … 152 139 InputNumber StepRange::roundByStep(const InputNumber& value, const InputNumber& base) const 153 140 { 154 return base + round((value - base) / m_step) * m_step;141 return base + ((value - base) / m_step).round() * m_step; 155 142 } 156 143 … … 159 146 if (!m_hasStep) 160 147 return false; 161 if (! isfinite(valueForCheck))148 if (!valueForCheck.isFinite()) 162 149 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()) 165 152 return false; 166 153 // InputNumber's fractional part size is DBL_MAN_DIG-bit. If the current value 167 154 // is greater than step*2^DBL_MANT_DIG, the following computation for 168 155 // 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) 170 158 return false; 171 159 // The computation follows HTML5 4.10.7.2.10 `The step attribute' : 172 160 // ... that number subtracted from the step base is not an integral multiple 173 161 // 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(); 175 163 // Accepts erros in lower fractional part which IEEE 754 single-precision 176 164 // can't represent. -
trunk/Source/WebCore/html/StepRange.h
r119809 r119948 22 22 #define StepRange_h 23 23 24 #include "Decimal.h" 24 25 #include <wtf/Forward.h> 25 26 #include <wtf/Noncopyable.h> … … 31 32 enum AnyStepHandling { RejectAny, AnyIsDefaultStep }; 32 33 33 // FIXME: The type InputNumber will be replaced with Decimal.34 typedef doubleInputNumber;34 // FIXME: We should rename InputNumber to Decimal in all places. 35 typedef Decimal InputNumber; 35 36 36 37 inline InputNumber convertDoubleToInputNumber(double doubleValue) 37 38 { 38 return doubleValue;39 return Decimal::fromDouble(doubleValue); 39 40 } 40 41 41 42 inline double convertInputNumberToDouble(const InputNumber& numericValue) 42 43 { 43 return numericValue ;44 return numericValue.toDouble(); 44 45 } 45 46 46 47 class StepRange { 47 48 public: 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 59 49 enum StepValueShouldBe { 60 50 StepValueShouldBeReal, … … 93 83 StepRange(); 94 84 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&); 96 86 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; 98 88 InputNumber clampValue(const InputNumber& value) const; 99 89 bool hasStep() const { return m_hasStep; } 100 90 InputNumber maximum() const { return m_maximum; } 101 91 InputNumber minimum() const { return m_minimum; } 102 static NumberWithDecimalPlacesparseStep(AnyStepHandling, const StepDescription&, const String&);92 static InputNumber parseStep(AnyStepHandling, const StepDescription&, const String&); 103 93 InputNumber step() const { return m_step; } 104 94 InputNumber stepBase() const { return m_stepBase; } 105 unsigned stepBaseDecimalPlaces() const { return m_stepBaseDecimalPlaces; }106 unsigned stepDecimalPlaces() const { return m_stepDecimalPlaces; }107 95 int stepScaleFactor() const { return m_stepDescription.stepScaleFactor; } 108 96 bool stepMismatch(const InputNumber&) const; … … 138 126 const InputNumber m_stepBase; 139 127 const StepDescription m_stepDescription; 140 const unsigned m_stepBaseDecimalPlaces;141 const unsigned m_stepDecimalPlaces;142 128 const bool m_hasStep; 143 129 }; -
trunk/Source/WebCore/html/TimeInputType.cpp
r119809 r119948 87 87 const InputNumber minimum = parseToNumber(element()->fastGetAttribute(minAttr), convertDoubleToInputNumber(DateComponents::minimumTime())); 88 88 const InputNumber maximum = parseToNumber(element()->fastGetAttribute(maxAttr), convertDoubleToInputNumber(DateComponents::maximumTime())); 89 const StepRange::NumberWithDecimalPlacesstep = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));89 const InputNumber step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr)); 90 90 return StepRange(stepBase, minimum, maximum, step, stepDescription); 91 91 } -
trunk/Source/WebCore/html/WeekInputType.cpp
r119809 r119948 69 69 const InputNumber minimum = parseToNumber(element()->fastGetAttribute(minAttr), convertDoubleToInputNumber(DateComponents::minimumWeek())); 70 70 const InputNumber maximum = parseToNumber(element()->fastGetAttribute(maxAttr), convertDoubleToInputNumber(DateComponents::maximumWeek())); 71 const StepRange::NumberWithDecimalPlacesstep = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));71 const InputNumber step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr)); 72 72 return StepRange(stepBase, minimum, maximum, step, stepDescription); 73 73 } -
trunk/Source/WebCore/html/parser/HTMLParserIdioms.cpp
r117929 r119948 26 26 #include "HTMLParserIdioms.h" 27 27 28 #include "Decimal.h" 28 29 #include <limits> 29 30 #include <wtf/MathExtras.h> … … 59 60 } 60 61 62 String 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 61 71 String serializeForNumberType(double number) 62 72 { … … 65 75 NumberToStringBuffer buffer; 66 76 return String(numberToString(number, buffer)); 77 } 78 79 Decimal 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 103 Decimal parseToDecimalForNumberType(const String& string) 104 { 105 return parseToDecimalForNumberType(string, Decimal::nan()); 67 106 } 68 107 -
trunk/Source/WebCore/html/parser/HTMLParserIdioms.h
r117929 r119948 31 31 namespace WebCore { 32 32 33 class Decimal; 34 33 35 // Space characters as defined by the HTML specification. 34 36 bool isHTMLSpace(UChar); … … 40 42 41 43 // An implementation of the HTML specification's algorithm to convert a number to a string for number and range types. 44 String serializeForNumberType(const Decimal&); 42 45 String serializeForNumberType(double); 43 46 44 // Convert the specified string to a d ouble. 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. 45 48 // Leading or trailing illegal characters cause failure, as does passing an empty string. 46 49 // The double* parameter may be 0 to check if the string can be parsed without getting the result. 50 Decimal parseToDecimalForNumberType(const String&); 51 Decimal parseToDecimalForNumberType(const String&, const Decimal& fallbackValue); 47 52 double parseToDoubleForNumberType(const String&); 48 53 double parseToDoubleForNumberType(const String&, double fallbackValue); -
trunk/Source/WebCore/html/shadow/SliderThumbElement.cpp
r119547 r119948 55 55 { 56 56 const StepRange stepRange(element->createStepRange(RejectAny)); 57 const double oldValue = parseToDoubleForNumberType(element->value(), stepRange.defaultValue());57 const InputNumber oldValue = parseToDecimalForNumberType(element->value(), stepRange.defaultValue()); 58 58 return stepRange.proportionFromValue(stepRange.clampValue(oldValue)); 59 59 }
Note: See TracChangeset
for help on using the changeset viewer.