[Tizen] Fix several hit issue for offscreen rendering 57/310257/3 accepted/tizen/8.0/unified/20240509.175855
authorSeungho Baek <sbsh.baek@samsung.com>
Wed, 24 Apr 2024 12:21:39 +0000 (21:21 +0900)
committerSeungho Baek <sbsh.baek@samsung.com>
Tue, 7 May 2024 08:45:03 +0000 (17:45 +0900)
 - Previous implementation
   - MappingActor is not hittable by default, but it was used to check
     whether it is hitted from OnScreen RenderTask or not in HitTestRenderTaskList.
   - There is nothing to check the layer including MappingActor is consuming hit.

 - Current implementation
   - For the OnScreen hit result, check whether there is a mappingActor of OffScreen
     hit results that can be hit in front of the OnScreen hit result.
     If it is, returns the OffScreen hit results.
   - If the OnScreen hit result is layer and the layer consumes hit(the layer must
     not be hittable), returns the OffScreen hit results.
   - If there is no hit in OnScreen but there are hit results from OffScreen
     RenderTask, returns the top OffScreen hit results.

Change-Id: I2788ed90dbe0145b4c263c371353b201c65c2a80
Signed-off-by: Seungho Baek <sbsh.baek@samsung.com>
automated-tests/src/dali/utc-Dali-HitTestAlgorithm.cpp
dali/internal/event/events/hit-test-algorithm-impl.cpp
dali/internal/event/render-tasks/render-task-impl.cpp
dali/internal/event/render-tasks/render-task-impl.h

index 64e7e7d..c01da5d 100644 (file)
@@ -109,6 +109,41 @@ bool DefaultIsActorTouchableFunction(Dali::Actor actor, Dali::HitTestAlgorithm::
   return hittable;
 };
 
+bool IsActorTouchableFunctionWithoutLayerHit(Dali::Actor actor, Dali::HitTestAlgorithm::TraverseType type)
+{
+  bool hittable = false;
+
+  switch(type)
+  {
+    case Dali::HitTestAlgorithm::CHECK_ACTOR:
+    {
+      if(actor.GetCurrentProperty<bool>(Actor::Property::VISIBLE) &&
+         actor.GetProperty<bool>(Actor::Property::SENSITIVE) &&
+         actor.GetCurrentProperty<Vector4>(Actor::Property::WORLD_COLOR).a > 0.01f &&
+         actor.GetLayer() != actor)
+      {
+        hittable = true;
+      }
+      break;
+    }
+    case Dali::HitTestAlgorithm::DESCEND_ACTOR_TREE:
+    {
+      if(actor.GetCurrentProperty<bool>(Actor::Property::VISIBLE) && // Actor is visible, if not visible then none of its children are visible.
+         actor.GetProperty<bool>(Actor::Property::SENSITIVE))        // Actor is sensitive, if insensitive none of its children should be hittable either.
+      {
+        hittable = true;
+      }
+      break;
+    }
+    default:
+    {
+      break;
+    }
+  }
+
+  return hittable;
+};
+
 } // anonymous namespace
 
 // Positive test case for a method
@@ -575,7 +610,7 @@ int UtcDaliHitTestAlgorithmDoesWantedHitTest(void)
   END_TEST;
 }
 
-int UtcDaliHitTestAlgorithmOrder(void)
+int UtcDaliHitTestAlgorithmOrder1(void)
 {
   TestApplication application;
   tet_infoline("Testing Dali::HitTestAlgorithm between On/Off render task");
@@ -630,6 +665,276 @@ int UtcDaliHitTestAlgorithmOrder(void)
   END_TEST;
 }
 
