Revert "[Tizen] Not execute the remove callback"
[platform/core/uifw/dali-core.git] / dali / internal / event / events / hit-test-algorithm-impl.cpp
index 1576efe..5409ed0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 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.
@@ -89,6 +89,11 @@ struct HitTestFunctionWrapper : public HitTestInterface
     return false;
   }
 
+  bool ActorRequiresHitResultCheck(Actor* actor, Integration::Point point, Vector2 hitPointLocal, uint32_t timeStamp) override
+  {
+    return actor->EmitHitTestResultSignal(point, hitPointLocal, timeStamp);
+  }
+
   Dali::HitTestAlgorithm::HitTestFunction mFunc;
 };
 
@@ -100,8 +105,8 @@ struct ActorTouchableCheck : public HitTestInterface
 {
   bool IsActorHittable(Actor* actor) override
   {
-    return (actor->GetTouchRequired() || actor->IsTouchFocusable()) && // Does the Application or derived actor type require a touch event? or focusable by touch?
-           actor->IsHittable();                                        // Is actor sensitive, visible and on the scene?
+    return (actor->GetTouchRequired() || actor->GetInterceptTouchRequired() || actor->IsTouchFocusable()) && // Does the Application or derived actor type require a touch event or a intercept touch event? or focusable by touch?
+           actor->IsHittable();                                                                              // Is actor sensitive, visible and on the scene?
   }
 
   bool DescendActorHierarchy(Actor* actor) override
@@ -114,6 +119,21 @@ struct ActorTouchableCheck : public HitTestInterface
   {
     return layer->IsTouchConsumed();
   }
+
+  bool ActorRequiresHitResultCheck(Actor* actor, Integration::Point point, Vector2 hitPointLocal, uint32_t timeStamp) override
+  {
+    if(point.GetState() != PointState::STARTED && actor->IsAllowedOnlyOwnTouch() && ownActor != actor)
+    {
+      return false;
+    }
+    return actor->EmitHitTestResultSignal(point, hitPointLocal, timeStamp);
+  }
+
+  void SetOwnActor(const Actor* actor)
+  {
+    ownActor = actor;
+  }
+  const Actor* ownActor;
 };
 
 /**
@@ -138,47 +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,
-                            float&                                     nearClippingPlane,
-                            float&                                     farClippingPlane,
-                            HitTestInterface&                          hitCheck,
-                            bool&                                      overlayHit,
-                            bool                                       layerIs3d,
-                            uint32_t                                   clippingDepth,
-                            uint32_t                                   clippingBitPlaneMask,
-                            const RayTest&                             rayTest)
+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,
-  // we increase the clipping depth if we have hit a clipping actor.
-  // This is used later to ensure all nested clipped children have hit
-  // all clipping actors also for them to be counted as hit.
-  uint32_t newClippingDepth = clippingDepth;
-  bool     clippingActor    = actor.GetClippingMode() != ClippingMode::DISABLED;
-  if(clippingActor)
-  {
-    ++newClippingDepth;
-  }
-
-  // If we are a clipping actor or hittable...
   if(clippingActor || hitCheck.IsActorHittable(&actor))
   {
     Vector3 size(actor.GetCurrentSize());
@@ -193,53 +189,27 @@ HitActor HitTestWithinLayer(Actor&                                     actor,
       // Finally, perform a more accurate ray test to see if our ray actually hits the actor.
       if(rayTest.ActorTest(actor, rayOrigin, rayDir, hitPointLocal, distance))
       {
-        if(distance >= nearClippingPlane && distance <= farClippingPlane)
-        {
-          // If the hit has happened on a clipping actor, then add this clipping depth to the mask of hit clipping depths.
-          // This mask shows all the actors that have been hit at different clipping depths.
-          if(clippingActor)
-          {
-            clippingBitPlaneMask |= 1u << clippingDepth;
-          }
+        // Calculate z coordinate value in Camera Space.
+        const Matrix&  viewMatrix          = renderTask.GetCameraActor()->GetViewMatrix();
+        const Vector4& hitDir              = Vector4(rayDir.x * distance, rayDir.y * distance, rayDir.z * distance, 0.0f);
+        const float    cameraDepthDistance = (viewMatrix * hitDir).z;
 
-          if(overlayHit && !actor.IsOverlay())
+        // Check if cameraDepthDistance is between clipping plane
+        if(cameraDepthDistance >= nearClippingPlane && cameraDepthDistance <= farClippingPlane)
+        {
+          if(overlayHit && !overlayedActor)
           {
             // If we have already hit an overlay and current actor is not an overlay ignore current actor.
           }
           else
           {
-            if(actor.IsOverlay())
+            if(overlayedActor)
             {
               overlayHit = true;
             }
 
-            // At this point we have hit an actor.
-            // Now perform checks for clipping.
-            // Assume we have hit the actor first as if it is not clipped this would be the case.
-            bool haveHitActor = true;
-
-            // Check if we are performing clipping. IE. if any actors so far have clipping enabled - not necessarily this one.
-            // We can do this by checking the clipping depth has a value 1 or above.
-            if(newClippingDepth >= 1u)
-            {
-              // Now for us to count this actor as hit, we must have also hit
-              // all CLIPPING actors up to this point in the hierarchy as well.
-              // This information is stored in the clippingBitPlaneMask we updated above.
-              // Here we calculate a comparison mask by setting all the bits up to the current depth value.
-              // EG. a depth of 4 (10000 binary) = a mask of 1111 binary.
-              // This allows us a fast way of comparing all bits are set up to this depth.
-              // Note: If the current Actor has clipping, that is included in the depth mask too.
-              uint32_t clippingDepthMask = (1u << newClippingDepth) - 1u;
-
-              // The two masks must be equal to be a hit, as we are already assuming a hit
-              // (for non-clipping mode) then they must be not-equal to disqualify the hit.
-              if(clippingBitPlaneMask != clippingDepthMask)
-              {
-                haveHitActor = false;
-              }
-            }
-
-            if(haveHitActor)
+            // If the hit actor does not want to hit, the hit-test continues.
+            if(hitCheck.ActorRequiresHitResultCheck(&actor, point, hitPointLocal, eventTime))
             {
               hit.actor       = &actor;
               hit.hitPosition = hitPointLocal;
@@ -266,6 +236,82 @@ 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))
+  {
+    return hit;
+  }
 
   // Find a child hit, until we run out of actors in the current layer.
   HitActor childHit;
@@ -292,42 +338,22 @@ HitActor HitTestWithinLayer(Actor&                                     actor,
                                                nearClippingPlane,
                                                farClippingPlane,
                                                hitCheck,
+                                               overlayedActor,
                                                overlayHit,
                                                layerIs3d,
-                                               newClippingDepth,
-                                               clippingBitPlaneMask,
-                                               rayTest));
+                                               rayTest,
+                                               point,
+                                               eventTime));
 
         // Make sure the set hit actor is actually hittable. This is usually required when we have some
         // clipping as we need to hit-test all actors as we descend the tree regardless of whether they
         // are hittable or not.
-        if(currentHit.actor && !hitCheck.IsActorHittable(currentHit.actor))
+        if(currentHit.actor && (!hitCheck.IsActorHittable(currentHit.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);
       }
     }
   }
@@ -437,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(
@@ -479,10 +505,11 @@ bool HitTestRenderTask(const RenderTaskList::ExclusivesContainer& exclusives,
                                        farClippingPlane,
                                        hitCheck,
                                        overlayHit,
+                                       overlayHit,
                                        layer->GetBehavior() == Dali::Layer::LAYER_3D,
-                                       0u,
-                                       0u,
-                                       rayTest);
+                                       rayTest,
+                                       results.point,
+                                       results.eventTime);
             }
             else if(IsWithinSourceActors(*sourceActor, *layer))
             {
@@ -496,16 +523,18 @@ bool HitTestRenderTask(const RenderTaskList::ExclusivesContainer& exclusives,
                                        farClippingPlane,
                                        hitCheck,
                                        overlayHit,
+                                       overlayHit,
                                        layer->GetBehavior() == Dali::Layer::LAYER_3D,
-                                       0u,
-                                       0u,
-                                       rayTest);
+                                       rayTest,
+                                       results.point,
+                                       results.eventTime);
             }
 
             // 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;
             }
           }
@@ -538,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,
@@ -546,28 +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;
     }
   }
 
@@ -582,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,
@@ -594,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;
@@ -637,9 +654,10 @@ bool HitTest(const Vector2& sceneSize, RenderTaskList& renderTaskList, LayerList
   return wasHit;
 }
 
-bool HitTest(const Vector2& sceneSize, RenderTaskList& renderTaskList, LayerList& layerList, const Vector2& screenCoordinates, Results& results)
+bool HitTest(const Vector2& sceneSize, RenderTaskList& renderTaskList, LayerList& layerList, const Vector2& screenCoordinates, Results& results, const Actor* ownActor)
 {
   ActorTouchableCheck actorTouchableCheck;
+  actorTouchableCheck.SetOwnActor(ownActor);
   return HitTest(sceneSize, renderTaskList, layerList, screenCoordinates, results, actorTouchableCheck);
 }