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