Merge branch 'devel/master' into tizen
[platform/core/uifw/dali-core.git] / dali / internal / event / actors / actor-impl.cpp
index caab998..ab20929 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.
@@ -20,7 +20,6 @@
 
 // EXTERNAL INCLUDES
 #include <algorithm>
-#include <cfloat>
 #include <cmath>
 
 // INTERNAL INCLUDES
 #include <dali/devel-api/common/capabilities.h>
 
 #include <dali/integration-api/debug.h>
+#include <dali/integration-api/events/touch-integ.h>
 
 #include <dali/internal/event/actors/actor-coords.h>
 #include <dali/internal/event/actors/actor-parent.h>
 #include <dali/internal/event/actors/actor-property-handler.h>
-#include <dali/internal/event/actors/actor-relayouter.h>
 #include <dali/internal/event/actors/camera-actor-impl.h>
 #include <dali/internal/event/common/event-thread-services.h>
 #include <dali/internal/event/common/property-helper.h>
@@ -51,9 +50,9 @@
 #include <dali/internal/event/render-tasks/render-task-impl.h>
 #include <dali/internal/event/render-tasks/render-task-list-impl.h>
 #include <dali/internal/event/rendering/renderer-impl.h>
-#include <dali/internal/event/size-negotiation/relayout-controller-impl.h>
 #include <dali/internal/update/manager/update-manager.h>
 #include <dali/internal/update/nodes/node-messages.h>
+#include <dali/public-api/size-negotiation/relayout-container.h>
 
 using Dali::Internal::SceneGraph::AnimatableProperty;
 using Dali::Internal::SceneGraph::Node;
@@ -142,13 +141,15 @@ DALI_PROPERTY("isRoot", BOOLEAN, false, false, false, Dali::Actor::Property::IS_
 DALI_PROPERTY("isLayer", BOOLEAN, false, false, false, Dali::Actor::Property::IS_LAYER)
 DALI_PROPERTY("connectedToScene", BOOLEAN, false, false, false, Dali::Actor::Property::CONNECTED_TO_SCENE)
 DALI_PROPERTY("keyboardFocusable", BOOLEAN, true, false, false, Dali::Actor::Property::KEYBOARD_FOCUSABLE)
+DALI_PROPERTY("updateAreaHint", VECTOR4, true, false, false, Dali::Actor::Property::UPDATE_AREA_HINT)
 DALI_PROPERTY("siblingOrder", INTEGER, true, false, false, Dali::DevelActor::Property::SIBLING_ORDER)
-DALI_PROPERTY("updateSizeHint", VECTOR2, true, false, false, Dali::DevelActor::Property::UPDATE_SIZE_HINT)
 DALI_PROPERTY("captureAllTouchAfterStart", BOOLEAN, true, false, false, Dali::DevelActor::Property::CAPTURE_ALL_TOUCH_AFTER_START)
 DALI_PROPERTY("touchAreaOffset", RECTANGLE, true, false, false, Dali::DevelActor::Property::TOUCH_AREA_OFFSET)
 DALI_PROPERTY("blendEquation", INTEGER, true, false, false, Dali::DevelActor::Property::BLEND_EQUATION)
 DALI_PROPERTY("touchFocusable", BOOLEAN, true, false, false, Dali::DevelActor::Property::TOUCH_FOCUSABLE)
 DALI_PROPERTY("keyboardFocusableChildren", BOOLEAN, true, false, false, Dali::DevelActor::Property::KEYBOARD_FOCUSABLE_CHILDREN)
+DALI_PROPERTY("userInteractionEnabled", BOOLEAN, true, false, false, Dali::DevelActor::Property::USER_INTERACTION_ENABLED)
+DALI_PROPERTY("allowOnlyOwnTouch", BOOLEAN, true, false, false, Dali::DevelActor::Property::ALLOW_ONLY_OWN_TOUCH)
 DALI_PROPERTY_TABLE_END(DEFAULT_ACTOR_PROPERTY_START_INDEX, ActorDefaultProperties)
 
 // Signals
@@ -290,45 +291,6 @@ SignalConnectorType signalConnector11(mType, std::string(SIGNAL_CHILD_REMOVED),
 TypeAction a1(mType, std::string(ACTION_SHOW), &DoAction);
 TypeAction a2(mType, std::string(ACTION_HIDE), &DoAction);
 
-/**
- * @brief Extract a given dimension from a Vector2
- *
- * @param[in] values The values to extract from
- * @param[in] dimension The dimension to extract
- * @return Return the value for the dimension
- */
-constexpr float GetDimensionValue(const Vector2& values, Dimension::Type dimension)
-{
-  switch(dimension)
-  {
-    case Dimension::WIDTH:
-    {
-      return values.width;
-    }
-    case Dimension::HEIGHT:
-    {
-      return values.height;
-    }
-    default:
-    {
-      break;
-    }
-  }
-  return 0.0f;
-}
-
-/**
- * @brief Extract a given dimension from a Vector3
- *
- * @param[in] values The values to extract from
- * @param[in] dimension The dimension to extract
- * @return Return the value for the dimension
- */
-float GetDimensionValue(const Vector3& values, Dimension::Type dimension)
-{
-  return GetDimensionValue(values.GetVectorXY(), dimension);
-}
-
 /// Helper for emitting a signal
 template<typename Signal, typename Event>
 bool EmitConsumingSignal(Actor& actor, Signal& signal, const Event& event)
@@ -355,7 +317,7 @@ void EmitSignal(Actor& actor, Signal& signal, Param... params)
   }
 }
 
