Reduce CC of TouchEventProcessor::ProcessTouchEvent 83/304583/8
authorAdeel Kazmi <adeel.kazmi@samsung.com>
Sat, 20 Jan 2024 10:38:32 +0000 (10:38 +0000)
committerAdeel Kazmi <adeel.kazmi@samsung.com>
Tue, 23 Jan 2024 11:06:35 +0000 (11:06 +0000)
Change-Id: I725981925bb16368ed146bba414ef8ed549bffbe

dali/internal/event/actors/layer-impl.cpp
dali/internal/event/actors/layer-impl.h
dali/internal/event/events/touch-event-processor.cpp
dali/internal/event/events/touch-event-processor.h

index 3c283d9..6e02cb0 100644 (file)
@@ -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;
index b94cf30..d65ee7c 100644 (file)
@@ -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
 
index fabbcab..5df9c31 100644 (file)
@@ -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 <dali/public-api/math/vector2.h>
 #include <dali/public-api/signals/callback.h>
 
-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<Dali::Internal::Actor*>& 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<Dali::Internal::Actor*>& actorLists, c
   Dali::Actor consumedActor;
 
   std::list<Dali::Internal::Actor*>::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<Dali::Internal::Actor*>& 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<Dali::Internal::Actor*> 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<Dali::Internal::Actor*> 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<void*>(&hitTestResults.actor.GetBaseObject()) : NULL), (hitTestResults.actor ? hitTestResults.actor.GetProperty<std::string>(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<Dali::Internal::Actor*> 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<Dali::Internal::Actor*> 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<Dali::Internal::Actor*>::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<Dali::Internal::Actor*>::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<void*>(&localVars.primaryHitActor.GetBaseObject()) : NULL,
+                      localVars.primaryHitActor ? localVars.primaryHitActor.GetProperty<int32_t>(Dali::Actor::Property::ID) : -1,
+                      localVars.primaryHitActor ? localVars.primaryHitActor.GetProperty<std::string>(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<void*>(&localVars.consumedActor.GetBaseObject()) : NULL,
+                      localVars.consumedActor ? localVars.consumedActor.GetProperty<int32_t>(Dali::Actor::Property::ID) : -1,
+                      localVars.consumedActor ? localVars.consumedActor.GetProperty<std::string>(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<void*>(&localVars.primaryHitActor.GetBaseObject()) : NULL,
+                              localVars.primaryHitActor ? localVars.primaryHitActor.GetProperty<int32_t>(Dali::Actor::Property::ID) : -1,
+                              localVars.primaryHitActor ? localVars.primaryHitActor.GetProperty<std::string>(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<void*>(&localVars.consumedActor.GetBaseObject()) : NULL,
+                              localVars.consumedActor ? localVars.consumedActor.GetProperty<int32_t>(Dali::Actor::Property::ID) : -1,
+                              localVars.consumedActor ? localVars.consumedActor.GetProperty<std::string>(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<void*>(&primaryHitActor.GetBaseObject()) : NULL, primaryHitActor ? primaryHitActor.GetProperty<int32_t>(Dali::Actor::Property::ID) : -1, primaryHitActor ? primaryHitActor.GetProperty<std::string>(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<void*>(&consumedActor.GetBaseObject()) : NULL, consumedActor ? consumedActor.GetProperty<int32_t>(Dali::Actor::Property::ID) : -1, consumedActor ? consumedActor.GetProperty<std::string>(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<bool>(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<void*>(&primaryHitActor.GetBaseObject()) : NULL, primaryHitActor ? primaryHitActor.GetProperty<int32_t>(Dali::Actor::Property::ID) : -1, primaryHitActor ? primaryHitActor.GetProperty<std::string>(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<void*>(&consumedActor.GetBaseObject()) : NULL, consumedActor ? consumedActor.GetProperty<int32_t>(Dali::Actor::Property::ID) : -1, consumedActor ? consumedActor.GetProperty<std::string>(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<bool>(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<void*>(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<void*>(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<void*>(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<void*>(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<void*>(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<void*>(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<void*>(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<void*>(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<void*>(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<void*>(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<void*>(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<void*>(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<Dali::Internal::Actor*> 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<Dali::Internal::Actor*> 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<void*>(&hitTestResults.actor.GetBaseObject()) : NULL),
+                  (hitTestResults.actor ? hitTestResults.actor.GetProperty<std::string>(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
index 6ecc67b..c128c42 100644 (file)
@@ -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<Dali::Internal::Actor*> mInterceptedActorLists;   ///< Stores the list from root to intercepted actors.
-  std::list<Dali::Internal::Actor*> 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<Dali::Internal::Actor*> mInterceptedActorLists;  ///< Stores the list from root to intercepted actors.
+  std::list<Dali::Internal::Actor*> mCandidateActorLists;    ///< Stores a list of actors that can be touched, from leaf actor to root.
+
+  struct Impl;
 };
 
 } // namespace Internal