Merge "Removed bogus consts and fixed out-of-line definitions." into tizen
[platform/core/uifw/dali-core.git] / dali / internal / event / events / hit-test-algorithm-impl.cpp
index f849756..b3eb5ad 100644 (file)
@@ -92,6 +92,14 @@ struct HitTestFunctionWrapper : public HitTestInterface
     return mFunc( Dali::Actor( actor ), Dali::HitTestAlgorithm::DESCEND_ACTOR_TREE );
   }
 
+  virtual bool DoesLayerConsumeHit( Layer* layer )
+  {
+    // Layer::IsTouchConsumed() focuses on touch only. Here we are a wrapper for the public-api
+    // where the caller may want to check for something completely different.
+    // TODO: Should provide a means to let caller decide. For now do not allow layers to consume
+    return false;
+  }
+
   Dali::HitTestAlgorithm::HitTestFunction mFunc;
 };
 
@@ -112,6 +120,11 @@ struct ActorTouchableCheck : public HitTestInterface
     return actor->IsVisible() && // Actor is visible, if not visible then none of its children are visible.
            actor->IsSensitive(); // Actor is sensitive, if insensitive none of its children should be hittable either.
   }
+
+  virtual bool DoesLayerConsumeHit( Layer* layer )
+  {
+    return layer->IsTouchConsumed();
+  }
 };
 
 /**
@@ -183,8 +196,8 @@ HitActor HitTestWithinLayer( Actor& actor,
     }
   }
 
-  // If there is a stencil on this layer and we've also registered a hit, then don't both searching any children
-  if ( stencilHit && hit.actor )
+  // If we are a stencil (or a child of a stencil) and we have already ascertained that the stencil has been hit then there is no need to hit-test the children of this stencil-actor
+  if ( isStencil && stencilHit  )
   {
     return hit;
   }
@@ -351,6 +364,7 @@ bool HitTestRenderTask( LayerList& layers,
         HitActor hit;
         bool stencilOnLayer = false;
         bool stencilHit = false;
+        bool layerConsumesHit = false;
         const Vector2& stageSize = Stage::GetCurrent()->GetSize();
 
         for (int i=layers.GetLayerCount()-1; i>=0 && !(hit.actor); --i)
@@ -375,10 +389,19 @@ bool HitTestRenderTask( LayerList& layers,
               // Recursively hit test all the actors, without crossing into other layers.
               hit = HitTestWithinLayer( *layer, results.rayOrigin, results.rayDirection, false, nearClippingPlane, farClippingPlane, hitCheck, stencilOnLayer, stencilHit, false );
             }
-            // If a stencil on this layer hasn't been hit, then discard hit results for this layer
-            if ( stencilOnLayer && !stencilHit )
+
+            // If a stencil on this layer hasn't been hit, then discard hit results for this layer if our current hit actor is renderable
+            if ( stencilOnLayer && !stencilHit &&
+                 hit.actor && hit.actor->IsRenderable() )
+            {
+              hit = previousHit;
+            }
+
+            // If this layer is set to consume the hit, then do not check any layers behind it
+            if ( hitCheck.DoesLayerConsumeHit( layer ) )
             {
-             hit = previousHit;
+              layerConsumesHit = true;
+              break;
             }
           }
         }
@@ -390,6 +413,10 @@ bool HitTestRenderTask( LayerList& layers,
           results.actorCoordinates.y = hit.y;
           return true; // Success
         }
+        else if ( layerConsumesHit )
+        {
+          return true; // Also success if layer is consuming the hit
+        }
       }
     }
   }
@@ -398,9 +425,10 @@ bool HitTestRenderTask( LayerList& layers,
 
 /**
  * Iterate through RenderTaskList and perform hit test.
+ *
+ * @return true if we have a hit, false otherwise
  */
-
-void HitTestForEachRenderTask( LayerList& layers,
+bool HitTestForEachRenderTask( LayerList& layers,
                                RenderTaskList& taskList,
                                const Vector2& screenCoordinates,
                                Results& results,
@@ -432,8 +460,8 @@ void HitTestForEachRenderTask( LayerList& layers,
 
     if ( HitTestRenderTask( layers, renderTask, screenCoordinates, results, hitCheck ) )
     {
-      // Exit when an actor is hit
-      return; // don't bother checking off screen tasks
+      // 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
     }
   }
 
@@ -457,31 +485,38 @@ void HitTestForEachRenderTask( LayerList& layers,
 
       if ( HitTestRenderTask( layers, renderTask, screenCoordinates, results, hitCheck ) )
       {
-        // Exit when an actor is hit
-        break;
+        // Return true when an actor is hit (or a layer in our render-task consumes the hit)
+        return true;
       }
     }
   }
+  return false;
 }
 
 } // unnamed namespace
 