-using ActorParentSiblingOrderMethod = void (ActorParent::*)(Actor&);
+using ActorParentSiblingOrderMethod           = void (ActorParent::*)(Actor&);
 using ActorParentSiblingOrderMethodWithTarget = void (ActorParent::*)(Actor&, Actor&);
 
 /// Helper to check and call actor sibling methods in ActorParent
@@ -575,21 +537,19 @@ const Vector3& Actor::GetCurrentWorldPosition() const
 
 const Vector2 Actor::GetCurrentScreenPosition() const
 {
-  if(mScene && OnScene())
+  if(mScene)
   {
-    Vector3 worldPosition  = GetNode().GetWorldPosition(GetEventThreadServices().GetEventBufferIndex());
-    Vector3 cameraPosition = mScene->GetDefaultCameraActor().GetNode().GetWorldPosition(GetEventThreadServices().GetEventBufferIndex());
-    worldPosition -= cameraPosition;
-
-    Vector3 actorSize = GetCurrentSize() * GetCurrentWorldScale();
-    Vector2 halfSceneSize(mScene->GetSize() * 0.5f); // World position origin is center of scene
-    Vector3 halfActorSize(actorSize * 0.5f);
-    Vector3 anchorPointOffSet = halfActorSize - actorSize * (mPositionUsesAnchorPoint ? GetCurrentAnchorPoint() : AnchorPoint::TOP_LEFT);
-
-    return Vector2(halfSceneSize.width + worldPosition.x - anchorPointOffSet.x,
-                   halfSceneSize.height + worldPosition.y - anchorPointOffSet.y);
+    BufferIndex bufferIndex = GetEventThreadServices().GetEventBufferIndex();
+    if(mLayer3DParentsCount == 0)
+    {
+      // We can assume that this actor is under 2d layer. Use faster, but imprecise algorithm
+      return CalculateActorScreenPosition(*this, bufferIndex);
+    }
+    else
+    {
+      return CalculateActorScreenPositionRenderTaskList(*this, bufferIndex);
+    }
   }
-
   return Vector2::ZERO;
 }
 
@@ -815,19 +775,12 @@ void Actor::SetInheritOrientation(bool inherit)
 
 void Actor::SetSizeModeFactor(const Vector3& factor)
 {
-  EnsureRelayouter();
-
-  mRelayoutData->sizeModeFactor = factor;
+  mSizer.SetSizeModeFactor(factor);
 }
 
 const Vector3& Actor::GetSizeModeFactor() const
 {
-  if(mRelayoutData)
-  {
-    return mRelayoutData->sizeModeFactor;
-  }
-
-  return Relayouter::DEFAULT_SIZE_MODE_FACTOR;
+  return mSizer.GetSizeModeFactor();
 }
 
 void Actor::SetColorMode(ColorMode colorMode)
@@ -853,154 +806,31 @@ void Actor::SetSize(const Vector2& size)
   SetSize(Vector3(size.width, size.height, 0.f));
 }
 
