Title: [214955] trunk
Revision
214955
Author
[email protected]
Date
2017-04-05 11:47:39 -0700 (Wed, 05 Apr 2017)

Log Message

<input type="range"> changing to disabled while active breaks all pointer events
https://bugs.webkit.org/show_bug.cgi?id=170447
<rdar://problem/31442875>

Reviewed by Geoffrey Garen.

Source/WebCore:

When a range's slider is being moved, we set SliderThumbElement's m_inDragMode flag
to true and mark the range elements as the CapturingMouseEventsElement. When we get
the mouseUp event, we are supposed to exit drag mode. However, when the range element
gets disabled while dragging, we do not get the mouseUp event and we need to make
sure we exit dragging mode anyway. r112547 tried to fix this by calling stopDragging()
in SliderThumbElement::defaultEventHandler() when the input element is disabled.
While this often works, this is fragile and we sometimes fail to exit dragging mode
when we should.

This patch addressed the issue by calling stopDragging() in
SliderThumbElement::disabledAttributeChanged() instead. This is much safer as we
guarantee will exit dragging mode whenever the range element gets disabled, even
if SliderThumbElement::defaultEventHandler() does not get called after that.

Test: fast/forms/range/disabled-while-dragging.html

* html/RangeInputType.cpp:
(WebCore::RangeInputType::disabledAttributeChanged):
* html/RangeInputType.h:
* html/shadow/SliderThumbElement.cpp:
(WebCore::SliderThumbElement::defaultEventHandler):
(WebCore::SliderThumbElement::disabledAttributeChanged):
* html/shadow/SliderThumbElement.h:

LayoutTests:

Add layout test coverage.

* fast/forms/range/disabled-while-dragging-expected.txt: Added.
* fast/forms/range/disabled-while-dragging.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (214954 => 214955)


--- trunk/LayoutTests/ChangeLog	2017-04-05 18:43:33 UTC (rev 214954)
+++ trunk/LayoutTests/ChangeLog	2017-04-05 18:47:39 UTC (rev 214955)
@@ -1,3 +1,16 @@
+2017-04-05  Chris Dumez  <[email protected]>
+
+        <input type="range"> changing to disabled while active breaks all pointer events
+        https://bugs.webkit.org/show_bug.cgi?id=170447
+        <rdar://problem/31442875>
+
+        Reviewed by Geoffrey Garen.
+
+        Add layout test coverage.
+
+        * fast/forms/range/disabled-while-dragging-expected.txt: Added.
+        * fast/forms/range/disabled-while-dragging.html: Added.
+
 2017-04-05  Jiewen Tan  <[email protected]>
 
         Unreviewed, rebasing crypto/subtle/rsa-import-key-malformed-parameters.html

Added: trunk/LayoutTests/fast/forms/range/disabled-while-dragging-expected.txt (0 => 214955)


--- trunk/LayoutTests/fast/forms/range/disabled-while-dragging-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/forms/range/disabled-while-dragging-expected.txt	2017-04-05 18:47:39 UTC (rev 214955)
@@ -0,0 +1,14 @@
+Tests that click events still work after a range is disabled while dragging.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS range.disabled is false
+Drag range slider.
+PASS range.disabled is true
+Click button
+PASS buttonClicked is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+ Click

Added: trunk/LayoutTests/fast/forms/range/disabled-while-dragging.html (0 => 214955)


