If CapturesAllTouchAfterStart() is true, it should be hit only after touchdown.
[platform/core/uifw/dali-core.git] / dali / internal / event / events / hit-test-algorithm-impl.cpp
index 2cb7b42..5330fe3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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() && // Does the Application or derived actor type require a touch event?
-           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,11 @@ struct ActorTouchableCheck : public HitTestInterface
   {
     return layer->IsTouchConsumed();
   }
+
+  bool ActorRequiresHitResultCheck(Actor* actor, Integration::Point point, Vector2 hitPointLocal, uint32_t timeStamp) override
+  {
+    return actor->EmitHitTestResultSignal(point, hitPointLocal, timeStamp);
+  }
 };
 
 /**
@@ -158,7 +168,9 @@ HitActor HitTestWithinLayer(Actor&                                     actor,
                             bool                                       layerIs3d,
                             uint32_t                                   clippingDepth,
                             uint32_t                                   clippingBitPlaneMask,
-                            const RayTest&                             rayTest)
+                            const RayTest&                             rayTest,
+                            const Integration::Point&                  point,
+                            const uint32_t                             eventTime)
 {
   HitActor hit;
 
@@ -193,7 +205,13 @@ 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)
+        // 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;
+
+        // Check if cameraDepthDistance is between clipping plane
+        if(cameraDepthDistance >= nearClippingPlane && cameraDepthDistance <= 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.
@@ -239,7 +257,15 @@ HitActor HitTestWithinLayer(Actor&                                     actor,
               }
             }
 
-            if(haveHitActor)
+            // If CapturesAllTouchAfterStart() is true, it should be hit only after touchdown.
+            // If the touch moves after another actor has been touched so that the current actor is hit, it should behave as if it didn't hit.
+            if(actor.CapturesAllTouchAfterStart() && point.GetState() != PointState::STARTED)
+            {
+              haveHitActor = false;
+            }
+
+            // If the hit actor does not want to hit, the hit-test continues.
+            if(haveHitActor && hitCheck.ActorRequiresHitResultCheck(&actor, point, hitPointLocal, eventTime))
             {
               hit.actor       = &actor;
               hit.hitPosition = hitPointLocal;
@@ -296,12 +322,14 @@ HitActor HitTestWithinLayer(Actor&                                     actor,
                                                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;
         }
@@ -482,7 +510,9 @@ bool HitTestRenderTask(const RenderTaskList::ExclusivesContainer& exclusives,
                                        layer->GetBehavior() == Dali::Layer::LAYER_3D,
                                        0u,
                                        0u,
-                                       rayTest);
+                                       rayTest,
+                                       results.point,
+                                       results.eventTime);
             }
             else if(IsWithinSourceActors(*sourceActor, *layer))
             {
@@ -499,7 +529,9 @@ bool HitTestRenderTask(const RenderTaskList::ExclusivesContainer& exclusives,
                                        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
@@ -563,7 +595,6 @@ bool HitTestRenderTaskList(const Vector2&    sceneSize,
       // Skip to next task
       continue;
     }
-
     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)