+int UtcDaliHitTestAlgorithmOrder2(void)
+{
+  TestApplication application;
+  tet_infoline("Testing Dali::HitTestAlgorithm in for the mapping actor and its child");
+
+  Stage   stage = Stage::GetCurrent();
+  Vector2 stageSize(stage.GetSize());
+
+  Actor blue                                        = Actor::New();
+  blue[Dali::Actor::Property::NAME]                 = "Blue";
+  blue[Dali::Actor::Property::ANCHOR_POINT]         = AnchorPoint::CENTER;
+  blue[Dali::Actor::Property::PARENT_ORIGIN]        = ParentOrigin::CENTER;
+  blue[Dali::Actor::Property::WIDTH_RESIZE_POLICY]  = ResizePolicy::FILL_TO_PARENT;
+  blue[Dali::Actor::Property::HEIGHT_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+
+  Actor green                                        = Actor::New();
+  green[Dali::Actor::Property::NAME]                 = "Green";
+  green[Dali::Actor::Property::ANCHOR_POINT]         = AnchorPoint::CENTER;
+  green[Dali::Actor::Property::PARENT_ORIGIN]        = ParentOrigin::CENTER;
+  green[Dali::Actor::Property::WIDTH_RESIZE_POLICY]  = ResizePolicy::FILL_TO_PARENT;
+  green[Dali::Actor::Property::HEIGHT_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+
+  Actor red                                        = Actor::New();
+  red[Dali::Actor::Property::NAME]                 = "Red";
+  red[Dali::Actor::Property::ANCHOR_POINT]         = AnchorPoint::CENTER;
+  red[Dali::Actor::Property::PARENT_ORIGIN]        = ParentOrigin::CENTER;
+  red[Dali::Actor::Property::WIDTH_RESIZE_POLICY]  = ResizePolicy::FILL_TO_PARENT;
+  red[Dali::Actor::Property::HEIGHT_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+
+  Actor yellow                                        = Actor::New();
+  yellow[Dali::Actor::Property::NAME]                 = "Yellow";
+  yellow[Dali::Actor::Property::ANCHOR_POINT]         = AnchorPoint::CENTER;
+  yellow[Dali::Actor::Property::PARENT_ORIGIN]        = ParentOrigin::CENTER;
+  yellow[Dali::Actor::Property::WIDTH_RESIZE_POLICY]  = ResizePolicy::FILL_TO_PARENT;
+  yellow[Dali::Actor::Property::HEIGHT_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+
+  stage.Add(blue);
+  stage.Add(green);
+  stage.Add(yellow);
+
+  RenderTaskList renderTaskList = stage.GetRenderTaskList();
+  RenderTask     offRenderTask  = renderTaskList.CreateTask();
+
+  Dali::CameraActor cameraActor                     = Dali::CameraActor::New(stageSize);
+  cameraActor[Dali::Actor::Property::ANCHOR_POINT]  = AnchorPoint::CENTER;
+  cameraActor[Dali::Actor::Property::PARENT_ORIGIN] = ParentOrigin::CENTER;
+  stage.Add(cameraActor);
+
+  offRenderTask.SetExclusive(true);
+  offRenderTask.SetInputEnabled(true);
+  offRenderTask.SetCameraActor(cameraActor);
+  offRenderTask.SetSourceActor(yellow);
+  offRenderTask.SetScreenToFrameBufferMappingActor(green);
+
+  Dali::Texture texture      = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGB888, unsigned(stageSize.width), unsigned(stageSize.height));
+  FrameBuffer   renderTarget = FrameBuffer::New(stageSize.width, stageSize.height, FrameBuffer::Attachment::DEPTH);
+  renderTarget.AttachColorTexture(texture);
+  offRenderTask.SetFrameBuffer(renderTarget);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render(10);
+
+  HitTestAlgorithm::Results results;
+  HitTest(stage, stageSize / 2.0f, results, &DefaultIsActorTouchableFunction);
+  DALI_TEST_CHECK(results.actor == yellow);
+
+  green.Add(red);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render(10);
+
+  results = HitTestAlgorithm::Results();
+  HitTest(stage, stageSize / 2.0f, results, &DefaultIsActorTouchableFunction);
+  DALI_TEST_CHECK(results.actor == red);
+
+  END_TEST;
+}
+
+int UtcDaliHitTestAlgorithmInMultipleLayer(void)
+{
+  TestApplication application;
+  tet_infoline("Testing UtcDaliHitTestAlgorithmInMultipleLayer");
+
+  Stage   stage = Stage::GetCurrent();
+  Vector2 stageSize(stage.GetSize());
+
+  Actor blue                                        = Actor::New();
+  blue[Dali::Actor::Property::NAME]                 = "Blue";
+  blue[Dali::Actor::Property::ANCHOR_POINT]         = AnchorPoint::CENTER;
+  blue[Dali::Actor::Property::PARENT_ORIGIN]        = ParentOrigin::CENTER;
+  blue[Dali::Actor::Property::WIDTH_RESIZE_POLICY]  = ResizePolicy::FILL_TO_PARENT;
+  blue[Dali::Actor::Property::HEIGHT_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+
+  Layer layer = Layer::New();
+  layer[Dali::Actor::Property::NAME]                 = "Layer";
+  layer[Dali::Actor::Property::ANCHOR_POINT]         = AnchorPoint::CENTER;
+  layer[Dali::Actor::Property::PARENT_ORIGIN]        = ParentOrigin::CENTER;
+  layer[Dali::Actor::Property::WIDTH_RESIZE_POLICY]  = ResizePolicy::FILL_TO_PARENT;
+  layer[Dali::Actor::Property::HEIGHT_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+
+  Actor green                                        = Actor::New();
+  green[Dali::Actor::Property::NAME]                 = "Green";
+  green[Dali::Actor::Property::ANCHOR_POINT]         = AnchorPoint::CENTER;
+  green[Dali::Actor::Property::PARENT_ORIGIN]        = ParentOrigin::CENTER;
+  green[Dali::Actor::Property::WIDTH_RESIZE_POLICY]  = ResizePolicy::FILL_TO_PARENT;
+  green[Dali::Actor::Property::HEIGHT_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+
+  Actor red                                        = Actor::New();
+  red[Dali::Actor::Property::NAME]                 = "Red";
+  red[Dali::Actor::Property::ANCHOR_POINT]         = AnchorPoint::CENTER;
+  red[Dali::Actor::Property::PARENT_ORIGIN]        = ParentOrigin::CENTER;
+  red[Dali::Actor::Property::WIDTH_RESIZE_POLICY]  = ResizePolicy::FILL_TO_PARENT;
+  red[Dali::Actor::Property::HEIGHT_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+
+  stage.Add(blue);
+  stage.Add(layer);
+  layer.Add(green);
+  stage.Add(red);
+
+  RenderTaskList renderTaskList = stage.GetRenderTaskList();
+  RenderTask     offRenderTask  = renderTaskList.CreateTask();
+
+  Dali::CameraActor cameraActor                     = Dali::CameraActor::New(stageSize);
+  cameraActor[Dali::Actor::Property::ANCHOR_POINT]  = AnchorPoint::CENTER;
+  cameraActor[Dali::Actor::Property::PARENT_ORIGIN] = ParentOrigin::CENTER;
+  stage.Add(cameraActor);
+
+  offRenderTask.SetExclusive(true);
+  offRenderTask.SetInputEnabled(true);
+  offRenderTask.SetCameraActor(cameraActor);
+  offRenderTask.SetSourceActor(layer);
+  offRenderTask.SetScreenToFrameBufferMappingActor(red);
+
+  Dali::Texture texture      = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGB888, unsigned(stageSize.width), unsigned(stageSize.height));
+  FrameBuffer   renderTarget = FrameBuffer::New(stageSize.width, stageSize.height, FrameBuffer::Attachment::DEPTH);
+  renderTarget.AttachColorTexture(texture);
+  offRenderTask.SetFrameBuffer(renderTarget);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render(10);
+
+  HitTestAlgorithm::Results results;
+  HitTest(stage, stageSize / 2.0f, results, &DefaultIsActorTouchableFunction);
+  DALI_TEST_CHECK(results.actor == green);
+
+  END_TEST;
+}
+
+int UtcDaliHitTestAlgorithmOffSceneMappingActor(void)
+{
+  TestApplication application;
+  tet_infoline("Testing Dali::HitTestAlgorithm with OffSceneMappingActor");
+
+  Stage   stage = Stage::GetCurrent();
+  Vector2 stageSize(stage.GetSize());
+
+  Actor blue                                        = Actor::New();
+  blue[Dali::Actor::Property::NAME]                 = "Blue";
+  blue[Dali::Actor::Property::ANCHOR_POINT]         = AnchorPoint::CENTER;
+  blue[Dali::Actor::Property::PARENT_ORIGIN]        = ParentOrigin::CENTER;
+  blue[Dali::Actor::Property::WIDTH_RESIZE_POLICY]  = ResizePolicy::FILL_TO_PARENT;
+  blue[Dali::Actor::Property::HEIGHT_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+
+  Actor green                                        = Actor::New();
+  green[Dali::Actor::Property::NAME]                 = "Green";
+  green[Dali::Actor::Property::ANCHOR_POINT]         = AnchorPoint::CENTER;
+  green[Dali::Actor::Property::PARENT_ORIGIN]        = ParentOrigin::CENTER;
+  green[Dali::Actor::Property::WIDTH_RESIZE_POLICY]  = ResizePolicy::FILL_TO_PARENT;
+  green[Dali::Actor::Property::HEIGHT_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+
+  Actor red                                        = Actor::New();
+  red[Dali::Actor::Property::NAME]                 = "Red";
+  red[Dali::Actor::Property::ANCHOR_POINT]         = AnchorPoint::CENTER;
+  red[Dali::Actor::Property::PARENT_ORIGIN]        = ParentOrigin::CENTER;
+  red[Dali::Actor::Property::WIDTH_RESIZE_POLICY]  = ResizePolicy::FILL_TO_PARENT;
+  red[Dali::Actor::Property::HEIGHT_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+
+  stage.Add(blue);
+  stage.Add(green);
+
+  RenderTaskList renderTaskList = stage.GetRenderTaskList();
+  RenderTask     offRenderTask  = renderTaskList.CreateTask();
+
+  Dali::CameraActor cameraActor                     = Dali::CameraActor::New(stageSize);
+  cameraActor[Dali::Actor::Property::ANCHOR_POINT]  = AnchorPoint::CENTER;
+  cameraActor[Dali::Actor::Property::PARENT_ORIGIN] = ParentOrigin::CENTER;
+  stage.Add(cameraActor);
+
+  offRenderTask.SetExclusive(true);
+  offRenderTask.SetInputEnabled(true);
+  offRenderTask.SetCameraActor(cameraActor);
+  offRenderTask.SetSourceActor(green);
+  offRenderTask.SetScreenToFrameBufferMappingActor(red);
+
+  Dali::Texture texture      = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGB888, unsigned(stageSize.width), unsigned(stageSize.height));
+  FrameBuffer   renderTarget = FrameBuffer::New(stageSize.width, stageSize.height, FrameBuffer::Attachment::DEPTH);
+  renderTarget.AttachColorTexture(texture);
+  offRenderTask.SetFrameBuffer(renderTarget);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render(10);
+
+  HitTestAlgorithm::Results results;
+  HitTest(stage, stageSize / 2.0f, results, &DefaultIsActorTouchableFunction);
+  DALI_TEST_CHECK(results.actor == blue);
+
+  stage.Add(red);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render(10);
+
+  HitTest(stage, stageSize / 2.0f, results, &DefaultIsActorTouchableFunction);
+  DALI_TEST_CHECK(results.actor == green);
+
+  END_TEST;
+}
+
+int UtcDaliHitTestAlgorithmScreenToFrameBufferFunction(void)
+{
+  TestApplication application;
+  tet_infoline("Testing Dali::HitTestAlgorithm using ScreenToFrameBufferFunction");
+
+  Stage   stage = Stage::GetCurrent();
+  Vector2 stageSize(stage.GetSize());
+
+  Actor green                                       = Actor::New();
+  green[Dali::Actor::Property::NAME]                 = "Green";
+  green[Dali::Actor::Property::ANCHOR_POINT]         = AnchorPoint::CENTER;
+  green[Dali::Actor::Property::PARENT_ORIGIN]        = ParentOrigin::CENTER;
+  green[Dali::Actor::Property::WIDTH_RESIZE_POLICY]  = ResizePolicy::FILL_TO_PARENT;
+  green[Dali::Actor::Property::HEIGHT_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+
+  stage.Add(green);
+
+  RenderTaskList renderTaskList = stage.GetRenderTaskList();
+  RenderTask     offRenderTask  = renderTaskList.CreateTask();
+
+  Dali::CameraActor cameraActor                     = Dali::CameraActor::New(stageSize);
+  cameraActor[Dali::Actor::Property::ANCHOR_POINT]  = AnchorPoint::CENTER;
+  cameraActor[Dali::Actor::Property::PARENT_ORIGIN] = ParentOrigin::CENTER;
+  stage.Add(cameraActor);
+
+  offRenderTask.SetExclusive(true);
+  offRenderTask.SetInputEnabled(true);
+  offRenderTask.SetCameraActor(cameraActor);
+  offRenderTask.SetSourceActor(green);
+  offRenderTask.SetScreenToFrameBufferFunction(RenderTask::FULLSCREEN_FRAMEBUFFER_FUNCTION);
+  offRenderTask.SetViewport(Viewport(Vector4(0, 0, 480, 800)));
+
+  Dali::Texture texture      = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGB888, unsigned(stageSize.width), unsigned(stageSize.height));
+  FrameBuffer   renderTarget = FrameBuffer::New(stageSize.width, stageSize.height, FrameBuffer::Attachment::DEPTH);
+  renderTarget.AttachColorTexture(texture);
+  offRenderTask.SetFrameBuffer(renderTarget);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render(10);
+
+  HitTestAlgorithm::Results results;
+  HitTest(stage, stageSize / 2.0f, results, &IsActorTouchableFunctionWithoutLayerHit);
+  DALI_TEST_CHECK(results.actor == green);
+
+  END_TEST;
+}
+
 int UtcDaliHitTestAlgorithmExclusiveMultiple(void)
 {
   TestApplication application;
index fdb45f7..578f5fe 100644 (file)
@@ -459,7 +459,26 @@ bool IsWithinSourceActors(const Actor& sourceActor, const Actor& actor)
 }
 
 /**
- * Returns true if the layer and all of the layer's parents are visible and sensitive.
+ * Returns true if the actor and all of the actor's parents are hittable.
+ */
+bool IsActorActuallyHittable(Actor* actor, HitTestInterface& hitCheck)
+{
+  Actor* currentActor = actor;
+  // Ensure that we can descend into the layer's (or any of its parent's) hierarchy.
+  while(currentActor)
+  {
+    if(!hitCheck.DescendActorHierarchy(currentActor))
+    {
+      return false;
+    }
+    currentActor = currentActor->GetParent();
+  }
+
+  return true;
+}
+
+/**
+ * Returns true if the layer and all of the layer's parents are hittable.
  */
 inline bool IsActuallyHittable(Layer& layer, const Vector2& screenCoordinates, const Vector2& stageSize, HitTestInterface& hitCheck)
 {
@@ -482,17 +501,7 @@ inline bool IsActuallyHittable(Layer& layer, const Vector2& screenCoordinates, c
   if(hittable)
   {
     Actor* actor(&layer);
-
-    // Ensure that we can descend into the layer's (or any of its parent's) hierarchy.
-    while(actor && hittable)
-    {
-      if(!hitCheck.DescendActorHierarchy(actor))
-      {
-        hittable = false;
-        break;
-      }
-      actor = actor->GetParent();
-    }
+    hittable = IsActorActuallyHittable(actor, hitCheck);
   }
 
   return hittable;
@@ -651,7 +660,9 @@ bool HitTestRenderTask(const RenderTaskList::ExclusivesContainer& exclusives,
 
     // Determine the layer depth of the source actor
     Actor* sourceActor(renderTask.GetSourceActor());
-    if(sourceActor)
+
+    // Check the source actor is actually hittable or not.
+    if(sourceActor && IsActorActuallyHittable(sourceActor, hitCheck))
     {
       Dali::Layer sourceLayer(sourceActor->GetLayer());
       if(sourceLayer)
@@ -780,6 +791,68 @@ bool HitTestRenderTask(const RenderTaskList::ExclusivesContainer& exclusives,
 }
 
 /**
+ * Selects Prior Actor that is rendered later between firstActor and secondActor in the layer of rootActor.
+ * if only one of Actor is included in the layer, returns the Actor.
+ * if both of the firstActor and secondActor are not included in the layer, returns empty Actor.
+ */
+Dali::Actor FindPriorActorInLayer(Dali::Actor rootActor, Dali::Actor firstActor, Dali::Actor secondActor)
+{
+  Dali::Actor priorActor;
+  Dali::Layer layer = rootActor.GetLayer();
+  bool firstActorIncluded = firstActor.GetLayer() == layer;
+  bool secondActorIncluded = secondActor.GetLayer() == layer;
+
+  if(firstActorIncluded && !secondActorIncluded)
+  {
+    priorActor = firstActor;
+  }
+  else if(!firstActorIncluded && secondActorIncluded)
+  {
+    priorActor = secondActor;
+  }
+  else if(firstActorIncluded && secondActorIncluded)
+  {
+    priorActor = (GetImplementation(firstActor).GetSortingDepth() < GetImplementation(secondActor).GetSortingDepth()) ? secondActor : firstActor;
+  }
+
+  return priorActor;
+}
+
+/**
+ * Selects Prior Actor that is rendered later between firstActor and secondActor from child scene tree of rootActor.
+ */
+Dali::Actor FindPriorActorInLayers(const LayerList& layers, Dali::Actor rootActor, Dali::Actor firstActor, Dali::Actor secondActor)
+{
+  Dali::Layer sourceLayer = rootActor.GetLayer();
+  const uint32_t sourceActorDepth(sourceLayer.GetProperty<int>(Dali::Layer::Property::DEPTH));
+
+  Dali::Actor priorActor;
+  uint32_t layerCount = layers.GetLayerCount();
+  if(layerCount > 0)
+  {
+    for(int32_t i = layerCount - 1; i >= 0; --i)
+    {
+      Layer* layer(layers.GetLayer(i));
+      if(sourceActorDepth == static_cast<uint32_t>(i))
+      {
+        priorActor = FindPriorActorInLayer(rootActor, firstActor, secondActor);
+      }
+      else if(IsWithinSourceActors(GetImplementation(rootActor), *layer))
+      {
+        Dali::Actor layerRoot = Dali::Actor(layer);
+        priorActor            = FindPriorActorInLayer(layerRoot, firstActor, secondActor);
+      }
+
+      if(priorActor)
+      {
+        break;
+      }
+    }
+  }
+  return priorActor;
+}
+
+/**
  * Iterate through the RenderTaskList and perform hit testing.
  *
  * @param[in] sceneSize The scene size the tests will be performed in
@@ -821,18 +894,68 @@ bool HitTestRenderTaskList(const Vector2&    sceneSize,
     const auto&                                           exclusives = taskList.GetExclusivesList();
     RayTest                                               rayTest;
 
+    Results                                      storedResults = results;
+    std::vector<std::pair<Dali::Actor, Results>> offScreenHitResults;
     // Hit test order should be reverse of draw order
     for(RenderTaskList::RenderTaskContainer::reverse_iterator iter = tasks.rbegin(); endIter != iter; ++iter)
     {
       RenderTask& renderTask = *iter->Get();
       if(HitTestRenderTask(exclusives, sceneSize, layers, renderTask, screenCoordinates, results, hitCheck, rayTest))
       {
+        if(renderTask.GetFrameBuffer())
+        {
+          Results result = results;
+          offScreenHitResults.push_back(std::make_pair(renderTask.GetScreenToFrameBufferMappingActor(), std::move(result)));
+          continue;
+        }
+
+        if(offScreenHitResults.empty())
+        {
+          return true;
+        }
+
+        Actor* sourceActor(renderTask.GetSourceActor());
+        for(auto&& pair : offScreenHitResults)
+        {
+          Dali::Actor mappingActor = pair.first;
+          if(!mappingActor || !IsWithinSourceActors(*sourceActor, GetImplementation(mappingActor)))
+          {
+            continue;
+          }
+
+          bool mappingActorInsideHitConsumingLayer = false;
+          if(GetImplementation(results.actor).IsLayer())
+          {
+            Dali::Layer resultLayer = Dali::Layer::DownCast(results.actor);
+            // Check the resultLayer is consuming hit even though the layer is not hittable.
+            // And check the resultLayer is the layer of mappingActor too.
+            if(hitCheck.DoesLayerConsumeHit(&GetImplementation(resultLayer)) && !hitCheck.IsActorHittable(&GetImplementation(results.actor)) && results.actor == mappingActor.GetLayer())
+            {
+              mappingActorInsideHitConsumingLayer = true;
+            }
+          }
+          if(mappingActorInsideHitConsumingLayer || mappingActor == FindPriorActorInLayers(layers, Dali::Actor(sourceActor), mappingActor, results.actor))
+          {
+            results = pair.second;
+            break;
+          }
+        }
         // Return true when an actor is hit (or layer in our render-task consumes the hit)
         return true;
       }
     }
-    return false;
+
+    // When no OnScreen Actor is hitted but there are hit results from OffScreen RenderTasks
+    // those use ScreenToFrameBufferFunction, simply returns first hitted result.
+    if(!offScreenHitResults.empty())
+    {
+      results = offScreenHitResults.front().second;
+      return true;
+    }
+
+    results = storedResults;
   }
+  return false;
 }
 
 /**
index 25ca2dc..4ac98f3 100644 (file)
@@ -490,6 +490,11 @@ bool RenderTask::TranslateCoordinates(Vector2& screenCoords) const
   if(mFrameBuffer && mappingActor)
   {
     Internal::Actor* inputMappingActor = &GetImplementation(mappingActor);
+    if(!inputMappingActor->OnScene())
+    {
+      return false;
+    }
+
     CameraActor*     localCamera       = GetCameraActor();
     StagePtr         stage             = Stage::GetCurrent();
     if(stage)
@@ -556,6 +561,11 @@ void RenderTask::GetHittableViewport(Viewport& viewPort) const
           viewPort.width          = static_cast<int32_t>(actorSize.x + 0.5f); // rounded
           viewPort.height         = static_cast<int32_t>(actorSize.y + 0.5f); // rounded
         }
+        else
+        {
+          // For the case to use ScreenToFrameBufferFunction
+          GetViewport(viewPort);
+        }
       }
       else
       {
index f8897b0..f2d7367 100644 (file)
@@ -127,7 +127,7 @@ public:
   void SetScreenToFrameBufferMappingActor(Dali::Actor& mappingActor);
 
   /**
-   * @copydoc Dali::RenderTask::GetScreenToFrameBufferMAppingActor
+   * @copydoc Dali::RenderTask::GetScreenToFrameBufferMappingActor
    */
   Dali::Actor GetScreenToFrameBufferMappingActor() const;