From 96312b338e79497a8c0d7af12a57b2e38d7fe7c3 Mon Sep 17 00:00:00 2001 From: Adeel Kazmi Date: Sat, 20 Jan 2024 10:38:32 +0000 Subject: [PATCH] [Tizen] Reduce CC of TouchEventProcessor::ProcessTouchEvent Change-Id: I725981925bb16368ed146bba414ef8ed549bffbe --- dali/internal/event/actors/layer-impl.cpp | 4 +- dali/internal/event/actors/layer-impl.h | 6 +- .../event/events/touch-event-processor.cpp | 836 ++++++++++++--------- dali/internal/event/events/touch-event-processor.h | 41 +- 4 files changed, 494 insertions(+), 393 deletions(-) diff --git a/dali/internal/event/actors/layer-impl.cpp b/dali/internal/event/actors/layer-impl.cpp index 3c283d9..6e02cb0 100644 --- a/dali/internal/event/actors/layer-impl.cpp +++ b/dali/internal/event/actors/layer-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Samsung Electronics Co., Ltd. + * Copyright (c) 2024 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -335,7 +335,7 @@ void Layer::SetTouchConsumed(bool consume) mTouchConsumed = consume; } -bool Layer::OnTouched(Dali::Actor actor, const TouchEvent& touch) +bool Layer::OnTouched(Dali::Actor actor, const Dali::TouchEvent& touch) { // This event is only called when mTouchConsumed is true. So touch always consumed. return true; diff --git a/dali/internal/event/actors/layer-impl.h b/dali/internal/event/actors/layer-impl.h index b94cf30..d65ee7c 100644 --- a/dali/internal/event/actors/layer-impl.h +++ b/dali/internal/event/actors/layer-impl.h @@ -2,7 +2,7 @@ #define DALI_INTERNAL_LAYER_H /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2024 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -252,9 +252,9 @@ private: * * @param[in] actor Layer touched * @param[in] touch Touch information - * @return True if the touch is consummed. + * @return True if the touch is consumed. */ - bool OnTouched(Dali::Actor actor, const TouchEvent& touch); + bool OnTouched(Dali::Actor actor, const Dali::TouchEvent& touch); LayerList* mLayerList; ///< Only valid when layer is on-scene diff --git a/dali/internal/event/events/touch-event-processor.cpp b/dali/internal/event/events/touch-event-processor.cpp index fabbcab..5df9c31 100644 --- a/dali/internal/event/events/touch-event-processor.cpp +++ b/dali/internal/event/events/touch-event-processor.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Samsung Electronics Co., Ltd. + * Copyright (c) 2024 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,9 +37,7 @@ #include #include -namespace Dali -{ -namespace Internal +namespace Dali::Internal { namespace { @@ -48,6 +46,30 @@ DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_PERFORMANCE_MARKER, false); Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_TOUCH_PROCESSOR"); #endif // defined(DEBUG_ENABLED) +/** + * Structure for Variables used in the ProcessTouchEvent method. + */ +struct ProcessTouchEventVariables +{ + ProcessTouchEventVariables(TouchEventProcessor& eventProcessor, bool geometry) + : processor(eventProcessor), + isGeometry(geometry) + { + } + + TouchEventProcessor& processor; ///< A handle to the touch-event-processor. + const bool isGeometry; ///< Whether it's a geometry or not. + Actor* lastPrimaryHitActor{nullptr}; ///< The last primary hit-actor. + Actor* lastConsumedActor{nullptr}; ///< The last consuming actor. + TouchEventPtr touchEventImpl; ///< The current touch-event-impl. + Dali::TouchEvent touchEventHandle; ///< The handle to the touch-event-impl. + RenderTaskPtr currentRenderTask; ///< The current render-task. + Dali::Actor consumedActor; ///< The actor that consumed the event. + Dali::Actor primaryHitActor; ///< The actor that has been hit by the primary point. + Integration::Point* primaryPoint{nullptr}; ///< The primary point of the hit. + PointState::Type primaryPointState{PointState::STARTED}; ///< The state of the primary point. +}; + const char* TOUCH_POINT_STATE[6] = { "DOWN", @@ -113,7 +135,7 @@ Dali::Actor EmitGeoInterceptTouchSignals(std::list& acto // If there is a consumed actor, the intercept is sent only up to the moment before the consumed actor. if(lastConsumedActor.GetActor() == actor) { - break; + break; } interceptActorList.push_back(actor); if(ShouldEmitInterceptTouchEvent(*actor, touchEvent)) @@ -181,7 +203,7 @@ Dali::Actor EmitGeoTouchSignals(std::list& actorLists, c Dali::Actor consumedActor; std::list::reverse_iterator rIter = actorLists.rbegin(); - for (; rIter != actorLists.rend(); rIter++) + for(; rIter != actorLists.rend(); rIter++) { Actor* actorImpl(*rIter); // Only emit the signal if the actor's touch signal has connections (or derived actor implementation requires touch). @@ -269,12 +291,12 @@ Dali::Actor EmitTouchSignals(Actor* actor, RenderTask& renderTask, const TouchEv * @param[in] actorLists The list of actors that can be touched, from leaf actor to root. */ void ParsePrimaryTouchPoint( - HitTestAlgorithm::Results& hitTestResults, - ActorObserver& capturingTouchActorObserver, - ActorObserver& ownTouchActorObserver, - const RenderTaskPtr& lastRenderTask, - const Integration::Point& currentPoint, - const Internal::Scene& scene, + HitTestAlgorithm::Results& hitTestResults, + ActorObserver& capturingTouchActorObserver, + ActorObserver& ownTouchActorObserver, + const RenderTaskPtr& lastRenderTask, + const Integration::Point& currentPoint, + const Internal::Scene& scene, std::list& actorLists) { Actor* capturingTouchActor = capturingTouchActorObserver.GetActor(); @@ -315,69 +337,32 @@ void ParsePrimaryTouchPoint( } // unnamed namespace -TouchEventProcessor::TouchEventProcessor(Scene& scene) -: mScene(scene), - mLastPrimaryHitActor(MakeCallback(this, &TouchEventProcessor::OnObservedActorDisconnected)), - mLastConsumedActor(), - mCapturingTouchActor(), - mOwnTouchActor(), - mTouchDownConsumedActor(), - mInterceptedTouchActor(), - mLastRenderTask(), - mLastPrimaryPointState(PointState::FINISHED) +struct TouchEventProcessor::Impl { - DALI_LOG_TRACE_METHOD(gLogFilter); -} - -TouchEventProcessor::~TouchEventProcessor() -{ - DALI_LOG_TRACE_METHOD(gLogFilter); -} - -void TouchEventProcessor::Clear() -{ - mLastPrimaryHitActor.SetActor(nullptr); - mLastConsumedActor.SetActor(nullptr); - mCapturingTouchActor.SetActor(nullptr); - mOwnTouchActor.SetActor(nullptr); - mInterceptedTouchActor.SetActor(nullptr); - mLastRenderTask.Reset(); - mLastPrimaryPointState = PointState::FINISHED; -} - -bool TouchEventProcessor::ProcessTouchEvent(const Integration::TouchEvent& event) -{ - DALI_LOG_TRACE_METHOD(gLogFilter); - DALI_ASSERT_ALWAYS(!event.points.empty() && "Empty TouchEvent sent from Integration\n"); - - PRINT_HIERARCHY(gLogFilter); - - DALI_TRACE_SCOPE(gTraceFilter, "DALI_PROCESS_TOUCH_EVENT"); - - bool isGeometry = mScene.IsGeometryHittestEnabled(); - - // 1) Check if it is an interrupted event - we should inform our last primary hit actor about this - // and emit the stage signal as well. - - if(event.points[0].GetState() == PointState::INTERRUPTED) + /** + * Emits an interrupted event. + * @param[in/out] localVars The struct of stack variables used by ProcessTouchEvent + * @param[in] event The touch event that has occurred + */ + static inline void EmitInterruptedEvent(ProcessTouchEventVariables& localVars, const Integration::TouchEvent& event) { Dali::Actor consumingActor; Integration::Point currentPoint(event.points[0]); - if(isGeometry) + if(localVars.isGeometry) { // Since the geometry way only receives touch events from the consumed actor, // it first searches for whether there is a consumed actor and then sends the event - Actor* touchConsumedActor(mLastConsumedActor.GetActor()); - Actor* touchDownConsumedActor(mTouchDownConsumedActor.GetActor()); - Actor* lastPrimaryHitActor(mLastPrimaryHitActor.GetActor()); + Actor* touchConsumedActor(localVars.processor.mLastConsumedActor.GetActor()); + Actor* touchDownConsumedActor(localVars.processor.mTouchDownConsumedActor.GetActor()); + Actor* lastPrimaryHitActor(localVars.processor.mLastPrimaryHitActor.GetActor()); if(touchConsumedActor) { Dali::Actor touchConsumedActorHandle(touchConsumedActor); currentPoint.SetHitActor(touchConsumedActorHandle); std::list actorLists; actorLists.push_back(touchConsumedActor); - GeoAllocAndEmitTouchSignals(actorLists, event.time, currentPoint, mLastRenderTask); + GeoAllocAndEmitTouchSignals(actorLists, event.time, currentPoint, localVars.processor.mLastRenderTask); } else if(touchDownConsumedActor) { @@ -385,54 +370,54 @@ bool TouchEventProcessor::ProcessTouchEvent(const Integration::TouchEvent& event currentPoint.SetHitActor(touchDownConsumedActorHandle); std::list actorLists; actorLists.push_back(touchDownConsumedActor); - GeoAllocAndEmitTouchSignals(actorLists, event.time, currentPoint, mLastRenderTask); + GeoAllocAndEmitTouchSignals(actorLists, event.time, currentPoint, localVars.processor.mLastRenderTask); } else if(lastPrimaryHitActor) { Dali::Actor lastPrimaryHitActorHandle(lastPrimaryHitActor); currentPoint.SetHitActor(lastPrimaryHitActorHandle); - GeoAllocAndEmitTouchSignals(mCandidateActorLists, event.time, currentPoint, mLastRenderTask); + GeoAllocAndEmitTouchSignals(localVars.processor.mCandidateActorLists, event.time, currentPoint, localVars.processor.mLastRenderTask); } } else { - Actor* lastPrimaryHitActor(mLastPrimaryHitActor.GetActor()); + Actor* lastPrimaryHitActor(localVars.processor.mLastPrimaryHitActor.GetActor()); if(lastPrimaryHitActor) { Dali::Actor lastPrimaryHitActorHandle(lastPrimaryHitActor); currentPoint.SetHitActor(lastPrimaryHitActorHandle); - consumingActor = AllocAndEmitTouchSignals(event.time, lastPrimaryHitActorHandle, currentPoint, mLastRenderTask); + consumingActor = AllocAndEmitTouchSignals(event.time, lastPrimaryHitActorHandle, currentPoint, localVars.processor.mLastRenderTask); } // If the last consumed actor was different to the primary hit actor then inform it as well (if it has not already been informed). - Actor* lastConsumedActor(mLastConsumedActor.GetActor()); + Actor* lastConsumedActor(localVars.processor.mLastConsumedActor.GetActor()); if(lastConsumedActor && - lastConsumedActor != lastPrimaryHitActor && - lastConsumedActor != consumingActor) + lastConsumedActor != lastPrimaryHitActor && + lastConsumedActor != consumingActor) { Dali::Actor lastConsumedActorHandle(lastConsumedActor); currentPoint.SetHitActor(lastConsumedActorHandle); - AllocAndEmitTouchSignals(event.time, lastConsumedActorHandle, currentPoint, mLastRenderTask); + AllocAndEmitTouchSignals(event.time, lastConsumedActorHandle, currentPoint, localVars.processor.mLastRenderTask); } // Tell the touch-down consuming actor as well, if required - Actor* touchDownConsumedActor(mTouchDownConsumedActor.GetActor()); + Actor* touchDownConsumedActor(localVars.processor.mTouchDownConsumedActor.GetActor()); if(touchDownConsumedActor && - touchDownConsumedActor != lastPrimaryHitActor && - touchDownConsumedActor != lastConsumedActor && - touchDownConsumedActor != consumingActor) + touchDownConsumedActor != lastPrimaryHitActor && + touchDownConsumedActor != lastConsumedActor && + touchDownConsumedActor != consumingActor) { Dali::Actor touchDownConsumedActorHandle(touchDownConsumedActor); currentPoint.SetHitActor(touchDownConsumedActorHandle); - AllocAndEmitTouchSignals(event.time, touchDownConsumedActorHandle, currentPoint, mLastRenderTask); + AllocAndEmitTouchSignals(event.time, touchDownConsumedActorHandle, currentPoint, localVars.processor.mLastRenderTask); } } - Clear(); - mTouchDownConsumedActor.SetActor(nullptr); + localVars.processor.Clear(); + localVars.processor.mTouchDownConsumedActor.SetActor(nullptr); currentPoint.SetHitActor(Dali::Actor()); @@ -441,381 +426,490 @@ bool TouchEventProcessor::ProcessTouchEvent(const Integration::TouchEvent& event touchEventImpl->AddPoint(currentPoint); - mScene.EmitTouchedSignal(touchEventHandle); - return false; // No need for hit testing & already an interrupted event so just return false - } - - // 2) Hit Testing. - TouchEventPtr touchEventImpl(new TouchEvent(event.time)); - Dali::TouchEvent touchEventHandle(touchEventImpl.Get()); - - DALI_LOG_INFO(gLogFilter, Debug::Concise, "\n"); - DALI_LOG_INFO(gLogFilter, Debug::General, "Point(s): %d\n", event.GetPointCount()); - - RenderTaskPtr currentRenderTask; - bool firstPointParsed = false; - - for(auto&& currentPoint : event.points) - { - HitTestAlgorithm::Results hitTestResults; - hitTestResults.point = currentPoint; - hitTestResults.eventTime = event.time; - if(!firstPointParsed) - { - firstPointParsed = true; - ParsePrimaryTouchPoint(hitTestResults, mCapturingTouchActor, mOwnTouchActor, mLastRenderTask, currentPoint, mScene, mCandidateActorLists); - - // Only set the currentRenderTask for the primary hit actor. - currentRenderTask = hitTestResults.renderTask; - touchEventImpl->SetRenderTask(Dali::RenderTask(currentRenderTask.Get())); - } - else - { - HitTestAlgorithm::HitTest(mScene.GetSize(), mScene.GetRenderTaskList(), mScene.GetLayerList(), currentPoint.GetScreenPosition(), hitTestResults, nullptr, isGeometry); - } - - Integration::Point newPoint(currentPoint); - newPoint.SetHitActor(hitTestResults.actor); - newPoint.SetLocalPosition(hitTestResults.actorCoordinates); - - touchEventImpl->AddPoint(newPoint); - - DALI_LOG_INFO(gLogFilter, Debug::General, " State(%s), Screen(%.0f, %.0f), HitActor(%p, %s), Local(%.2f, %.2f)\n", TOUCH_POINT_STATE[currentPoint.GetState()], currentPoint.GetScreenPosition().x, currentPoint.GetScreenPosition().y, (hitTestResults.actor ? reinterpret_cast(&hitTestResults.actor.GetBaseObject()) : NULL), (hitTestResults.actor ? hitTestResults.actor.GetProperty(Dali::Actor::Property::NAME).c_str() : ""), hitTestResults.actorCoordinates.x, hitTestResults.actorCoordinates.y); + localVars.processor.mScene.EmitTouchedSignal(touchEventHandle); } - // 3) Recursively deliver events to the actor and its parents, until the event is consumed or the stage is reached. - - bool consumed = false; - - // Emit the touch signal - Dali::Actor consumedActor; - - Integration::Point& primaryPoint = touchEventImpl->GetPoint(0); - Dali::Actor primaryHitActor = primaryPoint.GetHitActor(); - PointState::Type primaryPointState = primaryPoint.GetState(); - - if(currentRenderTask) + /** + * Recursively deliver events to the actor and its parents, until the event is consumed or the stage is reached. + * @param[in/out] localVars The struct of stack variables used by ProcessTouchEvent + * @return True if consumed, false otherwise. + */ + static inline bool DeliverEventsToActorAndParents(ProcessTouchEventVariables& localVars) { - if(isGeometry) + bool consumed = false; + TouchEventProcessor& processor = localVars.processor; + if(localVars.currentRenderTask) { - Actor* interceptedTouchActor(mInterceptedTouchActor.GetActor()); - if(interceptedTouchActor) + if(localVars.isGeometry) { - Actor* touchConsumedActor(mLastConsumedActor.GetActor()); - if(touchConsumedActor) // If there is a consumed actor, send events only to the consumed actor. - { - RenderTask& currentRenderTaskImpl = *currentRenderTask.Get(); - consumedActor = EmitTouchSignals(touchConsumedActor, currentRenderTaskImpl, touchEventImpl, primaryPointState, isGeometry); - } - else // If there is an intercepted actor, send a touch event starting from the intercepted actor. + Actor* interceptedTouchActor(processor.mInterceptedTouchActor.GetActor()); + if(interceptedTouchActor) { - Dali::Actor interceptedTouchActorHandle(interceptedTouchActor); - std::list interceptActorLists = mInterceptedActorLists; - consumedActor = EmitGeoTouchSignals(interceptActorLists, touchEventHandle); + Actor* touchConsumedActor(processor.mLastConsumedActor.GetActor()); + if(touchConsumedActor) // If there is a consumed actor, send events only to the consumed actor. + { + RenderTask& currentRenderTaskImpl = *localVars.currentRenderTask.Get(); + localVars.consumedActor = EmitTouchSignals(touchConsumedActor, currentRenderTaskImpl, localVars.touchEventImpl, localVars.primaryPointState, localVars.isGeometry); + } + else // If there is an intercepted actor, send a touch event starting from the intercepted actor. + { + Dali::Actor interceptedTouchActorHandle(interceptedTouchActor); + std::list interceptActorLists = localVars.processor.mInterceptedActorLists; + localVars.consumedActor = EmitGeoTouchSignals(interceptActorLists, localVars.touchEventHandle); + } } - } - else - { - Dali::Actor interceptedActor; - // Let's find out if there is an intercept actor. - interceptedActor = EmitGeoInterceptTouchSignals(mCandidateActorLists, mInterceptedActorLists, touchEventHandle, mLastConsumedActor); - if(interceptedActor) + else { - mInterceptedTouchActor.SetActor(&GetImplementation(interceptedActor)); + Dali::Actor interceptedActor; + // Let's find out if there is an intercept actor. + interceptedActor = EmitGeoInterceptTouchSignals(processor.mCandidateActorLists, processor.mInterceptedActorLists, localVars.touchEventHandle, processor.mLastConsumedActor); + if(interceptedActor) + { + processor.mInterceptedTouchActor.SetActor(&GetImplementation(interceptedActor)); - // If there is an interception, send an interrupted event to the last consumed actor or to the actor that hit previously. - if(mLastConsumedActor.GetActor() && - mLastConsumedActor.GetActor() != interceptedActor && - mLastRenderTask && - mLastPrimaryPointState != PointState::FINISHED) + // If there is an interception, send an interrupted event to the last consumed actor or to the actor that hit previously. + if(processor.mLastConsumedActor.GetActor() && + processor.mLastConsumedActor.GetActor() != interceptedActor && + processor.mLastRenderTask && + processor.mLastPrimaryPointState != PointState::FINISHED) + { + EmitTouchSignals(processor.mLastConsumedActor.GetActor(), *processor.mLastRenderTask.Get(), localVars.touchEventImpl, PointState::INTERRUPTED, localVars.isGeometry); + processor.mTouchDownConsumedActor.SetActor(nullptr); + processor.mLastConsumedActor.SetActor(nullptr); + } + else if(processor.mLastPrimaryHitActor.GetActor() && + processor.mLastPrimaryHitActor.GetActor() != interceptedActor && + processor.mLastRenderTask && + processor.mLastPrimaryPointState != PointState::FINISHED) + { + std::list::reverse_iterator rIter = processor.mCandidateActorLists.rbegin(); + for(; rIter != processor.mCandidateActorLists.rend(); rIter++) + { + Actor* actorImpl(*rIter); + EmitTouchSignals(actorImpl, *processor.mLastRenderTask.Get(), localVars.touchEventImpl, PointState::INTERRUPTED, localVars.isGeometry); + } + } + } + + Actor* touchConsumedActor(processor.mLastConsumedActor.GetActor()); + if(touchConsumedActor) // If there is a consumed actor, send events only to the consumed actor. { - EmitTouchSignals(mLastConsumedActor.GetActor(), *mLastRenderTask.Get(), touchEventImpl, PointState::INTERRUPTED, isGeometry); - mTouchDownConsumedActor.SetActor(nullptr); - mLastConsumedActor.SetActor(nullptr); + RenderTask& currentRenderTaskImpl = *localVars.currentRenderTask.Get(); + localVars.consumedActor = EmitTouchSignals(touchConsumedActor, currentRenderTaskImpl, localVars.touchEventImpl, localVars.primaryPointState, localVars.isGeometry); } - else if(mLastPrimaryHitActor.GetActor() && - mLastPrimaryHitActor.GetActor() != interceptedActor && - mLastRenderTask && - mLastPrimaryPointState != PointState::FINISHED) + else { - std::list::reverse_iterator rIter = mCandidateActorLists.rbegin(); - for (; rIter != mCandidateActorLists.rend(); rIter++) - { - Actor* actorImpl(*rIter); - EmitTouchSignals(actorImpl, *mLastRenderTask.Get(), touchEventImpl, PointState::INTERRUPTED, isGeometry); - } + // Let's propagate touch events from the intercepted actor or start propagating touch events from the leaf actor. + localVars.consumedActor = EmitGeoTouchSignals(interceptedActor ? processor.mInterceptedActorLists : processor.mCandidateActorLists, localVars.touchEventHandle); } } - - Actor* touchConsumedActor(mLastConsumedActor.GetActor()); - if(touchConsumedActor) // If there is a consumed actor, send events only to the consumed actor. + } + else + { + Actor* interceptedTouchActor(processor.mInterceptedTouchActor.GetActor()); + if(interceptedTouchActor) { - RenderTask& currentRenderTaskImpl = *currentRenderTask.Get(); - consumedActor = EmitTouchSignals(touchConsumedActor, currentRenderTaskImpl, touchEventImpl, primaryPointState, isGeometry); + Dali::Actor interceptedTouchActorHandle(interceptedTouchActor); + localVars.consumedActor = EmitTouchSignals(interceptedTouchActorHandle, localVars.touchEventHandle); } else { - // Let's propagate touch events from the intercepted actor or start propagating touch events from the leaf actor. - consumedActor = EmitGeoTouchSignals(interceptedActor ? mInterceptedActorLists : mCandidateActorLists, touchEventHandle); + // Emit the intercept touch signal + Dali::Actor interceptedActor = EmitInterceptTouchSignals(localVars.primaryHitActor, localVars.touchEventHandle); + if(interceptedActor) + { + processor.mInterceptedTouchActor.SetActor(&GetImplementation(interceptedActor)); + // If the child is being touched, INTERRUPTED is sent. + if(processor.mLastPrimaryHitActor.GetActor() && + processor.mLastPrimaryHitActor.GetActor() != interceptedActor && + processor.mLastRenderTask && + processor.mLastPrimaryPointState != PointState::FINISHED) + { + EmitTouchSignals(processor.mLastPrimaryHitActor.GetActor(), *processor.mLastRenderTask.Get(), localVars.touchEventImpl, PointState::INTERRUPTED, localVars.isGeometry); + processor.mTouchDownConsumedActor.SetActor(nullptr); + } + localVars.consumedActor = EmitTouchSignals(interceptedActor, localVars.touchEventHandle); + } + else + { + localVars.consumedActor = EmitTouchSignals(localVars.primaryHitActor, localVars.touchEventHandle); + } } } - } - else - { - Actor* interceptedTouchActor(mInterceptedTouchActor.GetActor()); - if(interceptedTouchActor) + + consumed = localVars.consumedActor ? true : false; + + if(localVars.primaryPointState == PointState::MOTION) { - Dali::Actor interceptedTouchActorHandle(interceptedTouchActor); - consumedActor = EmitTouchSignals(interceptedTouchActorHandle, touchEventHandle); + DALI_LOG_INFO(gLogFilter, + Debug::Concise, + "PrimaryHitActor: (%p) id(%d), name(%s), state(%s), screenPosition(%f, %f), isGeo : %d \n", + localVars.primaryHitActor ? reinterpret_cast(&localVars.primaryHitActor.GetBaseObject()) : NULL, + localVars.primaryHitActor ? localVars.primaryHitActor.GetProperty(Dali::Actor::Property::ID) : -1, + localVars.primaryHitActor ? localVars.primaryHitActor.GetProperty(Dali::Actor::Property::NAME).c_str() : "", + TOUCH_POINT_STATE[localVars.primaryPointState], + localVars.primaryPoint->GetScreenPosition().x, + localVars.primaryPoint->GetScreenPosition().y, + localVars.isGeometry); + DALI_LOG_INFO(gLogFilter, + Debug::Concise, + "ConsumedActor: (%p) id(%d), name(%s), state(%s), isGeo : %d \n", + localVars.consumedActor ? reinterpret_cast(&localVars.consumedActor.GetBaseObject()) : NULL, + localVars.consumedActor ? localVars.consumedActor.GetProperty(Dali::Actor::Property::ID) : -1, + localVars.consumedActor ? localVars.consumedActor.GetProperty(Dali::Actor::Property::NAME).c_str() : "", + TOUCH_POINT_STATE[localVars.primaryPointState], + localVars.isGeometry); } else { - // Emit the intercept touch signal - Dali::Actor interceptedActor = EmitInterceptTouchSignals(primaryHitActor, touchEventHandle); - if(interceptedActor) - { - mInterceptedTouchActor.SetActor(&GetImplementation(interceptedActor)); - // If the child is being touched, INTERRUPTED is sent. - if(mLastPrimaryHitActor.GetActor() && - mLastPrimaryHitActor.GetActor() != interceptedActor && - mLastRenderTask && - mLastPrimaryPointState != PointState::FINISHED) - { - EmitTouchSignals(mLastPrimaryHitActor.GetActor(), *mLastRenderTask.Get(), touchEventImpl, PointState::INTERRUPTED, isGeometry); - mTouchDownConsumedActor.SetActor(nullptr); - } - consumedActor = EmitTouchSignals(interceptedActor, touchEventHandle); - } - else - { - consumedActor = EmitTouchSignals(primaryHitActor, touchEventHandle); - } + DALI_LOG_RELEASE_INFO("PrimaryHitActor:(%p), id(%d), name(%s), state(%s), screenPosition(%f, %f), isGeo : %d \n", + localVars.primaryHitActor ? reinterpret_cast(&localVars.primaryHitActor.GetBaseObject()) : NULL, + localVars.primaryHitActor ? localVars.primaryHitActor.GetProperty(Dali::Actor::Property::ID) : -1, + localVars.primaryHitActor ? localVars.primaryHitActor.GetProperty(Dali::Actor::Property::NAME).c_str() : "", + TOUCH_POINT_STATE[localVars.primaryPointState], + localVars.primaryPoint->GetScreenPosition().x, + localVars.primaryPoint->GetScreenPosition().y, + localVars.isGeometry); + DALI_LOG_RELEASE_INFO("ConsumedActor: (%p), id(%d), name(%s), state(%s), isGeo : %d \n", + localVars.consumedActor ? reinterpret_cast(&localVars.consumedActor.GetBaseObject()) : NULL, + localVars.consumedActor ? localVars.consumedActor.GetProperty(Dali::Actor::Property::ID) : -1, + localVars.consumedActor ? localVars.consumedActor.GetProperty(Dali::Actor::Property::NAME).c_str() : "", + TOUCH_POINT_STATE[localVars.primaryPointState], + localVars.isGeometry); } } - consumed = consumedActor ? true : false; - - if(primaryPointState == PointState::MOTION) - { - DALI_LOG_INFO(gLogFilter, Debug::Concise, "PrimaryHitActor: (%p) id(%d), name(%s), state(%s), screenPosition(%f, %f), isGeo : %d \n", primaryHitActor ? reinterpret_cast(&primaryHitActor.GetBaseObject()) : NULL, primaryHitActor ? primaryHitActor.GetProperty(Dali::Actor::Property::ID) : -1, primaryHitActor ? primaryHitActor.GetProperty(Dali::Actor::Property::NAME).c_str() : "", TOUCH_POINT_STATE[primaryPointState], primaryPoint.GetScreenPosition().x, primaryPoint.GetScreenPosition().y, isGeometry); - DALI_LOG_INFO(gLogFilter, Debug::Concise, "ConsumedActor: (%p) id(%d), name(%s), state(%s), isGeo : %d \n", consumedActor ? reinterpret_cast(&consumedActor.GetBaseObject()) : NULL, consumedActor ? consumedActor.GetProperty(Dali::Actor::Property::ID) : -1, consumedActor ? consumedActor.GetProperty(Dali::Actor::Property::NAME).c_str() : "", TOUCH_POINT_STATE[primaryPointState], isGeometry); - } - else + if((localVars.primaryPointState == PointState::DOWN) && + (localVars.touchEventImpl->GetPointCount() == 1) && + (localVars.consumedActor && localVars.consumedActor.GetProperty(Dali::Actor::Property::CONNECTED_TO_SCENE))) { - DALI_LOG_RELEASE_INFO("PrimaryHitActor:(%p), id(%d), name(%s), state(%s), screenPosition(%f, %f), isGeo : %d \n", primaryHitActor ? reinterpret_cast(&primaryHitActor.GetBaseObject()) : NULL, primaryHitActor ? primaryHitActor.GetProperty(Dali::Actor::Property::ID) : -1, primaryHitActor ? primaryHitActor.GetProperty(Dali::Actor::Property::NAME).c_str() : "", TOUCH_POINT_STATE[primaryPointState], primaryPoint.GetScreenPosition().x, primaryPoint.GetScreenPosition().y, isGeometry); - DALI_LOG_RELEASE_INFO("ConsumedActor: (%p), id(%d), name(%s), state(%s), isGeo : %d \n", consumedActor ? reinterpret_cast(&consumedActor.GetBaseObject()) : NULL, consumedActor ? consumedActor.GetProperty(Dali::Actor::Property::ID) : -1, consumedActor ? consumedActor.GetProperty(Dali::Actor::Property::NAME).c_str() : "", TOUCH_POINT_STATE[primaryPointState], isGeometry); + processor.mTouchDownConsumedActor.SetActor(&GetImplementation(localVars.consumedActor)); } - } - if((primaryPointState == PointState::DOWN) && - (touchEventImpl->GetPointCount() == 1) && - (consumedActor && consumedActor.GetProperty(Dali::Actor::Property::CONNECTED_TO_SCENE))) - { - mTouchDownConsumedActor.SetActor(&GetImplementation(consumedActor)); + return consumed; } - // 4) Check if the last primary hit actor requires a leave event and if it was different to the current primary - // hit actor. Also process the last consumed actor in the same manner. - Actor* lastPrimaryHitActor(nullptr); - if(mInterceptedTouchActor.GetActor()) + /** + * Deliver Leave event to last hit or consuming actor if required. + * @param[in/out] localVars The struct of stack variables used by ProcessTouchEvent + * @return True if consumed, false otherwise. + */ + static inline bool DeliverLeaveEvent(ProcessTouchEventVariables& localVars) { - lastPrimaryHitActor = mInterceptedTouchActor.GetActor(); - } - else - { - lastPrimaryHitActor = mLastPrimaryHitActor.GetActor(); - } - Actor* lastConsumedActor(mLastConsumedActor.GetActor()); - if((primaryPointState == PointState::MOTION) || (primaryPointState == PointState::UP) || (primaryPointState == PointState::STATIONARY)) - { - if(mLastRenderTask) + bool consumed = false; + TouchEventProcessor& processor(localVars.processor); + if((localVars.primaryPointState == PointState::MOTION) || (localVars.primaryPointState == PointState::UP) || (localVars.primaryPointState == PointState::STATIONARY)) { - Dali::Actor leaveEventConsumer; - RenderTask& lastRenderTaskImpl = *mLastRenderTask.Get(); - - if(isGeometry) + if(processor.mLastRenderTask) { - if(lastPrimaryHitActor) + Dali::Actor leaveEventConsumer; + RenderTask& lastRenderTaskImpl = *processor.mLastRenderTask.Get(); + + if(localVars.isGeometry) { - if(!lastPrimaryHitActor->IsHittable() || !IsActuallySensitive(lastPrimaryHitActor)) + if(localVars.lastPrimaryHitActor) { - // At this point mLastPrimaryHitActor was touchable and sensitive in the previous touch event process but is not in the current one. - // An interrupted event is send to allow some actors to go back to their original state (i.e. Button controls) - DALI_LOG_RELEASE_INFO("InterruptedActor(Hit): (%p) %s\n", reinterpret_cast(lastPrimaryHitActor), lastPrimaryHitActor->GetName().data()); - leaveEventConsumer = EmitTouchSignals(lastPrimaryHitActor, lastRenderTaskImpl, touchEventImpl, PointState::INTERRUPTED, isGeometry); + if(!localVars.lastPrimaryHitActor->IsHittable() || !IsActuallySensitive(localVars.lastPrimaryHitActor)) + { + // At this point mLastPrimaryHitActor was touchable and sensitive in the previous touch event process but is not in the current one. + // An interrupted event is send to allow some actors to go back to their original state (i.e. Button controls) + DALI_LOG_RELEASE_INFO("InterruptedActor(Hit): (%p) %s\n", reinterpret_cast(localVars.lastPrimaryHitActor), localVars.lastPrimaryHitActor->GetName().data()); + leaveEventConsumer = EmitTouchSignals(localVars.lastPrimaryHitActor, lastRenderTaskImpl, localVars.touchEventImpl, PointState::INTERRUPTED, localVars.isGeometry); + } } - } - consumed |= leaveEventConsumer ? true : false; + consumed = leaveEventConsumer ? true : false; - // Check if the motion event has been consumed by another actor's listener. In this case, the previously - // consumed actor's listeners may need to be informed (through a leave event). - // Further checks here to ensure we do not signal the same actor twice for the same event. - if(lastConsumedActor && - lastConsumedActor != lastPrimaryHitActor && - lastConsumedActor != leaveEventConsumer) - { - if(!lastConsumedActor->IsHittable() || !IsActuallySensitive(lastConsumedActor)) + // Check if the motion event has been consumed by another actor's listener. In this case, the previously + // consumed actor's listeners may need to be informed (through a leave event). + // Further checks here to ensure we do not signal the same actor twice for the same event. + if(localVars.lastConsumedActor && + localVars.lastConsumedActor != localVars.lastPrimaryHitActor && + localVars.lastConsumedActor != leaveEventConsumer) { - // At this point mLastConsumedActor was touchable and sensitive in the previous touch event process but is not in the current one. - // An interrupted event is send to allow some actors to go back to their original state (i.e. Button controls) - DALI_LOG_RELEASE_INFO("InterruptedActor(Consume): (%p) %s\n", reinterpret_cast(lastConsumedActor), lastConsumedActor->GetName().data()); - EmitTouchSignals(mLastConsumedActor.GetActor(), lastRenderTaskImpl, touchEventImpl, PointState::INTERRUPTED, isGeometry); + if(!localVars.lastConsumedActor->IsHittable() || !IsActuallySensitive(localVars.lastConsumedActor)) + { + // At this point mLastConsumedActor was touchable and sensitive in the previous touch event process but is not in the current one. + // An interrupted event is send to allow some actors to go back to their original state (i.e. Button controls) + DALI_LOG_RELEASE_INFO("InterruptedActor(Consume): (%p) %s\n", reinterpret_cast(localVars.lastConsumedActor), localVars.lastConsumedActor->GetName().data()); + EmitTouchSignals(processor.mLastConsumedActor.GetActor(), lastRenderTaskImpl, localVars.touchEventImpl, PointState::INTERRUPTED, localVars.isGeometry); + } } } - } - else - { - if(lastPrimaryHitActor && - lastPrimaryHitActor != primaryHitActor && - lastPrimaryHitActor != consumedActor) + else { - if(lastPrimaryHitActor->IsHittable() && IsActuallySensitive(lastPrimaryHitActor)) + if(localVars.lastPrimaryHitActor && + localVars.lastPrimaryHitActor != localVars.primaryHitActor && + localVars.lastPrimaryHitActor != localVars.consumedActor) { - if(lastPrimaryHitActor->GetLeaveRequired()) + if(localVars.lastPrimaryHitActor->IsHittable() && IsActuallySensitive(localVars.lastPrimaryHitActor)) + { + if(localVars.lastPrimaryHitActor->GetLeaveRequired()) + { + DALI_LOG_RELEASE_INFO("LeaveActor(Hit): (%p) %d %s\n", reinterpret_cast(localVars.lastPrimaryHitActor), localVars.lastPrimaryHitActor->GetId(), localVars.lastPrimaryHitActor->GetName().data()); + leaveEventConsumer = EmitTouchSignals(localVars.lastPrimaryHitActor, lastRenderTaskImpl, localVars.touchEventImpl, PointState::LEAVE, localVars.isGeometry); + } + } + else { - DALI_LOG_RELEASE_INFO("LeaveActor(Hit): (%p) %d %s\n", reinterpret_cast(lastPrimaryHitActor), lastPrimaryHitActor->GetId(), lastPrimaryHitActor->GetName().data()); - leaveEventConsumer = EmitTouchSignals(lastPrimaryHitActor, lastRenderTaskImpl, touchEventImpl, PointState::LEAVE, isGeometry); + // At this point mLastPrimaryHitActor was touchable and sensitive in the previous touch event process but is not in the current one. + // An interrupted event is send to allow some actors to go back to their original state (i.e. Button controls) + DALI_LOG_RELEASE_INFO("InterruptedActor(Hit): (%p) %d %s\n", reinterpret_cast(localVars.lastPrimaryHitActor), localVars.lastPrimaryHitActor->GetId(), localVars.lastPrimaryHitActor->GetName().data()); + leaveEventConsumer = EmitTouchSignals(localVars.lastPrimaryHitActor, lastRenderTaskImpl, localVars.touchEventImpl, PointState::INTERRUPTED, localVars.isGeometry); } } - else + + consumed |= leaveEventConsumer ? true : false; + + // Check if the motion event has been consumed by another actor's listener. In this case, the previously + // consumed actor's listeners may need to be informed (through a leave event). + // Further checks here to ensure we do not signal the same actor twice for the same event. + if(localVars.lastConsumedActor && + localVars.lastConsumedActor != localVars.consumedActor && + localVars.lastConsumedActor != localVars.lastPrimaryHitActor && + localVars.lastConsumedActor != localVars.primaryHitActor && + localVars.lastConsumedActor != leaveEventConsumer) { - // At this point mLastPrimaryHitActor was touchable and sensitive in the previous touch event process but is not in the current one. - // An interrupted event is send to allow some actors to go back to their original state (i.e. Button controls) - DALI_LOG_RELEASE_INFO("InterruptedActor(Hit): (%p) %d %s\n", reinterpret_cast(lastPrimaryHitActor), lastPrimaryHitActor->GetId(), lastPrimaryHitActor->GetName().data()); - leaveEventConsumer = EmitTouchSignals(lastPrimaryHitActor, lastRenderTaskImpl, touchEventImpl, PointState::INTERRUPTED, isGeometry); + if(localVars.lastConsumedActor->IsHittable() && IsActuallySensitive(localVars.lastConsumedActor)) + { + if(localVars.lastConsumedActor->GetLeaveRequired()) + { + DALI_LOG_RELEASE_INFO("LeaveActor(Consume): (%p) %d %s\n", reinterpret_cast(localVars.lastConsumedActor), localVars.lastConsumedActor->GetId(), localVars.lastConsumedActor->GetName().data()); + EmitTouchSignals(localVars.lastConsumedActor, lastRenderTaskImpl, localVars.touchEventImpl, PointState::LEAVE, localVars.isGeometry); + } + } + else + { + // At this point mLastConsumedActor was touchable and sensitive in the previous touch event process but is not in the current one. + // An interrupted event is send to allow some actors to go back to their original state (i.e. Button controls) + DALI_LOG_RELEASE_INFO("InterruptedActor(Consume): (%p) %d %s\n", reinterpret_cast(localVars.lastConsumedActor), localVars.lastConsumedActor->GetId(), localVars.lastConsumedActor->GetName().data()); + EmitTouchSignals(processor.mLastConsumedActor.GetActor(), lastRenderTaskImpl, localVars.touchEventImpl, PointState::INTERRUPTED, localVars.isGeometry); + } } } + } + } + return consumed; + } - consumed |= leaveEventConsumer ? true : false; + /** + * Update the processor member appropriately by handling the final up event, and setting the last hit/consumed events etc. + * @param[in/out] localVars The struct of stack variables used by ProcessTouchEvent + */ + static inline void UpdateMembersWithCurrentHitInformation(ProcessTouchEventVariables& localVars) + { + // If our primary point is an Up event, then the primary point (in multi-touch) will change next + // time so set our last primary actor to NULL. Do the same to the last consumed actor as well. + + TouchEventProcessor& processor(localVars.processor); + if(localVars.primaryPointState == PointState::UP) + { + processor.Clear(); + } + else + { + // The primaryHitActor may have been removed from the scene so ensure it is still on the scene before setting members. + if(localVars.primaryHitActor && GetImplementation(localVars.primaryHitActor).OnScene()) + { + processor.mLastPrimaryHitActor.SetActor(&GetImplementation(localVars.primaryHitActor)); - // Check if the motion event has been consumed by another actor's listener. In this case, the previously - // consumed actor's listeners may need to be informed (through a leave event). - // Further checks here to ensure we do not signal the same actor twice for the same event. - if(lastConsumedActor && - lastConsumedActor != consumedActor && - lastConsumedActor != lastPrimaryHitActor && - lastConsumedActor != primaryHitActor && - lastConsumedActor != leaveEventConsumer) + // Only observe the consumed actor if we have a primaryHitActor (check if it is still on the scene). + if(localVars.consumedActor && GetImplementation(localVars.consumedActor).OnScene()) + { + processor.mLastConsumedActor.SetActor(&GetImplementation(localVars.consumedActor)); + } + else { - if(lastConsumedActor->IsHittable() && IsActuallySensitive(lastConsumedActor)) + if(localVars.isGeometry) { - if(lastConsumedActor->GetLeaveRequired()) + if(localVars.lastConsumedActor && !localVars.lastConsumedActor->OnScene()) { - DALI_LOG_RELEASE_INFO("LeaveActor(Consume): (%p) %d %s\n", reinterpret_cast(lastConsumedActor), lastConsumedActor->GetId(), lastConsumedActor->GetName().data()); - EmitTouchSignals(lastConsumedActor, lastRenderTaskImpl, touchEventImpl, PointState::LEAVE, isGeometry); + processor.mLastConsumedActor.SetActor(nullptr); } } else { - // At this point mLastConsumedActor was touchable and sensitive in the previous touch event process but is not in the current one. - // An interrupted event is send to allow some actors to go back to their original state (i.e. Button controls) - DALI_LOG_RELEASE_INFO("InterruptedActor(Consume): (%p) %d %s\n", reinterpret_cast(lastConsumedActor), lastConsumedActor->GetId(), lastConsumedActor->GetName().data()); - EmitTouchSignals(mLastConsumedActor.GetActor(), lastRenderTaskImpl, touchEventImpl, PointState::INTERRUPTED, isGeometry); + processor.mLastConsumedActor.SetActor(nullptr); } } + + processor.mLastRenderTask = localVars.currentRenderTask; + processor.mLastPrimaryPointState = localVars.primaryPointState; + } + else + { + processor.Clear(); } } } - // 5) If our primary point is an Up event, then the primary point (in multi-touch) will change next - // time so set our last primary actor to NULL. Do the same to the last consumed actor as well. - if(primaryPointState == PointState::UP) + /** + * Deliver an event to the touch-down actor and emit from the scene if required. + * @param[in/out] localVars The struct of stack variables used by ProcessTouchEvent + * @param[in] event The touch event that has occurred + */ + static inline void DeliverEventToTouchDownActorAndScene(ProcessTouchEventVariables& localVars, const Integration::TouchEvent& event) { - Clear(); - } - else - { - // The primaryHitActor may have been removed from the scene so ensure it is still on the scene before setting members. - if(primaryHitActor && GetImplementation(primaryHitActor).OnScene()) + TouchEventProcessor& processor(localVars.processor); + if(localVars.touchEventImpl->GetPointCount() == 1) // Only want the first touch and the last release { - mLastPrimaryHitActor.SetActor(&GetImplementation(primaryHitActor)); - - // Only observe the consumed actor if we have a primaryHitActor (check if it is still on the scene). - if(consumedActor && GetImplementation(consumedActor).OnScene()) + switch(localVars.primaryPointState) { - mLastConsumedActor.SetActor(&GetImplementation(consumedActor)); - } - else - { - if(isGeometry) + case PointState::UP: { - if(lastConsumedActor && !lastConsumedActor->OnScene()) + Actor* touchDownConsumedActor(processor.mTouchDownConsumedActor.GetActor()); + if(touchDownConsumedActor && + touchDownConsumedActor != localVars.consumedActor && + touchDownConsumedActor != localVars.lastPrimaryHitActor && + touchDownConsumedActor != localVars.lastConsumedActor) { - mLastConsumedActor.SetActor(nullptr); + Dali::Actor touchDownConsumedActorHandle(touchDownConsumedActor); + + Integration::Point currentPoint = localVars.touchEventImpl->GetPoint(0); + currentPoint.SetHitActor(touchDownConsumedActorHandle); + currentPoint.SetState(PointState::INTERRUPTED); + + if(localVars.isGeometry) + { + std::list actorLists; + actorLists.push_back(touchDownConsumedActor); + GeoAllocAndEmitTouchSignals(actorLists, event.time, currentPoint, nullptr /* Not Required for this use case */); + } + else + { + AllocAndEmitTouchSignals(event.time, touchDownConsumedActorHandle, currentPoint, nullptr /* Not Required for this use case */); + } } + + processor.mTouchDownConsumedActor.SetActor(nullptr); + processor.mInterceptedTouchActor.SetActor(nullptr); + + DALI_FALLTHROUGH; } - else + + case PointState::DOWN: { - mLastConsumedActor.SetActor(nullptr); + processor.mScene.EmitTouchedSignal(localVars.touchEventHandle); + break; } - } - mLastRenderTask = currentRenderTask; - mLastPrimaryPointState = primaryPointState; - } - else - { - Clear(); + case PointState::MOTION: + case PointState::LEAVE: + case PointState::STATIONARY: + case PointState::INTERRUPTED: + { + // Ignore + break; + } + } } } +}; - // 6) Emit an interrupted event to the touch-down actor if it hasn't consumed the up and - // emit the stage touched event if required. +TouchEventProcessor::TouchEventProcessor(Scene& scene) +: mScene(scene), + mLastPrimaryHitActor(MakeCallback(this, &TouchEventProcessor::OnObservedActorDisconnected)), + mLastConsumedActor(), + mCapturingTouchActor(), + mOwnTouchActor(), + mTouchDownConsumedActor(), + mInterceptedTouchActor(), + mLastRenderTask(), + mLastPrimaryPointState(PointState::FINISHED) +{ + DALI_LOG_TRACE_METHOD(gLogFilter); +} - if(touchEventImpl->GetPointCount() == 1) // Only want the first touch and the last release - { - switch(primaryPointState) - { - case PointState::UP: - { - Actor* touchDownConsumedActor(mTouchDownConsumedActor.GetActor()); - if(touchDownConsumedActor && - touchDownConsumedActor != consumedActor && - touchDownConsumedActor != lastPrimaryHitActor && - touchDownConsumedActor != lastConsumedActor) - { - Dali::Actor touchDownConsumedActorHandle(touchDownConsumedActor); +TouchEventProcessor::~TouchEventProcessor() +{ + DALI_LOG_TRACE_METHOD(gLogFilter); +} - Integration::Point currentPoint = touchEventImpl->GetPoint(0); - currentPoint.SetHitActor(touchDownConsumedActorHandle); - currentPoint.SetState(PointState::INTERRUPTED); +bool TouchEventProcessor::ProcessTouchEvent(const Integration::TouchEvent& event) +{ + DALI_LOG_TRACE_METHOD(gLogFilter); + DALI_ASSERT_ALWAYS(!event.points.empty() && "Empty TouchEvent sent from Integration\n"); - if(isGeometry) - { - std::list actorLists; - actorLists.push_back(touchDownConsumedActor); - GeoAllocAndEmitTouchSignals(actorLists, event.time, currentPoint, nullptr /* Not Required for this use case */); - } - else - { - AllocAndEmitTouchSignals(event.time, touchDownConsumedActorHandle, currentPoint, nullptr /* Not Required for this use case */); - } - } + PRINT_HIERARCHY(gLogFilter); - mTouchDownConsumedActor.SetActor(nullptr); - mInterceptedTouchActor.SetActor(nullptr); + DALI_TRACE_SCOPE(gTraceFilter, "DALI_PROCESS_TOUCH_EVENT"); - DALI_FALLTHROUGH; - } + ProcessTouchEventVariables localVars(*this, mScene.IsGeometryHittestEnabled()); - case PointState::DOWN: - { - mScene.EmitTouchedSignal(touchEventHandle); - break; - } + // 1) Check if it is an interrupted event - we should inform our last primary hit actor about this + // and emit the stage signal as well. - case PointState::MOTION: - case PointState::LEAVE: - case PointState::STATIONARY: - case PointState::INTERRUPTED: - { - // Ignore - break; - } + if(event.points[0].GetState() == PointState::INTERRUPTED) + { + Impl::EmitInterruptedEvent(localVars, event); + return false; // No need for hit testing & already an interrupted event so just return false + } + + // 2) Hit Testing. + localVars.touchEventImpl = new TouchEvent(event.time); + localVars.touchEventHandle = Dali::TouchEvent(localVars.touchEventImpl.Get()); + + DALI_LOG_INFO(gLogFilter, Debug::Concise, "\n"); + DALI_LOG_INFO(gLogFilter, Debug::General, "Point(s): %d\n", event.GetPointCount()); + + bool firstPointParsed = false; + for(auto&& currentPoint : event.points) + { + HitTestAlgorithm::Results hitTestResults; + hitTestResults.point = currentPoint; + hitTestResults.eventTime = event.time; + if(!firstPointParsed) + { + firstPointParsed = true; + ParsePrimaryTouchPoint(hitTestResults, mCapturingTouchActor, mOwnTouchActor, mLastRenderTask, currentPoint, mScene, mCandidateActorLists); + + // Only set the currentRenderTask for the primary hit actor. + localVars.currentRenderTask = hitTestResults.renderTask; + localVars.touchEventImpl->SetRenderTask(Dali::RenderTask(localVars.currentRenderTask.Get())); } + else + { + HitTestAlgorithm::HitTest(mScene.GetSize(), mScene.GetRenderTaskList(), mScene.GetLayerList(), currentPoint.GetScreenPosition(), hitTestResults, nullptr, localVars.isGeometry); + } + + Integration::Point newPoint(currentPoint); + newPoint.SetHitActor(hitTestResults.actor); + newPoint.SetLocalPosition(hitTestResults.actorCoordinates); + + localVars.touchEventImpl->AddPoint(newPoint); + + DALI_LOG_INFO(gLogFilter, + Debug::General, + " State(%s), Screen(%.0f, %.0f), HitActor(%p, %s), Local(%.2f, %.2f)\n", + TOUCH_POINT_STATE[currentPoint.GetState()], + currentPoint.GetScreenPosition().x, + currentPoint.GetScreenPosition().y, + (hitTestResults.actor ? reinterpret_cast(&hitTestResults.actor.GetBaseObject()) : NULL), + (hitTestResults.actor ? hitTestResults.actor.GetProperty(Dali::Actor::Property::NAME).c_str() : ""), + hitTestResults.actorCoordinates.x, + hitTestResults.actorCoordinates.y); } + // 3) Recursively deliver events to the actor and its parents, until the event is consumed or the stage is reached. + localVars.primaryPoint = &localVars.touchEventImpl->GetPoint(0); + localVars.primaryHitActor = localVars.primaryPoint->GetHitActor(); + localVars.primaryPointState = localVars.primaryPoint->GetState(); + + bool consumed = Impl::DeliverEventsToActorAndParents(localVars); + + // 4) Check if the last primary hit actor requires a leave event and if it was different to the current primary + // hit actor. Also process the last consumed actor in the same manner. + localVars.lastPrimaryHitActor = mInterceptedTouchActor.GetActor() ? mInterceptedTouchActor.GetActor() : mLastPrimaryHitActor.GetActor(); + localVars.lastConsumedActor = mLastConsumedActor.GetActor(); + consumed |= Impl::DeliverLeaveEvent(localVars); + + // 5) Update the processor member appropriately. + Impl::UpdateMembersWithCurrentHitInformation(localVars); + + // 6) Emit an interrupted event to the touch-down actor if it hasn't consumed the up and + // emit the stage touched event if required. + Impl::DeliverEventToTouchDownActorAndScene(localVars, event); + return consumed; } @@ -823,7 +917,7 @@ void TouchEventProcessor::OnObservedActorDisconnected(Actor* actor) { if(mScene.IsGeometryHittestEnabled() && (actor == mLastConsumedActor.GetActor() || actor == mLastPrimaryHitActor.GetActor())) { - Dali::Actor actorHandle(actor); + Dali::Actor actorHandle(actor); Integration::Point point; point.SetState(PointState::INTERRUPTED); point.SetHitActor(actorHandle); @@ -846,7 +940,7 @@ void TouchEventProcessor::OnObservedActorDisconnected(Actor* actor) { if(actor == mLastPrimaryHitActor.GetActor()) { - Dali::Actor actorHandle(actor); + Dali::Actor actorHandle(actor); Integration::Point point; point.SetState(PointState::INTERRUPTED); point.SetHitActor(actorHandle); @@ -867,9 +961,17 @@ void TouchEventProcessor::OnObservedActorDisconnected(Actor* actor) mLastPrimaryPointState = PointState::FINISHED; } } - } -} // namespace Internal +void TouchEventProcessor::Clear() +{ + mLastPrimaryHitActor.SetActor(nullptr); + mLastConsumedActor.SetActor(nullptr); + mCapturingTouchActor.SetActor(nullptr); + mOwnTouchActor.SetActor(nullptr); + mInterceptedTouchActor.SetActor(nullptr); + mLastRenderTask.Reset(); + mLastPrimaryPointState = PointState::FINISHED; +} -} // namespace Dali +} // namespace Dali::Internal \ No newline at end of file diff --git a/dali/internal/event/events/touch-event-processor.h b/dali/internal/event/events/touch-event-processor.h index 6ecc67b..c128c42 100644 --- a/dali/internal/event/events/touch-event-processor.h +++ b/dali/internal/event/events/touch-event-processor.h @@ -2,7 +2,7 @@ #define DALI_INTERNAL_TOUCH_EVENT_PROCESSOR_H /* - * Copyright (c) 2022 Samsung Electronics Co., Ltd. + * Copyright (c) 2024 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,7 +32,7 @@ struct Vector4; namespace Integration { struct TouchEvent; -} +} // namespace Integration namespace Internal { @@ -69,19 +69,15 @@ public: */ bool ProcessTouchEvent(const Integration::TouchEvent& event); -private: - // Undefined - TouchEventProcessor(const TouchEventProcessor&); - - // Undefined - TouchEventProcessor& operator=(const TouchEventProcessor& rhs); + // Movable but not copyable + TouchEventProcessor(const TouchEventProcessor&) = delete; + TouchEventProcessor(TouchEventProcessor&&) = default; + TouchEventProcessor& operator=(const TouchEventProcessor&) = delete; + TouchEventProcessor& operator=(TouchEventProcessor&&) = default; private: - Scene& mScene; ///< Used to deliver touch events - /** * Called by some actor-observers when the observed actor is disconnected. - * * @param[in] actor The actor that has been disconnected. */ void OnObservedActorDisconnected(Actor* actor); @@ -91,16 +87,19 @@ private: */ void Clear(); - ActorObserver mLastPrimaryHitActor; ///< Stores the last primary point hit actor - ActorObserver mLastConsumedActor; ///< Stores the last consumed actor - ActorObserver mCapturingTouchActor; ///< Stored the actor that captures touch - ActorObserver mOwnTouchActor; ///< Stored the actor that own touch - ActorObserver mTouchDownConsumedActor; ///< Stores the touch-down consumed actor - ActorObserver mInterceptedTouchActor; ///< Stores the intercepted actor - RenderTaskPtr mLastRenderTask; ///< The RenderTask used for the last hit actor - PointState::Type mLastPrimaryPointState; ///< Stores the last primary point state - std::list mInterceptedActorLists; ///< Stores the list from root to intercepted actors. - std::list mCandidateActorLists; ///< Stores a list of actors that can be touched, from leaf actor to root. + Scene& mScene; ///< Used to deliver touch events + ActorObserver mLastPrimaryHitActor; ///< Stores the last primary point hit actor + ActorObserver mLastConsumedActor; ///< Stores the last consumed actor + ActorObserver mCapturingTouchActor; ///< Stored the actor that captures touch + ActorObserver mOwnTouchActor; ///< Stored the actor that own touch + ActorObserver mTouchDownConsumedActor; ///< Stores the touch-down consumed actor + ActorObserver mInterceptedTouchActor; ///< Stores the intercepted actor + RenderTaskPtr mLastRenderTask; ///< The RenderTask used for the last hit actor + PointState::Type mLastPrimaryPointState; ///< Stores the last primary point state + std::list mInterceptedActorLists; ///< Stores the list from root to intercepted actors. + std::list mCandidateActorLists; ///< Stores a list of actors that can be touched, from leaf actor to root. + + struct Impl; }; } // namespace Internal -- 2.7.4