Revert "[Tizen] Not execute the remove callback"
[platform/core/uifw/dali-core.git] / dali / internal / event / events / hit-test-algorithm-impl.cpp
index e632717..5409ed0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 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.
@@ -158,43 +158,23 @@ bool IsActorExclusiveToAnotherRenderTask(const Actor&
 }
 
 /**
- * Recursively hit test all the actors, without crossing into other layers.
- * This algorithm performs a Depth-First-Search (DFS) on all Actors within Layer.
- * Hit-Testing each Actor, noting the distance from the Ray-Origin (3D origin
- * of touch vector). The closest Hit-Tested Actor is that which is returned.
- * Exceptions to this rule are:
- * - When comparing against renderable parents, if Actor is the same distance
- * or closer than it's renderable parent, then it takes priority.
+ * Hit tests the given actor and updates the in/out variables appropriately
  */
-HitActor HitTestWithinLayer(Actor&                                     actor,
-                            const RenderTask&                          renderTask,
-                            const RenderTaskList::ExclusivesContainer& exclusives,
-                            const Vector4&                             rayOrigin,
-                            const Vector4&                             rayDir,
-                            const float&                               nearClippingPlane,
-                            const float&                               farClippingPlane,
-                            HitTestInterface&                          hitCheck,
-                            const bool&                                overlayed,
-                            bool&                                      overlayHit,
-                            bool                                       layerIs3d,
-                            const RayTest&                             rayTest,
-                            const Integration::Point&                  point,
-                            const uint32_t                             eventTime)
+void HitTestActor(const RenderTask&         renderTask,
+                  const Vector4&            rayOrigin,
+                  const Vector4&            rayDir,
+                  const float&              nearClippingPlane,
+                  const float&              farClippingPlane,
+                  HitTestInterface&         hitCheck,
+                  const RayTest&            rayTest,
+                  const Integration::Point& point,
+                  const uint32_t            eventTime,
+                  bool                      clippingActor,
+                  bool                      overlayedActor,
+                  Actor&                    actor,
+                  bool&                     overlayHit,
+                  HitActor&                 hit)
 {
-  HitActor hit;
-
-  if(IsActorExclusiveToAnotherRenderTask(actor, renderTask, exclusives))
-  {
-    return hit;
-  }
-
-  // For clipping, regardless of whether we have hit this actor or not.
-  // This is used later to ensure all nested clipped children have hit
-  // all clipping actors also for them to be counted as hit.
-  bool clippingActor  = actor.GetClippingMode() != ClippingMode::DISABLED;
-  bool overlayedActor = overlayed || actor.IsOverlay();
-
-  // If we are a clipping actor or hittable...
   if(clippingActor || hitCheck.IsActorHittable(&actor))
   {
     Vector3 size(actor.GetCurrentSize());
@@ -256,6 +236,76 @@ HitActor HitTestWithinLayer(Actor&                                     actor,
       }
     }
   }
+}
+
+/**
+ * When iterating through the children of an actor, this method updates the child-hit-data.
+ */
+void UpdateChildHitData(const HitActor& hit, const HitActor& currentHit, const bool layerIs3d, const bool parentIsRenderable, HitActor& childHit)
+{
+  bool updateChildHit = false;
+  if(currentHit.distance >= 0.0f)
+  {
+    if(layerIs3d)
+    {
+      updateChildHit = ((currentHit.depth > childHit.depth) ||
+                        ((currentHit.depth == childHit.depth) && (currentHit.distance < childHit.distance)));
+    }
+    else
+    {
+      updateChildHit = currentHit.depth >= childHit.depth;
+    }
+  }
+
+  if(updateChildHit)
+  {
+    if(!parentIsRenderable || currentHit.depth > hit.depth ||
+       (layerIs3d && (currentHit.depth == hit.depth && currentHit.distance < hit.distance)))
+    {
+      childHit = currentHit;
+    }
+  }
+}
+
+/**
+ * Recursively hit test all the actors, without crossing into other layers.
+ * This algorithm performs a Depth-First-Search (DFS) on all Actors within Layer.
+ * Hit-Testing each Actor, noting the distance from the Ray-Origin (3D origin
+ * of touch vector). The closest Hit-Tested Actor is that which is returned.
+ * Exceptions to this rule are:
+ * - When comparing against renderable parents, if Actor is the same distance
+ * or closer than it's renderable parent, then it takes priority.
+ */
+HitActor HitTestWithinLayer(Actor&                                     actor,
+                            const RenderTask&                          renderTask,
+                            const RenderTaskList::ExclusivesContainer& exclusives,
+                            const Vector4&                             rayOrigin,
+                            const Vector4&                             rayDir,
+                            const float&                               nearClippingPlane,
+                            const float&                               farClippingPlane,
+                            HitTestInterface&                          hitCheck,
+                            const bool&                                overlayed,
+                            bool&                                      overlayHit,
+                            bool                                       layerIs3d,
+                            const RayTest&                             rayTest,
+                            const Integration::Point&                  point,
+                            const uint32_t                             eventTime)
+{
+  HitActor hit;
+
+  if(IsActorExclusiveToAnotherRenderTask(actor, renderTask, exclusives))
+  {
+    return hit;
+  }
+
+  // For clipping, regardless of whether we have hit this actor or not.
+  // This is used later to ensure all nested clipped children have hit
+  // all clipping actors also for them to be counted as hit.
+  bool clippingActor  = actor.GetClippingMode() != ClippingMode::DISABLED;
+  bool overlayedActor = overlayed || actor.IsOverlay();
+
+  // If we are a clipping actor or hittable...
+  HitTestActor(renderTask, rayOrigin, rayDir, nearClippingPlane, farClippingPlane, hitCheck, rayTest, point, eventTime, clippingActor, overlayedActor, actor, overlayHit, hit);
 
   // If current actor is clipping, and hit failed, We should not checkup child actors. Fast return
   if(clippingActor && !(hit.actor))
@@ -303,28 +353,7 @@ HitActor HitTestWithinLayer(Actor&                                     actor,
           continue;
         }
 
-        bool updateChildHit = false;
-        if(currentHit.distance >= 0.0f)
-        {
-          if(layerIs3d)
-          {
-            updateChildHit = ((currentHit.depth > childHit.depth) ||
-                              ((currentHit.depth == childHit.depth) && (currentHit.distance < childHit.distance)));
-          }
-          else
-          {
-            updateChildHit = currentHit.depth >= childHit.depth;
-          }
-        }
-
-        if(updateChildHit)
-        {
-          if(!parentIsRenderable || currentHit.depth > hit.depth ||
-             (layerIs3d && (currentHit.depth == hit.depth && currentHit.distance < hit.distance)))
-          {
-            childHit = currentHit;
-          }
-        }
+        UpdateChildHitData(hit, currentHit, layerIs3d, parentIsRenderable, childHit);
       }
     }
   }