--- trunk/LayoutTests/fast/forms/range/disabled-while-dragging.html	                        (rev 0)
+++ trunk/LayoutTests/fast/forms/range/disabled-while-dragging.html	2017-04-05 18:47:39 UTC (rev 214955)
@@ -0,0 +1,59 @@
+<!doctype html>
+<html>
+<body>
+<script src=""
+<script>
+description("Tests that click events still work after a range is disabled while dragging.");
+jsTestIsAsync = true;
+
+const input = (that) => {
+    if (Math.abs(that.value - 50) === 50)
+        that.disabled = true;
+};
+
+let buttonClicked = false;
+
+function buttonClick()
+{
+    buttonClicked = true;
+}
+
+_onload_ = function() {
+    range = document.querySelector("input");
+
+    shouldBeFalse("range.disabled");
+
+    debug("Drag range slider.");
+    var centerY = range.offsetTop + range.offsetHeight / 2;
+    var centerX = range.offsetLeft + range.offsetWidth / 2;
+    var rightEdgeX = range.offsetLeft + range.offsetWidth - 1;
+
+    eventSender.mouseMoveTo(centerX, centerY);
+    eventSender.mouseDown();
+    eventSender.mouseMoveTo(rightEdgeX, centerY);
+    eventSender.mouseUp();
+
+    setTimeout(function() {
+        shouldBeTrue("range.disabled");
+
+        debug("Click button");
+        button = document.querySelector("button");
+        var centerY = button.offsetTop + button.offsetHeight / 2;
+        var centerX = button.offsetLeft + button.offsetWidth / 2;
+        eventSender.mouseMoveTo(centerX, centerY);
+        eventSender.mouseDown();
+        eventSender.mouseUp();
+
+        setTimeout(function() {
+            shouldBeTrue("buttonClicked");
+            finishJSTest();
+        }, 0);
+    }, 0);
+}
+</script>
+
+<input type="range" _oninput_="input(this)">
+<button _onclick_="buttonClick()">Click</button>
+<script src=""
+</body>
+</html>

Modified: trunk/LayoutTests/platform/ios/TestExpectations (214954 => 214955)


--- trunk/LayoutTests/platform/ios/TestExpectations	2017-04-05 18:43:33 UTC (rev 214954)
+++ trunk/LayoutTests/platform/ios/TestExpectations	2017-04-05 18:47:39 UTC (rev 214955)
@@ -380,6 +380,8 @@
 media/audio-dealloc-crash.html [ Skip ]
 
 # This test uses EventSender's mouseMoveTo, mouseUp and mouseDown
+fast/forms/range/disabled-while-dragging.html [ Skip ]
+fast/forms/range/range-drag-when-toggled-disabled.html [ Skip ]
 fast/media/video-element-in-details-collapse.html [ Skip ]
 
 # The file-wrapper part of <attachment> is not yet working on iOS
@@ -1421,7 +1423,6 @@
 fast/forms/password-placeholder-text-security.html [ Pass ImageOnlyFailure ]
 fast/forms/placeholder-position.html [ Failure ]
 fast/forms/radio/indeterminate-radio.html [ Pass Failure ]
-fast/forms/range/range-drag-when-toggled-disabled.html [ Failure ]
 fast/forms/range/range-drag.html [ Failure ]
 fast/forms/range/range-hit-test-with-padding.html [ Failure ]
 fast/forms/range/range-slow-drag-to-edge.html [ Failure ]

Modified: trunk/Source/WebCore/ChangeLog (214954 => 214955)


--- trunk/Source/WebCore/ChangeLog	2017-04-05 18:43:33 UTC (rev 214954)
+++ trunk/Source/WebCore/ChangeLog	2017-04-05 18:47:39 UTC (rev 214955)
@@ -1,3 +1,35 @@
+2017-04-05  Chris Dumez  <[email protected]>
+
+        <input type="range"> changing to disabled while active breaks all pointer events
+        https://bugs.webkit.org/show_bug.cgi?id=170447
+        <rdar://problem/31442875>
+
+        Reviewed by Geoffrey Garen.
+
+        When a range's slider is being moved, we set SliderThumbElement's m_inDragMode flag
+        to true and mark the range elements as the CapturingMouseEventsElement. When we get
+        the mouseUp event, we are supposed to exit drag mode. However, when the range element
+        gets disabled while dragging, we do not get the mouseUp event and we need to make
+        sure we exit dragging mode anyway. r112547 tried to fix this by calling stopDragging()
+        in SliderThumbElement::defaultEventHandler() when the input element is disabled.
+        While this often works, this is fragile and we sometimes fail to exit dragging mode
+        when we should.
+
+        This patch addressed the issue by calling stopDragging() in
+        SliderThumbElement::disabledAttributeChanged() instead. This is much safer as we
+        guarantee will exit dragging mode whenever the range element gets disabled, even
+        if SliderThumbElement::defaultEventHandler() does not get called after that.
+
+        Test: fast/forms/range/disabled-while-dragging.html
+
+        * html/RangeInputType.cpp:
+        (WebCore::RangeInputType::disabledAttributeChanged):
+        * html/RangeInputType.h:
+        * html/shadow/SliderThumbElement.cpp:
+        (WebCore::SliderThumbElement::defaultEventHandler):
+        (WebCore::SliderThumbElement::disabledAttributeChanged):
+        * html/shadow/SliderThumbElement.h:
+
 2017-04-05  Eric Carlson  <[email protected]>
 
         [MediaStream] Video doesn't render in fullscreen on iOS

