WebKit Bugzilla
New
Browse
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
RESOLVED FIXED
92640
Slider should snap to datalist tick marks
https://bugs.webkit.org/show_bug.cgi?id=92640
Summary
Slider should snap to datalist tick marks
Keishi Hattori
Reported
2012-07-30 05:41:42 PDT
Slider maybe should snap to datalist tick marks.
Attachments
Patch
(8.36 KB, patch)
2012-07-31 04:35 PDT
,
Keishi Hattori
no flags
Details
Formatted Diff
Diff
Patch
(15.14 KB, patch)
2012-08-01 19:09 PDT
,
Keishi Hattori
no flags
Details
Formatted Diff
Diff
Patch
(14.72 KB, patch)
2012-08-02 01:34 PDT
,
Keishi Hattori
no flags
Details
Formatted Diff
Diff
Patch
(14.15 KB, patch)
2012-08-02 02:03 PDT
,
Keishi Hattori
no flags
Details
Formatted Diff
Diff
Patch
(14.08 KB, patch)
2012-08-02 03:36 PDT
,
Keishi Hattori
no flags
Details
Formatted Diff
Diff
Show Obsolete
(4)
View All
Add attachment
proposed patch, testcase, etc.
Keishi Hattori
Comment 1
2012-07-30 05:46:23 PDT
Here is a Mac build with snapping turned on so we can discuss whether we do this.
https://docs.google.com/open?id=0BwRi59l_ri74ZUtkTHZuLUhKUTA
Keishi Hattori
Comment 2
2012-07-31 04:35:35 PDT
Created
attachment 155490
[details]
Patch
Kent Tamura
Comment 3
2012-07-31 07:17:29 PDT
Comment on
attachment 155490
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=155490&action=review
> Source/WebCore/html/shadow/SliderThumbElement.cpp:277 > +#if ENABLE(DATALIST_ELEMENT)
We should have a new function for this code.
> Source/WebCore/html/shadow/SliderThumbElement.cpp:283 > + for (unsigned i = 0; Node* node = options->item(i); i++) {
Please follow an idiom; for (unsigned i = 0; i < options->length(); ++i) { Your current code disturbs code readers. BTW, this code is called whenever mousemove is dispatched during the thumb dragging, and this code is O(N). We should improve the complexity.
> Source/WebCore/html/shadow/SliderThumbElement.cpp:285 > + ASSERT(node->hasTagName(optionTag)); > + HTMLOptionElement* optionElement = static_cast<HTMLOptionElement*>(node);
We have toHTMLOptionElement().
> Source/WebCore/html/shadow/SliderThumbElement.cpp:306 > +&& closest.isFinite() && !closest.isNaN())
wrong indentation
yosin
Comment 4
2012-07-31 18:33:34 PDT
Comment on
attachment 155490
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=155490&action=review
> Source/WebCore/html/shadow/SliderThumbElement.cpp:287 > + if (!input->isValidValue(optionValue))
Do we need to use HTMLInputElement functions? Because of we have stepRange for input element. We can do as follows: const Decimal rawTickValue = parseToDecimalForNumberType(optionValue); if (!rawTickValue.isFinite()) continue; const Decimal tickValue = std::max(std::min(rawTickValue, stepRange.maximum()), stepRange.minimum());
> Source/WebCore/html/shadow/SliderThumbElement.cpp:291 > + if (difference > 0 && tickValue < closestRight)
You can use Decimal::isPositive() and isNegative() functions instead of comparing to zero.
> Source/WebCore/html/shadow/SliderThumbElement.cpp:292 > + closestRight = tickValue;
We can write this if (difference.isPositive()) closestRight = std::min(closestRight, tickValue) else if (difference.isNegative()) closestLeft = std::max(closestLeft, tickValue) else closestLeft = closestRight = tickValue;
> Source/WebCore/html/shadow/SliderThumbElement.cpp:301 > + double closestFraction = stepRange.proportionFromValue(closest).toDouble();
* Can we do decimal arithmetic instead of double arithmetic? * It is better to check closest.isFinite() and skip L301-L307 if !closest.isFinite(). We can see closest is ininity when !options.length().
>> Source/WebCore/html/shadow/SliderThumbElement.cpp:306 >> +&& closest.isFinite() && !closest.isNaN()) > > wrong indentation
closes.isFinite() implies !closes.isNaN(). So, we don't need to have "&& !closes.isNan()".
yosin
Comment 5
2012-07-31 18:50:33 PDT
Comment on
attachment 155490
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=155490&action=review
>> Source/WebCore/html/shadow/SliderThumbElement.cpp:287 >> + if (!input->isValidValue(optionValue)) > > Do we need to use HTMLInputElement functions? Because of we have stepRange for input element. We can do as follows: > const Decimal rawTickValue = parseToDecimalForNumberType(optionValue); > if (!rawTickValue.isFinite()) > continue; > const Decimal tickValue = std::max(std::min(rawTickValue, stepRange.maximum()), stepRange.minimum());
Oops, tickValue should be sanitized, so we can do const Decimal originalTickValue = parseToDecimalForNumberType(optionValue, stepRange.defaultValue()); const Decimal tickValue = stepRange.clampValue(originalTickValue);
Kent Tamura
Comment 6
2012-07-31 19:30:48 PDT
Comment on
attachment 155490
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=155490&action=review
>>> Source/WebCore/html/shadow/SliderThumbElement.cpp:287 >>> + if (!input->isValidValue(optionValue)) >> >> Do we need to use HTMLInputElement functions? Because of we have stepRange for input element. We can do as follows: >> const Decimal rawTickValue = parseToDecimalForNumberType(optionValue); >> if (!rawTickValue.isFinite()) >> continue; >> const Decimal tickValue = std::max(std::min(rawTickValue, stepRange.maximum()), stepRange.minimum()); > > Oops, tickValue should be sanitized, so we can do > const Decimal originalTickValue = parseToDecimalForNumberType(optionValue, stepRange.defaultValue()); > const Decimal tickValue = stepRange.clampValue(originalTickValue);
We should skip the step-mismatched values, and shouldn't alter the option value here. Skip the value with isValidValue() is ok.
yosin
Comment 7
2012-08-01 05:22:31 PDT
(In reply to
comment #6
)
> (From update of
attachment 155490
[details]
) > View in context:
https://bugs.webkit.org/attachment.cgi?id=155490&action=review
> > >>> Source/WebCore/html/shadow/SliderThumbElement.cpp:287 > >>> + if (!input->isValidValue(optionValue)) > >> > >> Do we need to use HTMLInputElement functions? Because of we have stepRange for input element. We can do as follows: > >> const Decimal rawTickValue = parseToDecimalForNumberType(optionValue); > >> if (!rawTickValue.isFinite()) > >> continue; > >> const Decimal tickValue = std::max(std::min(rawTickValue, stepRange.maximum()), stepRange.minimum()); > > > > Oops, tickValue should be sanitized, so we can do > > const Decimal originalTickValue = parseToDecimalForNumberType(optionValue, stepRange.defaultValue()); > > const Decimal tickValue = stepRange.clampValue(originalTickValue); > > We should skip the step-mismatched values, and shouldn't alter the option value here. Skip the value with isValidValue() is ok.
HTMLInputElement::isValidValue() creates StepRange class many times. How about adding bool StepRange::isValidValue(const Decimal&)? It can be bool StepRange::isValidalue(const Decimal& value) { if (!value.isFinite()) return false; if (value < m_minimum || value > m_maximum) return false; return value.remainder(m_step).isZero(); }
Keishi Hattori
Comment 8
2012-08-01 19:09:30 PDT
Created
attachment 155950
[details]
Patch
Keishi Hattori
Comment 9
2012-08-01 19:17:22 PDT
> HTMLInputElement::isValidValue() creates StepRange class many times.
I tried to avoid this by moving the code into RangeInputType and doing the equivalent to isValidValue with one StepRange.
Build Bot
Comment 10
2012-08-01 19:24:02 PDT
Comment on
attachment 155950
[details]
Patch
Attachment 155950
[details]
did not pass win-ews (win): Output:
http://queues.webkit.org/results/13411697
Build Bot
Comment 11
2012-08-01 19:24:08 PDT
Comment on
attachment 155950
[details]
Patch
Attachment 155950
[details]
did not pass mac-ews (mac): Output:
http://queues.webkit.org/results/13411695
Kent Tamura
Comment 12
2012-08-01 20:30:36 PDT
Comment on
attachment 155950
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=155950&action=review
> Source/WebCore/html/HTMLInputElement.cpp:320 > +Decimal HTMLInputElement::findClosestTickMarkValue(Decimal value) > +{ > + return m_inputType->findClosestTickMarkValue(value); > +} > +
Please move it into the existing #if ENABLE(DATALIST_ELEMENT) block.
> Source/WebCore/html/HTMLInputElement.h:77 > +#if ENABLE(DATALIST_ELEMENT) > + Decimal findClosestTickMarkValue(Decimal); > +#endif
Please move the declaration into the existing #if ENABLE(DATALIST_ELEMENT) block.
> Source/WebCore/html/RangeInputType.cpp:58 > +#if ENABLE(TOUCH_EVENTS)
Maybe DATALIST_ELEMENT ?
> Source/WebCore/html/RangeInputType.cpp:352 > + Vector<Decimal> tickValues;
This is not used.
> Source/WebCore/html/RangeInputType.cpp:366 > + String optionValue = optionElement->value(); > + if (typeMismatchFor(optionValue)) > + continue; > + Decimal rawOptionValue = parseToNumber(optionValue, Decimal::nan()); > + if (!rawOptionValue.isFinite() > + || stepRange.stepMismatch(rawOptionValue) > + || rawOptionValue < stepRange.minimum() > + || rawOptionValue > stepRange.maximum())
We should use HTMLInputElement::isValidValue() because - This is a duplication of HTMLInputElement::isValidValue(). It's hard to maintain both to be synchronized forever. - Now we have a cache of datalist values. The cost of StepRange creation is not important. If you'd like to improve the performance, you should improve isValidValue().
> Source/WebCore/html/RangeInputType.cpp:385 > + middle = (left + right) / 2;
possible integer overflow.
> Source/WebCore/html/RangeInputType.h:80 > #endif > + > + bool m_tickMarkValuesDirty; > + Vector<Decimal> m_tickMarkValues;
They should be in #if ENABLE(DATALIST_ELEMENT)
> Source/WebCore/html/shadow/SliderThumbElement.cpp:241 > > + > +
this change is unnecessary.
Keishi Hattori
Comment 13
2012-08-02 01:34:20 PDT
Created
attachment 156004
[details]
Patch
yosin
Comment 14
2012-08-02 01:42:09 PDT
Comment on
attachment 156004
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=156004&action=review
> Source/WebCore/html/HTMLInputElement.cpp:317 > +Decimal HTMLInputElement::findClosestTickMarkValue(Decimal value)
nit: Is it better to use const Decimal& as other functions which take Decimal?
> Source/WebCore/html/RangeInputType.cpp:340 > +static bool decimalCompare(Decimal a, Decimal b)
Please use "const Decimal&" to avoid copying Decimal objects.
> Source/WebCore/html/RangeInputType.cpp:363 > + m_tickMarkValues.append(stepRange.clampValue(parseToNumber(optionValue, stepRange.defaultValue())));
We don't need to call StepRange::clampValue, because isValidValue is true.
> Source/WebCore/html/RangeInputType.cpp:395 > + Decimal closestLeft = middle ? m_tickMarkValues[middle - 1] : Decimal::infinity(Decimal::Negative);
nit: const Decimal
> Source/WebCore/html/RangeInputType.cpp:396 > + Decimal closestRight = middle != m_tickMarkValues.size() ? m_tickMarkValues[middle] : Decimal::infinity(Decimal::Positive);
nit: const Decimal
> Source/WebCore/html/shadow/SliderThumbElement.cpp:278 > + Decimal closest = input->findClosestTickMarkValue(value);
nit: const Decimal
> Source/WebCore/html/shadow/SliderThumbElement.cpp:280 > + double closestFraction = stepRange.proportionFromValue(closest).toDouble();
Is it better to do in decimal arithmetic? Could you tell me why do we use double arithmetic? For speed?
Kent Tamura
Comment 15
2012-08-02 01:50:20 PDT
Comment on
attachment 156004
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=156004&action=review
> Source/WebCore/html/InputType.cpp:914 > + return Decimal::nan();
ASSERT_NOT_REACHED().
> Source/WebCore/html/RangeInputType.cpp:380 > + middle = (static_cast<long>(left) + static_cast<long>(right)) / 2;
Still have possibility of integer overflow because sizeof(size_t) is usually same as sizeof(long). middle = left + (right - left) / 2;
> LayoutTests/fast/forms/datalist/range-snap-to-datalist.html:66 > +<script> > + var input = document.getElementById("input"); > + var thumbWidth = 15; > + var halfThumbWidth = (thumbWidth - 1) / 2; > + function clickSlider(offsetLeft) { > + var centerY = input.offsetTop + input.offsetHeight / 2; > + eventSender.mouseMoveTo(input.offsetLeft + offsetLeft, centerY); > + eventSender.mouseDown(); > + eventSender.mouseUp(); > + } > + function resetSliderPosition() { > + clickSlider(0); > + shouldBe('input.value', '"0"'); > + } > + function expectedValueForPosition(pos) { > + clickSlider(pos); > + var value = Math.round((pos - halfThumbWidth - 0.5) / (input.offsetWidth - thumbWidth) * (input.max - input.min) + input.min); > + value = Math.max(Math.min(value, input.max), input.min); > + return value; > + } > + resetSliderPosition(); > + clickSlider(45); > + shouldBeTrue('parseInt(input.value, 10) < 500'); > + resetSliderPosition(); > + clickSlider(46); > + shouldBeTrue('parseInt(input.value, 10) < 500'); > + resetSliderPosition(); > + clickSlider(47); > + shouldBeTrue('parseInt(input.value, 10) < 500'); > + resetSliderPosition(); > + clickSlider(48); > + shouldBe('input.value', "'500'"); > + resetSliderPosition(); > + clickSlider(49); > + shouldBe('input.value', "'500'"); > + resetSliderPosition(); > + clickSlider(50); > + shouldBe('input.value', "'500'"); > + resetSliderPosition(); > + clickSlider(51); > + shouldBe('input.value', "'500'"); > + resetSliderPosition(); > + clickSlider(52); > + shouldBe('input.value', "'500'"); > + resetSliderPosition(); > + clickSlider(53); > + shouldBeTrue('parseInt(input.value, 10) > 500'); > + resetSliderPosition(); > + clickSlider(54); > + shouldBeTrue('parseInt(input.value, 10) > 500'); > + resetSliderPosition(); > + clickSlider(55); > + shouldBeTrue('parseInt(input.value, 10) > 500'); > +</script>
nit: Indenting everything is not helpful.
Kent Tamura
Comment 16
2012-08-02 01:55:40 PDT
Comment on
attachment 156004
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=156004&action=review
> LayoutTests/fast/forms/datalist/range-snap-to-datalist.html:32 > + function expectedValueForPosition(pos) { > + clickSlider(pos); > + var value = Math.round((pos - halfThumbWidth - 0.5) / (input.offsetWidth - thumbWidth) * (input.max - input.min) + input.min); > + value = Math.max(Math.min(value, input.max), input.min); > + return value; > + }
This function is not used.
Keishi Hattori
Comment 17
2012-08-02 02:03:22 PDT
Created
attachment 156010
[details]
Patch
Keishi Hattori
Comment 18
2012-08-02 02:05:40 PDT
> > Source/WebCore/html/shadow/SliderThumbElement.cpp:280 > > + double closestFraction = stepRange.proportionFromValue(closest).toDouble(); > > Is it better to do in decimal arithmetic? > Could you tell me why do we use double arithmetic? For speed?
Should I use decimal arithmetic? My thinking was that Decimal precision is unnecessary and it would be slightly faster to use double.
yosin
Comment 19
2012-08-02 02:15:57 PDT
(In reply to
comment #15
)
> (From update of
attachment 156004
[details]
) > View in context:
https://bugs.webkit.org/attachment.cgi?id=156004&action=review
> > > Source/WebCore/html/InputType.cpp:914 > > + return Decimal::nan(); > > ASSERT_NOT_REACHED(). > > > Source/WebCore/html/RangeInputType.cpp:380 > > + middle = (static_cast<long>(left) + static_cast<long>(right)) / 2; > > Still have possibility of integer overflow because sizeof(size_t) is usually same as sizeof(long). > > middle = left + (right - left) / 2; >
It is impossible to have elements in Vector due by available memory.
Kent Tamura
Comment 20
2012-08-02 02:21:40 PDT
(In reply to
comment #19
)
> > Still have possibility of integer overflow because sizeof(size_t) is usually same as sizeof(long). > > > > middle = left + (right - left) / 2; > > > > It is impossible to have elements in Vector due by available memory.
Right. However we should always write correct code because the code might be copied, and the copy might have integer overflow.
Kent Tamura
Comment 21
2012-08-02 02:23:47 PDT
Comment on
attachment 156010
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=156010&action=review
> Source/WebCore/html/RangeInputType.cpp:356 > + StepRange stepRange(createStepRange(RejectAny));
This StepRange looks unnecessary because parseToNumber call below never fails.
yosin
Comment 22
2012-08-02 02:26:55 PDT
(In reply to
comment #20
)
> (In reply to
comment #19
) > > > Still have possibility of integer overflow because sizeof(size_t) is usually same as sizeof(long). > > > > > > middle = left + (right - left) / 2; > > > > > > > It is impossible to have elements in Vector due by available memory. > > Right. However we should always write correct code because the code might be copied, and the copy might have integer overflow.
Can we use binarySearch in WTF/wtf/StdLibExtras.h?
http://trac.webkit.org/browser/trunk/Source/WTF/wtf/StdLibExtras.h
Keishi Hattori
Comment 23
2012-08-02 02:35:26 PDT
(In reply to
comment #22
)
> (In reply to
comment #20
) > > (In reply to
comment #19
) > > > > Still have possibility of integer overflow because sizeof(size_t) is usually same as sizeof(long). > > > > > > > > middle = left + (right - left) / 2; > > > > > > > > > > It is impossible to have elements in Vector due by available memory. > > > > Right. However we should always write correct code because the code might be copied, and the copy might have integer overflow. > > Can we use binarySearch in WTF/wtf/StdLibExtras.h? >
http://trac.webkit.org/browser/trunk/Source/WTF/wtf/StdLibExtras.h
I guess its possible by creating a new class that represents the space between tick marks. And doing a binary search against that.
yosin
Comment 24
2012-08-02 02:42:05 PDT
(In reply to
comment #18
)
> > > Source/WebCore/html/shadow/SliderThumbElement.cpp:280 > > > + double closestFraction = stepRange.proportionFromValue(closest).toDouble(); > > > > Is it better to do in decimal arithmetic? > > Could you tell me why do we use double arithmetic? For speed? > > Should I use decimal arithmetic? My thinking was that Decimal precision is unnecessary and it would be slightly faster to use double.
Agree, we don't need to use decimal arithmetic. However, it seems it is better to use LayoutUnit instead of double. Because postion and trackSize are LayoutUnit and closestPostion also can be LayoutUnit.
Kent Tamura
Comment 25
2012-08-02 03:07:11 PDT
(In reply to
comment #24
)
> (In reply to
comment #18
) > > > > Source/WebCore/html/shadow/SliderThumbElement.cpp:280 > > > > + double closestFraction = stepRange.proportionFromValue(closest).toDouble(); > > > > > > Is it better to do in decimal arithmetic? > > > Could you tell me why do we use double arithmetic? For speed? > > > > Should I use decimal arithmetic? My thinking was that Decimal precision is unnecessary and it would be slightly faster to use double. > > Agree, we don't need to use decimal arithmetic. > However, it seems it is better to use LayoutUnit instead of double. Because postion and trackSize are LayoutUnit and closestPostion also can be LayoutUnit.
We shouldn't use LayoutUnit here. LayoutUnit is an alias of int if !ENABLE(SUBPIXEL_LAYOUT).
Kent Tamura
Comment 26
2012-08-02 03:16:56 PDT
(In reply to
comment #25
)
> > However, it seems it is better to use LayoutUnit instead of double. Because postion and trackSize are LayoutUnit and closestPostion also can be LayoutUnit. > > We shouldn't use LayoutUnit here. LayoutUnit is an alias of int if !ENABLE(SUBPIXEL_LAYOUT).
We discussed offline. We had better make 'closestPosition' and 'snapThreashold' LayoutUnit because they are pixel lengths.
Keishi Hattori
Comment 27
2012-08-02 03:36:49 PDT
Created
attachment 156028
[details]
Patch
Kent Tamura
Comment 28
2012-08-02 03:45:38 PDT
Comment on
attachment 156028
[details]
Patch ok
WebKit Review Bot
Comment 29
2012-08-02 19:06:06 PDT
Comment on
attachment 156028
[details]
Patch Clearing flags on attachment: 156028 Committed
r124549
: <
http://trac.webkit.org/changeset/124549
>
WebKit Review Bot
Comment 30
2012-08-02 19:06:12 PDT
All reviewed patches have been landed. Closing bug.
János Badics
Comment 31
2012-08-03 00:40:22 PDT
Unfortunately the newly added test (fast/forms/datalist/range-snap-to-datalist.html) fails on Qt and EFL bots since
r124549
. I created a bug entry for the issue:
https://bugs.webkit.org/show_bug.cgi?id=93074
Would you give it a look please?
Note
You need to
log in
before you can comment on or make changes to this bug.
Top of Page
Format For Printing
XML
Clone This Bug