-void Actor::SetSizeInternal(const Vector2& size)
-{
-  SetSizeInternal(Vector3(size.width, size.height, 0.f));
-}
-
 void Actor::SetSize(const Vector3& size)
 {
-  if(IsRelayoutEnabled() && !mRelayoutData->insideRelayout)
-  {
-    // TODO we cannot just ignore the given Z but that means rewrite the size negotiation!!
-    SetPreferredSize(size.GetVectorXY());
-  }
-  else
-  {
-    SetSizeInternal(size);
-  }
-}
-
-void Actor::SetSizeInternal(const Vector3& size)
-{
-  // dont allow recursive loop
-  DALI_ASSERT_ALWAYS(!mInsideOnSizeSet && "Cannot call SetSize from OnSizeSet");
-  // check that we have a node AND the new size width, height or depth is at least a little bit different from the old one
-  Vector3 currentSize = GetCurrentSize();
-
-  if((fabsf(mTargetSize.width - size.width) > Math::MACHINE_EPSILON_1) ||
-     (fabsf(mTargetSize.height - size.height) > Math::MACHINE_EPSILON_1) ||
-     (fabsf(mTargetSize.depth - size.depth) > Math::MACHINE_EPSILON_1) ||
-     (fabsf(mTargetSize.width - currentSize.width) > Math::MACHINE_EPSILON_1) ||
-     (fabsf(mTargetSize.height - currentSize.height) > Math::MACHINE_EPSILON_1) ||
-     (fabsf(mTargetSize.depth - currentSize.depth) > Math::MACHINE_EPSILON_1))
-  {
-    mTargetSize = size;
-
-    // Update the preferred size after relayoutting
-    // It should be used in the next relayoutting
-    if(mUseAnimatedSize & AnimatedSizeFlag::WIDTH && mRelayoutData)
-    {
-      mRelayoutData->preferredSize.width = mAnimatedSize.width;
-    }
-
-    if(mUseAnimatedSize & AnimatedSizeFlag::HEIGHT && mRelayoutData)
-    {
-      mRelayoutData->preferredSize.height = mAnimatedSize.height;
-    }
-
-    // node is being used in a separate thread; queue a message to set the value & base value
-    SceneGraph::NodeTransformPropertyMessage<Vector3>::Send(GetEventThreadServices(), &GetNode(), &GetNode().mSize, &SceneGraph::TransformManagerPropertyHandler<Vector3>::Bake, mTargetSize);
-
-    // Notification for derived classes
-    mInsideOnSizeSet = true;
-    OnSizeSet(mTargetSize);
-    mInsideOnSizeSet = false;
-
-    // Raise a relayout request if the flag is not locked
-    if(mRelayoutData && !mRelayoutData->insideRelayout)
-    {
-      RelayoutRequest();
-    }
-  }
+  mSizer.SetSize(size);
 }
 
 void Actor::SetWidth(float width)
 {
-  if(IsRelayoutEnabled() && !mRelayoutData->insideRelayout)
-  {
-    SetResizePolicy(ResizePolicy::FIXED, Dimension::WIDTH);
-    mRelayoutData->preferredSize.width = width;
-  }
-  else
-  {
-    mTargetSize.width = width;
-
-    // node is being used in a separate thread; queue a message to set the value & base value
-    SceneGraph::NodeTransformComponentMessage<Vector3>::Send(GetEventThreadServices(), &GetNode(), &GetNode().mSize, &SceneGraph::TransformManagerPropertyHandler<Vector3>::BakeX, width);
-  }
-
-  mUseAnimatedSize &= ~AnimatedSizeFlag::WIDTH;
-
-  RelayoutRequest();
+  mSizer.SetWidth(width);
 }
 
 void Actor::SetHeight(float height)
 {
-  if(IsRelayoutEnabled() && !mRelayoutData->insideRelayout)
-  {
-    SetResizePolicy(ResizePolicy::FIXED, Dimension::HEIGHT);
-    mRelayoutData->preferredSize.height = height;
-  }
-  else
-  {
-    mTargetSize.height = height;
-
-    // node is being used in a separate thread; queue a message to set the value & base value
-    SceneGraph::NodeTransformComponentMessage<Vector3>::Send(GetEventThreadServices(), &GetNode(), &GetNode().mSize, &SceneGraph::TransformManagerPropertyHandler<Vector3>::BakeY, height);
-  }
-
-  mUseAnimatedSize &= ~AnimatedSizeFlag::HEIGHT;
-
-  RelayoutRequest();
+  mSizer.SetHeight(height);
 }
 
 void Actor::SetDepth(float depth)
 {
-  mTargetSize.depth = depth;
-
-  mUseAnimatedSize &= ~AnimatedSizeFlag::DEPTH;
-
+  mSizer.SetDepth(depth);
   // node is being used in a separate thread; queue a message to set the value & base value
   SceneGraph::NodeTransformComponentMessage<Vector3>::Send(GetEventThreadServices(), &GetNode(), &GetNode().mSize, &SceneGraph::TransformManagerPropertyHandler<Vector3>::BakeZ, depth);
 }
 
 Vector3 Actor::GetTargetSize() const
 {
-  Vector3 size = mTargetSize;
-
-  if(mUseAnimatedSize & AnimatedSizeFlag::WIDTH)
-  {
-    // Should return animated size if size is animated
-    size.width = mAnimatedSize.width;
-  }
-  else
-  {
-    // Should return preferred size if size is fixed as set by SetSize
-    if(GetResizePolicy(Dimension::WIDTH) == ResizePolicy::FIXED)
-    {
-      size.width = GetPreferredSize().width;
-    }
-  }
-
-  if(mUseAnimatedSize & AnimatedSizeFlag::HEIGHT)
-  {
-    size.height = mAnimatedSize.height;
-  }
-  else
-  {
-    if(GetResizePolicy(Dimension::HEIGHT) == ResizePolicy::FIXED)
-    {
-      size.height = GetPreferredSize().height;
-    }
-  }
-
-  if(mUseAnimatedSize & AnimatedSizeFlag::DEPTH)
-  {
-    size.depth = mAnimatedSize.depth;
-  }
-
-  return size;
+  return mSizer.GetTargetSize();
 }
 
 const Vector3& Actor::GetCurrentSize() const