@@ -434,10 +463,10 @@ bool HitTestRenderTask(const RenderTaskList::ExclusivesContainer& exclusives,
     Actor* sourceActor(renderTask.GetSourceActor());
     if(sourceActor)
     {
-      Dali::Layer layer(sourceActor->GetLayer());
-      if(layer)
+      Dali::Layer sourceLayer(sourceActor->GetLayer());
+      if(sourceLayer)
       {
-        const uint32_t sourceActorDepth(layer.GetProperty<bool>(Dali::Layer::Property::DEPTH));
+        const uint32_t sourceActorDepth(sourceLayer.GetProperty<bool>(Dali::Layer::Property::DEPTH));
 
         CameraActor* cameraActor     = renderTask.GetCameraActor();
         bool         pickingPossible = cameraActor->BuildPickingRay(
@@ -504,7 +533,8 @@ bool HitTestRenderTask(const RenderTaskList::ExclusivesContainer& exclusives,
             // If this layer is set to consume the hit, then do not check any layers behind it
             if(hitCheck.DoesLayerConsumeHit(layer))
             {
-              layerConsumesHit = true;
+              // Consume the hit if this layer is same as SourceActor's layer
+              layerConsumesHit = (sourceLayer == Dali::Layer(layer));
               break;
             }
           }
@@ -537,7 +567,6 @@ bool HitTestRenderTask(const RenderTaskList::ExclusivesContainer& exclusives,
  * @param[in] taskList The list of render tasks
  * @param[out] results Ray information calculated by the camera
  * @param[in] hitCheck The hit testing interface object to use
- * @param[in] onScreen True to test on-screen, false to test off-screen
  * @return True if we have a hit, false otherwise
  */
 bool HitTestRenderTaskList(const Vector2&    sceneSize,
@@ -545,27 +574,21 @@ bool HitTestRenderTaskList(const Vector2&    sceneSize,
                            RenderTaskList&   taskList,
                            const Vector2&    screenCoordinates,
                            Results&          results,
-                           HitTestInterface& hitCheck,
-                           bool              onScreen)
+                           HitTestInterface& hitCheck)
 {
   RenderTaskList::RenderTaskContainer&                  tasks      = taskList.GetTasks();
   RenderTaskList::RenderTaskContainer::reverse_iterator endIter    = tasks.rend();
   const auto&                                           exclusives = taskList.GetExclusivesList();
   RayTest                                               rayTest;
 
+  // Hit test order should be reverse of draw order
   for(RenderTaskList::RenderTaskContainer::reverse_iterator iter = tasks.rbegin(); endIter != iter; ++iter)
   {
-    RenderTask& renderTask            = *iter->Get();
-    const bool  isOffscreenRenderTask = renderTask.GetFrameBuffer();
-    if((onScreen && isOffscreenRenderTask) || (!onScreen && !isOffscreenRenderTask))
-    {
-      // Skip to next task
-      continue;
-    }
+    RenderTask& renderTask = *iter->Get();
     if(HitTestRenderTask(exclusives, sceneSize, layers, renderTask, screenCoordinates, results, hitCheck, rayTest))
     {
       // Return true when an actor is hit (or layer in our render-task consumes the hit)
-      return true; // don't bother checking off screen tasks
+      return true;
     }
   }
 
@@ -580,7 +603,6 @@ bool HitTestRenderTaskList(const Vector2&    sceneSize,
  * @param[in] taskList The list of render tasks
  * @param[out] results Ray information calculated by the camera
  * @param[in] hitCheck The hit testing interface object to use
- * @param[in] onScreen True to test on-screen, false to test off-screen
  * @return True if we have a hit, false otherwise
  */
 bool HitTestForEachRenderTask(const Vector2&    sceneSize,
@@ -592,10 +614,7 @@ bool HitTestForEachRenderTask(const Vector2&    sceneSize,
 {
   bool result = false;
 
-  // Check on-screen tasks before off-screen ones.
-  // Hit test order should be reverse of draw order (see ProcessRenderTasks() where off-screen tasks are drawn first).
-  if(HitTestRenderTaskList(sceneSize, layers, taskList, screenCoordinates, results, hitCheck, true) ||
-     HitTestRenderTaskList(sceneSize, layers, taskList, screenCoordinates, results, hitCheck, false))
+  if(HitTestRenderTaskList(sceneSize, layers, taskList, screenCoordinates, results, hitCheck))
   {
     // Found hit.
     result = true;