| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "core/input/TouchEventManager.h" | 5 #include "core/input/TouchEventManager.h" |
| 6 | 6 |
| 7 #include "core/dom/Document.h" | 7 #include "core/dom/Document.h" |
| 8 #include "core/events/TouchEvent.h" | 8 #include "core/events/TouchEvent.h" |
| 9 #include "core/frame/Deprecation.h" | 9 #include "core/frame/Deprecation.h" |
| 10 #include "core/frame/EventHandlerRegistry.h" | 10 #include "core/frame/EventHandlerRegistry.h" |
| 11 #include "core/frame/FrameHost.h" | 11 #include "core/frame/FrameHost.h" |
| 12 #include "core/frame/FrameView.h" | 12 #include "core/frame/FrameView.h" |
| 13 #include "core/html/HTMLCanvasElement.h" | 13 #include "core/html/HTMLCanvasElement.h" |
| 14 #include "core/input/EventHandlingUtil.h" | 14 #include "core/input/EventHandlingUtil.h" |
| 15 #include "core/input/TouchActionUtil.h" | 15 #include "core/input/TouchActionUtil.h" |
| 16 #include "core/layout/HitTestCanvasResult.h" | 16 #include "core/layout/HitTestCanvasResult.h" |
| 17 #include "core/page/ChromeClient.h" | 17 #include "core/page/ChromeClient.h" |
| 18 #include "core/page/Page.h" | 18 #include "core/page/Page.h" |
| 19 #include "platform/Histogram.h" | 19 #include "platform/Histogram.h" |
| 20 #include "platform/PlatformTouchEvent.h" | 20 #include "public/platform/WebTouchEvent.h" |
| 21 #include "wtf/CurrentTime.h" | 21 #include "wtf/CurrentTime.h" |
| 22 #include "wtf/PtrUtil.h" | 22 #include "wtf/PtrUtil.h" |
| 23 #include <memory> | 23 #include <memory> |
| 24 | 24 |
| 25 namespace blink { | 25 namespace blink { |
| 26 | 26 |
| 27 namespace { | 27 namespace { |
| 28 | 28 |
| 29 bool hasTouchHandlers(const EventHandlerRegistry& registry) { | 29 bool hasTouchHandlers(const EventHandlerRegistry& registry) { |
| 30 return registry.hasEventHandlers( | 30 return registry.hasEventHandlers( |
| 31 EventHandlerRegistry::TouchStartOrMoveEventBlocking) || | 31 EventHandlerRegistry::TouchStartOrMoveEventBlocking) || |
| 32 registry.hasEventHandlers( | 32 registry.hasEventHandlers( |
| 33 EventHandlerRegistry::TouchStartOrMoveEventPassive) || | 33 EventHandlerRegistry::TouchStartOrMoveEventPassive) || |
| 34 registry.hasEventHandlers( | 34 registry.hasEventHandlers( |
| 35 EventHandlerRegistry::TouchEndOrCancelEventBlocking) || | 35 EventHandlerRegistry::TouchEndOrCancelEventBlocking) || |
| 36 registry.hasEventHandlers( | 36 registry.hasEventHandlers( |
| 37 EventHandlerRegistry::TouchEndOrCancelEventPassive); | 37 EventHandlerRegistry::TouchEndOrCancelEventPassive); |
| 38 } | 38 } |
| 39 | 39 |
| 40 const AtomicString& touchEventNameForTouchPointState( | 40 const AtomicString& touchEventNameForTouchPointState( |
| 41 PlatformTouchPoint::TouchState state) { | 41 WebTouchPoint::State state) { |
| 42 switch (state) { | 42 switch (state) { |
| 43 case PlatformTouchPoint::TouchReleased: | 43 case WebTouchPoint::StateReleased: |
| 44 return EventTypeNames::touchend; | 44 return EventTypeNames::touchend; |
| 45 case PlatformTouchPoint::TouchCancelled: | 45 case WebTouchPoint::StateCancelled: |
| 46 return EventTypeNames::touchcancel; | 46 return EventTypeNames::touchcancel; |
| 47 case PlatformTouchPoint::TouchPressed: | 47 case WebTouchPoint::StatePressed: |
| 48 return EventTypeNames::touchstart; | 48 return EventTypeNames::touchstart; |
| 49 case PlatformTouchPoint::TouchMoved: | 49 case WebTouchPoint::StateMoved: |
| 50 return EventTypeNames::touchmove; | 50 return EventTypeNames::touchmove; |
| 51 case PlatformTouchPoint::TouchStationary: | 51 case WebTouchPoint::StateStationary: |
| 52 // Fall through to default | 52 // Fall through to default |
| 53 default: | 53 default: |
| 54 ASSERT_NOT_REACHED(); | 54 ASSERT_NOT_REACHED(); |
| 55 return emptyAtom; | 55 return emptyAtom; |
| 56 } | 56 } |
| 57 } | 57 } |
| 58 | 58 |
| 59 enum TouchEventDispatchResultType { | 59 enum TouchEventDispatchResultType { |
| 60 UnhandledTouches, // Unhandled touch events. | 60 UnhandledTouches, // Unhandled touch events. |
| 61 HandledTouches, // Handled touch events. | 61 HandledTouches, // Handled touch events. |
| (...skipping 26 matching lines...) Expand all Loading... |
| 88 | 88 |
| 89 TouchEventManager::TouchEventManager(LocalFrame& frame) : m_frame(frame) { | 89 TouchEventManager::TouchEventManager(LocalFrame& frame) : m_frame(frame) { |
| 90 clear(); | 90 clear(); |
| 91 } | 91 } |
| 92 | 92 |
| 93 void TouchEventManager::clear() { | 93 void TouchEventManager::clear() { |
| 94 m_touchSequenceDocument.clear(); | 94 m_touchSequenceDocument.clear(); |
| 95 m_targetForTouchID.clear(); | 95 m_targetForTouchID.clear(); |
| 96 m_regionForTouchID.clear(); | 96 m_regionForTouchID.clear(); |
| 97 m_touchPressed = false; | 97 m_touchPressed = false; |
| 98 m_currentEvent = PlatformEvent::NoType; | |
| 99 m_currentTouchAction = TouchActionAuto; | 98 m_currentTouchAction = TouchActionAuto; |
| 100 } | 99 } |
| 101 | 100 |
| 102 DEFINE_TRACE(TouchEventManager) { | 101 DEFINE_TRACE(TouchEventManager) { |
| 103 visitor->trace(m_frame); | 102 visitor->trace(m_frame); |
| 104 visitor->trace(m_touchSequenceDocument); | 103 visitor->trace(m_touchSequenceDocument); |
| 105 visitor->trace(m_targetForTouchID); | 104 visitor->trace(m_targetForTouchID); |
| 106 } | 105 } |
| 107 | 106 |
| 108 WebInputEventResult TouchEventManager::dispatchTouchEvents( | 107 WebInputEventResult TouchEventManager::dispatchTouchEvents( |
| 109 const PlatformTouchEvent& event, | 108 const WebTouchEvent& event, |
| 110 const HeapVector<TouchInfo>& touchInfos, | 109 const HeapVector<TouchInfo>& touchInfos, |
| 111 bool allTouchesReleased) { | 110 bool allTouchesReleased) { |
| 112 // Build up the lists to use for the |touches|, |targetTouches| and | 111 // Build up the lists to use for the |touches|, |targetTouches| and |
| 113 // |changedTouches| attributes in the JS event. See | 112 // |changedTouches| attributes in the JS event. See |
| 114 // http://www.w3.org/TR/touch-events/#touchevent-interface for how these | 113 // http://www.w3.org/TR/touch-events/#touchevent-interface for how these |
| 115 // lists fit together. | 114 // lists fit together. |
| 116 | 115 |
| 117 // Holds the complete set of touches on the screen. | 116 // Holds the complete set of touches on the screen. |
| 118 TouchList* touches = TouchList::create(); | 117 TouchList* touches = TouchList::create(); |
| 119 | 118 |
| 120 // A different view on the 'touches' list above, filtered and grouped by | 119 // A different view on the 'touches' list above, filtered and grouped by |
| 121 // event target. Used for the |targetTouches| list in the JS event. | 120 // event target. Used for the |targetTouches| list in the JS event. |
| 122 using TargetTouchesHeapMap = HeapHashMap<EventTarget*, Member<TouchList>>; | 121 using TargetTouchesHeapMap = HeapHashMap<EventTarget*, Member<TouchList>>; |
| 123 TargetTouchesHeapMap touchesByTarget; | 122 TargetTouchesHeapMap touchesByTarget; |
| 124 | 123 |
| 125 // Array of touches per state, used to assemble the |changedTouches| list. | 124 // Array of touches per state, used to assemble the |changedTouches| list. |
| 126 ChangedTouches changedTouches[PlatformTouchPoint::TouchStateEnd]; | 125 ChangedTouches changedTouches[WebTouchPoint::StateMax + 1]; |
| 127 | 126 |
| 128 for (auto touchInfo : touchInfos) { | 127 for (auto touchInfo : touchInfos) { |
| 129 const PlatformTouchPoint& point = touchInfo.point; | 128 const WebTouchPoint& point = touchInfo.point; |
| 130 PlatformTouchPoint::TouchState pointState = point.state(); | 129 WebTouchPoint::State pointState = point.state; |
| 131 | 130 |
| 132 Touch* touch = Touch::create( | 131 Touch* touch = Touch::create( |
| 133 touchInfo.targetFrame.get(), touchInfo.touchNode.get(), point.id(), | 132 touchInfo.targetFrame.get(), touchInfo.touchNode.get(), point.id, |
| 134 point.screenPos(), touchInfo.contentPoint, touchInfo.adjustedRadius, | 133 point.screenPosition, touchInfo.contentPoint, touchInfo.adjustedRadius, |
| 135 point.rotationAngle(), point.force(), touchInfo.region); | 134 point.rotationAngle, point.force, touchInfo.region); |
| 136 | 135 |
| 137 // Ensure this target's touch list exists, even if it ends up empty, so | 136 // Ensure this target's touch list exists, even if it ends up empty, so |
| 138 // it can always be passed to TouchEvent::Create below. | 137 // it can always be passed to TouchEvent::Create below. |
| 139 TargetTouchesHeapMap::iterator targetTouchesIterator = | 138 TargetTouchesHeapMap::iterator targetTouchesIterator = |
| 140 touchesByTarget.find(touchInfo.touchNode.get()); | 139 touchesByTarget.find(touchInfo.touchNode.get()); |
| 141 if (targetTouchesIterator == touchesByTarget.end()) { | 140 if (targetTouchesIterator == touchesByTarget.end()) { |
| 142 touchesByTarget.set(touchInfo.touchNode.get(), TouchList::create()); | 141 touchesByTarget.set(touchInfo.touchNode.get(), TouchList::create()); |
| 143 targetTouchesIterator = touchesByTarget.find(touchInfo.touchNode.get()); | 142 targetTouchesIterator = touchesByTarget.find(touchInfo.touchNode.get()); |
| 144 } | 143 } |
| 145 | 144 |
| 146 // |touches| and |targetTouches| should only contain information about | 145 // |touches| and |targetTouches| should only contain information about |
| 147 // touches still on the screen, so if this point is released or | 146 // touches still on the screen, so if this point is released or |
| 148 // cancelled it will only appear in the |changedTouches| list. | 147 // cancelled it will only appear in the |changedTouches| list. |
| 149 if (pointState != PlatformTouchPoint::TouchReleased && | 148 if (pointState != WebTouchPoint::StateReleased && |
| 150 pointState != PlatformTouchPoint::TouchCancelled) { | 149 pointState != WebTouchPoint::StateCancelled) { |
| 151 touches->append(touch); | 150 touches->append(touch); |
| 152 targetTouchesIterator->value->append(touch); | 151 targetTouchesIterator->value->append(touch); |
| 153 } | 152 } |
| 154 | 153 |
| 155 // Now build up the correct list for |changedTouches|. | 154 // Now build up the correct list for |changedTouches|. |
| 156 // Note that any touches that are in the TouchStationary state (e.g. if | 155 // Note that any touches that are in the TouchStationary state (e.g. if |
| 157 // the user had several points touched but did not move them all) should | 156 // the user had several points touched but did not move them all) should |
| 158 // never be in the |changedTouches| list so we do not handle them | 157 // never be in the |changedTouches| list so we do not handle them |
| 159 // explicitly here. See https://bugs.webkit.org/show_bug.cgi?id=37609 | 158 // explicitly here. See https://bugs.webkit.org/show_bug.cgi?id=37609 |
| 160 // for further discussion about the TouchStationary state. | 159 // for further discussion about the TouchStationary state. |
| 161 if (pointState != PlatformTouchPoint::TouchStationary && | 160 if (pointState != WebTouchPoint::StateStationary && touchInfo.knownTarget) { |
| 162 touchInfo.knownTarget) { | 161 DCHECK_LE(pointState, WebTouchPoint::StateMax); |
| 163 ASSERT(pointState < PlatformTouchPoint::TouchStateEnd); | |
| 164 if (!changedTouches[pointState].m_touches) | 162 if (!changedTouches[pointState].m_touches) |
| 165 changedTouches[pointState].m_touches = TouchList::create(); | 163 changedTouches[pointState].m_touches = TouchList::create(); |
| 166 changedTouches[pointState].m_touches->append(touch); | 164 changedTouches[pointState].m_touches->append(touch); |
| 167 changedTouches[pointState].m_targets.insert(touchInfo.touchNode); | 165 changedTouches[pointState].m_targets.insert(touchInfo.touchNode); |
| 168 changedTouches[pointState].m_pointerType = | 166 changedTouches[pointState].m_pointerType = point.pointerType; |
| 169 point.pointerProperties().pointerType; | |
| 170 } | 167 } |
| 171 } | 168 } |
| 172 | 169 |
| 173 if (allTouchesReleased) { | 170 if (allTouchesReleased) { |
| 174 m_touchSequenceDocument.clear(); | 171 m_touchSequenceDocument.clear(); |
| 175 m_currentTouchAction = TouchActionAuto; | 172 m_currentTouchAction = TouchActionAuto; |
| 176 } | 173 } |
| 177 | 174 |
| 178 WebInputEventResult eventResult = WebInputEventResult::NotHandled; | 175 WebInputEventResult eventResult = WebInputEventResult::NotHandled; |
| 179 | 176 |
| 180 // Now iterate through the |changedTouches| list and |m_targets| within it, | 177 // Now iterate through the |changedTouches| list and |m_targets| within it, |
| 181 // sending TouchEvents to the targets as required. | 178 // sending TouchEvents to the targets as required. |
| 182 for (unsigned state = 0; state != PlatformTouchPoint::TouchStateEnd; | 179 for (unsigned state = 0; state <= WebTouchPoint::StateMax; ++state) { |
| 183 ++state) { | |
| 184 if (!changedTouches[state].m_touches) | 180 if (!changedTouches[state].m_touches) |
| 185 continue; | 181 continue; |
| 186 | 182 |
| 187 const AtomicString& eventName(touchEventNameForTouchPointState( | 183 const AtomicString& eventName(touchEventNameForTouchPointState( |
| 188 static_cast<PlatformTouchPoint::TouchState>(state))); | 184 static_cast<WebTouchPoint::State>(state))); |
| 189 for (const auto& eventTarget : changedTouches[state].m_targets) { | 185 for (const auto& eventTarget : changedTouches[state].m_targets) { |
| 190 EventTarget* touchEventTarget = eventTarget; | 186 EventTarget* touchEventTarget = eventTarget; |
| 191 TouchEvent* touchEvent = TouchEvent::create( | 187 TouchEvent* touchEvent = TouchEvent::create( |
| 192 touches, touchesByTarget.get(touchEventTarget), | 188 event, touches, touchesByTarget.get(touchEventTarget), |
| 193 changedTouches[state].m_touches.get(), eventName, | 189 changedTouches[state].m_touches.get(), eventName, |
| 194 touchEventTarget->toNode()->document().domWindow(), | 190 touchEventTarget->toNode()->document().domWindow(), |
| 195 event.getModifiers(), event.cancelable(), | 191 m_currentTouchAction); |
| 196 event.causesScrollingIfUncanceled(), | |
| 197 event.touchStartOrFirstTouchMove(), event.timestamp(), | |
| 198 m_currentTouchAction, changedTouches[state].m_pointerType); | |
| 199 | 192 |
| 200 DispatchEventResult domDispatchResult = | 193 DispatchEventResult domDispatchResult = |
| 201 touchEventTarget->dispatchEvent(touchEvent); | 194 touchEventTarget->dispatchEvent(touchEvent); |
| 202 | 195 |
| 203 // Only report for top level documents with a single touch on | 196 // Only report for top level documents with a single touch on |
| 204 // touch-start or the first touch-move. | 197 // touch-start or the first touch-move. |
| 205 if (event.touchStartOrFirstTouchMove() && touchInfos.size() == 1 && | 198 if (event.touchStartOrFirstTouchMove && touchInfos.size() == 1 && |
| 206 m_frame->isMainFrame()) { | 199 m_frame->isMainFrame()) { |
| 207 // Record the disposition and latency of touch starts and first touch | 200 // Record the disposition and latency of touch starts and first touch |
| 208 // moves before and after the page is fully loaded respectively. | 201 // moves before and after the page is fully loaded respectively. |
| 209 int64_t latencyInMicros = | 202 int64_t latencyInMicros = |
| 210 (TimeTicks::Now() - event.timestamp()).InMicroseconds(); | 203 (TimeTicks::Now() - |
| 211 if (event.cancelable()) { | 204 TimeTicks::FromSeconds(event.timeStampSeconds())) |
| 205 .InMicroseconds(); |
| 206 if (event.isCancelable()) { |
| 212 if (m_frame->document()->isLoadCompleted()) { | 207 if (m_frame->document()->isLoadCompleted()) { |
| 213 DEFINE_STATIC_LOCAL(EnumerationHistogram, | 208 DEFINE_STATIC_LOCAL(EnumerationHistogram, |
| 214 touchDispositionsAfterPageLoadHistogram, | 209 touchDispositionsAfterPageLoadHistogram, |
| 215 ("Event.Touch.TouchDispositionsAfterPageLoad", | 210 ("Event.Touch.TouchDispositionsAfterPageLoad", |
| 216 TouchEventDispatchResultTypeMax)); | 211 TouchEventDispatchResultTypeMax)); |
| 217 touchDispositionsAfterPageLoadHistogram.count( | 212 touchDispositionsAfterPageLoadHistogram.count( |
| 218 (domDispatchResult != DispatchEventResult::NotCanceled) | 213 (domDispatchResult != DispatchEventResult::NotCanceled) |
| 219 ? HandledTouches | 214 ? HandledTouches |
| 220 : UnhandledTouches); | 215 : UnhandledTouches); |
| 221 | 216 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 243 touchDispositionsOutsideFlingHistogram, | 238 touchDispositionsOutsideFlingHistogram, |
| 244 ("Event.Touch.TouchDispositionsOutsideFling2", | 239 ("Event.Touch.TouchDispositionsOutsideFling2", |
| 245 TouchEventDispatchResultTypeMax)); | 240 TouchEventDispatchResultTypeMax)); |
| 246 touchDispositionsOutsideFlingHistogram.count( | 241 touchDispositionsOutsideFlingHistogram.count( |
| 247 (domDispatchResult != DispatchEventResult::NotCanceled) | 242 (domDispatchResult != DispatchEventResult::NotCanceled) |
| 248 ? HandledTouches | 243 ? HandledTouches |
| 249 : UnhandledTouches); | 244 : UnhandledTouches); |
| 250 } | 245 } |
| 251 | 246 |
| 252 // Report the touch disposition when there is an active fling animation. | 247 // Report the touch disposition when there is an active fling animation. |
| 253 if (event.dispatchType() == | 248 if (event.dispatchType == |
| 254 PlatformEvent::ListenersForcedNonBlockingDueToFling) { | 249 WebInputEvent::ListenersForcedNonBlockingDueToFling) { |
| 255 DEFINE_STATIC_LOCAL(EnumerationHistogram, | 250 DEFINE_STATIC_LOCAL(EnumerationHistogram, |
| 256 touchDispositionsDuringFlingHistogram, | 251 touchDispositionsDuringFlingHistogram, |
| 257 ("Event.Touch.TouchDispositionsDuringFling2", | 252 ("Event.Touch.TouchDispositionsDuringFling2", |
| 258 TouchEventDispatchResultTypeMax)); | 253 TouchEventDispatchResultTypeMax)); |
| 259 touchDispositionsDuringFlingHistogram.count( | 254 touchDispositionsDuringFlingHistogram.count( |
| 260 touchEvent->preventDefaultCalledOnUncancelableEvent() | 255 touchEvent->preventDefaultCalledOnUncancelableEvent() |
| 261 ? HandledTouches | 256 ? HandledTouches |
| 262 : UnhandledTouches); | 257 : UnhandledTouches); |
| 263 } | 258 } |
| 264 } | 259 } |
| 265 eventResult = EventHandlingUtil::mergeEventResult( | 260 eventResult = EventHandlingUtil::mergeEventResult( |
| 266 eventResult, | 261 eventResult, |
| 267 EventHandlingUtil::toWebInputEventResult(domDispatchResult)); | 262 EventHandlingUtil::toWebInputEventResult(domDispatchResult)); |
| 268 } | 263 } |
| 269 } | 264 } |
| 270 | 265 |
| 271 return eventResult; | 266 return eventResult; |
| 272 } | 267 } |
| 273 | 268 |
| 274 void TouchEventManager::updateTargetAndRegionMapsForTouchStarts( | 269 void TouchEventManager::updateTargetAndRegionMapsForTouchStarts( |
| 275 HeapVector<TouchInfo>& touchInfos) { | 270 HeapVector<TouchInfo>& touchInfos) { |
| 276 for (auto& touchInfo : touchInfos) { | 271 for (auto& touchInfo : touchInfos) { |
| 277 // Touch events implicitly capture to the touched node, and don't change | 272 // Touch events implicitly capture to the touched node, and don't change |
| 278 // active/hover states themselves (Gesture events do). So we only need | 273 // active/hover states themselves (Gesture events do). So we only need |
| 279 // to hit-test on touchstart and when the target could be different than | 274 // to hit-test on touchstart and when the target could be different than |
| 280 // the corresponding pointer event target. | 275 // the corresponding pointer event target. |
| 281 if (touchInfo.point.state() == PlatformTouchPoint::TouchPressed) { | 276 if (touchInfo.point.state == WebTouchPoint::StatePressed) { |
| 282 HitTestRequest::HitTestRequestType hitType = HitTestRequest::TouchEvent | | 277 HitTestRequest::HitTestRequestType hitType = HitTestRequest::TouchEvent | |
| 283 HitTestRequest::ReadOnly | | 278 HitTestRequest::ReadOnly | |
| 284 HitTestRequest::Active; | 279 HitTestRequest::Active; |
| 285 HitTestResult result; | 280 HitTestResult result; |
| 286 // For the touchPressed points hit-testing is done in | 281 // For the touchPressed points hit-testing is done in |
| 287 // PointerEventManager. If it was the second touch there is a | 282 // PointerEventManager. If it was the second touch there is a |
| 288 // capturing documents for the touch and |m_touchSequenceDocument| | 283 // capturing documents for the touch and |m_touchSequenceDocument| |
| 289 // is not null. So if PointerEventManager should hit-test again | 284 // is not null. So if PointerEventManager should hit-test again |
| 290 // against |m_touchSequenceDocument| if the target set by | 285 // against |m_touchSequenceDocument| if the target set by |
| 291 // PointerEventManager was either null or not in | 286 // PointerEventManager was either null or not in |
| 292 // |m_touchSequenceDocument|. | 287 // |m_touchSequenceDocument|. |
| 293 if (m_touchSequenceDocument && | 288 if (m_touchSequenceDocument && |
| 294 (!touchInfo.touchNode || | 289 (!touchInfo.touchNode || |
| 295 &touchInfo.touchNode->document() != m_touchSequenceDocument)) { | 290 &touchInfo.touchNode->document() != m_touchSequenceDocument)) { |
| 296 if (m_touchSequenceDocument->frame()) { | 291 if (m_touchSequenceDocument->frame()) { |
| 297 LayoutPoint framePoint = LayoutPoint( | 292 LayoutPoint framePoint = LayoutPoint( |
| 298 m_touchSequenceDocument->frame()->view()->rootFrameToContents( | 293 m_touchSequenceDocument->frame()->view()->rootFrameToContents( |
| 299 touchInfo.point.pos())); | 294 touchInfo.point.position)); |
| 300 result = EventHandlingUtil::hitTestResultInFrame( | 295 result = EventHandlingUtil::hitTestResultInFrame( |
| 301 m_touchSequenceDocument->frame(), framePoint, hitType); | 296 m_touchSequenceDocument->frame(), framePoint, hitType); |
| 302 Node* node = result.innerNode(); | 297 Node* node = result.innerNode(); |
| 303 if (!node) | 298 if (!node) |
| 304 continue; | 299 continue; |
| 305 if (isHTMLCanvasElement(node)) { | 300 if (isHTMLCanvasElement(node)) { |
| 306 HitTestCanvasResult* hitTestCanvasResult = | 301 HitTestCanvasResult* hitTestCanvasResult = |
| 307 toHTMLCanvasElement(node)->getControlAndIdIfHitRegionExists( | 302 toHTMLCanvasElement(node)->getControlAndIdIfHitRegionExists( |
| 308 result.pointInInnerNodeFrame()); | 303 result.pointInInnerNodeFrame()); |
| 309 if (hitTestCanvasResult->getControl()) | 304 if (hitTestCanvasResult->getControl()) |
| (...skipping 17 matching lines...) Expand all Loading... |
| 327 m_touchSequenceDocument = &(touchInfo.touchNode->document()); | 322 m_touchSequenceDocument = &(touchInfo.touchNode->document()); |
| 328 ASSERT(m_touchSequenceDocument->frame()->view()); | 323 ASSERT(m_touchSequenceDocument->frame()->view()); |
| 329 } | 324 } |
| 330 | 325 |
| 331 // Ideally we'd ASSERT(!m_targetForTouchID.contains(point.id()) | 326 // Ideally we'd ASSERT(!m_targetForTouchID.contains(point.id()) |
| 332 // since we shouldn't get a touchstart for a touch that's already | 327 // since we shouldn't get a touchstart for a touch that's already |
| 333 // down. However EventSender allows this to be violated and there's | 328 // down. However EventSender allows this to be violated and there's |
| 334 // some tests that take advantage of it. There may also be edge | 329 // some tests that take advantage of it. There may also be edge |
| 335 // cases in the browser where this happens. | 330 // cases in the browser where this happens. |
| 336 // See http://crbug.com/345372. | 331 // See http://crbug.com/345372. |
| 337 m_targetForTouchID.set(touchInfo.point.id(), touchInfo.touchNode); | 332 m_targetForTouchID.set(touchInfo.point.id, touchInfo.touchNode); |
| 338 | 333 |
| 339 m_regionForTouchID.set(touchInfo.point.id(), touchInfo.region); | 334 m_regionForTouchID.set(touchInfo.point.id, touchInfo.region); |
| 340 | 335 |
| 341 TouchAction effectiveTouchAction = | 336 TouchAction effectiveTouchAction = |
| 342 TouchActionUtil::computeEffectiveTouchAction(*touchInfo.touchNode); | 337 TouchActionUtil::computeEffectiveTouchAction(*touchInfo.touchNode); |
| 343 if (effectiveTouchAction != TouchActionAuto) { | 338 if (effectiveTouchAction != TouchActionAuto) { |
| 344 m_frame->page()->chromeClient().setTouchAction(m_frame, | 339 m_frame->page()->chromeClient().setTouchAction(m_frame, |
| 345 effectiveTouchAction); | 340 effectiveTouchAction); |
| 346 | 341 |
| 347 // Combine the current touch action sequence with the touch action | 342 // Combine the current touch action sequence with the touch action |
| 348 // for the current finger press. | 343 // for the current finger press. |
| 349 m_currentTouchAction &= effectiveTouchAction; | 344 m_currentTouchAction &= effectiveTouchAction; |
| 350 } | 345 } |
| 351 } | 346 } |
| 352 } | 347 } |
| 353 } | 348 } |
| 354 | 349 |
| 355 void TouchEventManager::setAllPropertiesOfTouchInfos( | 350 void TouchEventManager::setAllPropertiesOfTouchInfos( |
| 356 HeapVector<TouchInfo>& touchInfos) { | 351 HeapVector<TouchInfo>& touchInfos) { |
| 357 for (auto& touchInfo : touchInfos) { | 352 for (auto& touchInfo : touchInfos) { |
| 358 PlatformTouchPoint::TouchState pointState = touchInfo.point.state(); | 353 WebTouchPoint::State pointState = touchInfo.point.state; |
| 359 Node* touchNode = nullptr; | 354 Node* touchNode = nullptr; |
| 360 String regionID; | 355 String regionID; |
| 361 | 356 |
| 362 if (pointState == PlatformTouchPoint::TouchReleased || | 357 if (pointState == WebTouchPoint::StateReleased || |
| 363 pointState == PlatformTouchPoint::TouchCancelled) { | 358 pointState == WebTouchPoint::StateCancelled) { |
| 364 // The target should be the original target for this touch, so get | 359 // The target should be the original target for this touch, so get |
| 365 // it from the hashmap. As it's a release or cancel we also remove | 360 // it from the hashmap. As it's a release or cancel we also remove |
| 366 // it from the map. | 361 // it from the map. |
| 367 touchNode = m_targetForTouchID.take(touchInfo.point.id()); | 362 touchNode = m_targetForTouchID.take(touchInfo.point.id); |
| 368 regionID = m_regionForTouchID.take(touchInfo.point.id()); | 363 regionID = m_regionForTouchID.take(touchInfo.point.id); |
| 369 } else { | 364 } else { |
| 370 // No hittest is performed on move or stationary, since the target | 365 // No hittest is performed on move or stationary, since the target |
| 371 // is not allowed to change anyway. | 366 // is not allowed to change anyway. |
| 372 touchNode = m_targetForTouchID.get(touchInfo.point.id()); | 367 touchNode = m_targetForTouchID.get(touchInfo.point.id); |
| 373 regionID = m_regionForTouchID.get(touchInfo.point.id()); | 368 regionID = m_regionForTouchID.get(touchInfo.point.id); |
| 374 } | 369 } |
| 375 | 370 |
| 376 LocalFrame* targetFrame = nullptr; | 371 LocalFrame* targetFrame = nullptr; |
| 377 bool knownTarget = false; | 372 bool knownTarget = false; |
| 378 if (touchNode) { | 373 if (touchNode) { |
| 379 Document& doc = touchNode->document(); | 374 Document& doc = touchNode->document(); |
| 380 // If the target node has moved to a new document while it was being | 375 // If the target node has moved to a new document while it was being |
| 381 // touched, we can't send events to the new document because that could | 376 // touched, we can't send events to the new document because that could |
| 382 // leak nodes from one document to another. See http://crbug.com/394339. | 377 // leak nodes from one document to another. See http://crbug.com/394339. |
| 383 if (&doc == m_touchSequenceDocument.get()) { | 378 if (&doc == m_touchSequenceDocument.get()) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 399 // a Touch is a Node so using the window could be a breaking change. | 394 // a Touch is a Node so using the window could be a breaking change. |
| 400 // Since we know there was no handler invoked, the specific target | 395 // Since we know there was no handler invoked, the specific target |
| 401 // should be completely irrelevant to the application. | 396 // should be completely irrelevant to the application. |
| 402 touchNode = m_touchSequenceDocument; | 397 touchNode = m_touchSequenceDocument; |
| 403 targetFrame = m_touchSequenceDocument->frame(); | 398 targetFrame = m_touchSequenceDocument->frame(); |
| 404 } | 399 } |
| 405 ASSERT(targetFrame); | 400 ASSERT(targetFrame); |
| 406 | 401 |
| 407 // pagePoint should always be in the target element's document coordinates. | 402 // pagePoint should always be in the target element's document coordinates. |
| 408 FloatPoint pagePoint = | 403 FloatPoint pagePoint = |
| 409 targetFrame->view()->rootFrameToContents(touchInfo.point.pos()); | 404 targetFrame->view()->rootFrameToContents(touchInfo.point.position); |
| 410 float scaleFactor = 1.0f / targetFrame->pageZoomFactor(); | 405 float scaleFactor = 1.0f / targetFrame->pageZoomFactor(); |
| 411 | 406 |
| 412 touchInfo.touchNode = touchNode; | 407 touchInfo.touchNode = touchNode; |
| 413 touchInfo.targetFrame = targetFrame; | 408 touchInfo.targetFrame = targetFrame; |
| 414 touchInfo.contentPoint = pagePoint.scaledBy(scaleFactor); | 409 touchInfo.contentPoint = pagePoint.scaledBy(scaleFactor); |
| 415 touchInfo.adjustedRadius = touchInfo.point.radius().scaledBy(scaleFactor); | 410 touchInfo.adjustedRadius = |
| 411 FloatSize(touchInfo.point.radiusX, touchInfo.point.radiusY) |
| 412 .scaledBy(scaleFactor); |
| 416 touchInfo.knownTarget = knownTarget; | 413 touchInfo.knownTarget = knownTarget; |
| 417 touchInfo.region = regionID; | 414 touchInfo.region = regionID; |
| 418 } | 415 } |
| 419 } | 416 } |
| 420 | 417 |
| 421 bool TouchEventManager::reHitTestTouchPointsIfNeeded( | 418 bool TouchEventManager::reHitTestTouchPointsIfNeeded( |
| 422 const PlatformTouchEvent& event, | 419 const WebTouchEvent& event, |
| 423 HeapVector<TouchInfo>& touchInfos) { | 420 HeapVector<TouchInfo>& touchInfos) { |
| 424 bool newTouchSequence = true; | 421 bool newTouchSequence = true; |
| 425 bool allTouchesReleased = true; | 422 bool allTouchesReleased = true; |
| 426 | 423 |
| 427 for (const auto& point : event.touchPoints()) { | 424 for (unsigned i = 0; i < event.touchesLength; ++i) { |
| 428 if (point.state() != PlatformTouchPoint::TouchPressed) | 425 WebTouchPoint::State state = event.touches[i].state; |
| 426 if (state != WebTouchPoint::StatePressed) |
| 429 newTouchSequence = false; | 427 newTouchSequence = false; |
| 430 if (point.state() != PlatformTouchPoint::TouchReleased && | 428 if (state != WebTouchPoint::StateReleased && |
| 431 point.state() != PlatformTouchPoint::TouchCancelled) | 429 state != WebTouchPoint::StateCancelled) |
| 432 allTouchesReleased = false; | 430 allTouchesReleased = false; |
| 433 } | 431 } |
| 434 if (newTouchSequence) { | 432 if (newTouchSequence) { |
| 435 // Ideally we'd ASSERT(!m_touchSequenceDocument) here since we should | 433 // Ideally we'd ASSERT(!m_touchSequenceDocument) here since we should |
| 436 // have cleared the active document when we saw the last release. But we | 434 // have cleared the active document when we saw the last release. But we |
| 437 // have some tests that violate this, ClusterFuzz could trigger it, and | 435 // have some tests that violate this, ClusterFuzz could trigger it, and |
| 438 // there may be cases where the browser doesn't reliably release all | 436 // there may be cases where the browser doesn't reliably release all |
| 439 // touches. http://crbug.com/345372 tracks this. | 437 // touches. http://crbug.com/345372 tracks this. |
| 440 m_touchSequenceDocument.clear(); | 438 m_touchSequenceDocument.clear(); |
| 441 } | 439 } |
| (...skipping 21 matching lines...) Expand all Loading... |
| 463 m_touchSequenceDocument.clear(); | 461 m_touchSequenceDocument.clear(); |
| 464 } | 462 } |
| 465 return false; | 463 return false; |
| 466 } | 464 } |
| 467 | 465 |
| 468 setAllPropertiesOfTouchInfos(touchInfos); | 466 setAllPropertiesOfTouchInfos(touchInfos); |
| 469 | 467 |
| 470 return true; | 468 return true; |
| 471 } | 469 } |
| 472 | 470 |
| 473 // TODO(rbyers): Replace with AutoReset as base/WTF unification permits. | |
| 474 class CurrentEventHolder { | |
| 475 // Always stack allocated to ensure lifetime doesn't exceed that of target | |
| 476 DISALLOW_NEW(); | |
| 477 | |
| 478 public: | |
| 479 CurrentEventHolder(PlatformEvent::EventType& target, | |
| 480 PlatformEvent::EventType value) | |
| 481 : m_target(target) { | |
| 482 m_target = value; | |
| 483 } | |
| 484 ~CurrentEventHolder() { m_target = PlatformEvent::NoType; } | |
| 485 | |
| 486 private: | |
| 487 PlatformEvent::EventType& m_target; | |
| 488 }; | |
| 489 | |
| 490 WebInputEventResult TouchEventManager::handleTouchEvent( | 471 WebInputEventResult TouchEventManager::handleTouchEvent( |
| 491 const PlatformTouchEvent& event, | 472 const WebTouchEvent& event, |
| 492 HeapVector<TouchInfo>& touchInfos) { | 473 HeapVector<TouchInfo>& touchInfos) { |
| 493 | |
| 494 // Track the current event for the scope of this function. | |
| 495 CurrentEventHolder holder(m_currentEvent, event.type()); | |
| 496 | |
| 497 if (!reHitTestTouchPointsIfNeeded(event, touchInfos)) | 474 if (!reHitTestTouchPointsIfNeeded(event, touchInfos)) |
| 498 return WebInputEventResult::NotHandled; | 475 return WebInputEventResult::NotHandled; |
| 499 | 476 |
| 500 bool allTouchesReleased = true; | 477 bool allTouchesReleased = true; |
| 501 for (const auto& point : event.touchPoints()) { | 478 for (unsigned i = 0; i < event.touchesLength; ++i) { |
| 502 if (point.state() != PlatformTouchPoint::TouchReleased && | 479 WebTouchPoint::State state = event.touches[i].state; |
| 503 point.state() != PlatformTouchPoint::TouchCancelled) | 480 if (state != WebTouchPoint::StateReleased && |
| 481 state != WebTouchPoint::StateCancelled) |
| 504 allTouchesReleased = false; | 482 allTouchesReleased = false; |
| 505 } | 483 } |
| 506 | 484 |
| 507 return dispatchTouchEvents(event, touchInfos, allTouchesReleased); | 485 return dispatchTouchEvents(event, touchInfos, allTouchesReleased); |
| 508 } | 486 } |
| 509 | 487 |
| 510 bool TouchEventManager::isAnyTouchActive() const { | 488 bool TouchEventManager::isAnyTouchActive() const { |
| 511 return m_touchPressed; | 489 return m_touchPressed; |
| 512 } | 490 } |
| 513 | 491 |
| 514 } // namespace blink | 492 } // namespace blink |
| OLD | NEW |