Refactored more code into Actor::Relayouter
[platform/core/uifw/dali-core.git] / dali / internal / event / actors / actor-relayouter.cpp
index 0e1fcf3..f8e57d1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 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.
 #include <dali/internal/event/actors/actor-relayouter.h>
 
 // INTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/actors/actor.h>
 #include <dali/public-api/math/vector2.h>
 #include <dali/public-api/math/vector3.h>
+
 #include <dali/internal/event/size-negotiation/relayout-controller-impl.h>
 
 namespace
 {
 #if defined(DEBUG_ENABLED)
-Debug::Filter* gLogRelayoutFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_RELAYOUT_TIMER" );
+Debug::Filter* gLogRelayoutFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_RELAYOUT_TIMER");
 #endif
+
+/**
+ * @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 Dali::Vector2& values, const Dali::Dimension::Type dimension)
+{
+  switch(dimension)
+  {
+    case Dali::Dimension::WIDTH:
+    {
+      return values.width;
+    }
+    case Dali::Dimension::HEIGHT:
+    {
+      return values.height;
+    }
+    default:
+    {
+      break;
+    }
+  }
+  return 0.0f;
+}
+
 } // unnamed namespace
 
 namespace Dali
 {
-
 namespace Internal
 {
-
 Actor::Relayouter::Relayouter()
-: sizeModeFactor( DEFAULT_SIZE_MODE_FACTOR ),
-  preferredSize( DEFAULT_PREFERRED_SIZE ),
-  sizeSetPolicy( DEFAULT_SIZE_SCALE_POLICY ),
-  relayoutEnabled( false ),
-  insideRelayout( false )
+: sizeModeFactor(DEFAULT_SIZE_MODE_FACTOR),
+  preferredSize(DEFAULT_PREFERRED_SIZE),
+  sizeSetPolicy(DEFAULT_SIZE_SCALE_POLICY),
+  relayoutEnabled(false),
+  insideRelayout(false),
+  relayoutRequested(false)
 {
   // Set size negotiation defaults
-  for( uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i )
+  for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
   {
-    resizePolicies[ i ] = ResizePolicy::DEFAULT;
-    useAssignedSize[ i ] = false;
-    negotiatedDimensions[ i ] = 0.0f;
-    dimensionNegotiated[ i ] = false;
-    dimensionDirty[ i ] = false;
-    dimensionDependencies[ i ] = Dimension::ALL_DIMENSIONS;
-    dimensionPadding[ i ] = DEFAULT_DIMENSION_PADDING;
-    minimumSize[ i ] = 0.0f;
-    maximumSize[ i ] = FLT_MAX;
+    resizePolicies[i]        = ResizePolicy::DEFAULT;
+    useAssignedSize[i]       = false;
+    negotiatedDimensions[i]  = 0.0f;
+    dimensionNegotiated[i]   = false;
+    dimensionDirty[i]        = false;
+    dimensionDependencies[i] = Dimension::ALL_DIMENSIONS;
+    dimensionPadding[i]      = DEFAULT_DIMENSION_PADDING;
+    minimumSize[i]           = 0.0f;
+    maximumSize[i]           = FLT_MAX;
   }
 }
 
-ResizePolicy::Type Actor::Relayouter::GetResizePolicy( Dimension::Type dimension ) const
+ResizePolicy::Type Actor::Relayouter::GetResizePolicy(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 )
+  for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
   {
-    if( ( dimension & ( 1 << i ) ) )
+    if((dimension & (1 << i)))
     {
-      if( useAssignedSize[ i ] )
+      if(useAssignedSize[i])
       {
         return ResizePolicy::USE_ASSIGNED_SIZE;
       }
       else
       {
-        return resizePolicies[ i ];
+        return resizePolicies[i];
       }
     }
   }
@@ -79,33 +109,47 @@ ResizePolicy::Type Actor::Relayouter::GetResizePolicy( Dimension::Type dimension
   return ResizePolicy::DEFAULT;
 }
 
-void Actor::Relayouter::SetPadding( const Vector2& padding, Dimension::Type dimension )
+void Actor::Relayouter::SetPadding(const Vector2& padding, Dimension::Type dimension)
 {
-  for( uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i )
+  for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
   {
-    if( dimension & ( 1 << i ) )
+    if(dimension & (1 << i))
     {
-      dimensionPadding[ i ] = padding;
+      dimensionPadding[i] = padding;
     }
   }
 }
 
-void Actor::Relayouter::SetLayoutNegotiated( bool negotiated, Dimension::Type dimension )
+Vector2 Actor::Relayouter::GetPadding(Dimension::Type dimension)
 {
-  for( uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i )
+  // 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 dimensionPadding[i];
+    }
+  }
+
+  return DEFAULT_DIMENSION_PADDING;
+}
+
+void Actor::Relayouter::SetLayoutNegotiated(bool negotiated, Dimension::Type dimension)
+{
+  for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
   {
-    if( dimension & ( 1 << i ) )
+    if(dimension & (1 << i))
     {
-      dimensionNegotiated[ i ] = negotiated;
+      dimensionNegotiated[i] = negotiated;
     }
   }
 }
 
-bool Actor::Relayouter::IsLayoutNegotiated( Dimension::Type dimension ) const
+bool Actor::Relayouter::IsLayoutNegotiated(Dimension::Type dimension) const
 {
-  for( uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i )
+  for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
   {
-    if( ( dimension & ( 1 << i ) ) && dimensionNegotiated[ i ] )
+    if((dimension & (1 << i)) && dimensionNegotiated[i])
     {
       return true;
     }
@@ -113,9 +157,9 @@ bool Actor::Relayouter::IsLayoutNegotiated( Dimension::Type dimension ) const
   return false;
 }
 
-Vector2 Actor::Relayouter::ApplySizeSetPolicy( Internal::Actor& actor, const Vector2& size )
+Vector2 Actor::Relayouter::ApplySizeSetPolicy(Internal::Actor& actor, const Vector2& size)
 {
-  switch( sizeSetPolicy )
+  switch(sizeSetPolicy)
   {
     case SizeScalePolicy::USE_SIZE_SET:
     {
@@ -126,18 +170,18 @@ Vector2 Actor::Relayouter::ApplySizeSetPolicy( Internal::Actor& actor, const Vec
     {
       // Scale size to fit within the original size bounds, keeping the natural size aspect ratio
       const Vector3 naturalSize = actor.GetNaturalSize();
-      if( naturalSize.width > 0.0f && naturalSize.height > 0.0f && size.width > 0.0f && size.height > 0.0f )
+      if(naturalSize.width > 0.0f && naturalSize.height > 0.0f && size.width > 0.0f && size.height > 0.0f)
       {
-        const float sizeRatio = size.width / size.height;
+        const float sizeRatio        = size.width / size.height;
         const float naturalSizeRatio = naturalSize.width / naturalSize.height;
 
-        if( naturalSizeRatio < sizeRatio )
+        if(naturalSizeRatio < sizeRatio)
         {
-          return Vector2( naturalSizeRatio * size.height, size.height );
+          return Vector2(naturalSizeRatio * size.height, size.height);
         }
-        else if( naturalSizeRatio > sizeRatio )
+        else if(naturalSizeRatio > sizeRatio)
         {
-          return Vector2( size.width, size.width / naturalSizeRatio );
+          return Vector2(size.width, size.width / naturalSizeRatio);
         }
         else
         {
@@ -152,18 +196,18 @@ Vector2 Actor::Relayouter::ApplySizeSetPolicy( Internal::Actor& actor, const Vec
     {
       // Scale size to fill the original size bounds, keeping the natural size aspect ratio. Potentially exceeding the original bounds.
       const Vector3 naturalSize = actor.GetNaturalSize();
-      if( naturalSize.width > 0.0f && naturalSize.height > 0.0f && size.width > 0.0f && size.height > 0.0f )
+      if(naturalSize.width > 0.0f && naturalSize.height > 0.0f && size.width > 0.0f && size.height > 0.0f)
       {
-        const float sizeRatio = size.width / size.height;
+        const float sizeRatio        = size.width / size.height;
         const float naturalSizeRatio = naturalSize.width / naturalSize.height;
 
-        if( naturalSizeRatio < sizeRatio )
+        if(naturalSizeRatio < sizeRatio)
         {
-          return Vector2( size.width, size.width / naturalSizeRatio );
+          return Vector2(size.width, size.width / naturalSizeRatio);
         }
-        else if( naturalSizeRatio > sizeRatio )
+        else if(naturalSizeRatio > sizeRatio)
         {
-          return Vector2( naturalSizeRatio * size.height, size.height );
+          return Vector2(naturalSizeRatio * size.height, size.height);
         }
         else
         {
@@ -182,110 +226,110 @@ Vector2 Actor::Relayouter::ApplySizeSetPolicy( Internal::Actor& actor, const Vec
   return size;
 }
 
-void Actor::Relayouter::SetUseAssignedSize( bool use, Dimension::Type dimension )
+void Actor::Relayouter::SetUseAssignedSize(bool use, Dimension::Type dimension)
 {
-  for( uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i )
+  for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
   {
-    if( dimension & ( 1 << i ) )
+    if(dimension & (1 << i))
     {
-      useAssignedSize[ i ] = use;
+      useAssignedSize[i] = use;
     }
   }
 }
 
-bool Actor::Relayouter::GetUseAssignedSize( Dimension::Type dimension ) const
+bool Actor::Relayouter::GetUseAssignedSize(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 )
+  for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
   {
-    if( dimension & ( 1 << i ) )
+    if(dimension & (1 << i))
     {
-      return useAssignedSize[ i ];
+      return useAssignedSize[i];
     }
   }
 
   return false;
 }
 
-void Actor::Relayouter::SetMinimumSize( float size, Dimension::Type dimension )
+void Actor::Relayouter::SetMinimumSize(float size, Dimension::Type dimension)
 {
-  for( uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i )
+  for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
   {
-    if( dimension & ( 1 << i ) )
+    if(dimension & (1 << i))
     {
-      minimumSize[ i ] = size;
+      minimumSize[i] = size;
     }
   }
 }
 
-float Actor::Relayouter::GetMinimumSize( Dimension::Type dimension ) const
+float Actor::Relayouter::GetMinimumSize(Dimension::Type dimension) const
 {
-  for( uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i )
+  for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
   {
-    if( dimension & ( 1 << i ) )
+    if(dimension & (1 << i))
     {
-      return minimumSize[ i ];
+      return minimumSize[i];
     }
   }
 
-  return 0.0f;  // Default
+  return 0.0f; // Default
 }
 
-void Actor::Relayouter::SetMaximumSize( float size, Dimension::Type dimension )
+void Actor::Relayouter::SetMaximumSize(float size, Dimension::Type dimension)
 {
-  for( uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i )
+  for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
   {
-    if( dimension & ( 1 << i ) )
+    if(dimension & (1 << i))
     {
-      maximumSize[ i ] = size;
+      maximumSize[i] = size;
     }
   }
 }
 
-float Actor::Relayouter::GetMaximumSize( Dimension::Type dimension ) const
+float Actor::Relayouter::GetMaximumSize(Dimension::Type dimension) const
 {
-  for( uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i )
+  for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
   {
-    if( dimension & ( 1 << i ) )
+    if(dimension & (1 << i))
     {
-      return maximumSize[ i ];
+      return maximumSize[i];
     }
   }
 
-  return FLT_MAX;  // Default
+  return FLT_MAX; // Default
 }
 
-void Actor::Relayouter::SetResizePolicy( ResizePolicy::Type policy, Dimension::Type dimension, Vector3& targetSize )
+void Actor::Relayouter::SetResizePolicy(ResizePolicy::Type policy, Dimension::Type dimension, Vector3& targetSize)
 {
-  ResizePolicy::Type originalWidthPolicy = GetResizePolicy(Dimension::WIDTH);
+  ResizePolicy::Type originalWidthPolicy  = GetResizePolicy(Dimension::WIDTH);
   ResizePolicy::Type originalHeightPolicy = GetResizePolicy(Dimension::HEIGHT);
 
-  for( uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i )
+  for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
   {
-    if( dimension & ( 1 << i ) )
+    if(dimension & (1 << i))
     {
-      if ( policy == ResizePolicy::USE_ASSIGNED_SIZE )
+      if(policy == ResizePolicy::USE_ASSIGNED_SIZE)
       {
-        useAssignedSize[ i ] = true;
+        useAssignedSize[i] = true;
       }
       else
       {
-        resizePolicies[ i ] = policy;
-        useAssignedSize[ i ] = false;
+        resizePolicies[i]  = policy;
+        useAssignedSize[i] = false;
       }
     }
   }
 
-  if( policy == ResizePolicy::DIMENSION_DEPENDENCY )
+  if(policy == ResizePolicy::DIMENSION_DEPENDENCY)
   {
-    if( dimension & Dimension::WIDTH )
+    if(dimension & Dimension::WIDTH)
     {
-      SetDimensionDependency( Dimension::WIDTH, Dimension::HEIGHT );
+      SetDimensionDependency(Dimension::WIDTH, Dimension::HEIGHT);
     }
 
-    if( dimension & Dimension::HEIGHT )
+    if(dimension & Dimension::HEIGHT)
     {
-      SetDimensionDependency( Dimension::HEIGHT, Dimension::WIDTH );
+      SetDimensionDependency(Dimension::HEIGHT, Dimension::WIDTH);
     }
   }
 
@@ -296,72 +340,122 @@ void Actor::Relayouter::SetResizePolicy( ResizePolicy::Type policy, Dimension::T
   // should be overrided by the target size. Otherwise the target
   // size should be overrided by the preferred size.
 
-  if( dimension & Dimension::WIDTH )
+  if(dimension & Dimension::WIDTH)
   {
-    if( originalWidthPolicy != ResizePolicy::FIXED && policy == ResizePolicy::FIXED )
+    if(originalWidthPolicy != ResizePolicy::FIXED && policy == ResizePolicy::FIXED)
     {
       preferredSize.width = targetSize.width;
     }
-    else if( originalWidthPolicy == ResizePolicy::FIXED && policy != ResizePolicy::FIXED )
+    else if(originalWidthPolicy == ResizePolicy::FIXED && policy != ResizePolicy::FIXED)
     {
       targetSize.width = preferredSize.width;
     }
   }
 
-  if( dimension & Dimension::HEIGHT )
+  if(dimension & Dimension::HEIGHT)
   {
-    if( originalHeightPolicy != ResizePolicy::FIXED && policy == ResizePolicy::FIXED )
+    if(originalHeightPolicy != ResizePolicy::FIXED && policy == ResizePolicy::FIXED)
     {
       preferredSize.height = targetSize.height;
     }
-    else if( originalHeightPolicy == ResizePolicy::FIXED && policy != ResizePolicy::FIXED )
+    else if(originalHeightPolicy == ResizePolicy::FIXED && policy != ResizePolicy::FIXED)
     {
       targetSize.height = preferredSize.height;
     }
   }
 }
 
-void Actor::Relayouter::SetDimensionDependency( Dimension::Type dimension, Dimension::Type dependency )
+bool Actor::Relayouter::GetRelayoutDependentOnParent(Dimension::Type dimension)
 {
-  for( uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i )
+  // Check if actor is dependent on parent
+  for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
   {
-    if( dimension & ( 1 << i ) )
+    if((dimension & (1 << i)))
     {
-      dimensionDependencies[ i ] = dependency;
+      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;
 }
 
-Dimension::Type Actor::Relayouter::GetDimensionDependency( Dimension::Type dimension ) const
+bool Actor::Relayouter::GetRelayoutDependentOnChildren(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));
+      if(resizePolicy == ResizePolicy::FIT_TO_CHILDREN || resizePolicy == ResizePolicy::USE_NATURAL_SIZE)
+      {
+        return true;
+      }
+      break;
+    }
+  }
+
+  return false;
+}
+
+bool Actor::Relayouter::GetRelayoutDependentOnDimension(Dimension::Type dimension, Dimension::Type dependency)
+{
+  // 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 resizePolicies[i] == ResizePolicy::DIMENSION_DEPENDENCY && dimensionDependencies[i] == dependency;
+    }
+  }
+
+  return false;
+}
+
+void Actor::Relayouter::SetDimensionDependency(Dimension::Type dimension, Dimension::Type dependency)
+{
+  for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
+  {
+    if(dimension & (1 << i))
+    {
+      dimensionDependencies[i] = dependency;
+    }
+  }
+}
+
+Dimension::Type Actor::Relayouter::GetDimensionDependency(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 )
+  for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
   {
-    if( ( dimension & ( 1 << i ) ) )
+    if((dimension & (1 << i)))
     {
-      return dimensionDependencies[ i ];
+      return dimensionDependencies[i];
     }
   }
 
-  return Dimension::ALL_DIMENSIONS;   // Default
+  return Dimension::ALL_DIMENSIONS; // Default
 }
 
-void Actor::Relayouter::SetLayoutDirty( bool dirty, Dimension::Type dimension )
+void Actor::Relayouter::SetLayoutDirty(bool dirty, Dimension::Type dimension)
 {
-  for( uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i )
+  for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
   {
-    if( dimension & ( 1 << i ) )
+    if(dimension & (1 << i))
     {
-      dimensionDirty[ i ] = dirty;
+      dimensionDirty[i] = dirty;
     }
   }
 }
 
-bool Actor::Relayouter::IsLayoutDirty( Dimension::Type dimension ) const
+bool Actor::Relayouter::IsLayoutDirty(Dimension::Type dimension) const
 {
-  for( uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i )
+  for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
   {
-    if( ( dimension & ( 1 << i ) ) && dimensionDirty[ i ] )
+    if((dimension & (1 << i)) && dimensionDirty[i])
     {
       return true;
     }
@@ -370,20 +464,20 @@ bool Actor::Relayouter::IsLayoutDirty( Dimension::Type dimension ) const
   return false;
 }
 
-void Actor::Relayouter::SetPreferredSize( Actor& actor, const Vector2& size )
+void Actor::Relayouter::SetPreferredSize(Actor& actor, const Vector2& size)
 {
   // If valid width or height, then set the resize policy to FIXED
   // A 0 width or height may also be required so if the resize policy has not been changed, i.e. is still set to DEFAULT,
   // then change to FIXED as well
 
-  if( size.width > 0.0f || GetResizePolicy( Dimension::WIDTH ) == ResizePolicy::DEFAULT )
+  if(size.width > 0.0f || GetResizePolicy(Dimension::WIDTH) == ResizePolicy::DEFAULT)
   {
-    actor.SetResizePolicy( ResizePolicy::FIXED, Dimension::WIDTH );
+    actor.SetResizePolicy(ResizePolicy::FIXED, Dimension::WIDTH);
   }
 
-  if( size.height > 0.0f || GetResizePolicy( Dimension::HEIGHT ) == ResizePolicy::DEFAULT )
+  if(size.height > 0.0f || GetResizePolicy(Dimension::HEIGHT) == ResizePolicy::DEFAULT)
   {
-    actor.SetResizePolicy( ResizePolicy::FIXED, Dimension::HEIGHT );
+    actor.SetResizePolicy(ResizePolicy::FIXED, Dimension::HEIGHT);
   }
 
   actor.mRelayoutData->preferredSize = size;
@@ -393,80 +487,140 @@ void Actor::Relayouter::SetPreferredSize( Actor& actor, const Vector2& size )
   actor.RelayoutRequest();
 }
 
-float Actor::Relayouter::ClampDimension( const Internal::Actor& actor, float size, Dimension::Type dimension )
+float Actor::Relayouter::ClampDimension(const Internal::Actor& actor, float size, Dimension::Type dimension)
+{
+  const float minSize = actor.GetMinimumSize(dimension);
+  const float maxSize = actor.GetMaximumSize(dimension);
+
+  return std::max(minSize, std::min(size, maxSize));
+}
+
+void Actor::Relayouter::SetNegotiatedDimension(float negotiatedDimension, Dimension::Type dimension)
+{
+  for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
+  {
+    if(dimension & (1 << i))
+    {
+      negotiatedDimensions[i] = negotiatedDimension;
+    }
+  }
+}
+
+float Actor::Relayouter::GetNegotiatedDimension(Dimension::Type dimension)
+{
+  // 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 negotiatedDimensions[i];
+    }
+  }
+
+  return 0.0f; // Default
+}
+
+float Actor::Relayouter::NegotiateDimensionFromParent(Actor& actor, Dimension::Type dimension)
 {
-  const float minSize = actor.GetMinimumSize( dimension );
-  const float maxSize = actor.GetMaximumSize( dimension );
+  Actor* parent = actor.GetParent();
+  if(parent)
+  {
+    Vector2 padding(actor.GetPadding(dimension));
+    Vector2 parentPadding(parent->GetPadding(dimension));
 
-  return std::max( minSize, std::min( size, maxSize ) );
+    // Need to use actor API here to allow deriving actors to layout their children
+    return parent->CalculateChildSize(Dali::Actor(&actor), dimension) - parentPadding.x - parentPadding.y - padding.x - padding.y;
+  }
+
+  return 0.0f;
 }
 
-void Actor::Relayouter::NegotiateDimension( Actor& actor, Dimension::Type dimension, const Vector2& allocatedSize, Actor::ActorDimensionStack& recursionStack )
+float Actor::Relayouter::NegotiateDimensionFromChildren(Actor& actor, Dimension::Type dimension)
+{
+  float maxDimensionPoint = 0.0f;
+
+  for(uint32_t i = 0, count = actor.GetChildCount(); i < count; ++i)
+  {
+    ActorPtr child = actor.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;
+}
+
+void Actor::Relayouter::NegotiateDimension(Actor& actor, Dimension::Type dimension, const Vector2& allocatedSize, Actor::ActorDimensionStack& recursionStack)
 {
   // Check if it needs to be negotiated
-  if( actor.IsLayoutDirty( dimension ) && !actor.IsLayoutNegotiated( dimension ) )
+  if(actor.IsLayoutDirty(dimension) && !actor.IsLayoutNegotiated(dimension))
   {
     // Check that we havn't gotten into an infinite loop
-    Actor::ActorDimensionPair searchActor = Actor::ActorDimensionPair( &actor, dimension );
-    bool recursionFound = false;
-    for( auto& element : recursionStack )
+    Actor::ActorDimensionPair searchActor    = Actor::ActorDimensionPair(&actor, dimension);
+    bool                      recursionFound = false;
+    for(auto& element : recursionStack)
     {
-      if( element == searchActor )
+      if(element == searchActor)
       {
         recursionFound = true;
         break;
       }
     }
 
-    if( !recursionFound )
+    if(!recursionFound)
     {
       // Record the path that we have taken
-      recursionStack.push_back( Actor::ActorDimensionPair( &actor, dimension ) );
+      recursionStack.push_back(Actor::ActorDimensionPair(&actor, dimension));
 
       // Dimension dependency check
-      for( uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i )
+      for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
       {
-        Dimension::Type dimensionToCheck = static_cast< Dimension::Type >( 1 << i );
+        Dimension::Type dimensionToCheck = static_cast<Dimension::Type>(1 << i);
 
-        if( actor.RelayoutDependentOnDimension( dimension, dimensionToCheck ) )
+        if(actor.RelayoutDependentOnDimension(dimension, dimensionToCheck))
         {
-          NegotiateDimension( actor, dimensionToCheck, allocatedSize, recursionStack );
+          NegotiateDimension(actor, dimensionToCheck, allocatedSize, recursionStack);
         }
       }
 
       // Parent dependency check
       Actor* parent = actor.GetParent();
-      if( parent && actor.RelayoutDependentOnParent( dimension ) )
+      if(parent && actor.RelayoutDependentOnParent(dimension))
       {
-        NegotiateDimension( *parent, dimension, allocatedSize, recursionStack );
+        NegotiateDimension(*parent, dimension, allocatedSize, recursionStack);
       }
 
       // Children dependency check
-      if( actor.RelayoutDependentOnChildren( dimension ) )
+      if(actor.RelayoutDependentOnChildren(dimension))
       {
-        for( uint32_t i = 0, count = actor.GetChildCount(); i < count; ++i )
+        for(uint32_t i = 0, count = actor.GetChildCount(); i < count; ++i)
         {
-          ActorPtr child = actor.GetChildAt( i );
+          ActorPtr child = actor.GetChildAt(i);
 
           // Only relayout child first if it is not dependent on this actor
-          if( !child->RelayoutDependentOnParent( dimension ) )
+          if(!child->RelayoutDependentOnParent(dimension))
           {
-            NegotiateDimension( *child, dimension, allocatedSize, recursionStack );
+            NegotiateDimension(*child, dimension, allocatedSize, recursionStack);
           }
         }
       }
 
       // For deriving classes
-      actor.OnCalculateRelayoutSize( dimension );
+      actor.OnCalculateRelayoutSize(dimension);
 
       // All dependencies checked, calculate the size and set negotiated flag
-      const float newSize = ClampDimension( actor, actor.CalculateSize( dimension, allocatedSize ), dimension );
+      const float newSize = ClampDimension(actor, actor.CalculateSize(dimension, allocatedSize), dimension);
 
-      actor.SetNegotiatedDimension( newSize, dimension );
-      actor.SetLayoutNegotiated( true, dimension );
+      actor.SetNegotiatedDimension(newSize, dimension);
+      actor.SetLayoutNegotiated(true, dimension);
 
       // For deriving classes
-      actor.OnLayoutNegotiated( newSize, dimension );
+      actor.OnLayoutNegotiated(newSize, dimension);
 
       // This actor has been successfully processed, pop it off the recursion stack
       recursionStack.pop_back();
@@ -474,7 +628,7 @@ void Actor::Relayouter::NegotiateDimension( Actor& actor, Dimension::Type dimens
     else
     {
       // TODO: Break infinite loop
-      actor.SetLayoutNegotiated( true, dimension );
+      actor.SetLayoutNegotiated(true, dimension);
     }
   }
 }
@@ -484,9 +638,9 @@ void Actor::Relayouter::NegotiateDimensions(Actor& actor, const Vector2& allocat
   // Negotiate all dimensions that require it
   ActorDimensionStack recursionStack;
 
-  for( uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i )
+  for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
   {
-    const Dimension::Type dimension = static_cast< Dimension::Type >( 1 << i );
+    const Dimension::Type dimension = static_cast<Dimension::Type>(1 << i);
 
     // Negotiate
     NegotiateDimension(actor, dimension, allocatedSize, recursionStack);
@@ -502,49 +656,150 @@ void Actor::Relayouter::NegotiateSize(Actor& actor, const Vector2& allocatedSize
   // relayout container afterwards, the dirty flags would still be clear...
   // causing a relayout to be skipped. Here we force any actors added to the
   // container to be relayed out.
-  DALI_LOG_TIMER_START( NegSizeTimer1 );
+  DALI_LOG_TIMER_START(NegSizeTimer1);
 
-  if( actor.GetUseAssignedSize(Dimension::WIDTH ) )
+  if(actor.GetUseAssignedSize(Dimension::WIDTH))
   {
-    actor.SetLayoutNegotiated( false, Dimension::WIDTH );
+    actor.SetLayoutNegotiated(false, Dimension::WIDTH);
   }
-  if( actor.GetUseAssignedSize( Dimension::HEIGHT ) )
+  if(actor.GetUseAssignedSize(Dimension::HEIGHT))
   {
-    actor.SetLayoutNegotiated( false, Dimension::HEIGHT );
+    actor.SetLayoutNegotiated(false, Dimension::HEIGHT);
   }
 
   // Do the negotiation
   NegotiateDimensions(actor, allocatedSize);
 
   // Set the actor size
-  actor.SetNegotiatedSize( container );
+  actor.SetNegotiatedSize(container);
 
   // Negotiate down to children
-  for( uint32_t i = 0, count = actor.GetChildCount(); i < count; ++i )
+  for(uint32_t i = 0, count = actor.GetChildCount(); i < count; ++i)
   {
-    ActorPtr child = actor.GetChildAt( i );
+    ActorPtr child = actor.GetChildAt(i);
 
     // Forces children that have already been laid out to be relayed out
     // if they have assigned size during relayout.
-    if( child->GetUseAssignedSize(Dimension::WIDTH) )
+    if(child->GetUseAssignedSize(Dimension::WIDTH))
     {
       child->SetLayoutNegotiated(false, Dimension::WIDTH);
       child->SetLayoutDirty(true, Dimension::WIDTH);
     }
 
-    if( child->GetUseAssignedSize(Dimension::HEIGHT) )
+    if(child->GetUseAssignedSize(Dimension::HEIGHT))
     {
       child->SetLayoutNegotiated(false, Dimension::HEIGHT);
       child->SetLayoutDirty(true, Dimension::HEIGHT);
     }
 
     // Only relayout if required
-    if( child->RelayoutRequired() )
+    if(child->RelayoutRequired())
+    {
+      container.Add(Dali::Actor(child.Get()), actor.mTargetSize.GetVectorXY());
+    }
+  }
+  DALI_LOG_TIMER_END(NegSizeTimer1, gLogRelayoutFilter, Debug::Concise, "NegotiateSize() took: ");
+}
+
+/**
+ * @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 Actor::Relayouter::GetDimensionValue(const Vector3& values, const Dimension::Type dimension)
+{
+  return ::GetDimensionValue(values.GetVectorXY(), dimension);
+}
+
+float Actor::Relayouter::CalculateSize(Actor& actor, Dimension::Type dimension, const Vector2& maximumSize)
+{
+  switch(actor.GetResizePolicy(dimension))
+  {
+    case ResizePolicy::USE_NATURAL_SIZE:
+    {
+      return actor.GetNaturalSize(dimension);
+    }
+
+    case ResizePolicy::FIXED:
+    {
+      return ::GetDimensionValue(actor.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 NegotiateDimensionFromParent(actor, dimension);
+    }
+
+    case ResizePolicy::FIT_TO_CHILDREN:
+    {
+      return NegotiateDimensionFromChildren(actor, dimension);
+    }
+
+    case ResizePolicy::DIMENSION_DEPENDENCY:
+    {
+      const Dimension::Type dimensionDependency = actor.GetDimensionDependency(dimension);
+
+      // Custom rules
+      if(dimension == Dimension::WIDTH && dimensionDependency == Dimension::HEIGHT)
+      {
+        return actor.GetWidthForHeight(actor.GetNegotiatedDimension(Dimension::HEIGHT));
+      }
+
+      if(dimension == Dimension::HEIGHT && dimensionDependency == Dimension::WIDTH)
+      {
+        return actor.GetHeightForWidth(actor.GetNegotiatedDimension(Dimension::WIDTH));
+      }
+
+      break;
+    }
+
+    default:
+    {
+      break;
+    }
+  }
+
+  return 0.0f; // Default
+}
+
+float Actor::Relayouter::CalculateChildSize(Actor& actor, const Actor& child, Dimension::Type dimension)
+{
+  // Fill to parent, taking size mode factor into account
+  switch(child.GetResizePolicy(dimension))
+  {
+    case ResizePolicy::FILL_TO_PARENT:
+    {
+      return actor.GetLatestSize(dimension);
+    }
+
+    case ResizePolicy::SIZE_RELATIVE_TO_PARENT:
+    {
+      Property::Value value               = child.GetProperty(Dali::Actor::Property::SIZE_MODE_FACTOR);
+      Vector3         childSizeModeFactor = value.Get<Vector3>();
+      return actor.GetLatestSize(dimension) * GetDimensionValue(childSizeModeFactor, dimension);
+    }
+
+    case ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT:
+    {
+      Property::Value value               = child.GetProperty(Dali::Actor::Property::SIZE_MODE_FACTOR);
+      Vector3         childSizeModeFactor = value.Get<Vector3>();
+      return actor.GetLatestSize(dimension) + GetDimensionValue(childSizeModeFactor, dimension);
+    }
+
+    default:
     {
-      container.Add( Dali::Actor( child.Get() ), actor.mTargetSize.GetVectorXY() );
+      return actor.GetLatestSize(dimension);
     }
   }
-  DALI_LOG_TIMER_END( NegSizeTimer1, gLogRelayoutFilter, Debug::Concise, "NegotiateSize() took: ");
 }
 
 } // namespace Internal