Index: third_party/WebKit/Source/core/html/shadow/SliderThumbElement.cpp |
diff --git a/third_party/WebKit/Source/core/html/shadow/SliderThumbElement.cpp b/third_party/WebKit/Source/core/html/shadow/SliderThumbElement.cpp |
index 40baeeb07c8448ab3af006fe57b275ac6d5ae3d5..3f147c3489f62434f5a7ec79f692fb61b8fdb747 100644 |
--- a/third_party/WebKit/Source/core/html/shadow/SliderThumbElement.cpp |
+++ b/third_party/WebKit/Source/core/html/shadow/SliderThumbElement.cpp |
@@ -34,6 +34,8 @@ |
#include "core/dom/shadow/ShadowRoot.h" |
#include "core/events/Event.h" |
#include "core/events/MouseEvent.h" |
+#include "core/events/TouchEvent.h" |
+#include "core/frame/EventHandlerRegistry.h" |
#include "core/frame/LocalFrame.h" |
#include "core/html/HTMLInputElement.h" |
#include "core/html/forms/StepRange.h" |
@@ -299,16 +301,106 @@ const AtomicString& SliderThumbElement::shadowPseudoId() const |
inline SliderContainerElement::SliderContainerElement(Document& document) |
: HTMLDivElement(document) |
+ , m_hasTouchEventHandler(false) |
+ , m_touchStarted(false) |
+ , m_slidingDirection(NoMove) |
{ |
+ updateTouchEventHandlerRegistry(); |
} |
DEFINE_NODE_FACTORY(SliderContainerElement) |
+HTMLInputElement* SliderContainerElement::hostInput() const |
+{ |
+ return toHTMLInputElement(shadowHost()); |
+} |
+ |
LayoutObject* SliderContainerElement::createLayoutObject(const ComputedStyle&) |
{ |
return new LayoutSliderContainer(this); |
} |
+void SliderContainerElement::defaultEventHandler(Event* event) |
+{ |
+ if (event->isTouchEvent()) { |
+ handleTouchEvent(toTouchEvent(event)); |
+ return; |
+ } |
+} |
+ |
+void SliderContainerElement::handleTouchEvent(TouchEvent* event) |
+{ |
+ HTMLInputElement* input = hostInput(); |
+ if (input->isDisabledOrReadOnly()) |
+ return; |
+ |
+ if (event->type() == EventTypeNames::touchend) { |
+ input->dispatchFormControlChangeEvent(); |
+ event->setDefaultHandled(); |
+ m_slidingDirection = NoMove; |
+ m_touchStarted = false; |
+ return; |
+ } |
+ |
+ // The direction of this series of touch actions has been determined, which is |
+ // perpendicular to the slider, so no need to adjust the value. |
+ if (!canSlide()) { |
+ return; |
+ } |
+ |
+ TouchList* touches = event->targetTouches(); |
+ SliderThumbElement* thumb = toSliderThumbElement(treeScope().getElementById(ShadowElementNames::sliderThumb())); |
+ if (touches->length() == 1) { |
+ if (event->type() == EventTypeNames::touchstart) { |
+ m_startPoint = touches->item(0)->absoluteLocation(); |
+ m_slidingDirection = NoMove; |
+ m_touchStarted = true; |
+ thumb->setPositionFromPoint(touches->item(0)->absoluteLocation()); |
+ } else if (m_touchStarted) { |
+ LayoutPoint currentPoint = touches->item(0)->absoluteLocation(); |
+ if (m_slidingDirection == NoMove) { // Still needs to update the direction. |
+ m_slidingDirection = getDirection(currentPoint, m_startPoint); |
+ } |
+ |
+ // m_slidingDirection has been updated, so check whether it's okay to slide again. |
+ if (canSlide()) { |
+ thumb->setPositionFromPoint(touches->item(0)->absoluteLocation()); |
+ event->setDefaultHandled(); |
+ } |
+ } |
+ } |
+} |
+ |
+SliderContainerElement::Direction SliderContainerElement::getDirection(LayoutPoint& point1, LayoutPoint& point2) |
+{ |
+ if (point1 == point2) { |
+ return NoMove; |
+ } |
+ if ((point1.x() - point2.x()).abs() >= (point1.y() - point2.y()).abs()) { |
+ return Horizontal; |
+ } |
+ return Vertical; |
+} |
+ |
+bool SliderContainerElement::canSlide() |
+{ |
+ DCHECK(hostInput()->layoutObject()); |
+ const ComputedStyle& sliderStyle = hostInput()->layoutObject()->styleRef(); |
+ const TransformOperations& transforms = sliderStyle.transform(); |
+ int transformSize = transforms.size(); |
+ if (transformSize > 0) { |
+ for (int i = 0; i < transformSize; ++i) { |
+ if (transforms.at(i)->type() == TransformOperation::Rotate) { |
+ return true; |
+ } |
+ } |
+ } |
+ if ((m_slidingDirection == Vertical && sliderStyle.appearance() == SliderHorizontalPart) || (m_slidingDirection == Horizontal && sliderStyle.appearance() == SliderVerticalPart)) { |
+ return false; |
+ } |
+ return true; |
+} |
+ |
const AtomicString& SliderContainerElement::shadowPseudoId() const |
{ |
DEFINE_STATIC_LOCAL(const AtomicString, mediaSliderContainer, ("-webkit-media-slider-container")); |
@@ -331,4 +423,28 @@ const AtomicString& SliderContainerElement::shadowPseudoId() const |
} |
} |
+void SliderContainerElement::updateTouchEventHandlerRegistry() |
+{ |
+ if (m_hasTouchEventHandler) { |
+ return; |
+ } |
+ if (document().frameHost() && document().lifecycle().state() < DocumentLifecycle::Stopping) { |
+ EventHandlerRegistry& registry = document().frameHost()->eventHandlerRegistry(); |
+ registry.didAddEventHandler(*this, EventHandlerRegistry::TouchStartOrMoveEventPassive); |
+ m_hasTouchEventHandler = true; |
+ } |
+} |
+ |
+void SliderContainerElement::didMoveToNewDocument(Document& oldDocument) |
+{ |
+ updateTouchEventHandlerRegistry(); |
+ HTMLElement::didMoveToNewDocument(oldDocument); |
+} |
+ |
+void SliderContainerElement::removeAllEventListeners() |
+{ |
+ Node::removeAllEventListeners(); |
+ m_hasTouchEventHandler = false; |
+} |
+ |
} // namespace blink |