Merge branch 'devel/master' into devel/new_mesh
[platform/core/uifw/dali-core.git] / dali / internal / event / size-negotiation / relayout-controller-impl.cpp
1 /*
2  * Copyright (c) 2014 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 // FILE HEADER
19
20 #include "relayout-controller-impl.h"
21
22 // EXTERNAL INCLUDES
23 #if defined(DEBUG_ENABLED)
24 #include <sstream>
25 #include <dali/internal/event/common/system-overlay-impl.h>
26 #endif // defined(DEBUG_ENABLED)
27
28 // INTERNAL INCLUDES
29 #include <dali/public-api/actors/layer.h>
30 #include <dali/public-api/common/stage.h>
31 #include <dali/integration-api/debug.h>
32 #include <dali/integration-api/render-controller.h>
33 #include <dali/public-api/object/type-registry.h>
34 #include <dali/public-api/object/object-registry.h>
35 #include <dali/internal/event/actors/actor-impl.h>
36 #include <dali/internal/event/common/thread-local-storage.h>
37
38 namespace Dali
39 {
40
41 namespace Internal
42 {
43
44 namespace
45 {
46 #if defined(DEBUG_ENABLED)
47
48 Integration::Log::Filter* gLogFilter( Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_RELAYOUT_CONTROLLER") );
49
50 /**
51  * Prints out all the children of the given actor when debug is enabled.
52  *
53  * @param[in]  actor  The actor whose children to print.
54  * @param[in]  level  The number of " | " to put in front of the children.
55  */
56 void PrintChildren( Dali::Actor actor, int level )
57 {
58   std::ostringstream output;
59
60   for ( int t = 0; t < level; ++t )
61   {
62     output << " | ";
63   }
64
65   output << actor.GetTypeName();
66
67   output << ", " << actor.GetName();
68
69   output << " - Pos: " << actor.GetCurrentPosition() << " Size: " << actor.GetTargetSize();
70
71   output << ", Dirty: (" << ( GetImplementation( actor ).IsLayoutDirty( Dimension::WIDTH ) ? "TRUE" : "FALSE" ) << "," << ( GetImplementation( actor ).IsLayoutDirty( Dimension::HEIGHT ) ? "TRUE" : "FALSE" ) << ")";
72   output << ", Negotiated: (" << ( GetImplementation( actor ).IsLayoutNegotiated( Dimension::WIDTH ) ? "TRUE" : "FALSE" ) << "," << ( GetImplementation( actor ).IsLayoutNegotiated( Dimension::HEIGHT ) ? "TRUE" : "FALSE" ) << ")";
73   output << ", Enabled: " << ( GetImplementation( actor ).IsRelayoutEnabled() ? "TRUE" : "FALSE" );
74
75   output << ", (" << actor.GetObjectPtr() << ")" << std::endl;
76
77   DALI_LOG_INFO( gLogFilter, Debug::Verbose, output.str().c_str() );
78
79   ++level;
80   unsigned int numChildren = actor.GetChildCount();
81   for( unsigned int i=0; i<numChildren; ++i )
82   {
83     PrintChildren( actor.GetChildAt(i), level );
84   }
85   --level;
86 }
87
88 /**
89  * Prints the entire hierarchy of the scene.
90  */
91 void PrintHierarchy()
92 {
93   if ( gLogFilter->IsEnabledFor( Debug::Verbose ) )
94   {
95     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "---------- ROOT LAYER ----------\n" );
96     PrintChildren( Dali::Stage().GetCurrent().GetRootLayer(), 0 );
97   }
98 }
99
100 #define PRINT_HIERARCHY PrintHierarchy()
101
102 #else // defined(DEBUG_ENABLED)
103
104 #define PRINT_HIERARCHY
105
106 #endif // defined(DEBUG_ENABLED)
107
108 } // unnamed namespace
109
110 RelayoutController* RelayoutController::Get()
111 {
112   return &ThreadLocalStorage::Get().GetRelayoutController();
113 }
114
115 RelayoutController::RelayoutController( Integration::RenderController& controller )
116 : mRenderController( controller ),
117   mRelayoutInfoAllocator(),
118   mSlotDelegate( this ),
119   mRelayoutStack( new MemoryPoolRelayoutContainer( mRelayoutInfoAllocator ) ),
120   mRelayoutConnection( false ),
121   mRelayoutFlag( false ),
122   mEnabled( false ),
123   mPerformingRelayout( false ),
124   mProcessingCoreEvents( false )
125 {
126   // Make space for 32 controls to avoid having to copy construct a lot in the beginning
127   mRelayoutStack->Reserve( 32 );
128 }
129
130 RelayoutController::~RelayoutController()
131 {
132   delete mRelayoutStack;
133 }
134
135 void RelayoutController::QueueActor( Dali::Actor& actor, RelayoutContainer& actors, Vector2 size )
136 {
137   if( GetImplementation( actor ).RelayoutRequired() )
138   {
139     actors.Add( actor, size );
140   }
141 }
142
143 void RelayoutController::RequestRelayout( Dali::Actor& actor, Dimension::Type dimension )
144 {
145   if( !mEnabled )
146   {
147     return;
148   }
149
150   std::vector< Dali::Actor > potentialRedundantSubRoots;
151   std::vector< Dali::Actor > topOfSubTreeStack;
152
153   topOfSubTreeStack.push_back( actor );
154
155   // Propagate on all dimensions
156   for( unsigned int i = 0; i < Dimension::DIMENSION_COUNT; ++i )
157   {
158     if( dimension & ( 1 << i ) )
159     {
160       // Do the propagation
161       PropagateAll( actor, static_cast< Dimension::Type >( 1 << i ), topOfSubTreeStack, potentialRedundantSubRoots );
162     }
163   }
164
165   while( !topOfSubTreeStack.empty() )
166   {
167     // Request this actor as head of sub-tree if it is not dependent on a parent that is dirty
168     Dali::Actor subTreeActor = topOfSubTreeStack.back();
169     topOfSubTreeStack.pop_back();
170
171     Dali::Actor parent = subTreeActor.GetParent();
172     if( !parent || !( GetImplementation( subTreeActor ).RelayoutDependentOnParent() && GetImplementation( parent ).RelayoutRequired() ) )
173     {
174       // Add sub tree root to relayout list
175       AddRequest( subTreeActor );
176
177       // Flag request for end of frame
178       Request();
179     }
180     else
181     {
182       potentialRedundantSubRoots.push_back( subTreeActor );
183     }
184   }
185
186   // Remove any redundant sub-tree heads
187   for( std::vector< Dali::Actor >::iterator it = potentialRedundantSubRoots.begin(), itEnd = potentialRedundantSubRoots.end(); it != itEnd; ++it )
188   {
189     Dali::Actor subRoot = *it;
190
191     RemoveRequest( subRoot );
192   }
193
194   if ( !mProcessingCoreEvents )
195   {
196     mRenderController.RequestProcessEventsOnIdle();
197   }
198 }
199
200 void RelayoutController::OnApplicationSceneCreated()
201 {
202   DALI_LOG_INFO( gLogFilter, Debug::General, "[Internal::RelayoutController::OnApplicationSceneCreated]\n" );
203
204   // Open relayout controller to receive relayout requests
205   mEnabled = true;
206
207   // Spread the dirty flag through whole tree - don't need to explicity
208   // add request on rootLayer as it will automatically be added below.
209   Dali::Actor rootLayer = Dali::Stage::GetCurrent().GetRootLayer();
210   RequestRelayoutTree( rootLayer );
211
212   // Flag request for end of frame
213   Request();
214 }
215
216 void RelayoutController::RequestRelayoutTree( Dali::Actor& actor )
217 {
218   if( !mEnabled )
219   {
220     return;
221   }
222
223   // Only set dirty flag if doing relayout and not already marked as dirty
224   Actor& actorImpl = GetImplementation( actor );
225   if( actorImpl.RelayoutPossible() )
226   {
227     // If parent is not in relayout we are at the top of a new sub-tree
228     Dali::Actor parent = actor.GetParent();
229     if( !parent || !GetImplementation( parent ).IsRelayoutEnabled() )
230     {
231       AddRequest( actor );
232     }
233
234     // Set dirty flag on actors that are enabled
235     actorImpl.SetLayoutDirty( true );
236     actorImpl.SetLayoutNegotiated( false );    // Reset this flag ready for next relayout
237   }
238
239   // Propagate down to children
240   for( unsigned int i = 0; i < actor.GetChildCount(); ++i )
241   {
242     Dali::Actor child = actor.GetChildAt( i );
243
244     RequestRelayoutTree( child );
245   }
246 }
247
248 void RelayoutController::PropagateAll( Dali::Actor& actor, Dimension::Type dimension, std::vector< Dali::Actor >& topOfSubTreeStack, std::vector< Dali::Actor >& potentialRedundantSubRoots )
249 {
250   // Only set dirty flag if doing relayout and not already marked as dirty
251   Actor& actorImpl = GetImplementation( actor );
252   if( actorImpl.RelayoutPossible( dimension ) )
253   {
254     // Set dirty and negotiated flags
255     actorImpl.SetLayoutDirty( true, dimension );
256     actorImpl.SetLayoutNegotiated( false, dimension );    // Reset this flag ready for next relayout
257
258     // Check for dimension dependecy: width for height/height for width etc
259     // Check each possible dimension and see if it is dependent on the input one
260     for( unsigned int i = 0; i < Dimension::DIMENSION_COUNT; ++i )
261     {
262       Dimension::Type dimensionToCheck = static_cast< Dimension::Type >( 1 << i );
263
264       if( actorImpl.RelayoutDependentOnDimension( dimension, dimensionToCheck ) &&
265           !actorImpl.IsLayoutDirty( dimensionToCheck ) )
266       {
267         PropagateAll( actor, dimensionToCheck, topOfSubTreeStack, potentialRedundantSubRoots );
268       }
269     }
270
271     // Propagate up to parent
272     Dali::Actor parent = actor.GetParent();
273     if( parent )
274     {
275       Actor& parentImpl = GetImplementation( parent );
276       if( parentImpl.RelayoutDependentOnChildren( dimension ) && !parentImpl.IsLayoutDirty( dimension ) )
277       {
278         // Store the highest parent reached
279         bool found = false;
280         for( unsigned int i = 0, count = topOfSubTreeStack.size(); i < count; ++i )
281         {
282           if( topOfSubTreeStack[ i ] == parent )
283           {
284             found = true;
285             break;
286           }
287         }
288
289         if( !found )
290         {
291           topOfSubTreeStack.push_back( parent );
292         }
293
294         // Propagate up
295         PropagateAll( parent, dimension, topOfSubTreeStack, potentialRedundantSubRoots );
296       }
297     }
298
299     // Propagate down to children
300     for( unsigned int i = 0, childCount = actor.GetChildCount(); i < childCount; ++i )
301     {
302       Dali::Actor child = actor.GetChildAt( i );
303       Actor& childImpl = GetImplementation( child );
304
305       if( childImpl.IsRelayoutEnabled() && childImpl.RelayoutDependentOnParent( dimension ) )
306       {
307         if( childImpl.IsLayoutDirty( dimension ) )
308         {
309           // We have found a child that could potentially have already been collected for relayout
310           potentialRedundantSubRoots.push_back( child );
311         }
312         else
313         {
314           PropagateAll( child, dimension, topOfSubTreeStack, potentialRedundantSubRoots );
315         }
316       }
317     }
318   }
319 }
320
321
322 void RelayoutController::PropagateFlags( Dali::Actor& actor, Dimension::Type dimension )
323 {
324   // Only set dirty flag if doing relayout and not already marked as dirty
325   Actor& actorImpl = GetImplementation( actor );
326   if( actorImpl.IsRelayoutEnabled() )
327   {
328     // Set dirty and negotiated flags
329     actorImpl.SetLayoutDirty( true, dimension );
330     actorImpl.SetLayoutNegotiated( false, dimension );    // Reset this flag ready for next relayout
331
332     // Check for dimension dependecy: width for height/height for width etc
333     // Check each possible dimension and see if it is dependent on the input one
334     for( unsigned int i = 0; i < Dimension::DIMENSION_COUNT; ++i )
335     {
336       Dimension::Type dimensionToCheck = static_cast< Dimension::Type >( 1 << i );
337
338       if( actorImpl.RelayoutDependentOnDimension( dimension, dimensionToCheck ) )
339       {
340         PropagateFlags( actor, dimensionToCheck );
341       }
342     }
343
344     // Propagate up to parent
345     Dali::Actor parent = actor.GetParent();
346     if( parent )
347     {
348       Actor& parentImpl = GetImplementation( parent );
349       if( parentImpl.RelayoutDependentOnChildren( dimension ) )
350       {
351         // Propagate up
352         PropagateFlags( parent, dimension );
353       }
354     }
355
356     // Propagate down to children
357     for( unsigned int i = 0, childCount = actor.GetChildCount(); i < childCount; ++i )
358     {
359       Dali::Actor child = actor.GetChildAt( i );
360       Actor& childImpl = GetImplementation( child );
361
362       if( childImpl.RelayoutDependentOnParent( dimension ) )
363       {
364         PropagateFlags( child, dimension );
365       }
366     }
367   }
368 }
369
370 void RelayoutController::AddRequest( Dali::Actor& actor )
371 {
372   BaseObject* actorPtr = &GetImplementation( actor );
373
374   // Only add the rootActor if it is not already recorded
375   bool found = false;
376   for( unsigned int i = 0, count = mDirtyLayoutSubTrees.Size(); i < count; ++i )
377   {
378     if( mDirtyLayoutSubTrees[ i ] == actorPtr )
379     {
380       found = true;
381       break;
382     }
383   }
384
385   if( !found )
386   {
387     mDirtyLayoutSubTrees.PushBack( actorPtr );
388   }
389 }
390
391 void RelayoutController::RemoveRequest( Dali::Actor& actor )
392 {
393   BaseObject* actorPtr = &GetImplementation( actor );
394
395   // Remove actor from dirty sub trees
396   for( RawActorList::Iterator it = mDirtyLayoutSubTrees.Begin(), itEnd = mDirtyLayoutSubTrees.End(); it != itEnd; ++it )
397   {
398     if( *it == actorPtr )
399     {
400       mDirtyLayoutSubTrees.Erase( it );
401       break;
402     }
403   }
404 }
405
406 void RelayoutController::Request()
407 {
408   mRelayoutFlag = true;
409
410   if( !mRelayoutConnection )
411   {
412     Dali::Stage stage = Dali::Stage::GetCurrent();
413     stage.GetObjectRegistry().ObjectDestroyedSignal().Connect( mSlotDelegate, &RelayoutController::OnObjectDestroyed );
414
415     mRelayoutConnection = true;
416   }
417 }
418
419 void RelayoutController::OnObjectDestroyed( const Dali::RefObject* object )
420 {
421   // Search for and null the object if found in the following lists
422   FindAndZero( mDirtyLayoutSubTrees, object );
423 }
424
425 void RelayoutController::Relayout()
426 {
427   // Only do something when requested
428   if( mRelayoutFlag )
429   {
430     mPerformingRelayout = true;
431
432     // Clear the flag as we're now doing the relayout
433     mRelayoutFlag = false;
434
435     // 1. Finds all top-level controls from the dirty list and allocate them the size of the stage
436     //    These controls are paired with the parent/stage size and added to the stack.
437     const Vector2 stageSize = Dali::Stage::GetCurrent().GetSize();
438
439     for( RawActorList::Iterator it = mDirtyLayoutSubTrees.Begin(), itEnd = mDirtyLayoutSubTrees.End(); it != itEnd; ++it )
440     {
441       BaseObject* dirtyActor = *it;
442
443       // Need to test if actor is valid (could have been deleted and had the pointer cleared)
444       if( dirtyActor )
445       {
446         // We know that BaseObject is a base class of Internal::Actor but need to instruct the compiler to do the cast
447         Dali::Actor actor = Dali::Actor( reinterpret_cast<Dali::Internal::Actor*>( dirtyActor ) );
448
449         // Only negotiate actors that are on stage
450         if( actor.OnStage() )
451         {
452           Dali::Actor parent = actor.GetParent();
453           QueueActor( actor, *mRelayoutStack, ( parent ) ? Vector2( parent.GetTargetSize() ) : stageSize );
454         }
455       }
456     }
457
458     mDirtyLayoutSubTrees.Clear();
459
460     // 2. Iterate through the stack until it's empty.
461     if( mRelayoutStack->Size() > 0 )
462     {
463       PRINT_HIERARCHY;
464
465       while( mRelayoutStack->Size() > 0 )
466       {
467         Dali::Actor actor;
468         Vector2 size;
469         mRelayoutStack->Get( mRelayoutStack->Size() - 1, actor, size );
470         Actor& actorImpl = GetImplementation( actor );
471         mRelayoutStack->PopBack();
472
473         if( actorImpl.RelayoutRequired() )
474         {
475           DALI_LOG_INFO( gLogFilter, Debug::General, "[Internal::RelayoutController::Relayout] Negotiating %p %s %s (%.2f, %.2f)\n", &actorImpl, actor.GetTypeName().c_str(), actor.GetName().c_str(), size.width, size.height );
476
477           // 3. Negotiate the size with the current actor. Pass it an empty container which the actor
478           //    has to fill with all the actors it has not done any size negotiation for.
479           actorImpl.NegotiateSize( size, *mRelayoutStack );
480         }
481       }
482
483       // We are done with the RelayoutInfos now so delete the pool
484       mRelayoutInfoAllocator.ResetMemoryPool();
485
486       PRINT_HIERARCHY;
487     }
488
489     mPerformingRelayout = false;
490   }
491   // should not disconnect the signal as that causes some control size negotiations to not work correctly
492   // this algorithm needs more optimization as well
493 }
494
495 void RelayoutController::SetEnabled( bool enabled )
496 {
497   mEnabled = enabled;
498 }
499
500 bool RelayoutController::IsPerformingRelayout() const
501 {
502   return mPerformingRelayout;
503 }
504
505 void RelayoutController::SetProcessingCoreEvents( bool processingEvents )
506 {
507   mProcessingCoreEvents = processingEvents;
508 }
509
510 void RelayoutController::FindAndZero( const RawActorList& list, const Dali::RefObject* object )
511 {
512   // Object has been destroyed so clear it from this list
513   for( RawActorList::Iterator it = list.Begin(), itEnd = list.End(); it != itEnd; ++it )
514   {
515     BaseObject* actor = *it;
516
517     if( actor && ( actor == object ) )
518     {
519       *it = NULL;    // Reset the pointer in the list. We don't want to remove it in case something is iterating over the list.
520     }
521   }
522 }
523
524 } // namespace Internal
525
526 } // namespace Dali