From: Eunki, Hong Date: Thu, 13 Feb 2025 10:12:36 +0000 (+0900) Subject: Reduce IntrusivePtr reference change during PropagateAll X-Git-Tag: accepted/tizen/unified/20250227.050118~6^2~2^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=5429df7d5b2682c8568f5615e016850194adb248;p=platform%2Fcore%2Fuifw%2Fdali-core.git Reduce IntrusivePtr reference change during PropagateAll std::atomic value changeness might gave overhead if we call it very frequencly. To reduce it's overhead, let we use Interal::Actor& instead Actor handle if we can. Note that we cannot remove Dali::Actor handle at RelayoutInfo, since we need to guard case that Actor itself destruct during Relayout callback at application side. Change-Id: I5f058be4706c8c2be77f1677e1f5624f37d50478 Signed-off-by: Eunki, Hong --- diff --git a/dali/internal/event/actors/actor-sizer.cpp b/dali/internal/event/actors/actor-sizer.cpp index cd6116752..be37cc084 100644 --- a/dali/internal/event/actors/actor-sizer.cpp +++ b/dali/internal/event/actors/actor-sizer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Samsung Electronics Co., Ltd. + * Copyright (c) 2025 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. @@ -686,7 +686,7 @@ float ActorSizer::GetMaximumSize(Dimension::Type dimension) const void ActorSizer::OnAnimateSize(Animation& animation, Vector3 targetSize, bool relative) { Vector3 originalTargetSize = mTargetSize; - mTargetSize = targetSize + mTargetSize * float(relative); + mTargetSize = targetSize + mTargetSize * float(relative); if(originalTargetSize != mTargetSize) { mTargetSizeDirtyFlag = true; @@ -708,8 +708,8 @@ void ActorSizer::OnAnimateSize(Animation& animation, Vector3 targetSize, bool re void ActorSizer::OnAnimateWidth(Animation& animation, float width, bool relative) { const float originalWidth = mTargetSize.width; - mTargetSize.width = width + float(relative) * mTargetSize.width; - if(!Equals(originalWidth,mTargetSize.width)) + mTargetSize.width = width + float(relative) * mTargetSize.width; + if(!Equals(originalWidth, mTargetSize.width)) { mTargetSizeDirtyFlag = true; } @@ -728,7 +728,7 @@ void ActorSizer::OnAnimateWidth(Animation& animation, float width, bool relative void ActorSizer::OnAnimateHeight(Animation& animation, float height, bool relative) { const float originalHeight = mTargetSize.height; - mTargetSize.height = height + float(relative) * mTargetSize.height; + mTargetSize.height = height + float(relative) * mTargetSize.height; if(!Equals(originalHeight, mTargetSize.height)) { mTargetSizeDirtyFlag = true; @@ -748,7 +748,7 @@ void ActorSizer::OnAnimateHeight(Animation& animation, float height, bool relati void ActorSizer::OnAnimateDepth(Animation& animation, float depth, bool relative) { const float originalDepth = mTargetSize.depth; - mTargetSize.depth = depth + float(relative) * mTargetSize.depth; + mTargetSize.depth = depth + float(relative) * mTargetSize.depth; if(!Equals(originalDepth, mTargetSize.depth)) { mTargetSizeDirtyFlag = true; diff --git a/dali/internal/event/size-negotiation/memory-pool-relayout-container.cpp b/dali/internal/event/size-negotiation/memory-pool-relayout-container.cpp index 901d5b10a..a1ee16943 100644 --- a/dali/internal/event/size-negotiation/memory-pool-relayout-container.cpp +++ b/dali/internal/event/size-negotiation/memory-pool-relayout-container.cpp @@ -30,56 +30,45 @@ MemoryPoolRelayoutContainer::MemoryPoolRelayoutContainer(MemoryPoolObjectAllocat MemoryPoolRelayoutContainer::~MemoryPoolRelayoutContainer() = default; -bool MemoryPoolRelayoutContainer::Contains(const Dali::Actor& actor) +void MemoryPoolRelayoutContainer::Add(const Dali::Actor& actor, const Vector2& size) { // Store actor into dummy info. // It will be used for check comparision. + // TODO : Can't we remove this handle copying, to avoid useless IntrusivePtr ref count? mDummyRelayoutInfo->actor = actor; - bool ret = (mRelayoutInfos.Find(mDummyRelayoutInfo.get()) != mRelayoutInfos.End()); - - // Reset empty handle for deference. - mDummyRelayoutInfo->actor = Dali::Actor(); - return ret; -} - -void MemoryPoolRelayoutContainer::Add(const Dali::Actor& actor, const Vector2& size) -{ - if(!Contains(actor)) + if(mRelayoutInfos.Find(mDummyRelayoutInfo.get()) == mRelayoutInfos.End()) { void* ptr = mAllocator.AllocateRaw(); RelayoutInfo* info = new(ptr) RelayoutInfo(); - info->actor = actor; - info->size = size; + + info->actor = std::move(mDummyRelayoutInfo->actor); + info->size = size; mRelayoutInfos.PushBack(info); } -} - -void MemoryPoolRelayoutContainer::PopBack() -{ - if(mRelayoutInfos.Count() > 0) + else { - RelayoutInfoContainer::Iterator back = mRelayoutInfos.End(); - back--; - RelayoutInfo* info = *back; - mRelayoutInfos.Erase(back); - - // Need to be destroyed after mRelayoutInfos erased. - mAllocator.Destroy(info); + // Reset empty handle for deference. + mDummyRelayoutInfo->actor = Dali::Actor(); } } -void MemoryPoolRelayoutContainer::GetBack(Dali::Actor& actorOut, Vector2& sizeOut) const +void MemoryPoolRelayoutContainer::PopBack(Dali::Actor& actorOut, Vector2& sizeOut) { - if(mRelayoutInfos.Count() > 0) - { - RelayoutInfoContainer::ConstIterator back = mRelayoutInfos.End(); - back--; - RelayoutInfo* info = *back; - actorOut = info->actor; - sizeOut = info->size; - } + DALI_ASSERT_ALWAYS(mRelayoutInfos.Count() > 0 && "Try to pop from empty relayout container!"); + + RelayoutInfoContainer::ConstIterator back = mRelayoutInfos.End(); + back--; + RelayoutInfo* info = *back; + + mRelayoutInfos.Erase(back); + + actorOut = std::move(info->actor); + sizeOut = std::move(info->size); + + // Need to be destroyed after mRelayoutInfos erased. + mAllocator.Destroy(info); } size_t MemoryPoolRelayoutContainer::Size() const diff --git a/dali/internal/event/size-negotiation/memory-pool-relayout-container.h b/dali/internal/event/size-negotiation/memory-pool-relayout-container.h index 38e760154..f7846d411 100644 --- a/dali/internal/event/size-negotiation/memory-pool-relayout-container.h +++ b/dali/internal/event/size-negotiation/memory-pool-relayout-container.h @@ -2,7 +2,7 @@ #define DALI_INTERNAL_MEMORY_POOL_RELAYOUT_CONTAINER_H /* - * Copyright (c) 2024 Samsung Electronics Co., Ltd. + * Copyright (c) 2025 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. @@ -46,7 +46,7 @@ public: */ struct RelayoutInfo { - Dali::Actor actor; ///< The actor to relayout + Dali::Actor actor; ///< The actor to relayout (Keep reference, to guard destruct case during Relayout) Vector2 size; ///< The desired size of the actor #if defined(LOW_SPEC_MEMORY_MANAGEMENT_ENABLED) struct RelayoutInfoCompareLess @@ -95,17 +95,12 @@ public: void Add(const Dali::Actor& actor, const Vector2& size) override; /** - * @brief Remove information from the container - */ - void PopBack(); - - /** - * @brief Retrieve relayout information for the latest added + * @brief Retrieve relayout information for the latest added, and remove from the container * * @param[out] actorOut Latest added actor * @param[out] sizeOt Latest added size */ - void GetBack(Dali::Actor& actorOut, Vector2& sizeOut) const; + void PopBack(Dali::Actor& actorOut, Vector2& sizeOut); /** * @brief The count of information in the container @@ -124,15 +119,6 @@ public: */ void Clear(); -private: - /** - * @brief Returns if the container contains the actor or not - * - * @param actor The actor to search for - * @return Return if the actor was found or not - */ - bool Contains(const Dali::Actor& actor); - private: #if defined(LOW_SPEC_MEMORY_MANAGEMENT_ENABLED) using RelayoutInfoContainer = Dali::Integration::OrderedSet; diff --git a/dali/internal/event/size-negotiation/relayout-controller-impl.cpp b/dali/internal/event/size-negotiation/relayout-controller-impl.cpp index 094073873..1ca993eb5 100644 --- a/dali/internal/event/size-negotiation/relayout-controller-impl.cpp +++ b/dali/internal/event/size-negotiation/relayout-controller-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Samsung Electronics Co., Ltd. + * Copyright (c) 2025 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. @@ -138,12 +138,11 @@ RelayoutController* RelayoutController::Get() return nullptr; } -void RelayoutController::QueueActor(Internal::Actor* actor, RelayoutContainer& actors, Vector2 size) +void RelayoutController::QueueActor(Internal::Actor& actorImpl, RelayoutContainer& actors, Vector2 size) { - if(actor && actor->RelayoutRequired()) + if(actorImpl.RelayoutRequired()) { - Dali::Actor actorHandle = Dali::Actor(actor); - actors.Add(actorHandle, size); + actors.Add(Dali::Actor(&actorImpl), size); } } @@ -154,49 +153,53 @@ void RelayoutController::RequestRelayout(Dali::Actor& actor, Dimension::Type dim return; } - std::vector& potentialRedundantSubRoots = mPotentialRedundantSubRoots; - std::vector& topOfSubTreeStack = mTopOfSubTreeStack; + RawActorList& potentialRedundantSubRoots = mPotentialRedundantSubRoots; + RawActorList& topOfSubTreeStack = mTopOfSubTreeStack; DALI_ASSERT_ALWAYS(potentialRedundantSubRoots.empty() && "potentialRedundantSubRoots must be empty before RequestRelayout!"); DALI_ASSERT_ALWAYS(topOfSubTreeStack.empty() && "topOfSubTreeStack must be empty before RequestRelayout!"); - topOfSubTreeStack.push_back(actor); - - // Propagate on all dimensions - for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i) { - if(dimension & (1 << i)) + Dali::Internal::Actor& actorImpl = GetImplementation(actor); + + topOfSubTreeStack.push_back(&actorImpl); + + // Propagate on all dimensions + for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i) { - // Do the propagation - PropagateAll(actor, static_cast(1 << i), topOfSubTreeStack, potentialRedundantSubRoots); + if(dimension & (1 << i)) + { + // Do the propagation + PropagateAll(actorImpl, static_cast(1 << i), topOfSubTreeStack, potentialRedundantSubRoots); + } } } while(!topOfSubTreeStack.empty()) { // Request this actor as head of sub-tree if it is not dependent on a parent that is dirty - Dali::Actor subTreeActor = topOfSubTreeStack.back(); + Dali::Internal::Actor& subTreeActorImpl = *topOfSubTreeStack.back(); topOfSubTreeStack.pop_back(); - Dali::Actor parent = subTreeActor.GetParent(); - if(!parent || !(GetImplementation(subTreeActor).RelayoutDependentOnParent() && GetImplementation(parent).RelayoutRequired())) + Dali::Internal::Actor* parentImplPtr = subTreeActorImpl.GetParent(); + if(!parentImplPtr || !(subTreeActorImpl.RelayoutDependentOnParent() && (*parentImplPtr).RelayoutRequired())) { // Add sub tree root to relayout list - AddRequest(subTreeActor); + AddRequest(subTreeActorImpl); // Flag request for end of frame Request(); } else { - potentialRedundantSubRoots.push_back(subTreeActor); + potentialRedundantSubRoots.push_back(&subTreeActorImpl); } } // Remove any redundant sub-tree heads - for(auto& subRoot : potentialRedundantSubRoots) + for(const auto& subRoot : potentialRedundantSubRoots) { - RemoveRequest(subRoot); + RemoveRequest(*subRoot); } potentialRedundantSubRoots.clear(); @@ -218,22 +221,16 @@ void RelayoutController::OnApplicationSceneCreated() Request(); } -void RelayoutController::RequestRelayoutTree(Dali::Actor& actor) +void RelayoutController::RequestRelayoutRecursively(Dali::Internal::Actor& actorImpl) { - if(!mEnabled) - { - return; - } - // Only set dirty flag if doing relayout and not already marked as dirty - Actor& actorImpl = GetImplementation(actor); if(actorImpl.RelayoutPossible()) { // If parent is not in relayout we are at the top of a new sub-tree - Dali::Actor parent = actor.GetParent(); - if(!parent || !GetImplementation(parent).IsRelayoutEnabled()) + Dali::Internal::Actor* parentImplPtr = actorImpl.GetParent(); + if(!parentImplPtr || !(*parentImplPtr).IsRelayoutEnabled()) { - AddRequest(actor); + AddRequest(actorImpl); } // Set dirty flag on actors that are enabled @@ -242,18 +239,20 @@ void RelayoutController::RequestRelayoutTree(Dali::Actor& actor) } // Propagate down to children - for(uint32_t i = 0; i < actor.GetChildCount(); ++i) + if(actorImpl.GetChildCount()) { - Dali::Actor child = actor.GetChildAt(i); - - RequestRelayoutTree(child); + // Get reference of children container, to avoid useless reference count changing + auto& children = actorImpl.GetChildrenInternal(); + for(auto& childImplPtr : children) + { + RequestRelayoutRecursively(*childImplPtr); + } } } -void RelayoutController::PropagateAll(Dali::Actor& actor, Dimension::Type dimension, std::vector& topOfSubTreeStack, std::vector& potentialRedundantSubRoots) +void RelayoutController::PropagateAll(Dali::Internal::Actor& actorImpl, Dimension::Type dimension, RawActorList& topOfSubTreeStack, RawActorList& potentialRedundantSubRoots) { // Only set dirty flag if doing relayout and not already marked as dirty - Actor& actorImpl = GetImplementation(actor); if(actorImpl.RelayoutPossible(dimension)) { // Set dirty and negotiated flags @@ -269,60 +268,76 @@ void RelayoutController::PropagateAll(Dali::Actor& actor, Dimension::Type dimens if(actorImpl.RelayoutDependentOnDimension(dimension, dimensionToCheck) && !actorImpl.IsLayoutDirty(dimensionToCheck)) { - PropagateAll(actor, dimensionToCheck, topOfSubTreeStack, potentialRedundantSubRoots); + PropagateAll(actorImpl, dimensionToCheck, topOfSubTreeStack, potentialRedundantSubRoots); } } // Propagate up to parent - Dali::Actor parent = actor.GetParent(); - if(parent) { - Actor& parentImpl = GetImplementation(parent); - if(parentImpl.RelayoutDependentOnChildren(dimension) && !parentImpl.IsLayoutDirty(dimension)) + Dali::Internal::Actor* parentImplPtr = actorImpl.GetParent(); + if(parentImplPtr) { - // Store the highest parent reached - bool found = false; - for(auto&& element : topOfSubTreeStack) + Actor& parentImpl = *parentImplPtr; + if(parentImpl.RelayoutDependentOnChildren(dimension) && !parentImpl.IsLayoutDirty(dimension)) { - if(element == parent) + // Store the highest parent reached + bool found = false; + for(auto&& element : topOfSubTreeStack) { - found = true; - break; + if(element == &parentImpl) + { + found = true; + break; + } } - } - if(!found) - { - topOfSubTreeStack.push_back(parent); - } + if(!found) + { + topOfSubTreeStack.push_back(&parentImpl); + } - // Propagate up - PropagateAll(parent, dimension, topOfSubTreeStack, potentialRedundantSubRoots); + // Propagate up + PropagateAll(parentImpl, dimension, topOfSubTreeStack, potentialRedundantSubRoots); + } } } // Propagate down to children - for(unsigned int i = 0, childCount = actor.GetChildCount(); i < childCount; ++i) + if(actorImpl.GetChildCount()) { - Dali::Actor child = actor.GetChildAt(i); - Actor& childImpl = GetImplementation(child); - - if(childImpl.IsRelayoutEnabled() && childImpl.RelayoutDependentOnParent(dimension)) + // Get reference of children container, to avoid useless reference count changing + auto& children = actorImpl.GetChildrenInternal(); + for(auto& childImplPtr : children) { - if(childImpl.IsLayoutDirty(dimension)) - { - // We have found a child that could potentially have already been collected for relayout - potentialRedundantSubRoots.push_back(child); - } - else + Internal::Actor& childImpl = *childImplPtr; + + if(childImpl.IsRelayoutEnabled() && childImpl.RelayoutDependentOnParent(dimension)) { - PropagateAll(child, dimension, topOfSubTreeStack, potentialRedundantSubRoots); + if(childImpl.IsLayoutDirty(dimension)) + { + // We have found a child that could potentially have already been collected for relayout + potentialRedundantSubRoots.push_back(&childImpl); + } + else + { + PropagateAll(childImpl, dimension, topOfSubTreeStack, potentialRedundantSubRoots); + } } } } } } +void RelayoutController::RequestRelayoutTree(Dali::Actor& actor) +{ + if(!mEnabled) + { + return; + } + + RequestRelayoutRecursively(GetImplementation(actor)); +} + void RelayoutController::PropagateFlags(Dali::Actor& actor, Dimension::Type dimension) { // Only set dirty flag if doing relayout and not already marked as dirty @@ -371,23 +386,20 @@ void RelayoutController::PropagateFlags(Dali::Actor& actor, Dimension::Type dime } } -void RelayoutController::AddRequest(Dali::Actor& actor) +void RelayoutController::AddRequest(Internal::Actor& actorImpl) { - Internal::Actor* actorPtr = &GetImplementation(actor); - // Only add the rootActor if it is not already recorded - auto iter = mDirtyLayoutSubTrees.Find(actorPtr); + auto iter = mDirtyLayoutSubTrees.Find(&actorImpl); if(iter == mDirtyLayoutSubTrees.End()) { - mDirtyLayoutSubTrees.PushBack(actorPtr); + mDirtyLayoutSubTrees.PushBack(&actorImpl); } } -void RelayoutController::RemoveRequest(Dali::Actor& actor) +void RelayoutController::RemoveRequest(const Internal::Actor& actorImpl) { - Internal::Actor* actorPtr = &GetImplementation(actor); - mDirtyLayoutSubTrees.EraseObject(actorPtr); + mDirtyLayoutSubTrees.EraseObject(&actorImpl); } void RelayoutController::Request() @@ -419,22 +431,23 @@ void RelayoutController::Relayout() // 1. Finds all top-level controls from the dirty list and allocate them the size of the scene // These controls are paired with the parent/scene size and added to the stack. - for(auto& dirtyActor : mDirtyLayoutSubTrees) + for(auto iter = mDirtyLayoutSubTrees.Begin(); iter != mDirtyLayoutSubTrees.End();) { + Internal::Actor* dirtyActorImplPtr = *iter; // Need to test if actor is valid (could have been deleted and had the pointer cleared) - if(dirtyActor) + if(dirtyActorImplPtr) { + auto& dirtyActorImpl = *dirtyActorImplPtr; // Only negotiate actors that are on the scene - if(dirtyActor->OnScene()) + if(dirtyActorImpl.OnScene()) { - Internal::Actor* parent = dirtyActor->GetParent(); - QueueActor(dirtyActor, *mRelayoutStack, (parent) ? Vector2(parent->GetTargetSize()) : dirtyActor->GetScene().GetSize()); + Internal::Actor* parent = dirtyActorImpl.GetParent(); + QueueActor(dirtyActorImpl, *mRelayoutStack, (parent) ? Vector2(parent->GetTargetSize()) : dirtyActorImpl.GetScene().GetSize()); } } + iter = mDirtyLayoutSubTrees.Erase(iter); } - mDirtyLayoutSubTrees.Clear(); - // 2. Iterate through the stack until it's empty. if(mRelayoutStack->Size() > 0) { @@ -447,23 +460,22 @@ void RelayoutController::Relayout() while(mRelayoutStack->Size() > 0) { - Dali::Actor actor; - Vector2 size; - #ifdef TRACE_ENABLED ++relayoutActorCount; #endif + Dali::Actor actor; + Vector2 size; + + mRelayoutStack->PopBack(actor, size); - mRelayoutStack->GetBack(actor, size); - Actor& actorImpl = GetImplementation(actor); - mRelayoutStack->PopBack(); + Internal::Actor& actorImpl = GetImplementation(actor); if(actorImpl.RelayoutRequired() && actorImpl.OnScene()) { #ifdef TRACE_ENABLED ++negotiatedActorCount; #endif - DALI_LOG_INFO(gLogFilter, Debug::General, "[Internal::RelayoutController::Relayout] Negotiating %p %s %s (%.2f, %.2f)\n", &actorImpl, actor.GetTypeName().c_str(), actor.GetProperty(Dali::Actor::Property::NAME).c_str(), size.width, size.height); + DALI_LOG_INFO(gLogFilter, Debug::General, "[Internal::RelayoutController::Relayout] Negotiating %p %s %s (%.2f, %.2f)\n", &actorImpl, actorImpl.GetTypeName().c_str(), std::string(actorImpl.GetName()).c_str(), size.width, size.height); // 3. Negotiate the size with the current actor. Pass it an empty container which the actor // has to fill with all the actors it has not done any size negotiation for. diff --git a/dali/internal/event/size-negotiation/relayout-controller-impl.h b/dali/internal/event/size-negotiation/relayout-controller-impl.h index d0045dd4d..c359706ae 100644 --- a/dali/internal/event/size-negotiation/relayout-controller-impl.h +++ b/dali/internal/event/size-negotiation/relayout-controller-impl.h @@ -2,7 +2,7 @@ #define DALI_INTERNAL_RELAYOUT_CONTROLLER_IMPL_H /* - * Copyright (c) 2024 Samsung Electronics Co., Ltd. + * Copyright (c) 2025 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. @@ -146,7 +146,8 @@ public: // CALLBACKS void OnObjectDestroyed(const Dali::RefObject* object); private: - using RawActorList = Dali::Integration::OrderedSet; + using RawActorOrderedSet = Dali::Integration::OrderedSet; ///< Specialised container to find duplication list, and order + using RawActorList = std::vector; /** * @brief Request for relayout. Relays out whole scene. @@ -156,16 +157,16 @@ private: /** * @brief Add actor to request list * - * @param[in] actor The root of the sub tree to add + * @param[in] actorImpl The root of the sub tree to add */ - void AddRequest(Dali::Actor& actor); + void AddRequest(Dali::Internal::Actor& actorImpl); /** * @brief Remove actor from request list * - * @param[in] actor The root of the sub tree to remove + * @param[in] actorImpl The root of the sub tree to remove */ - void RemoveRequest(Dali::Actor& actor); + void RemoveRequest(const Dali::Internal::Actor& actorImpl); /** * @brief Disconnect the Relayout() method from the Stage::EventProcessingFinishedSignal(). @@ -176,12 +177,12 @@ private: * @brief Propagate dirty layout flags to actor and all sub-actors. This will stop propagating when a dirty actor * is found. * - * @param[in] actor The actor to propagate on + * @param[in] actorImpl The actor to propagate on * @param[in] dimension The dimension to propagate on * @param[in] topOfSubTreeStack The top of the sub tree that this actor is in * @param[in] potentialRedundantSubRoots Actors collected as potentially already being included in relayout */ - void PropagateAll(Dali::Actor& actor, Dimension::Type dimension, std::vector& topOfSubTreeStack, std::vector& potentialRedundantSubRoots); + void PropagateAll(Dali::Internal::Actor& actorImpl, Dimension::Type dimension, RawActorList& topOfSubTreeStack, RawActorList& potentialRedundantSubRoots); /** * Queue an actor on the relayout container @@ -190,7 +191,14 @@ private: * @param[in] actors The container to add the actor to * @param[in] size The size that this actor should be */ - void QueueActor(Internal::Actor* actor, RelayoutContainer& actors, Vector2 size); + void QueueActor(Internal::Actor& actor, RelayoutContainer& actors, Vector2 size); + + /** + * Internal recursive logic for relayout tree + * + * @param[in] actorImpl The root of the sub tree to request relayout + */ + void RequestRelayoutRecursively(Internal::Actor& actorImpl); // Undefined RelayoutController(const RelayoutController&) = delete; @@ -202,12 +210,12 @@ private: SlotDelegate mSlotDelegate; - RawActorList mDirtyLayoutSubTrees; ///< List of roots of sub trees that are dirty + RawActorOrderedSet mDirtyLayoutSubTrees; ///< List of roots of sub trees that are dirty std::unique_ptr mRelayoutStack; ///< Stack for relayouting - std::vector mPotentialRedundantSubRoots; ///< Stack of Actor when RequestLayout comes. Keep it as member to avoid vector size reserving. - std::vector mTopOfSubTreeStack; + RawActorList mPotentialRedundantSubRoots; ///< Stack of Actor when RequestLayout comes. Keep it as member to avoid vector size reserving. + RawActorList mTopOfSubTreeStack; bool mRelayoutConnection : 1; ///< Whether EventProcessingFinishedSignal signal is connected. bool mRelayoutFlag : 1; ///< Relayout flag to avoid unnecessary calls