If a RenderTask's exclusive actor is destoryed, then ensure the RenderTaskList of...
[platform/core/uifw/dali-core.git] / dali / internal / event / events / hit-test-algorithm-impl.cpp
index 56027a0..f685837 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 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.
@@ -19,7 +19,6 @@
 #include <dali/internal/event/events/hit-test-algorithm-impl.h>
 
 // INTERNAL INCLUDES
-#include <dali/integration-api/system-overlay.h>
 #include <dali/public-api/actors/layer.h>
 #include <dali/public-api/math/vector2.h>
 #include <dali/public-api/math/vector4.h>
@@ -28,8 +27,6 @@
 #include <dali/internal/event/actors/camera-actor-impl.h>
 #include <dali/internal/event/actors/layer-impl.h>
 #include <dali/internal/event/actors/layer-list.h>
-#include <dali/internal/event/common/system-overlay-impl.h>
-#include <dali/internal/event/common/stage-impl.h>
 #include <dali/internal/event/common/projection.h>
 #include <dali/internal/event/images/frame-buffer-image-impl.h>
 #include <dali/internal/event/render-tasks/render-task-impl.h>
@@ -56,10 +53,10 @@ struct HitActor
   {
   }
 
-  Actor *actor;                         ///< The actor hit (if actor is hit, then this is initialised).
-  Vector2 hitPosition;                  ///< Position of hit (only valid if actor valid).
-  float distance;                       ///< Distance from ray origin to hit actor.
-  int depth;                            ///< Depth index of this actor.
+  Actor *actor;        ///< The actor hit (if actor is hit, then this is initialised).
+  Vector2 hitPosition; ///< Position of hit (only valid if actor valid).
+  float distance;      ///< Distance from ray origin to hit actor.
+  int32_t depth;       ///< Depth index of this actor.
 };
 
 /**
@@ -127,14 +124,14 @@ struct ActorTouchableCheck : public HitTestInterface
  */
 bool IsActorExclusiveToAnotherRenderTask( const Actor& actor,
                                           const RenderTask& renderTask,
-                                          const Vector< RenderTaskList::Exclusive >& exclusives )
+                                          const RenderTaskList::ExclusivesContainer& exclusives )
 
 {
-  if( exclusives.Size() )
+  if( exclusives.size() )
   {
-    for( Vector< RenderTaskList::Exclusive >::Iterator exclusiveIt = exclusives.Begin(); exclusives.End() != exclusiveIt; ++exclusiveIt )
+    for( const auto& exclusive : exclusives )
     {
-      if( ( exclusiveIt->renderTaskPtr != &renderTask ) && ( exclusiveIt->actorPtr == &actor ) )
+      if( ( exclusive.renderTaskPtr != &renderTask ) && ( exclusive.actor.GetActor() == &actor ) )
       {
         return true;
       }
@@ -154,7 +151,7 @@ bool IsActorExclusiveToAnotherRenderTask( const Actor& actor,
  */
 HitActor HitTestWithinLayer( Actor& actor,
                              const RenderTask& renderTask,
-                             const Vector< RenderTaskList::Exclusive >& exclusives,
+                             const RenderTaskList::ExclusivesContainer& exclusives,
                              const Vector4& rayOrigin,
                              const Vector4& rayDir,
                              float& nearClippingPlane,
@@ -162,8 +159,8 @@ HitActor HitTestWithinLayer( Actor& actor,
                              HitTestInterface& hitCheck,
                              bool& overlayHit,
                              bool layerIs3d,
-                             unsigned int clippingDepth,
-                             unsigned int clippingBitPlaneMask )
+                             uint32_t clippingDepth,
+                             uint32_t clippingBitPlaneMask )
 {
   HitActor hit;
 
@@ -176,7 +173,7 @@ HitActor HitTestWithinLayer( Actor& actor,
   // 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.
-  unsigned int newClippingDepth = clippingDepth;
+  uint32_t newClippingDepth = clippingDepth;
   bool clippingActor = actor.GetClippingMode() != ClippingMode::DISABLED;
   if( clippingActor )
   {
@@ -234,7 +231,7 @@ HitActor HitTestWithinLayer( Actor& actor,
               // 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.
-              unsigned int clippingDepthMask = ( 1u << newClippingDepth ) - 1u;
+              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.
@@ -255,7 +252,7 @@ HitActor HitTestWithinLayer( Actor& actor,
               {
                 //Get renderer with maximum depth
                 int rendererMaxDepth(actor.GetRendererAt( 0 ).Get()->GetDepthIndex());
-                for( unsigned int i(1); i < actor.GetRendererCount(); ++i )
+                for( uint32_t i(1); i < actor.GetRendererCount(); ++i )
                 {
                   int depth = actor.GetRendererAt( i ).Get()->GetDepthIndex();
                   if( depth > rendererMaxDepth )
@@ -277,7 +274,7 @@ HitActor HitTestWithinLayer( Actor& actor,
   if( actor.GetChildCount() > 0 )
   {
     childHit.distance = std::numeric_limits<float>::max();
-    childHit.depth = std::numeric_limits<int>::min();
+    childHit.depth = std::numeric_limits<int32_t>::min();
     ActorContainer& children = actor.GetChildrenInternal();
 
     // Hit test ALL children and calculate their distance.
@@ -362,10 +359,10 @@ inline bool IsActuallyHittable( Layer& layer, const Vector2& screenCoordinates,
   {
     ClippingBox box = layer.GetClippingBox();
 
-    if( screenCoordinates.x < box.x ||
-        screenCoordinates.x > box.x + box.width ||
-        screenCoordinates.y < stageSize.y - (box.y + box.height) ||
-        screenCoordinates.y > stageSize.y - box.y)
+    if( screenCoordinates.x < static_cast<float>( box.x )||
+        screenCoordinates.x > static_cast<float>( box.x + box.width )||
+        screenCoordinates.y < stageSize.y - static_cast<float>( box.y + box.height ) ||
+        screenCoordinates.y > stageSize.y - static_cast<float>( box.y ) )
     {
       // Not touchable if clipping is enabled in the layer and the screen coordinate is outside the clip region.
       hittable = false;
@@ -404,8 +401,8 @@ void GetCameraClippingPlane( RenderTask& renderTask, float& nearClippingPlane, f
 /**
  * Hit test a RenderTask
  */
-bool HitTestRenderTask( const Vector< RenderTaskList::Exclusive >& exclusives,
-                        Stage& stage,
+bool HitTestRenderTask( const RenderTaskList::ExclusivesContainer& exclusives,
+                        const Vector2& sceneSize,
                         LayerList& layers,
                         RenderTask& renderTask,
                         Vector2 screenCoordinates,
@@ -416,10 +413,10 @@ bool HitTestRenderTask( const Vector< RenderTaskList::Exclusive >& exclusives,
   {
     Viewport viewport;
     renderTask.GetViewport( viewport );
-    if( screenCoordinates.x < viewport.x ||
-        screenCoordinates.x > viewport.x + viewport.width ||
-        screenCoordinates.y < viewport.y ||
-        screenCoordinates.y > viewport.y + viewport.height )
+    if( screenCoordinates.x < static_cast<float>( viewport.x ) ||
+        screenCoordinates.x > static_cast<float>( viewport.x + viewport.width ) ||
+        screenCoordinates.y < static_cast<float>( viewport.y ) ||
+        screenCoordinates.y > static_cast<float>( viewport.y + viewport.height ) )
     {
       // The screen coordinate is outside the viewport of render task. The viewport clips all layers.
       return false;
@@ -435,7 +432,7 @@ bool HitTestRenderTask( const Vector< RenderTaskList::Exclusive >& exclusives,
       Dali::Layer layer( sourceActor->GetLayer() );
       if( layer )
       {
-        const unsigned int sourceActorDepth( layer.GetDepth() );
+        const uint32_t sourceActorDepth( layer.GetDepth() );
 
         CameraActor* cameraActor = renderTask.GetCameraActor();
         bool pickingPossible = cameraActor->BuildPickingRay(
@@ -452,18 +449,17 @@ bool HitTestRenderTask( const Vector< RenderTaskList::Exclusive >& exclusives,
         HitActor hit;
         bool overlayHit = false;
         bool layerConsumesHit = false;
-        const Vector2& stageSize = stage.GetSize();
 
-        for( int i = layers.GetLayerCount() - 1; i >= 0 && !( hit.actor ); --i )
+        for( int32_t i = layers.GetLayerCount() - 1; i >= 0 && !( hit.actor ); --i )
         {
           Layer* layer( layers.GetLayer( i ) );
           overlayHit = false;
 
           // Ensure layer is touchable (also checks whether ancestors are also touchable)
-          if( IsActuallyHittable( *layer, screenCoordinates, stageSize, hitCheck ) )
+          if( IsActuallyHittable( *layer, screenCoordinates, sceneSize, hitCheck ) )
           {
             // Always hit-test the source actor; otherwise test whether the layer is below the source actor in the hierarchy
-            if( sourceActorDepth == static_cast<unsigned int>( i ) )
+            if( sourceActorDepth == static_cast<uint32_t>( i ) )
             {
               // Recursively hit test the source actor & children, without crossing into other layers.
               hit = HitTestWithinLayer( *sourceActor,
@@ -507,7 +503,7 @@ bool HitTestRenderTask( const Vector< RenderTaskList::Exclusive >& exclusives,
 
         if( hit.actor )
         {
-          results.renderTask = Dali::RenderTask( &renderTask );
+          results.renderTask = RenderTaskPtr( &renderTask );
           results.actor = Dali::Actor( hit.actor );
           results.actorCoordinates = hit.hitPosition;
 
@@ -527,7 +523,7 @@ bool HitTestRenderTask( const Vector< RenderTaskList::Exclusive >& exclusives,
 /**
  * Iterate through the RenderTaskList and perform hit testing.
  *
- * @param[in] stage The stage the tests will be performed in
+ * @param[in] sceneSize The scene size the tests will be performed in
  * @param[in] layers The list of layers to test
  * @param[in] taskList The list of render tasks
  * @param[out] results Ray information calculated by the camera
@@ -535,7 +531,7 @@ bool HitTestRenderTask( const Vector< RenderTaskList::Exclusive >& exclusives,
  * @param[in] onScreen True to test on-screen, false to test off-screen
  * @return True if we have a hit, false otherwise
  */
-bool HitTestRenderTaskList( Stage& stage,
+bool HitTestRenderTaskList( const Vector2& sceneSize,
                             LayerList& layers,
                             RenderTaskList& taskList,
                             const Vector2& screenCoordinates,
@@ -545,19 +541,19 @@ bool HitTestRenderTaskList( Stage& stage,
 {
   RenderTaskList::RenderTaskContainer& tasks = taskList.GetTasks();
   RenderTaskList::RenderTaskContainer::reverse_iterator endIter = tasks.rend();
-  const Vector< RenderTaskList::Exclusive >& exclusives = taskList.GetExclusivesList();
+  const auto& exclusives = taskList.GetExclusivesList();
 
   for( RenderTaskList::RenderTaskContainer::reverse_iterator iter = tasks.rbegin(); endIter != iter; ++iter )
   {
-    RenderTask& renderTask = GetImplementation( *iter );
-    bool isOffscreenRenderTask = ( iter->GetTargetFrameBuffer() || iter->GetFrameBuffer() );
+    RenderTask& renderTask = *iter->Get();
+    bool isOffscreenRenderTask = ( renderTask.GetTargetFrameBuffer() || renderTask.GetFrameBuffer() );
     if( (onScreen && isOffscreenRenderTask) || (!onScreen && !isOffscreenRenderTask) )
     {
       // Skip to next task
       continue;
     }
 
-    if( HitTestRenderTask( exclusives, stage, layers, renderTask, screenCoordinates, results, hitCheck ) )
+    if( HitTestRenderTask( exclusives, sceneSize, layers, renderTask, screenCoordinates, results, hitCheck ) )
     {
       // 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
@@ -570,7 +566,7 @@ bool HitTestRenderTaskList( Stage& stage,
 /**
  * Iterate through the RenderTaskList and perform hit testing for both on-screen and off-screen.
  *
- * @param[in] stage The stage the tests will be performed in
+ * @param[in] sceneSize The scene size the tests will be performed in
  * @param[in] layers The list of layers to test
  * @param[in] taskList The list of render tasks
  * @param[out] results Ray information calculated by the camera
@@ -578,7 +574,7 @@ bool HitTestRenderTaskList( Stage& stage,
  * @param[in] onScreen True to test on-screen, false to test off-screen
  * @return True if we have a hit, false otherwise
  */
-bool HitTestForEachRenderTask( Stage& stage,
+bool HitTestForEachRenderTask( const Vector2& sceneSize,
                                LayerList& layers,
                                RenderTaskList& taskList,
                                const Vector2& screenCoordinates,
@@ -589,8 +585,8 @@ bool HitTestForEachRenderTask( Stage& stage,
 
   // 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( stage, layers, taskList, screenCoordinates, results, hitCheck, true  ) ||
-      HitTestRenderTaskList( stage, layers, taskList, screenCoordinates, results, hitCheck, false ) )
+  if( HitTestRenderTaskList( sceneSize, layers, taskList, screenCoordinates, results, hitCheck, true  ) ||
+      HitTestRenderTaskList( sceneSize, layers, taskList, screenCoordinates, results, hitCheck, false ) )
   {
     // Found hit.
     result = true;
@@ -605,16 +601,13 @@ HitTestInterface::~HitTestInterface()
 {
 }
 
-bool HitTest( Stage& stage, const Vector2& screenCoordinates, Dali::HitTestAlgorithm::Results& results, Dali::HitTestAlgorithm::HitTestFunction func )
+bool HitTest( const Vector2& sceneSize, RenderTaskList& taskList, LayerList& layerList, 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();
-
+  // Hit-test the regular on-scene actors
   Results hitTestResults;
   HitTestFunctionWrapper hitTestFunctionWrapper( func );
-  if( HitTestForEachRenderTask( stage, layerList, taskList, screenCoordinates, hitTestResults, hitTestFunctionWrapper ) )
+  if( HitTestForEachRenderTask( sceneSize, layerList, taskList, screenCoordinates, hitTestResults, hitTestFunctionWrapper ) )
   {
     results.actor = hitTestResults.actor;
     results.actorCoordinates = hitTestResults.actorCoordinates;
@@ -623,56 +616,24 @@ bool HitTest( Stage& stage, const Vector2& screenCoordinates, Dali::HitTestAlgor
   return wasHit;
 }
 
-bool HitTest( Stage& stage, const Vector2& screenCoordinates, Results& results, HitTestInterface& hitTestInterface )
+bool HitTest( const Vector2& sceneSize, RenderTaskList& renderTaskList, LayerList& layerList, const Vector2& screenCoordinates, Results& results, HitTestInterface& hitTestInterface )
 {
   bool wasHit( false );
 
-  // Hit-test the system-overlay actors first
-  SystemOverlay* systemOverlay = stage.GetSystemOverlayInternal();
-
-  if( systemOverlay )
-  {
-    RenderTaskList& overlayTaskList = systemOverlay->GetOverlayRenderTasks();
-    LayerList& overlayLayerList = systemOverlay->GetLayerList();
-
-    wasHit = HitTestForEachRenderTask( stage, overlayLayerList, overlayTaskList, screenCoordinates, results, hitTestInterface );
-  }
-
-  // Hit-test the regular on-stage actors
+  // Hit-test the regular on-scene actors
   if( !wasHit )
   {
-    RenderTaskList& taskList = stage.GetRenderTaskList();
-    LayerList& layerList = stage.GetLayerList();
-
-    wasHit = HitTestForEachRenderTask( stage, layerList, taskList, screenCoordinates, results, hitTestInterface );
+    wasHit = HitTestForEachRenderTask( sceneSize, layerList, renderTaskList, screenCoordinates, results, hitTestInterface );
   }
   return wasHit;
 }
 
-bool HitTest( Stage& stage, const Vector2& screenCoordinates, Results& results )
+bool HitTest( const Vector2& sceneSize, RenderTaskList& renderTaskList, LayerList& layerList, const Vector2& screenCoordinates, Results& results )
 {
   ActorTouchableCheck actorTouchableCheck;
-  return HitTest( stage, screenCoordinates, results, actorTouchableCheck );
+  return HitTest( sceneSize, renderTaskList, layerList, screenCoordinates, results, actorTouchableCheck );
 }
 
-bool HitTest( Stage& stage, RenderTask& renderTask, const Vector2& screenCoordinates,
-              Dali::HitTestAlgorithm::Results& results, Dali::HitTestAlgorithm::HitTestFunction func )
-{
-  bool wasHit( false );
-  Results hitTestResults;
-
-  const Vector< RenderTaskList::Exclusive >& exclusives = stage.GetRenderTaskList().GetExclusivesList();
-  HitTestFunctionWrapper hitTestFunctionWrapper( func );
-  if( HitTestRenderTask( exclusives, stage, stage.GetLayerList(), renderTask, screenCoordinates, hitTestResults, hitTestFunctionWrapper ) )
-  {
-    results.actor = hitTestResults.actor;
-    results.actorCoordinates = hitTestResults.actorCoordinates;
-    wasHit = true;
-  }
-  return wasHit;
-}
-
-
 } // namespace HitTestAlgorithm
 
 } // namespace Internal