@@ -1017,98 +847,42 @@ Vector3 Actor::GetNaturalSize() const
 
 void Actor::SetResizePolicy(ResizePolicy::Type policy, Dimension::Type dimension)
 {
-  EnsureRelayouter().SetResizePolicy(policy, dimension, mTargetSize);
-
-  OnSetResizePolicy(policy, dimension);
-
-  // Trigger relayout on this control
-  RelayoutRequest();
+  mSizer.SetResizePolicy(policy, dimension);
 }
 
 ResizePolicy::Type Actor::GetResizePolicy(Dimension::Type dimension) const
 {
-  if(mRelayoutData)
-  {
-    return mRelayoutData->GetResizePolicy(dimension);
-  }
-
-  return ResizePolicy::DEFAULT;
-}
-
-void Actor::SetSizeScalePolicy(SizeScalePolicy::Type policy)
-{
-  EnsureRelayouter();
-
-  mRelayoutData->sizeSetPolicy = policy;
-
-  // Trigger relayout on this control
-  RelayoutRequest();
-}
-
-SizeScalePolicy::Type Actor::GetSizeScalePolicy() const
-{
-  if(mRelayoutData)
-  {
-    return mRelayoutData->sizeSetPolicy;
-  }
-
-  return Relayouter::DEFAULT_SIZE_SCALE_POLICY;
-}
-
-void Actor::SetDimensionDependency(Dimension::Type dimension, Dimension::Type dependency)
-{
-  EnsureRelayouter().SetDimensionDependency(dimension, dependency);
-}
-
-Dimension::Type Actor::GetDimensionDependency(Dimension::Type dimension) const
-{
-  if(mRelayoutData)
-  {
-    return mRelayoutData->GetDimensionDependency(dimension);
-  }
-
-  return Dimension::ALL_DIMENSIONS; // Default
+  return mSizer.GetResizePolicy(dimension);
 }
 
 void Actor::SetRelayoutEnabled(bool relayoutEnabled)
 {
-  // If relayout data has not been allocated yet and the client is requesting
-  // to disable it, do nothing
-  if(mRelayoutData || relayoutEnabled)
-  {
-    EnsureRelayouter();
-
-    DALI_ASSERT_DEBUG(mRelayoutData && "mRelayoutData not created");
-
-    mRelayoutData->relayoutEnabled = relayoutEnabled;
-  }
+  mSizer.SetRelayoutEnabled(relayoutEnabled);
 }
 
 bool Actor::IsRelayoutEnabled() const
 {
-  // Assume that if relayout data has not been allocated yet then
-  // relayout is disabled
-  return mRelayoutData && mRelayoutData->relayoutEnabled;
+  return mSizer.IsRelayoutEnabled();
 }
 
 void Actor::SetLayoutDirty(bool dirty, Dimension::Type dimension)
 {
-  EnsureRelayouter().SetLayoutDirty(dirty, dimension);
+  mSizer.SetLayoutDirty(dirty, dimension);
 }
 
 bool Actor::IsLayoutDirty(Dimension::Type dimension) const
 {
-  return mRelayoutData && mRelayoutData->IsLayoutDirty(dimension);
+  return mSizer.IsLayoutDirty(dimension);
 }
 
 bool Actor::RelayoutPossible(Dimension::Type dimension) const
 {
-  return mRelayoutData && mRelayoutData->relayoutEnabled && !IsLayoutDirty(dimension);
+  return mSizer.RelayoutPossible(dimension);
 }
 
 bool Actor::RelayoutRequired(Dimension::Type dimension) const
 {
-  return mRelayoutData && mRelayoutData->relayoutEnabled && IsLayoutDirty(dimension);
+  return mSizer.RelayoutRequired(dimension);
 }
 
 uint32_t Actor::AddRenderer(Renderer& renderer)
@@ -1251,6 +1025,22 @@ void Actor::EmitLayoutDirectionChangedSignal(LayoutDirection::Type type)
   EmitSignal(*this, mLayoutDirectionChangedSignal, type);
 }
 
+bool Actor::EmitHitTestResultSignal(Integration::Point point, Vector2 hitPointLocal, uint32_t timeStamp)
+{
+  bool hit = true;
+
+  if(IsHitTestResultRequired())
+  {
+    Dali::Actor        handle(this);
+    Integration::Point newPoint(point);
+    newPoint.SetHitActor(handle);
+    newPoint.SetLocalPosition(hitPointLocal);
+    Dali::TouchEvent touchEvent = Dali::Integration::NewTouchEvent(timeStamp, newPoint);
+    hit                         = mHitTestResultSignal.Emit(handle, touchEvent);
+  }
+  return hit;
+}
+
 DevelActor::ChildChangedSignalType& Actor::ChildAddedSignal()
 {
   return mParentImpl.ChildAddedSignal();
@@ -1269,12 +1059,12 @@ DevelActor::ChildOrderChangedSignalType& Actor::ChildOrderChangedSignal()
 Actor::Actor(DerivedType derivedType, const SceneGraph::Node& node)
 : Object(&node),
   mParentImpl(*this),
+  mSizer(*this),
   mParent(nullptr),
   mScene(nullptr),
   mRenderers(nullptr),
   mParentOrigin(nullptr),
   mAnchorPoint(nullptr),
-  mRelayoutData(nullptr),
   mGestureData(nullptr),
   mInterceptTouchedSignal(),
   mTouchedSignal(),
@@ -1285,17 +1075,16 @@ Actor::Actor(DerivedType derivedType, const SceneGraph::Node& node)
   mOnRelayoutSignal(),
   mVisibilityChangedSignal(),
   mLayoutDirectionChangedSignal(),
+  mHitTestResultSignal(),
   mTargetOrientation(Quaternion::IDENTITY),
   mTargetColor(Color::WHITE),
-  mTargetSize(Vector3::ZERO),
   mTargetPosition(Vector3::ZERO),
   mTargetScale(Vector3::ONE),
-  mAnimatedSize(Vector3::ZERO),
   mTouchAreaOffset(0, 0, 0, 0),
   mName(),
   mSortedDepth(0u),
   mDepth(0u),
-  mUseAnimatedSize(AnimatedSizeFlag::CLEAR),
+  mLayer3DParentsCount(0),
   mIsRoot(ROOT_LAYER == derivedType),
   mIsLayer(LAYER == derivedType || ROOT_LAYER == derivedType),
   mIsOnScene(false),
@@ -1305,7 +1094,6 @@ Actor::Actor(DerivedType derivedType, const SceneGraph::Node& node)
   mKeyboardFocusableChildren(true),
   mTouchFocusable(false),
   mOnSceneSignalled(false),
-  mInsideOnSizeSet(false),
   mInheritPosition(true),
   mInheritOrientation(true),
   mInheritScale(true),
@@ -1315,6 +1103,8 @@ Actor::Actor(DerivedType derivedType, const SceneGraph::Node& node)
   mCaptureAllTouchAfterStart(false),
   mIsBlendEquationSet(false),
   mNeedGesturePropagation(false),
+  mUserInteractionEnabled(true),
+  mAllowOnlyOwnTouch(false),
   mLayoutDirection(LayoutDirection::LEFT_TO_RIGHT),
   mDrawMode(DrawMode::NORMAL),
   mColorMode(Node::DEFAULT_COLOR_MODE),
@@ -1355,9 +1145,6 @@ Actor::~Actor()
   // Cleanup optional parent origin and anchor
   delete mParentOrigin;
   delete mAnchorPoint;
-
-  // Delete optional relayout data
-  delete mRelayoutData;
 }
 
 void Actor::Add(Actor& child, bool notify)