Modified: trunk/Source/WebCore/html/RangeInputType.cpp (214954 => 214955)


--- trunk/Source/WebCore/html/RangeInputType.cpp	2017-04-05 18:43:33 UTC (rev 214954)
+++ trunk/Source/WebCore/html/RangeInputType.cpp	2017-04-05 18:47:39 UTC (rev 214955)
@@ -182,14 +182,12 @@
     return true;
 }
 #endif
+#endif // ENABLE(TOUCH_EVENTS)
 
-#if PLATFORM(IOS)
 void RangeInputType::disabledAttributeChanged()
 {
     typedSliderThumbElement().disabledAttributeChanged();
 }
-#endif
-#endif // ENABLE(TOUCH_EVENTS)
 
 void RangeInputType::handleKeydownEvent(KeyboardEvent& event)
 {

Modified: trunk/Source/WebCore/html/RangeInputType.h (214954 => 214955)


--- trunk/Source/WebCore/html/RangeInputType.h	2017-04-05 18:43:33 UTC (rev 214954)
+++ trunk/Source/WebCore/html/RangeInputType.h	2017-04-05 18:47:39 UTC (rev 214955)
@@ -81,9 +81,7 @@
     void handleTouchEvent(TouchEvent&) final;
 #endif
 
-#if ENABLE(TOUCH_EVENTS) && PLATFORM(IOS)
     void disabledAttributeChanged() final;
-#endif
 
 #if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS) && ENABLE(TOUCH_SLIDER)
     bool hasTouchEventHandler() const final;

Modified: trunk/Source/WebCore/html/shadow/SliderThumbElement.cpp (214954 => 214955)


--- trunk/Source/WebCore/html/shadow/SliderThumbElement.cpp	2017-04-05 18:43:33 UTC (rev 214954)
+++ trunk/Source/WebCore/html/shadow/SliderThumbElement.cpp	2017-04-05 18:47:39 UTC (rev 214955)
@@ -349,7 +349,6 @@
     // Missing this kind of check is likely to occur elsewhere if adding it in each shadow element.
     HTMLInputElement* input = hostInput();
     if (!input || input->isDisabledFormControl()) {
-        stopDragging();
         HTMLDivElement::defaultEventHandler(event);
         return;
     }
@@ -564,15 +563,20 @@
     document().removeTouchEventHandler(*this);
     m_isRegisteredAsTouchEventListener = false;
 }
+#endif // ENABLE(IOS_TOUCH_EVENTS)
 
 void SliderThumbElement::disabledAttributeChanged()
 {
+    if (isDisabledFormControl())
+        stopDragging();
+
+#if ENABLE(IOS_TOUCH_EVENTS)
     if (shouldAcceptTouchEvents())
         registerForTouchEvents();
     else
         unregisterForTouchEvents();
+#endif
 }
-#endif // ENABLE(IOS_TOUCH_EVENTS)
 
 HTMLInputElement* SliderThumbElement::hostInput() const
 {

Modified: trunk/Source/WebCore/html/shadow/SliderThumbElement.h (214954 => 214955)


--- trunk/Source/WebCore/html/shadow/SliderThumbElement.h	2017-04-05 18:43:33 UTC (rev 214954)
+++ trunk/Source/WebCore/html/shadow/SliderThumbElement.h	2017-04-05 18:47:39 UTC (rev 214955)
@@ -52,9 +52,9 @@
 
 #if ENABLE(IOS_TOUCH_EVENTS)
     void handleTouchEvent(TouchEvent&);
+#endif
 
     void disabledAttributeChanged();
-#endif
 
 private:
     SliderThumbElement(Document&);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to