f8e57d1ccf7ec16ada83c25e36008cb3a6ac0600
[platform/core/uifw/dali-core.git] / dali / internal / event / actors / actor-relayouter.cpp
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/event/actors/actor-relayouter.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23 #include <dali/public-api/actors/actor.h>
24 #include <dali/public-api/math/vector2.h>
25 #include <dali/public-api/math/vector3.h>
26
27 #include <dali/internal/event/size-negotiation/relayout-controller-impl.h>
28
29 namespace
30 {
31 #if defined(DEBUG_ENABLED)
32 Debug::Filter* gLogRelayoutFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_RELAYOUT_TIMER");
33 #endif
34
35 /**
36  * @brief Extract a given dimension from a Vector2
37  *
38  * @param[in] values The values to extract from
39  * @param[in] dimension The dimension to extract
40  * @return Return the value for the dimension
41  */
42 constexpr float GetDimensionValue(const Dali::Vector2& values, const Dali::Dimension::Type dimension)
43 {
44   switch(dimension)
45   {
46     case Dali::Dimension::WIDTH:
47     {
48       return values.width;
49     }
50     case Dali::Dimension::HEIGHT:
51     {
52       return values.height;
53     }
54     default:
55     {
56       break;
57     }
58   }
59   return 0.0f;
60 }
61
62 } // unnamed namespace
63
64 namespace Dali
65 {
66 namespace Internal
67 {
68 Actor::Relayouter::Relayouter()
69 : sizeModeFactor(DEFAULT_SIZE_MODE_FACTOR),
70   preferredSize(DEFAULT_PREFERRED_SIZE),
71   sizeSetPolicy(DEFAULT_SIZE_SCALE_POLICY),
72   relayoutEnabled(false),
73   insideRelayout(false),
74   relayoutRequested(false)
75 {
76   // Set size negotiation defaults
77   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
78   {
79     resizePolicies[i]        = ResizePolicy::DEFAULT;
80     useAssignedSize[i]       = false;
81     negotiatedDimensions[i]  = 0.0f;
82     dimensionNegotiated[i]   = false;
83     dimensionDirty[i]        = false;
84     dimensionDependencies[i] = Dimension::ALL_DIMENSIONS;
85     dimensionPadding[i]      = DEFAULT_DIMENSION_PADDING;
86     minimumSize[i]           = 0.0f;
87     maximumSize[i]           = FLT_MAX;
88   }
89 }
90
91 ResizePolicy::Type Actor::Relayouter::GetResizePolicy(Dimension::Type dimension) const
92 {
93   // If more than one dimension is requested, just return the first one found
94   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
95   {
96     if((dimension & (1 << i)))
97     {
98       if(useAssignedSize[i])
99       {
100         return ResizePolicy::USE_ASSIGNED_SIZE;
101       }
102       else
103       {
104         return resizePolicies[i];
105       }
106     }
107   }
108
109   return ResizePolicy::DEFAULT;
110 }
111
112 void Actor::Relayouter::SetPadding(const Vector2& padding, Dimension::Type dimension)
113 {
114   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
115   {
116     if(dimension & (1 << i))
117     {
118       dimensionPadding[i] = padding;
119     }
120   }
121 }
122
123 Vector2 Actor::Relayouter::GetPadding(Dimension::Type dimension)
124 {
125   // If more than one dimension is requested, just return the first one found
126   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
127   {
128     if((dimension & (1 << i)))
129     {
130       return dimensionPadding[i];
131     }
132   }
133
134   return DEFAULT_DIMENSION_PADDING;
135 }
136
137 void Actor::Relayouter::SetLayoutNegotiated(bool negotiated, Dimension::Type dimension)
138 {
139   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
140   {
141     if(dimension & (1 << i))
142     {
143       dimensionNegotiated[i] = negotiated;
144     }
145   }
146 }
147
148 bool Actor::Relayouter::IsLayoutNegotiated(Dimension::Type dimension) const
149 {
150   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
151   {
152     if((dimension & (1 << i)) && dimensionNegotiated[i])
153     {
154       return true;
155     }
156   }
157   return false;
158 }
159
160 Vector2 Actor::Relayouter::ApplySizeSetPolicy(Internal::Actor& actor, const Vector2& size)
161 {
162   switch(sizeSetPolicy)
163   {
164     case SizeScalePolicy::USE_SIZE_SET:
165     {
166       return size;
167     }
168
169     case SizeScalePolicy::FIT_WITH_ASPECT_RATIO:
170     {
171       // Scale size to fit within the original size bounds, keeping the natural size aspect ratio
172       const Vector3 naturalSize = actor.GetNaturalSize();
173       if(naturalSize.width > 0.0f && naturalSize.height > 0.0f && size.width > 0.0f && size.height > 0.0f)
174       {
175         const float sizeRatio        = size.width / size.height;
176         const float naturalSizeRatio = naturalSize.width / naturalSize.height;
177
178         if(naturalSizeRatio < sizeRatio)
179         {
180           return Vector2(naturalSizeRatio * size.height, size.height);
181         }
182         else if(naturalSizeRatio > sizeRatio)
183         {
184           return Vector2(size.width, size.width / naturalSizeRatio);
185         }
186         else
187         {
188           return size;
189         }
190       }
191
192       break;
193     }
194
195     case SizeScalePolicy::FILL_WITH_ASPECT_RATIO:
196     {
197       // Scale size to fill the original size bounds, keeping the natural size aspect ratio. Potentially exceeding the original bounds.
198       const Vector3 naturalSize = actor.GetNaturalSize();
199       if(naturalSize.width > 0.0f && naturalSize.height > 0.0f && size.width > 0.0f && size.height > 0.0f)
200       {
201         const float sizeRatio        = size.width / size.height;
202         const float naturalSizeRatio = naturalSize.width / naturalSize.height;
203
204         if(naturalSizeRatio < sizeRatio)
205         {
206           return Vector2(size.width, size.width / naturalSizeRatio);
207         }
208         else if(naturalSizeRatio > sizeRatio)
209         {
210           return Vector2(naturalSizeRatio * size.height, size.height);
211         }
212         else
213         {
214           return size;
215         }
216       }
217       break;
218     }
219
220     default:
221     {
222       break;
223     }
224   }
225
226   return size;
227 }
228
229 void Actor::Relayouter::SetUseAssignedSize(bool use, Dimension::Type dimension)
230 {
231   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
232   {
233     if(dimension & (1 << i))
234     {
235       useAssignedSize[i] = use;
236     }
237   }
238 }
239
240 bool Actor::Relayouter::GetUseAssignedSize(Dimension::Type dimension) const
241 {
242   // If more than one dimension is requested, just return the first one found
243   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
244   {
245     if(dimension & (1 << i))
246     {
247       return useAssignedSize[i];
248     }
249   }
250
251   return false;
252 }
253
254 void Actor::Relayouter::SetMinimumSize(float size, Dimension::Type dimension)
255 {
256   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
257   {
258     if(dimension & (1 << i))
259     {
260       minimumSize[i] = size;
261     }
262   }
263 }
264
265 float Actor::Relayouter::GetMinimumSize(Dimension::Type dimension) const
266 {
267   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
268   {
269     if(dimension & (1 << i))
270     {
271       return minimumSize[i];
272     }
273   }
274
275   return 0.0f; // Default
276 }
277
278 void Actor::Relayouter::SetMaximumSize(float size, Dimension::Type dimension)
279 {
280   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
281   {
282     if(dimension & (1 << i))
283     {
284       maximumSize[i] = size;
285     }
286   }
287 }
288
289 float Actor::Relayouter::GetMaximumSize(Dimension::Type dimension) const
290 {
291   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
292   {
293     if(dimension & (1 << i))
294     {
295       return maximumSize[i];
296     }
297   }
298
299   return FLT_MAX; // Default
300 }
301
302 void Actor::Relayouter::SetResizePolicy(ResizePolicy::Type policy, Dimension::Type dimension, Vector3& targetSize)
303 {
304   ResizePolicy::Type originalWidthPolicy  = GetResizePolicy(Dimension::WIDTH);
305   ResizePolicy::Type originalHeightPolicy = GetResizePolicy(Dimension::HEIGHT);
306
307   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
308   {
309     if(dimension & (1 << i))
310     {
311       if(policy == ResizePolicy::USE_ASSIGNED_SIZE)
312       {
313         useAssignedSize[i] = true;
314       }
315       else
316       {
317         resizePolicies[i]  = policy;
318         useAssignedSize[i] = false;
319       }
320     }
321   }
322
323   if(policy == ResizePolicy::DIMENSION_DEPENDENCY)
324   {
325     if(dimension & Dimension::WIDTH)
326     {
327       SetDimensionDependency(Dimension::WIDTH, Dimension::HEIGHT);
328     }
329
330     if(dimension & Dimension::HEIGHT)
331     {
332       SetDimensionDependency(Dimension::HEIGHT, Dimension::WIDTH);
333     }
334   }
335
336   // If calling SetResizePolicy, assume we want relayout enabled
337   relayoutEnabled = true;
338
339   // If the resize policy is set to be FIXED, the preferred size
340   // should be overrided by the target size. Otherwise the target
341   // size should be overrided by the preferred size.
342
343   if(dimension & Dimension::WIDTH)
344   {
345     if(originalWidthPolicy != ResizePolicy::FIXED && policy == ResizePolicy::FIXED)
346     {
347       preferredSize.width = targetSize.width;
348     }
349     else if(originalWidthPolicy == ResizePolicy::FIXED && policy != ResizePolicy::FIXED)
350     {
351       targetSize.width = preferredSize.width;
352     }
353   }
354
355   if(dimension & Dimension::HEIGHT)
356   {
357     if(originalHeightPolicy != ResizePolicy::FIXED && policy == ResizePolicy::FIXED)
358     {
359       preferredSize.height = targetSize.height;
360     }
361     else if(originalHeightPolicy == ResizePolicy::FIXED && policy != ResizePolicy::FIXED)
362     {
363       targetSize.height = preferredSize.height;
364     }
365   }
366 }
367
368 bool Actor::Relayouter::GetRelayoutDependentOnParent(Dimension::Type dimension)
369 {
370   // Check if actor is dependent on parent
371   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
372   {
373     if((dimension & (1 << i)))
374     {
375       const ResizePolicy::Type resizePolicy = GetResizePolicy(static_cast<Dimension::Type>(1 << i));
376       if(resizePolicy == ResizePolicy::FILL_TO_PARENT || resizePolicy == ResizePolicy::SIZE_RELATIVE_TO_PARENT || resizePolicy == ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT)
377       {
378         return true;
379       }
380     }
381   }
382   return false;
383 }
384
385 bool Actor::Relayouter::GetRelayoutDependentOnChildren(Dimension::Type dimension)
386 {
387   // Check if actor is dependent on children
388   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
389   {
390     if((dimension & (1 << i)))
391     {
392       const ResizePolicy::Type resizePolicy = GetResizePolicy(static_cast<Dimension::Type>(1 << i));
393       if(resizePolicy == ResizePolicy::FIT_TO_CHILDREN || resizePolicy == ResizePolicy::USE_NATURAL_SIZE)
394       {
395         return true;
396       }
397       break;
398     }
399   }
400
401   return false;
402 }
403
404 bool Actor::Relayouter::GetRelayoutDependentOnDimension(Dimension::Type dimension, Dimension::Type dependency)
405 {
406   // Check each possible dimension and see if it is dependent on the input one
407   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
408   {
409     if(dimension & (1 << i))
410     {
411       return resizePolicies[i] == ResizePolicy::DIMENSION_DEPENDENCY && dimensionDependencies[i] == dependency;
412     }
413   }
414
415   return false;
416 }
417
418 void Actor::Relayouter::SetDimensionDependency(Dimension::Type dimension, Dimension::Type dependency)
419 {
420   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
421   {
422     if(dimension & (1 << i))
423     {
424       dimensionDependencies[i] = dependency;
425     }
426   }
427 }
428
429 Dimension::Type Actor::Relayouter::GetDimensionDependency(Dimension::Type dimension) const
430 {
431   // If more than one dimension is requested, just return the first one found
432   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
433   {
434     if((dimension & (1 << i)))
435     {
436       return dimensionDependencies[i];
437     }
438   }
439
440   return Dimension::ALL_DIMENSIONS; // Default
441 }
442
443 void Actor::Relayouter::SetLayoutDirty(bool dirty, Dimension::Type dimension)
444 {
445   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
446   {
447     if(dimension & (1 << i))
448     {
449       dimensionDirty[i] = dirty;
450     }
451   }
452 }
453
454 bool Actor::Relayouter::IsLayoutDirty(Dimension::Type dimension) const
455 {
456   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
457   {
458     if((dimension & (1 << i)) && dimensionDirty[i])
459     {
460       return true;
461     }
462   }
463
464   return false;
465 }
466
467 void Actor::Relayouter::SetPreferredSize(Actor& actor, const Vector2& size)
468 {
469   // If valid width or height, then set the resize policy to FIXED
470   // 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,
471   // then change to FIXED as well
472
473   if(size.width > 0.0f || GetResizePolicy(Dimension::WIDTH) == ResizePolicy::DEFAULT)
474   {
475     actor.SetResizePolicy(ResizePolicy::FIXED, Dimension::WIDTH);
476   }
477
478   if(size.height > 0.0f || GetResizePolicy(Dimension::HEIGHT) == ResizePolicy::DEFAULT)
479   {
480     actor.SetResizePolicy(ResizePolicy::FIXED, Dimension::HEIGHT);
481   }
482
483   actor.mRelayoutData->preferredSize = size;
484
485   actor.mUseAnimatedSize = AnimatedSizeFlag::CLEAR;
486
487   actor.RelayoutRequest();
488 }
489
490 float Actor::Relayouter::ClampDimension(const Internal::Actor& actor, float size, Dimension::Type dimension)
491 {
492   const float minSize = actor.GetMinimumSize(dimension);
493   const float maxSize = actor.GetMaximumSize(dimension);
494
495   return std::max(minSize, std::min(size, maxSize));
496 }
497
498 void Actor::Relayouter::SetNegotiatedDimension(float negotiatedDimension, Dimension::Type dimension)
499 {
500   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
501   {
502     if(dimension & (1 << i))
503     {
504       negotiatedDimensions[i] = negotiatedDimension;
505     }
506   }
507 }
508
509 float Actor::Relayouter::GetNegotiatedDimension(Dimension::Type dimension)
510 {
511   // If more than one dimension is requested, just return the first one found
512   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
513   {
514     if((dimension & (1 << i)))
515     {
516       return negotiatedDimensions[i];
517     }
518   }
519
520   return 0.0f; // Default
521 }
522
523 float Actor::Relayouter::NegotiateDimensionFromParent(Actor& actor, Dimension::Type dimension)
524 {
525   Actor* parent = actor.GetParent();
526   if(parent)
527   {
528     Vector2 padding(actor.GetPadding(dimension));
529     Vector2 parentPadding(parent->GetPadding(dimension));
530
531     // Need to use actor API here to allow deriving actors to layout their children
532     return parent->CalculateChildSize(Dali::Actor(&actor), dimension) - parentPadding.x - parentPadding.y - padding.x - padding.y;
533   }
534
535   return 0.0f;
536 }
537
538 float Actor::Relayouter::NegotiateDimensionFromChildren(Actor& actor, Dimension::Type dimension)
539 {
540   float maxDimensionPoint = 0.0f;
541
542   for(uint32_t i = 0, count = actor.GetChildCount(); i < count; ++i)
543   {
544     ActorPtr child = actor.GetChildAt(i);
545
546     if(!child->RelayoutDependentOnParent(dimension))
547     {
548       // Calculate the min and max points that the children range across
549       float childPosition = GetDimensionValue(child->GetTargetPosition(), dimension);
550       float dimensionSize = child->GetRelayoutSize(dimension);
551       maxDimensionPoint   = std::max(maxDimensionPoint, childPosition + dimensionSize);
552     }
553   }
554
555   return maxDimensionPoint;
556 }
557
558 void Actor::Relayouter::NegotiateDimension(Actor& actor, Dimension::Type dimension, const Vector2& allocatedSize, Actor::ActorDimensionStack& recursionStack)
559 {
560   // Check if it needs to be negotiated
561   if(actor.IsLayoutDirty(dimension) && !actor.IsLayoutNegotiated(dimension))
562   {
563     // Check that we havn't gotten into an infinite loop
564     Actor::ActorDimensionPair searchActor    = Actor::ActorDimensionPair(&actor, dimension);
565     bool                      recursionFound = false;
566     for(auto& element : recursionStack)
567     {
568       if(element == searchActor)
569       {
570         recursionFound = true;
571         break;
572       }
573     }
574
575     if(!recursionFound)
576     {
577       // Record the path that we have taken
578       recursionStack.push_back(Actor::ActorDimensionPair(&actor, dimension));
579
580       // Dimension dependency check
581       for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
582       {
583         Dimension::Type dimensionToCheck = static_cast<Dimension::Type>(1 << i);
584
585         if(actor.RelayoutDependentOnDimension(dimension, dimensionToCheck))
586         {
587           NegotiateDimension(actor, dimensionToCheck, allocatedSize, recursionStack);
588         }
589       }
590
591       // Parent dependency check
592       Actor* parent = actor.GetParent();
593       if(parent && actor.RelayoutDependentOnParent(dimension))
594       {
595         NegotiateDimension(*parent, dimension, allocatedSize, recursionStack);
596       }
597
598       // Children dependency check
599       if(actor.RelayoutDependentOnChildren(dimension))
600       {
601         for(uint32_t i = 0, count = actor.GetChildCount(); i < count; ++i)
602         {
603           ActorPtr child = actor.GetChildAt(i);
604
605           // Only relayout child first if it is not dependent on this actor
606           if(!child->RelayoutDependentOnParent(dimension))
607           {
608             NegotiateDimension(*child, dimension, allocatedSize, recursionStack);
609           }
610         }
611       }
612
613       // For deriving classes
614       actor.OnCalculateRelayoutSize(dimension);
615
616       // All dependencies checked, calculate the size and set negotiated flag
617       const float newSize = ClampDimension(actor, actor.CalculateSize(dimension, allocatedSize), dimension);
618
619       actor.SetNegotiatedDimension(newSize, dimension);
620       actor.SetLayoutNegotiated(true, dimension);
621
622       // For deriving classes
623       actor.OnLayoutNegotiated(newSize, dimension);
624
625       // This actor has been successfully processed, pop it off the recursion stack
626       recursionStack.pop_back();
627     }
628     else
629     {
630       // TODO: Break infinite loop
631       actor.SetLayoutNegotiated(true, dimension);
632     }
633   }
634 }
635
636 void Actor::Relayouter::NegotiateDimensions(Actor& actor, const Vector2& allocatedSize)
637 {
638   // Negotiate all dimensions that require it
639   ActorDimensionStack recursionStack;
640
641   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
642   {
643     const Dimension::Type dimension = static_cast<Dimension::Type>(1 << i);
644
645     // Negotiate
646     NegotiateDimension(actor, dimension, allocatedSize, recursionStack);
647   }
648 }
649
650 void Actor::Relayouter::NegotiateSize(Actor& actor, const Vector2& allocatedSize, RelayoutContainer& container)
651 {
652   // Force a size negotiation for actors that has assigned size during relayout
653   // This is required as otherwise the flags that force a relayout will not
654   // necessarilly be set. This will occur if the actor has already been laid out.
655   // The dirty flags are then cleared. Then if the actor is added back into the
656   // relayout container afterwards, the dirty flags would still be clear...
657   // causing a relayout to be skipped. Here we force any actors added to the
658   // container to be relayed out.
659   DALI_LOG_TIMER_START(NegSizeTimer1);
660
661   if(actor.GetUseAssignedSize(Dimension::WIDTH))
662   {
663     actor.SetLayoutNegotiated(false, Dimension::WIDTH);
664   }
665   if(actor.GetUseAssignedSize(Dimension::HEIGHT))
666   {
667     actor.SetLayoutNegotiated(false, Dimension::HEIGHT);
668   }
669
670   // Do the negotiation
671   NegotiateDimensions(actor, allocatedSize);
672
673   // Set the actor size
674   actor.SetNegotiatedSize(container);
675
676   // Negotiate down to children
677   for(uint32_t i = 0, count = actor.GetChildCount(); i < count; ++i)
678   {
679     ActorPtr child = actor.GetChildAt(i);
680
681     // Forces children that have already been laid out to be relayed out
682     // if they have assigned size during relayout.
683     if(child->GetUseAssignedSize(Dimension::WIDTH))
684     {
685       child->SetLayoutNegotiated(false, Dimension::WIDTH);
686       child->SetLayoutDirty(true, Dimension::WIDTH);
687     }
688
689     if(child->GetUseAssignedSize(Dimension::HEIGHT))
690     {
691       child->SetLayoutNegotiated(false, Dimension::HEIGHT);
692       child->SetLayoutDirty(true, Dimension::HEIGHT);
693     }
694
695     // Only relayout if required
696     if(child->RelayoutRequired())
697     {
698       container.Add(Dali::Actor(child.Get()), actor.mTargetSize.GetVectorXY());
699     }
700   }
701   DALI_LOG_TIMER_END(NegSizeTimer1, gLogRelayoutFilter, Debug::Concise, "NegotiateSize() took: ");
702 }
703
704 /**
705  * @brief Extract a given dimension from a Vector3
706  *
707  * @param[in] values The values to extract from
708  * @param[in] dimension The dimension to extract
709  * @return Return the value for the dimension
710  */
711 float Actor::Relayouter::GetDimensionValue(const Vector3& values, const Dimension::Type dimension)
712 {
713   return ::GetDimensionValue(values.GetVectorXY(), dimension);
714 }
715
716 float Actor::Relayouter::CalculateSize(Actor& actor, Dimension::Type dimension, const Vector2& maximumSize)
717 {
718   switch(actor.GetResizePolicy(dimension))
719   {
720     case ResizePolicy::USE_NATURAL_SIZE:
721     {
722       return actor.GetNaturalSize(dimension);
723     }
724
725     case ResizePolicy::FIXED:
726     {
727       return ::GetDimensionValue(actor.GetPreferredSize(), dimension);
728     }
729
730     case ResizePolicy::USE_ASSIGNED_SIZE:
731     {
732       return ::GetDimensionValue(maximumSize, dimension);
733     }
734
735     case ResizePolicy::FILL_TO_PARENT:
736     case ResizePolicy::SIZE_RELATIVE_TO_PARENT:
737     case ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT:
738     {
739       return NegotiateDimensionFromParent(actor, dimension);
740     }
741
742     case ResizePolicy::FIT_TO_CHILDREN:
743     {
744       return NegotiateDimensionFromChildren(actor, dimension);
745     }
746
747     case ResizePolicy::DIMENSION_DEPENDENCY:
748     {
749       const Dimension::Type dimensionDependency = actor.GetDimensionDependency(dimension);
750
751       // Custom rules
752       if(dimension == Dimension::WIDTH && dimensionDependency == Dimension::HEIGHT)
753       {
754         return actor.GetWidthForHeight(actor.GetNegotiatedDimension(Dimension::HEIGHT));
755       }
756
757       if(dimension == Dimension::HEIGHT && dimensionDependency == Dimension::WIDTH)
758       {
759         return actor.GetHeightForWidth(actor.GetNegotiatedDimension(Dimension::WIDTH));
760       }
761
762       break;
763     }
764
765     default:
766     {
767       break;
768     }
769   }
770
771   return 0.0f; // Default
772 }
773
774 float Actor::Relayouter::CalculateChildSize(Actor& actor, const Actor& child, Dimension::Type dimension)
775 {
776   // Fill to parent, taking size mode factor into account
777   switch(child.GetResizePolicy(dimension))
778   {
779     case ResizePolicy::FILL_TO_PARENT:
780     {
781       return actor.GetLatestSize(dimension);
782     }
783
784     case ResizePolicy::SIZE_RELATIVE_TO_PARENT:
785     {
786       Property::Value value               = child.GetProperty(Dali::Actor::Property::SIZE_MODE_FACTOR);
787       Vector3         childSizeModeFactor = value.Get<Vector3>();
788       return actor.GetLatestSize(dimension) * GetDimensionValue(childSizeModeFactor, dimension);
789     }
790
791     case ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT:
792     {
793       Property::Value value               = child.GetProperty(Dali::Actor::Property::SIZE_MODE_FACTOR);
794       Vector3         childSizeModeFactor = value.Get<Vector3>();
795       return actor.GetLatestSize(dimension) + GetDimensionValue(childSizeModeFactor, dimension);
796     }
797
798     default:
799     {
800       return actor.GetLatestSize(dimension);
801     }
802   }
803 }
804
805 } // namespace Internal
806
807 } // namespace Dali