-void HitTest( Stage& stage, const Vector2& screenCoordinates, Dali::HitTestAlgorithm::Results& results, Dali::HitTestAlgorithm::HitTestFunction func )
+bool HitTest( Stage& stage, const Vector2& screenCoordinates, Dali::HitTestAlgorithm::Results& results, Dali::HitTestAlgorithm::HitTestFunction func )
 {
+  bool wasHit( false );
   // Hit-test the regular on-stage actors
   RenderTaskList& taskList = stage.GetRenderTaskList();
   LayerList& layerList = stage.GetLayerList();
 
   Results hitTestResults;
   HitTestFunctionWrapper hitTestFunctionWrapper( func );
-  HitTestForEachRenderTask( layerList, taskList, screenCoordinates, hitTestResults, hitTestFunctionWrapper );
-
-  results.actor = hitTestResults.actor;
-  results.actorCoordinates = hitTestResults.actorCoordinates;
+  if (  HitTestForEachRenderTask( layerList, taskList, screenCoordinates, hitTestResults, hitTestFunctionWrapper ) )
+  {
+    results.actor = hitTestResults.actor;
+    results.actorCoordinates = hitTestResults.actorCoordinates;
+    wasHit = true;
+  }
+  return wasHit;
 }
 
-void HitTest( Stage& stage, const Vector2& screenCoordinates, Results& results, HitTestInterface& hitTestInterface )
+bool HitTest( Stage& stage, const Vector2& screenCoordinates, Results& results, HitTestInterface& hitTestInterface )
 {
+  bool wasHit( false );
+
   // Hit-test the system-overlay actors first
   SystemOverlay* systemOverlay = stage.GetSystemOverlayInternal();
 
@@ -490,33 +525,40 @@ void HitTest( Stage& stage, const Vector2& screenCoordinates, Results& results,
     RenderTaskList& overlayTaskList = systemOverlay->GetOverlayRenderTasks();
     LayerList& overlayLayerList = systemOverlay->GetLayerList();
 
-    HitTestForEachRenderTask( overlayLayerList, overlayTaskList, screenCoordinates, results, hitTestInterface );
+    wasHit = HitTestForEachRenderTask( overlayLayerList, overlayTaskList, screenCoordinates, results, hitTestInterface );
   }
 
   // Hit-test the regular on-stage actors
-  if ( !results.actor )
+  if ( !wasHit )
   {
     RenderTaskList& taskList = stage.GetRenderTaskList();
     LayerList& layerList = stage.GetLayerList();
 
-    HitTestForEachRenderTask( layerList, taskList, screenCoordinates, results, hitTestInterface );
+    wasHit = HitTestForEachRenderTask( layerList, taskList, screenCoordinates, results, hitTestInterface );
   }
+  return wasHit;
 }
 
-void HitTest( Stage& stage, const Vector2& screenCoordinates, Results& results )
+bool HitTest( Stage& stage, const Vector2& screenCoordinates, Results& results )
 {
   ActorTouchableCheck actorTouchableCheck;
-  HitTest( stage, screenCoordinates, results, actorTouchableCheck );
+  return HitTest( stage, screenCoordinates, results, actorTouchableCheck );
 }
 
-void HitTest( Stage& stage, RenderTask& renderTask, const Vector2& screenCoordinates,
+bool HitTest( Stage& stage, RenderTask& renderTask, const Vector2& screenCoordinates,
               Dali::HitTestAlgorithm::Results& results, Dali::HitTestAlgorithm::HitTestFunction func )
 {
+  bool wasHit( false );
   Results hitTestResults;
+
   HitTestFunctionWrapper hitTestFunctionWrapper( func );
-  HitTestRenderTask( stage.GetLayerList(), renderTask, screenCoordinates, hitTestResults, hitTestFunctionWrapper );
-  results.actor = hitTestResults.actor;
-  results.actorCoordinates = hitTestResults.actorCoordinates;
+  if ( HitTestRenderTask( stage.GetLayerList(), renderTask, screenCoordinates, hitTestResults, hitTestFunctionWrapper ) )
+  {
+    results.actor = hitTestResults.actor;
+    results.actorCoordinates = hitTestResults.actorCoordinates;
+    wasHit = true;
+  }
+  return wasHit;
 }
 
 } // namespace HitTestAlgorithm