[dali_2.3.25] Merge branch 'devel/master'
[platform/core/uifw/dali-core.git] / dali / internal / event / events / touch-event-processor.cpp
1 /*
2  * Copyright (c) 2024 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/event/events/touch-event-processor.h>
20
21 #if defined(DEBUG_ENABLED)
22 #include <sstream>
23 #endif
24
25 // INTERNAL INCLUDES
26 #include <dali/integration-api/debug.h>
27 #include <dali/integration-api/events/touch-event-integ.h>
28 #include <dali/integration-api/trace.h>
29 #include <dali/internal/event/actors/actor-impl.h>
30 #include <dali/internal/event/actors/layer-impl.h>
31 #include <dali/internal/event/common/scene-impl.h>
32 #include <dali/internal/event/events/hit-test-algorithm-impl.h>
33 #include <dali/internal/event/events/multi-point-event-util.h>
34 #include <dali/internal/event/events/touch-event-impl.h>
35 #include <dali/internal/event/render-tasks/render-task-impl.h>
36 #include <dali/public-api/events/touch-event.h>
37 #include <dali/public-api/math/vector2.h>
38 #include <dali/public-api/signals/callback.h>
39
40 namespace Dali::Internal
41 {
42 namespace
43 {
44 DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_PERFORMANCE_MARKER, false);
45 #if defined(DEBUG_ENABLED)
46 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_TOUCH_PROCESSOR");
47 #endif // defined(DEBUG_ENABLED)
48
49 /**
50  * Structure for Variables used in the ProcessTouchEvent method.
51  */
52 struct ProcessTouchEventVariables
53 {
54   ProcessTouchEventVariables(TouchEventProcessor& eventProcessor, bool geometry)
55   : processor(eventProcessor),
56     isGeometry(geometry)
57   {
58   }
59
60   TouchEventProcessor& processor;                              ///< A handle to the touch-event-processor.
61   const bool           isGeometry;                             ///< Whether it's a geometry or not.
62   Actor*               lastPrimaryHitActor{nullptr};           ///< The last primary hit-actor.
63   Actor*               lastConsumedActor{nullptr};             ///< The last consuming actor.
64   TouchEventPtr        touchEventImpl;                         ///< The current touch-event-impl.
65   Dali::TouchEvent     touchEventHandle;                       ///< The handle to the touch-event-impl.
66   RenderTaskPtr        currentRenderTask;                      ///< The current render-task.
67   Dali::Actor          consumedActor;                          ///< The actor that consumed the event.
68   Dali::Actor          primaryHitActor;                        ///< The actor that has been hit by the primary point.
69   Integration::Point*  primaryPoint{nullptr};                  ///< The primary point of the hit.
70   PointState::Type     primaryPointState{PointState::STARTED}; ///< The state of the primary point.
71 };
72
73 const char* TOUCH_POINT_STATE[6] =
74   {
75     "DOWN",
76     "UP",
77     "MOTION",
78     "LEAVE",
79     "STATIONARY",
80     "INTERRUPTED",
81 };
82
83 bool ShouldEmitInterceptTouchEvent(const Actor& actorImpl, const Dali::TouchEvent& event)
84 {
85   PointState::Type state = event.GetState(0);
86   return actorImpl.GetInterceptTouchRequired() && (state != PointState::MOTION || actorImpl.IsDispatchTouchMotion());
87 }
88
89 bool ShouldEmitTouchEvent(const Actor& actorImpl, const Dali::TouchEvent& event)
90 {
91   PointState::Type state = event.GetState(0);
92   return actorImpl.GetTouchRequired() && (state != PointState::MOTION || actorImpl.IsDispatchTouchMotion());
93 }
94
95 // child -> parent
96 Dali::Actor EmitInterceptTouchSignals(Dali::Actor actor, const Dali::TouchEvent& touchEvent)
97 {
98   Dali::Actor interceptedActor;
99
100   if(actor)
101   {
102     Dali::Actor parent = actor.GetParent();
103     if(parent)
104     {
105       // Recursively deliver events to the actor and its parents for intercept touch event.
106       interceptedActor = EmitInterceptTouchSignals(parent, touchEvent);
107     }
108
109     if(!interceptedActor)
110     {
111       bool   intercepted = false;
112       Actor& actorImpl(GetImplementation(actor));
113       if(ShouldEmitInterceptTouchEvent(actorImpl, touchEvent))
114       {
115         DALI_TRACE_SCOPE(gTraceFilter, "DALI_EMIT_INTERCEPT_TOUCH_EVENT_SIGNAL");
116         intercepted = actorImpl.EmitInterceptTouchEventSignal(touchEvent);
117         if(intercepted)
118         {
119           interceptedActor = Dali::Actor(&actorImpl);
120         }
121       }
122     }
123   }
124   return interceptedActor;
125 }
126
127 // geometry
128 // child -> below
129 Dali::Actor EmitGeoInterceptTouchSignals(std::list<Dali::Internal::Actor*>& actorLists, std::list<Dali::Internal::Actor*>& interceptActorList, const Dali::TouchEvent& touchEvent, ActorObserver& lastConsumedActor)
130 {
131   interceptActorList.clear();
132   Dali::Actor interceptedActor;
133   for(auto&& actor : actorLists)
134   {
135     interceptActorList.push_back(actor);
136     if(ShouldEmitInterceptTouchEvent(*actor, touchEvent))
137     {
138       DALI_TRACE_SCOPE(gTraceFilter, "DALI_EMIT_INTERCEPT_TOUCH_EVENT_SIGNAL");
139       if(actor->EmitInterceptTouchEventSignal(touchEvent))
140       {
141         interceptedActor = Dali::Actor(actor);
142         break;
143       }
144     }
145     // If there is a consumed actor, the intercept is sent only up to the moment before the consumed actor.
146     if(lastConsumedActor.GetActor() == actor)
147     {
148       break;
149     }
150   }
151   return interceptedActor;
152 }
153
154 /**
155  *  Recursively deliver events to the actor and its parents, until the event is consumed or the stage is reached.
156  */
157 Dali::Actor EmitTouchSignals(Dali::Actor actor, const Dali::TouchEvent& touchEvent)
158 {
159   Dali::Actor consumedActor;
160
161   if(actor)
162   {
163     Dali::Actor oldParent(actor.GetParent());
164
165     Actor& actorImpl(GetImplementation(actor));
166
167     bool consumed(false);
168
169     // Only emit the signal if the actor's touch signal has connections (or derived actor implementation requires touch).
170     if(ShouldEmitTouchEvent(actorImpl, touchEvent))
171     {
172       DALI_TRACE_SCOPE(gTraceFilter, "DALI_EMIT_TOUCH_EVENT_SIGNAL");
173       consumed = actorImpl.EmitTouchEventSignal(touchEvent);
174     }
175
176     if(consumed)
177     {
178       // One of this actor's listeners has consumed the event so set this actor as the consumed actor.
179       consumedActor = Dali::Actor(&actorImpl);
180     }
181     else
182     {
183       // The actor may have been removed/reparented during the signal callbacks.
184       Dali::Actor parent = actor.GetParent();
185
186       if(parent &&
187          (parent == oldParent))
188       {
189         // One of the actor's parents may consumed the event and they should be set as the consumed actor.
190         consumedActor = EmitTouchSignals(parent, touchEvent);
191       }
192     }
193   }
194
195   return consumedActor;
196 }
197
198 /**
199  *  Recursively deliver events to the actor and its below actor, until the event is consumed or the stage is reached.
200  */
201 Dali::Actor EmitGeoTouchSignals(std::list<Dali::Internal::Actor*>& actorLists, const Dali::TouchEvent& touchEvent)
202 {
203   Dali::Actor consumedActor;
204
205   std::list<Dali::Internal::Actor*>::reverse_iterator rIter = actorLists.rbegin();
206   for(; rIter != actorLists.rend(); rIter++)
207   {
208     Actor* actorImpl(*rIter);
209     // Only emit the signal if the actor's touch signal has connections (or derived actor implementation requires touch).
210     if(ShouldEmitTouchEvent(*actorImpl, touchEvent))
211     {
212       DALI_TRACE_SCOPE(gTraceFilter, "DALI_EMIT_TOUCH_EVENT_SIGNAL");
213       if(actorImpl->EmitTouchEventSignal(touchEvent))
214       {
215         // One of this actor's listeners has consumed the event so set this actor as the consumed actor.
216         consumedActor = Dali::Actor(actorImpl);
217         break;
218       }
219     }
220   }
221   return consumedActor;
222 }
223
224 Dali::Actor AllocAndEmitTouchSignals(unsigned long time, Dali::Actor actor, const Integration::Point& point, RenderTaskPtr renderTask)
225 {
226   TouchEventPtr    touchEvent(new TouchEvent(time));
227   Dali::TouchEvent touchEventHandle(touchEvent.Get());
228
229   touchEvent->AddPoint(point);
230   touchEvent->SetRenderTask(Dali::RenderTask(renderTask.Get()));
231
232   return EmitTouchSignals(actor, touchEventHandle);
233 }
234
235 Dali::Actor GeoAllocAndEmitTouchSignals(std::list<Dali::Internal::Actor*>& actorLists, unsigned long time, const Integration::Point& point, RenderTaskPtr renderTask)
236 {
237   TouchEventPtr    touchEvent(new TouchEvent(time));
238   Dali::TouchEvent touchEventHandle(touchEvent.Get());
239
240   touchEvent->AddPoint(point);
241   touchEvent->SetRenderTask(Dali::RenderTask(renderTask.Get()));
242
243   return EmitGeoTouchSignals(actorLists, touchEventHandle);
244 }
245
246 /**
247  * Changes the state of the primary point to leave and emits the touch signals
248  */
249 Dali::Actor EmitTouchSignals(Actor* actor, RenderTask& renderTask, const TouchEventPtr& originalTouchEvent, PointState::Type state, bool isGeometry)
250 {
251   Dali::Actor consumingActor;
252
253   if(actor)
254   {
255     TouchEventPtr touchEventImpl = TouchEvent::Clone(*originalTouchEvent.Get());
256     touchEventImpl->SetRenderTask(Dali::RenderTask(&renderTask));
257
258     Integration::Point& primaryPoint = touchEventImpl->GetPoint(0);
259
260     const Vector2& screenPosition = primaryPoint.GetScreenPosition();
261     Vector2        localPosition;
262     actor->ScreenToLocal(renderTask, localPosition.x, localPosition.y, screenPosition.x, screenPosition.y);
263
264     primaryPoint.SetLocalPosition(localPosition);
265     primaryPoint.SetHitActor(Dali::Actor(actor));
266     primaryPoint.SetState(state);
267
268     if(isGeometry)
269     {
270       std::list<Dali::Internal::Actor*> actorLists;
271       actorLists.push_back(actor);
272       consumingActor = EmitGeoTouchSignals(actorLists, Dali::TouchEvent(touchEventImpl.Get()));
273     }
274     else
275     {
276       consumingActor = EmitTouchSignals(Dali::Actor(actor), Dali::TouchEvent(touchEventImpl.Get()));
277     }
278   }
279
280   return consumingActor;
281 }
282
283 /**
284  * @brief Parses the primary touch point by performing a hit-test if necessary
285  *
286  * @param[out] hitTestResults The hit test results are put into this variable
287  * @param[in/out] capturingTouchActorObserver The observer for the capturing touch actor member
288  * @param[in] lastRenderTask The last render task member
289  * @param[in] currentPoint The current point information
290  * @param[in] scene The scene that this touch is related to
291  * @param[in] actorLists The list of actors that can be touched, from leaf actor to root.
292  */
293 void ParsePrimaryTouchPoint(
294   HitTestAlgorithm::Results&         hitTestResults,
295   ActorObserver&                     capturingTouchActorObserver,
296   ActorObserver&                     ownTouchActorObserver,
297   const RenderTaskPtr&               lastRenderTask,
298   const Integration::Point&          currentPoint,
299   const Internal::Scene&             scene,
300   std::list<Dali::Internal::Actor*>& actorLists)
301 {
302   Actor* capturingTouchActor = capturingTouchActorObserver.GetActor();
303
304   // We only set the capturing touch actor when the first touch-started actor captures all touch so if it's set, just use it
305   if(capturingTouchActor && lastRenderTask)
306   {
307     hitTestResults.actor          = Dali::Actor(capturingTouchActor);
308     hitTestResults.renderTask     = lastRenderTask;
309     const Vector2& screenPosition = currentPoint.GetScreenPosition();
310     capturingTouchActor->ScreenToLocal(*lastRenderTask, hitTestResults.actorCoordinates.x, hitTestResults.actorCoordinates.y, screenPosition.x, screenPosition.y);
311   }
312   else
313   {
314     Actor* ownTouchActor = ownTouchActorObserver.GetActor();
315     HitTestAlgorithm::HitTest(scene.GetSize(), scene.GetRenderTaskList(), scene.GetLayerList(), currentPoint.GetScreenPosition(), hitTestResults, ownTouchActor, scene.IsGeometryHittestEnabled());
316
317     if(currentPoint.GetState() == PointState::STARTED && hitTestResults.actor)
318     {
319       bool isGeometry = scene.IsGeometryHittestEnabled();
320       // If we've just started touch, then check whether the actor has requested to capture all touch events
321       Actor* hitActor = &GetImplementation(hitTestResults.actor);
322       if(hitActor->CapturesAllTouchAfterStart() || isGeometry)
323       {
324         capturingTouchActorObserver.SetActor(hitActor);
325       }
326       if(hitActor->IsAllowedOnlyOwnTouch() || isGeometry)
327       {
328         ownTouchActorObserver.SetActor(hitActor);
329       }
330       if(isGeometry)
331       {
332         actorLists = hitTestResults.actorLists;
333       }
334     }
335   }
336 }
337
338 } // unnamed namespace
339
340 struct TouchEventProcessor::Impl
341 {
342   /**
343    * Emits an interrupted event.
344    * @param[in/out] localVars The struct of stack variables used by ProcessTouchEvent
345    * @param[in] event The touch event that has occurred
346    */
347   static inline void EmitInterruptedEvent(ProcessTouchEventVariables& localVars, const Integration::TouchEvent& event)
348   {
349     Dali::Actor        consumingActor;
350     Integration::Point currentPoint(event.points[0]);
351
352     if(localVars.isGeometry)
353     {
354       // Since the geometry way only receives touch events from the consumed actor,
355       // it first searches for whether there is a consumed actor and then sends the event
356       Actor* touchConsumedActor(localVars.processor.mLastConsumedActor.GetActor());
357       Actor* touchDownConsumedActor(localVars.processor.mTouchDownConsumedActor.GetActor());
358       Actor* lastPrimaryHitActor(localVars.processor.mLastPrimaryHitActor.GetActor());
359       if(touchConsumedActor)
360       {
361         Dali::Actor touchConsumedActorHandle(touchConsumedActor);
362         currentPoint.SetHitActor(touchConsumedActorHandle);
363         std::list<Dali::Internal::Actor*> actorLists;
364         actorLists.push_back(touchConsumedActor);
365         GeoAllocAndEmitTouchSignals(actorLists, event.time, currentPoint, localVars.processor.mLastRenderTask);
366       }
367       else if(touchDownConsumedActor)
368       {
369         Dali::Actor touchDownConsumedActorHandle(touchDownConsumedActor);
370         currentPoint.SetHitActor(touchDownConsumedActorHandle);
371         std::list<Dali::Internal::Actor*> actorLists;
372         actorLists.push_back(touchDownConsumedActor);
373         GeoAllocAndEmitTouchSignals(actorLists, event.time, currentPoint, localVars.processor.mLastRenderTask);
374       }
375       else if(lastPrimaryHitActor)
376       {
377         Dali::Actor lastPrimaryHitActorHandle(lastPrimaryHitActor);
378         currentPoint.SetHitActor(lastPrimaryHitActorHandle);
379
380         GeoAllocAndEmitTouchSignals(localVars.processor.mCandidateActorLists, event.time, currentPoint, localVars.processor.mLastRenderTask);
381       }
382     }
383     else
384     {
385       Actor* lastPrimaryHitActor(localVars.processor.mLastPrimaryHitActor.GetActor());
386       if(lastPrimaryHitActor)
387       {
388         Dali::Actor lastPrimaryHitActorHandle(lastPrimaryHitActor);
389         currentPoint.SetHitActor(lastPrimaryHitActorHandle);
390
391         consumingActor = AllocAndEmitTouchSignals(event.time, lastPrimaryHitActorHandle, currentPoint, localVars.processor.mLastRenderTask);
392       }
393
394       // If the last consumed actor was different to the primary hit actor then inform it as well (if it has not already been informed).
395       Actor* lastConsumedActor(localVars.processor.mLastConsumedActor.GetActor());
396       if(lastConsumedActor &&
397          lastConsumedActor != lastPrimaryHitActor &&
398          lastConsumedActor != consumingActor)
399       {
400         Dali::Actor lastConsumedActorHandle(lastConsumedActor);
401         currentPoint.SetHitActor(lastConsumedActorHandle);
402         AllocAndEmitTouchSignals(event.time, lastConsumedActorHandle, currentPoint, localVars.processor.mLastRenderTask);
403       }
404
405       // Tell the touch-down consuming actor as well, if required
406       Actor* touchDownConsumedActor(localVars.processor.mTouchDownConsumedActor.GetActor());
407       if(touchDownConsumedActor &&
408          touchDownConsumedActor != lastPrimaryHitActor &&
409          touchDownConsumedActor != lastConsumedActor &&
410          touchDownConsumedActor != consumingActor)
411       {
412         Dali::Actor touchDownConsumedActorHandle(touchDownConsumedActor);
413
414         currentPoint.SetHitActor(touchDownConsumedActorHandle);
415         AllocAndEmitTouchSignals(event.time, touchDownConsumedActorHandle, currentPoint, localVars.processor.mLastRenderTask);
416       }
417     }
418
419     localVars.processor.Clear();
420     localVars.processor.mTouchDownConsumedActor.SetActor(nullptr);
421
422     currentPoint.SetHitActor(Dali::Actor());
423
424     TouchEventPtr    touchEventImpl(new TouchEvent(event.time));
425     Dali::TouchEvent touchEventHandle(touchEventImpl.Get());
426
427     touchEventImpl->AddPoint(currentPoint);
428
429     localVars.processor.mScene.EmitTouchedSignal(touchEventHandle);
430   }
431
432   /**
433    * Recursively deliver events to the actor and its parents, until the event is consumed or the stage is reached.
434    * @param[in/out] localVars The struct of stack variables used by ProcessTouchEvent
435    * @return True if consumed, false otherwise.
436    */
437   static inline bool DeliverEventsToActorAndParents(ProcessTouchEventVariables& localVars)
438   {
439     bool                 consumed  = false;
440     TouchEventProcessor& processor = localVars.processor;
441     if(localVars.currentRenderTask)
442     {
443       if(localVars.isGeometry)
444       {
445         Actor* interceptedTouchActor(processor.mInterceptedTouchActor.GetActor());
446         if(interceptedTouchActor)
447         {
448           Actor* touchConsumedActor(processor.mLastConsumedActor.GetActor());
449           if(touchConsumedActor) // If there is a consumed actor, send events only to the consumed actor.
450           {
451             RenderTask& currentRenderTaskImpl = *localVars.currentRenderTask.Get();
452             localVars.consumedActor           = EmitTouchSignals(touchConsumedActor, currentRenderTaskImpl, localVars.touchEventImpl, localVars.primaryPointState, localVars.isGeometry);
453           }
454           else // If there is an intercepted actor, send a touch event starting from the intercepted actor.
455           {
456             Dali::Actor                       interceptedTouchActorHandle(interceptedTouchActor);
457             std::list<Dali::Internal::Actor*> interceptActorLists = localVars.processor.mInterceptedActorLists;
458             localVars.consumedActor                               = EmitGeoTouchSignals(interceptActorLists, localVars.touchEventHandle);
459           }
460         }
461         else
462         {
463           Dali::Actor interceptedActor;
464           // Let's find out if there is an intercept actor.
465           interceptedActor = EmitGeoInterceptTouchSignals(processor.mCandidateActorLists, processor.mInterceptedActorLists, localVars.touchEventHandle, processor.mLastConsumedActor);
466           if(interceptedActor)
467           {
468             processor.mInterceptedTouchActor.SetActor(&GetImplementation(interceptedActor));
469
470             // If there is an interception, send an interrupted event to the last consumed actor or to the actor that hit previously.
471             if(processor.mLastConsumedActor.GetActor() &&
472                processor.mLastConsumedActor.GetActor() != interceptedActor &&
473                processor.mLastRenderTask &&
474                processor.mLastPrimaryPointState != PointState::FINISHED)
475             {
476               EmitTouchSignals(processor.mLastConsumedActor.GetActor(), *processor.mLastRenderTask.Get(), localVars.touchEventImpl, PointState::INTERRUPTED, localVars.isGeometry);
477               processor.mTouchDownConsumedActor.SetActor(nullptr);
478               processor.mLastConsumedActor.SetActor(nullptr);
479             }
480             else if(processor.mLastPrimaryHitActor.GetActor() &&
481                     processor.mLastPrimaryHitActor.GetActor() != interceptedActor &&
482                     processor.mLastRenderTask &&
483                     processor.mLastPrimaryPointState != PointState::FINISHED)
484             {
485               std::list<Dali::Internal::Actor*>::reverse_iterator rIter = processor.mCandidateActorLists.rbegin();
486               for(; rIter != processor.mCandidateActorLists.rend(); rIter++)
487               {
488                 Actor* actorImpl(*rIter);
489                 EmitTouchSignals(actorImpl, *processor.mLastRenderTask.Get(), localVars.touchEventImpl, PointState::INTERRUPTED, localVars.isGeometry);
490               }
491             }
492           }
493
494           Actor* touchConsumedActor(processor.mLastConsumedActor.GetActor());
495           if(touchConsumedActor) // If there is a consumed actor, send events only to the consumed actor.
496           {
497             RenderTask& currentRenderTaskImpl = *localVars.currentRenderTask.Get();
498             localVars.consumedActor           = EmitTouchSignals(touchConsumedActor, currentRenderTaskImpl, localVars.touchEventImpl, localVars.primaryPointState, localVars.isGeometry);
499           }
500           else
501           {
502             // Let's propagate touch events from the intercepted actor or start propagating touch events from the leaf actor.
503             localVars.consumedActor = EmitGeoTouchSignals(interceptedActor ? processor.mInterceptedActorLists : processor.mCandidateActorLists, localVars.touchEventHandle);
504
505             // If consumed, the actors who previously received the touch are interrupted, indicating that the touch has been consumed by another actor.
506             if(localVars.consumedActor && localVars.primaryPointState != PointState::DOWN)
507             {
508               std::list<Dali::Internal::Actor*>::reverse_iterator rIter = std::find(processor.mCandidateActorLists.rbegin(), processor.mCandidateActorLists.rend(), localVars.consumedActor);
509               for(++rIter; rIter != processor.mCandidateActorLists.rend(); ++rIter)
510               {
511                 Actor* actorImpl(*rIter);
512                 EmitTouchSignals(actorImpl, *processor.mLastRenderTask.Get(), localVars.touchEventImpl, PointState::INTERRUPTED, localVars.isGeometry);
513               }
514             }
515           }
516         }
517       }
518       else
519       {
520         Actor* interceptedTouchActor(processor.mInterceptedTouchActor.GetActor());
521         if(interceptedTouchActor)
522         {
523           Dali::Actor interceptedTouchActorHandle(interceptedTouchActor);
524           localVars.consumedActor = EmitTouchSignals(interceptedTouchActorHandle, localVars.touchEventHandle);
525         }
526         else
527         {
528           // Emit the intercept touch signal
529           Dali::Actor interceptedActor = EmitInterceptTouchSignals(localVars.primaryHitActor, localVars.touchEventHandle);
530           if(interceptedActor)
531           {
532             processor.mInterceptedTouchActor.SetActor(&GetImplementation(interceptedActor));
533             // If the child is being touched, INTERRUPTED is sent.
534             if(processor.mLastPrimaryHitActor.GetActor() &&
535                processor.mLastPrimaryHitActor.GetActor() != interceptedActor &&
536                processor.mLastRenderTask &&
537                processor.mLastPrimaryPointState != PointState::FINISHED)
538             {
539               EmitTouchSignals(processor.mLastPrimaryHitActor.GetActor(), *processor.mLastRenderTask.Get(), localVars.touchEventImpl, PointState::INTERRUPTED, localVars.isGeometry);
540               processor.mTouchDownConsumedActor.SetActor(nullptr);
541             }
542             localVars.consumedActor = EmitTouchSignals(interceptedActor, localVars.touchEventHandle);
543           }
544           else
545           {
546             localVars.consumedActor = EmitTouchSignals(localVars.primaryHitActor, localVars.touchEventHandle);
547           }
548         }
549       }
550
551       consumed = localVars.consumedActor ? true : false;
552
553       if(localVars.primaryPointState == PointState::MOTION)
554       {
555         DALI_LOG_INFO(gLogFilter,
556                       Debug::Concise,
557                       "PrimaryHitActor: (%p) id(%d), name(%s), state(%s), screenPosition(%f, %f), isGeo : %d \n",
558                       localVars.primaryHitActor ? reinterpret_cast<void*>(&localVars.primaryHitActor.GetBaseObject()) : NULL,
559                       localVars.primaryHitActor ? localVars.primaryHitActor.GetProperty<int32_t>(Dali::Actor::Property::ID) : -1,
560                       localVars.primaryHitActor ? localVars.primaryHitActor.GetProperty<std::string>(Dali::Actor::Property::NAME).c_str() : "",
561                       TOUCH_POINT_STATE[localVars.primaryPointState],
562                       localVars.primaryPoint->GetScreenPosition().x,
563                       localVars.primaryPoint->GetScreenPosition().y,
564                       localVars.isGeometry);
565         DALI_LOG_INFO(gLogFilter,
566                       Debug::Concise,
567                       "ConsumedActor:   (%p) id(%d), name(%s), state(%s), isGeo : %d \n",
568                       localVars.consumedActor ? reinterpret_cast<void*>(&localVars.consumedActor.GetBaseObject()) : NULL,
569                       localVars.consumedActor ? localVars.consumedActor.GetProperty<int32_t>(Dali::Actor::Property::ID) : -1,
570                       localVars.consumedActor ? localVars.consumedActor.GetProperty<std::string>(Dali::Actor::Property::NAME).c_str() : "",
571                       TOUCH_POINT_STATE[localVars.primaryPointState],
572                       localVars.isGeometry);
573       }
574       else
575       {
576         DALI_LOG_RELEASE_INFO("PrimaryHitActor:(%p), id(%d), name(%s), state(%s), screenPosition(%f, %f), isGeo : %d \n",
577                               localVars.primaryHitActor ? reinterpret_cast<void*>(&localVars.primaryHitActor.GetBaseObject()) : NULL,
578                               localVars.primaryHitActor ? localVars.primaryHitActor.GetProperty<int32_t>(Dali::Actor::Property::ID) : -1,
579                               localVars.primaryHitActor ? localVars.primaryHitActor.GetProperty<std::string>(Dali::Actor::Property::NAME).c_str() : "",
580                               TOUCH_POINT_STATE[localVars.primaryPointState],
581                               localVars.primaryPoint->GetScreenPosition().x,
582                               localVars.primaryPoint->GetScreenPosition().y,
583                               localVars.isGeometry);
584         DALI_LOG_RELEASE_INFO("ConsumedActor:  (%p), id(%d), name(%s), state(%s), isGeo : %d \n",
585                               localVars.consumedActor ? reinterpret_cast<void*>(&localVars.consumedActor.GetBaseObject()) : NULL,
586                               localVars.consumedActor ? localVars.consumedActor.GetProperty<int32_t>(Dali::Actor::Property::ID) : -1,
587                               localVars.consumedActor ? localVars.consumedActor.GetProperty<std::string>(Dali::Actor::Property::NAME).c_str() : "",
588                               TOUCH_POINT_STATE[localVars.primaryPointState],
589                               localVars.isGeometry);
590       }
591     }
592
593     if((localVars.primaryPointState == PointState::DOWN) &&
594        (localVars.touchEventImpl->GetPointCount() == 1) &&
595        (localVars.consumedActor && localVars.consumedActor.GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE)))
596     {
597       processor.mTouchDownConsumedActor.SetActor(&GetImplementation(localVars.consumedActor));
598     }
599
600     return consumed;
601   }
602
603   /**
604    * Deliver Leave event to last hit or consuming actor if required.
605    * @param[in/out] localVars The struct of stack variables used by ProcessTouchEvent
606    * @return True if consumed, false otherwise.
607    */
608   static inline bool DeliverLeaveEvent(ProcessTouchEventVariables& localVars)
609   {
610     bool                 consumed = false;
611     TouchEventProcessor& processor(localVars.processor);
612     if((localVars.primaryPointState == PointState::MOTION) || (localVars.primaryPointState == PointState::UP) || (localVars.primaryPointState == PointState::STATIONARY))
613     {
614       if(processor.mLastRenderTask)
615       {
616         Dali::Actor leaveEventConsumer;
617         RenderTask& lastRenderTaskImpl = *processor.mLastRenderTask.Get();
618
619         if(localVars.isGeometry)
620         {
621           if(localVars.lastPrimaryHitActor)
622           {
623             if(!localVars.lastPrimaryHitActor->IsHittable() || !IsActuallySensitive(localVars.lastPrimaryHitActor))
624             {
625               // At this point mLastPrimaryHitActor was touchable and sensitive in the previous touch event process but is not in the current one.
626               // An interrupted event is send to allow some actors to go back to their original state (i.e. Button controls)
627               DALI_LOG_RELEASE_INFO("InterruptedActor(Hit):     (%p) %s\n", reinterpret_cast<void*>(localVars.lastPrimaryHitActor), localVars.lastPrimaryHitActor->GetName().data());
628               leaveEventConsumer = EmitTouchSignals(localVars.lastPrimaryHitActor, lastRenderTaskImpl, localVars.touchEventImpl, PointState::INTERRUPTED, localVars.isGeometry);
629             }
630           }
631
632           consumed = leaveEventConsumer ? true : false;
633
634           // Check if the motion event has been consumed by another actor's listener.  In this case, the previously
635           // consumed actor's listeners may need to be informed (through a leave event).
636           // Further checks here to ensure we do not signal the same actor twice for the same event.
637           if(localVars.lastConsumedActor &&
638              localVars.lastConsumedActor != localVars.lastPrimaryHitActor &&
639              localVars.lastConsumedActor != leaveEventConsumer)
640           {
641             if(!localVars.lastConsumedActor->IsHittable() || !IsActuallySensitive(localVars.lastConsumedActor))
642             {
643               // At this point mLastConsumedActor was touchable and sensitive in the previous touch event process but is not in the current one.
644               // An interrupted event is send to allow some actors to go back to their original state (i.e. Button controls)
645               DALI_LOG_RELEASE_INFO("InterruptedActor(Consume):     (%p) %s\n", reinterpret_cast<void*>(localVars.lastConsumedActor), localVars.lastConsumedActor->GetName().data());
646               EmitTouchSignals(processor.mLastConsumedActor.GetActor(), lastRenderTaskImpl, localVars.touchEventImpl, PointState::INTERRUPTED, localVars.isGeometry);
647             }
648           }
649         }
650         else
651         {
652           if(localVars.lastPrimaryHitActor &&
653              localVars.lastPrimaryHitActor != localVars.primaryHitActor &&
654              localVars.lastPrimaryHitActor != localVars.consumedActor)
655           {
656             if(localVars.lastPrimaryHitActor->IsHittable() && IsActuallySensitive(localVars.lastPrimaryHitActor))
657             {
658               if(localVars.lastPrimaryHitActor->GetLeaveRequired())
659               {
660                 DALI_LOG_RELEASE_INFO("LeaveActor(Hit): (%p) %d %s\n", reinterpret_cast<void*>(localVars.lastPrimaryHitActor), localVars.lastPrimaryHitActor->GetId(), localVars.lastPrimaryHitActor->GetName().data());
661                 leaveEventConsumer = EmitTouchSignals(localVars.lastPrimaryHitActor, lastRenderTaskImpl, localVars.touchEventImpl, PointState::LEAVE, localVars.isGeometry);
662               }
663             }
664             else
665             {
666               // At this point mLastPrimaryHitActor was touchable and sensitive in the previous touch event process but is not in the current one.
667               // An interrupted event is send to allow some actors to go back to their original state (i.e. Button controls)
668               DALI_LOG_RELEASE_INFO("InterruptedActor(Hit): (%p) %d %s\n", reinterpret_cast<void*>(localVars.lastPrimaryHitActor), localVars.lastPrimaryHitActor->GetId(), localVars.lastPrimaryHitActor->GetName().data());
669               leaveEventConsumer = EmitTouchSignals(localVars.lastPrimaryHitActor, lastRenderTaskImpl, localVars.touchEventImpl, PointState::INTERRUPTED, localVars.isGeometry);
670             }
671           }
672
673           consumed |= leaveEventConsumer ? true : false;
674
675           // Check if the motion event has been consumed by another actor's listener.  In this case, the previously
676           // consumed actor's listeners may need to be informed (through a leave event).
677           // Further checks here to ensure we do not signal the same actor twice for the same event.
678           if(localVars.lastConsumedActor &&
679              localVars.lastConsumedActor != localVars.consumedActor &&
680              localVars.lastConsumedActor != localVars.lastPrimaryHitActor &&
681              localVars.lastConsumedActor != localVars.primaryHitActor &&
682              localVars.lastConsumedActor != leaveEventConsumer)
683           {
684             if(localVars.lastConsumedActor->IsHittable() && IsActuallySensitive(localVars.lastConsumedActor))
685             {
686               if(localVars.lastConsumedActor->GetLeaveRequired())
687               {
688                 DALI_LOG_RELEASE_INFO("LeaveActor(Consume): (%p) %d %s\n", reinterpret_cast<void*>(localVars.lastConsumedActor), localVars.lastConsumedActor->GetId(), localVars.lastConsumedActor->GetName().data());
689                 EmitTouchSignals(localVars.lastConsumedActor, lastRenderTaskImpl, localVars.touchEventImpl, PointState::LEAVE, localVars.isGeometry);
690               }
691             }
692             else
693             {
694               // At this point mLastConsumedActor was touchable and sensitive in the previous touch event process but is not in the current one.
695               // An interrupted event is send to allow some actors to go back to their original state (i.e. Button controls)
696               DALI_LOG_RELEASE_INFO("InterruptedActor(Consume): (%p) %d %s\n", reinterpret_cast<void*>(localVars.lastConsumedActor), localVars.lastConsumedActor->GetId(), localVars.lastConsumedActor->GetName().data());
697               EmitTouchSignals(processor.mLastConsumedActor.GetActor(), lastRenderTaskImpl, localVars.touchEventImpl, PointState::INTERRUPTED, localVars.isGeometry);
698             }
699           }
700         }
701       }
702     }
703     return consumed;
704   }
705
706   /**
707    * Update the processor member appropriately by handling the final up event, and setting the last hit/consumed events etc.
708    * @param[in/out] localVars The struct of stack variables used by ProcessTouchEvent
709    */
710   static inline void UpdateMembersWithCurrentHitInformation(ProcessTouchEventVariables& localVars)
711   {
712     // If our primary point is an Up event, then the primary point (in multi-touch) will change next
713     // time so set our last primary actor to NULL.  Do the same to the last consumed actor as well.
714
715     TouchEventProcessor& processor(localVars.processor);
716     if(localVars.primaryPointState == PointState::UP)
717     {
718       processor.Clear();
719     }
720     else
721     {
722       // The primaryHitActor may have been removed from the scene so ensure it is still on the scene before setting members.
723       if(localVars.primaryHitActor && GetImplementation(localVars.primaryHitActor).OnScene())
724       {
725         processor.mLastPrimaryHitActor.SetActor(&GetImplementation(localVars.primaryHitActor));
726
727         // Only observe the consumed actor if we have a primaryHitActor (check if it is still on the scene).
728         if(localVars.consumedActor && GetImplementation(localVars.consumedActor).OnScene())
729         {
730           processor.mLastConsumedActor.SetActor(&GetImplementation(localVars.consumedActor));
731         }
732         else
733         {
734           if(localVars.isGeometry)
735           {
736             if(localVars.lastConsumedActor && !localVars.lastConsumedActor->OnScene())
737             {
738               processor.mLastConsumedActor.SetActor(nullptr);
739             }
740           }
741           else
742           {
743             processor.mLastConsumedActor.SetActor(nullptr);
744           }
745         }
746
747         processor.mLastRenderTask        = localVars.currentRenderTask;
748         processor.mLastPrimaryPointState = localVars.primaryPointState;
749       }
750       else
751       {
752         processor.Clear();
753       }
754     }
755   }
756
757   /**
758    * Deliver an event to the touch-down actor and emit from the scene if required.
759    * @param[in/out] localVars The struct of stack variables used by ProcessTouchEvent
760    * @param[in] event The touch event that has occurred
761    */
762   static inline void DeliverEventToTouchDownActorAndScene(ProcessTouchEventVariables& localVars, const Integration::TouchEvent& event)
763   {
764     TouchEventProcessor& processor(localVars.processor);
765     if(localVars.touchEventImpl->GetPointCount() == 1) // Only want the first touch and the last release
766     {
767       switch(localVars.primaryPointState)
768       {
769         case PointState::UP:
770         {
771           Actor* touchDownConsumedActor(processor.mTouchDownConsumedActor.GetActor());
772           if(touchDownConsumedActor &&
773              touchDownConsumedActor != localVars.consumedActor &&
774              touchDownConsumedActor != localVars.lastPrimaryHitActor &&
775              touchDownConsumedActor != localVars.lastConsumedActor)
776           {
777             Dali::Actor touchDownConsumedActorHandle(touchDownConsumedActor);
778
779             Integration::Point currentPoint = localVars.touchEventImpl->GetPoint(0);
780             currentPoint.SetHitActor(touchDownConsumedActorHandle);
781             currentPoint.SetState(PointState::INTERRUPTED);
782
783             if(localVars.isGeometry)
784             {
785               std::list<Dali::Internal::Actor*> actorLists;
786               actorLists.push_back(touchDownConsumedActor);
787               GeoAllocAndEmitTouchSignals(actorLists, event.time, currentPoint, nullptr /* Not Required for this use case */);
788             }
789             else
790             {
791               AllocAndEmitTouchSignals(event.time, touchDownConsumedActorHandle, currentPoint, nullptr /* Not Required for this use case */);
792             }
793           }
794
795           processor.mTouchDownConsumedActor.SetActor(nullptr);
796           processor.mInterceptedTouchActor.SetActor(nullptr);
797
798           DALI_FALLTHROUGH;
799         }
800
801         case PointState::DOWN:
802         {
803           processor.mScene.EmitTouchedSignal(localVars.touchEventHandle);
804           break;
805         }
806
807         case PointState::MOTION:
808         case PointState::LEAVE:
809         case PointState::STATIONARY:
810         case PointState::INTERRUPTED:
811         {
812           // Ignore
813           break;
814         }
815       }
816     }
817   }
818 };
819
820 TouchEventProcessor::TouchEventProcessor(Scene& scene)
821 : mScene(scene),
822   mLastPrimaryHitActor(MakeCallback(this, &TouchEventProcessor::OnObservedActorDisconnected)),
823   mLastConsumedActor(),
824   mCapturingTouchActor(),
825   mOwnTouchActor(),
826   mTouchDownConsumedActor(),
827   mInterceptedTouchActor(),
828   mLastRenderTask(),
829   mLastPrimaryPointState(PointState::FINISHED)
830 {
831   DALI_LOG_TRACE_METHOD(gLogFilter);
832 }
833
834 TouchEventProcessor::~TouchEventProcessor()
835 {
836   DALI_LOG_TRACE_METHOD(gLogFilter);
837 }
838
839 bool TouchEventProcessor::ProcessTouchEvent(const Integration::TouchEvent& event)
840 {
841   DALI_LOG_TRACE_METHOD(gLogFilter);
842   DALI_ASSERT_ALWAYS(!event.points.empty() && "Empty TouchEvent sent from Integration\n");
843
844   PRINT_HIERARCHY(gLogFilter);
845
846   DALI_TRACE_SCOPE(gTraceFilter, "DALI_PROCESS_TOUCH_EVENT");
847
848   ProcessTouchEventVariables localVars(*this, mScene.IsGeometryHittestEnabled());
849
850   // 1) Check if it is an interrupted event - we should inform our last primary hit actor about this
851   //    and emit the stage signal as well.
852
853   if(event.points[0].GetState() == PointState::INTERRUPTED)
854   {
855     Impl::EmitInterruptedEvent(localVars, event);
856     return false; // No need for hit testing & already an interrupted event so just return false
857   }
858
859   // 2) Hit Testing.
860   localVars.touchEventImpl   = new TouchEvent(event.time);
861   localVars.touchEventHandle = Dali::TouchEvent(localVars.touchEventImpl.Get());
862
863   DALI_LOG_INFO(gLogFilter, Debug::Concise, "\n");
864   DALI_LOG_INFO(gLogFilter, Debug::General, "Point(s): %d\n", event.GetPointCount());
865
866   bool firstPointParsed = false;
867   for(auto&& currentPoint : event.points)
868   {
869     HitTestAlgorithm::Results hitTestResults;
870     hitTestResults.point     = currentPoint;
871     hitTestResults.eventTime = event.time;
872     if(!firstPointParsed)
873     {
874       firstPointParsed = true;
875       ParsePrimaryTouchPoint(hitTestResults, mCapturingTouchActor, mOwnTouchActor, mLastRenderTask, currentPoint, mScene, mCandidateActorLists);
876
877       // Only set the currentRenderTask for the primary hit actor.
878       localVars.currentRenderTask = hitTestResults.renderTask;
879       localVars.touchEventImpl->SetRenderTask(Dali::RenderTask(localVars.currentRenderTask.Get()));
880     }
881     else
882     {
883       Actor* capturingTouchActor = mCapturingTouchActor.GetActor();
884       if(capturingTouchActor && mLastRenderTask)
885       {
886         hitTestResults.actor          = Dali::Actor(capturingTouchActor);
887         hitTestResults.renderTask     = mLastRenderTask;
888         const Vector2& screenPosition = currentPoint.GetScreenPosition();
889         capturingTouchActor->ScreenToLocal(*mLastRenderTask, hitTestResults.actorCoordinates.x, hitTestResults.actorCoordinates.y, screenPosition.x, screenPosition.y);
890       }
891       else
892       {
893         HitTestAlgorithm::HitTest(mScene.GetSize(), mScene.GetRenderTaskList(), mScene.GetLayerList(), currentPoint.GetScreenPosition(), hitTestResults, nullptr, localVars.isGeometry);
894       }
895     }
896
897     Integration::Point newPoint(currentPoint);
898     newPoint.SetHitActor(hitTestResults.actor);
899     newPoint.SetLocalPosition(hitTestResults.actorCoordinates);
900
901     localVars.touchEventImpl->AddPoint(newPoint);
902
903     DALI_LOG_INFO(gLogFilter,
904                   Debug::General,
905                   "  State(%s), Screen(%.0f, %.0f), HitActor(%p, %s), Local(%.2f, %.2f)\n",
906                   TOUCH_POINT_STATE[currentPoint.GetState()],
907                   currentPoint.GetScreenPosition().x,
908                   currentPoint.GetScreenPosition().y,
909                   (hitTestResults.actor ? reinterpret_cast<void*>(&hitTestResults.actor.GetBaseObject()) : NULL),
910                   (hitTestResults.actor ? hitTestResults.actor.GetProperty<std::string>(Dali::Actor::Property::NAME).c_str() : ""),
911                   hitTestResults.actorCoordinates.x,
912                   hitTestResults.actorCoordinates.y);
913   }
914
915   // 3) Recursively deliver events to the actor and its parents, until the event is consumed or the stage is reached.
916   localVars.primaryPoint      = &localVars.touchEventImpl->GetPoint(0);
917   localVars.primaryHitActor   = localVars.primaryPoint->GetHitActor();
918   localVars.primaryPointState = localVars.primaryPoint->GetState();
919
920   bool consumed = Impl::DeliverEventsToActorAndParents(localVars);
921
922   // 4) Check if the last primary hit actor requires a leave event and if it was different to the current primary
923   //    hit actor.  Also process the last consumed actor in the same manner.
924   localVars.lastPrimaryHitActor = mInterceptedTouchActor.GetActor() ? mInterceptedTouchActor.GetActor() : mLastPrimaryHitActor.GetActor();
925   localVars.lastConsumedActor   = mLastConsumedActor.GetActor();
926   consumed |= Impl::DeliverLeaveEvent(localVars);
927
928   // 5) Update the processor member appropriately.
929   Impl::UpdateMembersWithCurrentHitInformation(localVars);
930
931   // 6) Emit an interrupted event to the touch-down actor if it hasn't consumed the up and
932   //    emit the stage touched event if required.
933   Impl::DeliverEventToTouchDownActorAndScene(localVars, event);
934
935   return consumed;
936 }
937
938 void TouchEventProcessor::OnObservedActorDisconnected(Actor* actor)
939 {
940   if(mScene.IsGeometryHittestEnabled() && (actor == mLastConsumedActor.GetActor() || actor == mLastPrimaryHitActor.GetActor()))
941   {
942     Dali::Actor        actorHandle(actor);
943     Integration::Point point;
944     point.SetState(PointState::INTERRUPTED);
945     point.SetHitActor(actorHandle);
946     if(actor == mLastConsumedActor.GetActor())
947     {
948       std::list<Dali::Internal::Actor*> actorLists;
949       actorLists.push_back(mLastConsumedActor.GetActor());
950       GeoAllocAndEmitTouchSignals(actorLists, 0, point, mLastRenderTask);
951     }
952     else if(!mLastConsumedActor.GetActor())
953     {
954       GeoAllocAndEmitTouchSignals(mCandidateActorLists, 0, point, mLastRenderTask);
955     }
956     // Do not set mLastPrimaryHitActor to NULL we may be iterating through its observers
957     mLastConsumedActor.SetActor(nullptr);
958     mLastRenderTask.Reset();
959     mLastPrimaryPointState = PointState::FINISHED;
960   }
961   else
962   {
963     if(actor == mLastPrimaryHitActor.GetActor())
964     {
965       Dali::Actor        actorHandle(actor);
966       Integration::Point point;
967       point.SetState(PointState::INTERRUPTED);
968       point.SetHitActor(actorHandle);
969
970       TouchEventPtr touchEventImpl(new TouchEvent);
971       touchEventImpl->AddPoint(point);
972       Dali::TouchEvent touchEventHandle(touchEventImpl.Get());
973
974       Dali::Actor eventConsumer = EmitTouchSignals(actorHandle, touchEventHandle);
975       if(mLastConsumedActor.GetActor() != eventConsumer)
976       {
977         EmitTouchSignals(Dali::Actor(mLastConsumedActor.GetActor()), touchEventHandle);
978       }
979
980       // Do not set mLastPrimaryHitActor to NULL we may be iterating through its observers
981       mLastConsumedActor.SetActor(nullptr);
982       mLastRenderTask.Reset();
983       mLastPrimaryPointState = PointState::FINISHED;
984     }
985   }
986 }
987
988 void TouchEventProcessor::Clear()
989 {
990   mLastPrimaryHitActor.SetActor(nullptr);
991   mLastConsumedActor.SetActor(nullptr);
992   mCapturingTouchActor.SetActor(nullptr);
993   mOwnTouchActor.SetActor(nullptr);
994   mInterceptedTouchActor.SetActor(nullptr);
995   mLastRenderTask.Reset();
996   mLastPrimaryPointState = PointState::FINISHED;
997 }
998
999 } // namespace Dali::Internal