@@ -1417,7 +1204,7 @@ void Actor::UnparentChildren()
   mParentImpl.UnparentChildren();
 }
 
-void Actor::ConnectToScene(uint32_t parentDepth, bool notify)
+void Actor::ConnectToScene(uint32_t parentDepth, uint32_t layer3DParentsCount, bool notify)
 {
   // This container is used instead of walking the Actor hierarchy.
   // It protects us when the Actor hierarchy is modified during OnSceneConnectionExternal callbacks.
@@ -1429,7 +1216,7 @@ void Actor::ConnectToScene(uint32_t parentDepth, bool notify)
   }
 
   // This stage is not interrupted by user callbacks.
-  mParentImpl.RecursiveConnectToScene(connectionList, parentDepth + 1);
+  mParentImpl.RecursiveConnectToScene(connectionList, layer3DParentsCount, parentDepth + 1);
 
   // Notify applications about the newly connected actors.
   for(const auto& actor : connectionList)
@@ -1694,11 +1481,11 @@ void Actor::SetParent(ActorParent* parent, bool notify)
     Actor* parentActor = static_cast<Actor*>(parent);
     mScene             = parentActor->mScene;
 
-    if(EventThreadServices::IsCoreRunning() && // Don't emit signals or send messages during Core destruction
+    if(!EventThreadServices::IsShuttingDown() && // Don't emit signals or send messages during Core destruction
        parentActor->OnScene())
     {
       // Instruct each actor to create a corresponding node in the scene graph
-      ConnectToScene(parentActor->GetHierarchyDepth(), notify);
+      ConnectToScene(parentActor->GetHierarchyDepth(), parentActor->GetLayer3DParentCount(), notify);
     }
 
     // Resolve the name and index for the child properties if any
@@ -1710,7 +1497,7 @@ void Actor::SetParent(ActorParent* parent, bool notify)
 
     mParent = nullptr;
 
-    if(EventThreadServices::IsCoreRunning() && // Don't emit signals or send messages during Core destruction
+    if(!EventThreadServices::IsShuttingDown() && // Don't emit signals or send messages during Core destruction
        OnScene())
     {
       // Disconnect the Node & its children from the scene-graph.
@@ -1726,11 +1513,23 @@ void Actor::SetParent(ActorParent* parent, bool notify)
 
 Rect<> Actor::CalculateScreenExtents() const
 {
-  auto    screenPosition    = GetCurrentScreenPosition();
-  Vector3 size              = GetCurrentSize() * GetCurrentWorldScale();
-  Vector3 anchorPointOffSet = size * (mPositionUsesAnchorPoint ? GetCurrentAnchorPoint() : AnchorPoint::TOP_LEFT);
-  Vector2 position          = Vector2(screenPosition.x - anchorPointOffSet.x, screenPosition.y - anchorPointOffSet.y);
-  return {position.x, position.y, size.x, size.y};
+  if(mLayer3DParentsCount == 0)
+  {
+    // We can assume that this actor is under 2d layer. Use faster, but imprecise algorithm
+    auto        screenPosition = GetCurrentScreenPosition();
+    BufferIndex bufferIndex    = GetEventThreadServices().GetEventBufferIndex();
+    return CalculateActorScreenExtents(*this, screenPosition, bufferIndex);
+  }
+  else
+  {
+    BufferIndex bufferIndex = GetEventThreadServices().GetEventBufferIndex();
+    return CalculateActorScreenExtentsRenderTaskList(*this, bufferIndex);
+  }
+}
+
+Vector3 Actor::GetAnchorPointForPosition() const
+{
+  return (mPositionUsesAnchorPoint ? GetCurrentAnchorPoint() : AnchorPoint::TOP_LEFT);
 }
 
 bool Actor::GetCachedPropertyValue(Property::Index index, Property::Value& value) const
@@ -1743,404 +1542,115 @@ bool Actor::GetCurrentPropertyValue(Property::Index index, Property::Value& valu
   return PropertyHandler::GetCurrentPropertyValue(*this, index, value);
 }
 
-Actor::Relayouter& Actor::EnsureRelayouter()
-{
-  // Assign relayouter
-  if(!mRelayoutData)
-  {
-    mRelayoutData = new Relayouter();
-  }
-
-  return *mRelayoutData;
-}
-
 bool Actor::RelayoutDependentOnParent(Dimension::Type dimension)
 {
-  // Check if actor is dependent on parent
-  for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
-  {
-    if((dimension & (1 << i)))
-    {
-      const ResizePolicy::Type resizePolicy = GetResizePolicy(static_cast<Dimension::Type>(1 << i));
-      if(resizePolicy == ResizePolicy::FILL_TO_PARENT || resizePolicy == ResizePolicy::SIZE_RELATIVE_TO_PARENT || resizePolicy == ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT)
-      {
-        return true;
-      }
-    }
-  }
-
-  return false;
+  return mSizer.RelayoutDependentOnParent(dimension);
 }
 
 bool Actor::RelayoutDependentOnChildren(Dimension::Type dimension)
 {
-  // Check if actor is dependent on children
-  for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
-  {
-    if((dimension & (1 << i)))
-    {
-      const ResizePolicy::Type resizePolicy = GetResizePolicy(static_cast<Dimension::Type>(1 << i));
-      switch(resizePolicy)
-      {
-        case ResizePolicy::FIT_TO_CHILDREN:
-        case ResizePolicy::USE_NATURAL_SIZE: // i.e. For things that calculate their size based on children
-        {
-          return true;
-        }
-
-        default:
-        {
-          break;
-        }
-      }
-    }
-  }
-
-  return false;
-}
-
-bool Actor::RelayoutDependentOnChildrenBase(Dimension::Type dimension)
-{
-  return Actor::RelayoutDependentOnChildren(dimension);
+  return mSizer.RelayoutDependentOnChildrenBase(dimension);
 }
 
 bool Actor::RelayoutDependentOnDimension(Dimension::Type dimension, Dimension::Type dependentDimension)
 {
-  // Check each possible dimension and see if it is dependent on the input one
-  for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
-  {
-    if(dimension & (1 << i))
-    {
-      return mRelayoutData->resizePolicies[i] == ResizePolicy::DIMENSION_DEPENDENCY && mRelayoutData->dimensionDependencies[i] == dependentDimension;
-    }
-  }
-
-  return false;
-}
-
-void Actor::SetNegotiatedDimension(float negotiatedDimension, Dimension::Type dimension)
-{
-  for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
-  {
-    if(dimension & (1 << i))
-    {
-      mRelayoutData->negotiatedDimensions[i] = negotiatedDimension;
-    }
-  }
-}
-
-float Actor::GetNegotiatedDimension(Dimension::Type dimension) const
-{
-  // If more than one dimension is requested, just return the first one found
-  for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
-  {
-    if((dimension & (1 << i)))
-    {
-      return mRelayoutData->negotiatedDimensions[i];
-    }
-  }
-
-  return 0.0f; // Default
+  return mSizer.RelayoutDependentOnDimension(dimension, dependentDimension);
 }
 
 void Actor::SetPadding(const Vector2& padding, Dimension::Type dimension)
 {
-  EnsureRelayouter().SetPadding(padding, dimension);
+  mSizer.SetPadding(padding, dimension);
 }
 
 Vector2 Actor::GetPadding(Dimension::Type dimension) const
 {
-  if(mRelayoutData)
-  {
-    // If more than one dimension is requested, just return the first one found
-    for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
-    {
-      if((dimension & (1 << i)))
-      {
-        return mRelayoutData->dimensionPadding[i];
-      }
-    }
-  }
-
-  return Relayouter::DEFAULT_DIMENSION_PADDING;
+  return mSizer.GetPadding(dimension);
 }
 
 void Actor::SetLayoutNegotiated(bool negotiated, Dimension::Type dimension)
 {
-  EnsureRelayouter().SetLayoutNegotiated(negotiated, dimension);
+  mSizer.SetLayoutNegotiated(negotiated, dimension);
 }
 
 bool Actor::IsLayoutNegotiated(Dimension::Type dimension) const
 {
-  return mRelayoutData && mRelayoutData->IsLayoutNegotiated(dimension);
+  return mSizer.IsLayoutNegotiated(dimension);
 }
 
 float Actor::GetHeightForWidthBase(float width)
 {
-  const Vector3 naturalSize = GetNaturalSize();
-  return naturalSize.width > 0.0f ? naturalSize.height * width / naturalSize.width : width;
+  // Can be overridden in derived class
+  return mSizer.GetHeightForWidthBase(width);
 }
 
 float Actor::GetWidthForHeightBase(float height)
 {
-  const Vector3 naturalSize = GetNaturalSize();
-  return naturalSize.height > 0.0f ? naturalSize.width * height / naturalSize.height : height;
+  // Can be overridden in derived class
+  return mSizer.GetWidthForHeightBase(height);
 }
 
 float Actor::CalculateChildSizeBase(const Dali::Actor& child, Dimension::Type dimension)
 {
-  // Fill to parent, taking size mode factor into account
-  switch(child.GetResizePolicy(dimension))
-  {
-    case ResizePolicy::FILL_TO_PARENT:
-    {
-      return GetLatestSize(dimension);
-    }
-
-    case ResizePolicy::SIZE_RELATIVE_TO_PARENT:
-    {
-      return GetLatestSize(dimension) * GetDimensionValue(child.GetProperty<Vector3>(Dali::Actor::Property::SIZE_MODE_FACTOR), dimension);
-    }
-
-    case ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT:
-    {
-      return GetLatestSize(dimension) + GetDimensionValue(child.GetProperty<Vector3>(Dali::Actor::Property::SIZE_MODE_FACTOR), dimension);
-    }
+  // Can be overridden in derived class
+  return mSizer.CalculateChildSizeBase(child, dimension);
+}
 
-    default:
-    {
-      return GetLatestSize(dimension);
-    }
-  }
+bool Actor::RelayoutDependentOnChildrenBase(Dimension::Type dimension)
+{
+  return mSizer.RelayoutDependentOnChildrenBase(dimension);
 }
 
 float Actor::CalculateChildSize(const Dali::Actor& child, Dimension::Type dimension)
 {
   // Can be overridden in derived class
-  return CalculateChildSizeBase(child, dimension);
+  return mSizer.CalculateChildSizeBase(child, dimension);
 }
 
 float Actor::GetHeightForWidth(float width)
 {
   // Can be overridden in derived class
-  return GetHeightForWidthBase(width);
+  return mSizer.GetHeightForWidthBase(width);
 }
 
 float Actor::GetWidthForHeight(float height)
 {
   // Can be overridden in derived class
-  return GetWidthForHeightBase(height);
-}
-
-float Actor::GetLatestSize(Dimension::Type dimension) const
-{
-  return IsLayoutNegotiated(dimension) ? GetNegotiatedDimension(dimension) : GetSize(dimension);
+  return mSizer.GetWidthForHeightBase(height);
 }
 
 float Actor::GetRelayoutSize(Dimension::Type dimension) const
 {
-  Vector2 padding = GetPadding(dimension);
-
-  return GetLatestSize(dimension) + padding.x + padding.y;
-}
-
-float Actor::NegotiateFromParent(Dimension::Type dimension)
-{
-  Actor* parent = GetParent();
-  if(parent)
-  {
-    Vector2 padding(GetPadding(dimension));
-    Vector2 parentPadding(parent->GetPadding(dimension));
-    return parent->CalculateChildSize(Dali::Actor(this), dimension) - parentPadding.x - parentPadding.y - padding.x - padding.y;
-  }
-
-  return 0.0f;
-}
-
-float Actor::NegotiateFromChildren(Dimension::Type dimension)
-{
-  float maxDimensionPoint = 0.0f;
-
-  for(uint32_t i = 0, count = GetChildCount(); i < count; ++i)
-  {
-    ActorPtr child = GetChildAt(i);
-
-    if(!child->RelayoutDependentOnParent(dimension))
-    {
-      // Calculate the min and max points that the children range across
-      float childPosition = GetDimensionValue(child->GetTargetPosition(), dimension);
-      float dimensionSize = child->GetRelayoutSize(dimension);
-      maxDimensionPoint   = std::max(maxDimensionPoint, childPosition + dimensionSize);
-    }
-  }
-
-  return maxDimensionPoint;
-}
-
-float Actor::GetSize(Dimension::Type dimension) const
-{
-  return GetDimensionValue(mTargetSize, dimension);
-}
-
-float Actor::GetNaturalSize(Dimension::Type dimension) const
-{
-  return GetDimensionValue(GetNaturalSize(), dimension);
-}
-
-float Actor::CalculateSize(Dimension::Type dimension, const Vector2& maximumSize)
-{
-  switch(GetResizePolicy(dimension))
-  {
-    case ResizePolicy::USE_NATURAL_SIZE:
-    {
-      return GetNaturalSize(dimension);
-    }
-
-    case ResizePolicy::FIXED:
-    {
-      return GetDimensionValue(GetPreferredSize(), dimension);
-    }
-
-    case ResizePolicy::USE_ASSIGNED_SIZE:
-    {
-      return GetDimensionValue(maximumSize, dimension);
-    }
-
-    case ResizePolicy::FILL_TO_PARENT:
-    case ResizePolicy::SIZE_RELATIVE_TO_PARENT:
-    case ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT:
-    {
-      return NegotiateFromParent(dimension);
-    }
-
-    case ResizePolicy::FIT_TO_CHILDREN:
-    {
-      return NegotiateFromChildren(dimension);
-    }
-
-    case ResizePolicy::DIMENSION_DEPENDENCY:
-    {
-      const Dimension::Type dimensionDependency = GetDimensionDependency(dimension);
-
-      // Custom rules
-      if(dimension == Dimension::WIDTH && dimensionDependency == Dimension::HEIGHT)
-      {
-        return GetWidthForHeight(GetNegotiatedDimension(Dimension::HEIGHT));
-      }
-
-      if(dimension == Dimension::HEIGHT && dimensionDependency == Dimension::WIDTH)
-      {
-        return GetHeightForWidth(GetNegotiatedDimension(Dimension::WIDTH));
-      }
-
-      break;
-    }
-
-    default:
-    {
-      break;
-    }
-  }
-
-  return 0.0f; // Default
-}
-
-Vector2 Actor::ApplySizeSetPolicy(const Vector2& size)
-{
-  return mRelayoutData->ApplySizeSetPolicy(*this, size);
-}
-
-void Actor::SetNegotiatedSize(RelayoutContainer& container)
-{
-  // Do the set actor size
-  Vector2 negotiatedSize(GetLatestSize(Dimension::WIDTH), GetLatestSize(Dimension::HEIGHT));
-
-  // Adjust for size set policy
-  negotiatedSize = ApplySizeSetPolicy(negotiatedSize);
-
-  // Lock the flag to stop recursive relayouts on set size
-  mRelayoutData->insideRelayout = true;
-  SetSize(negotiatedSize);
-  mRelayoutData->insideRelayout = false;
-
-  // Clear flags for all dimensions
-  SetLayoutDirty(false);
-
-  // Give deriving classes a chance to respond
-  OnRelayout(negotiatedSize, container);
-
-  if(!mOnRelayoutSignal.Empty())
-  {
-    Dali::Actor handle(this);
-    mOnRelayoutSignal.Emit(handle);
-  }
-
-  mRelayoutData->relayoutRequested = false;
+  return mSizer.GetRelayoutSize(dimension);
 }
 
 void Actor::NegotiateSize(const Vector2& allocatedSize, RelayoutContainer& container)
 {
-  Relayouter::NegotiateSize(*this, allocatedSize, container);
-}
-
-void Actor::SetUseAssignedSize(bool use, Dimension::Type dimension)
-{
-  if(mRelayoutData)
-  {
-    mRelayoutData->SetUseAssignedSize(use, dimension);
-  }
-}
-
-bool Actor::GetUseAssignedSize(Dimension::Type dimension) const
-{
-  return mRelayoutData && mRelayoutData->GetUseAssignedSize(dimension);
+  mSizer.NegotiateSize(allocatedSize, container);
 }
 
 void Actor::RelayoutRequest(Dimension::Type dimension)
 {
-  Internal::RelayoutController* relayoutController = Internal::RelayoutController::Get();
-  if(relayoutController)
-  {
-    Dali::Actor self(this);
-    relayoutController->RequestRelayout(self, dimension);
-
-    if(mRelayoutData)
-    {
-      mRelayoutData->relayoutRequested = true;
-    }
-  }
-}
-
-void Actor::SetPreferredSize(const Vector2& size)
-{
-  EnsureRelayouter().SetPreferredSize(*this, size);
-}
-
-Vector2 Actor::GetPreferredSize() const
-{
-  return mRelayoutData ? Vector2(mRelayoutData->preferredSize) : Relayouter::DEFAULT_PREFERRED_SIZE;
+  mSizer.RelayoutRequest(dimension);
 }
 
 void Actor::SetMinimumSize(float size, Dimension::Type dimension)
 {
-  EnsureRelayouter().SetMinimumSize(size, dimension);
-  RelayoutRequest();
+  mSizer.SetMinimumSize(size, dimension);
 }
 
 float Actor::GetMinimumSize(Dimension::Type dimension) const
 {
-  return mRelayoutData ? mRelayoutData->GetMinimumSize(dimension) : 0.0f;
+  return mSizer.GetMinimumSize(dimension);
 }
 
 void Actor::SetMaximumSize(float size, Dimension::Type dimension)
 {
-  EnsureRelayouter().SetMaximumSize(size, dimension);
-  RelayoutRequest();
+  mSizer.SetMaximumSize(size, dimension);
 }
 
 float Actor::GetMaximumSize(Dimension::Type dimension) const
 {
-  return mRelayoutData ? mRelayoutData->GetMaximumSize(dimension) : FLT_MAX;
+  return mSizer.GetMaximumSize(dimension);
 }
 
 void Actor::SetVisibleInternal(bool visible, SendMessage::Type sendMessage)
@@ -2215,10 +1725,10 @@ void Actor::SetInheritLayoutDirection(bool inherit)
   }
 }
 
-void Actor::SetUpdateSizeHint(const Vector2& updateSizeHint)
+void Actor::SetUpdateAreaHint(const Vector4& updateAreaHint)
 {
   // node is being used in a separate thread; queue a message to set the value & base value
-  SceneGraph::NodePropertyMessage<Vector3>::Send(GetEventThreadServices(), &GetNode(), &GetNode().mUpdateSizeHint, &AnimatableProperty<Vector3>::Bake, Vector3(updateSizeHint.width, updateSizeHint.height, 0.f));
+  SceneGraph::NodePropertyMessage<Vector4>::Send(GetEventThreadServices(), &GetNode(), &GetNode().mUpdateAreaHint, &AnimatableProperty<Vector4>::Bake, updateAreaHint);
 }
 
 } // namespace Internal