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
/*
- * 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.
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);
}
}
return;
}
- std::vector<Dali::Actor>& potentialRedundantSubRoots = mPotentialRedundantSubRoots;
- std::vector<Dali::Actor>& 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<Dimension::Type>(1 << i), topOfSubTreeStack, potentialRedundantSubRoots);
+ if(dimension & (1 << i))
+ {
+ // Do the propagation
+ PropagateAll(actorImpl, static_cast<Dimension::Type>(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();
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
}
// 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<Dali::Actor>& topOfSubTreeStack, std::vector<Dali::Actor>& 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
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
}
}
-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()
// 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)
{
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<std::string>(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.
#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.
void OnObjectDestroyed(const Dali::RefObject* object);
private:
- using RawActorList = Dali::Integration::OrderedSet<Dali::Internal::Actor, false>;
+ using RawActorOrderedSet = Dali::Integration::OrderedSet<Dali::Internal::Actor, false>; ///< Specialised container to find duplication list, and order
+ using RawActorList = std::vector<Dali::Internal::Actor*>;
/**
* @brief Request for relayout. Relays out whole scene.
/**
* @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().
* @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<Dali::Actor>& topOfSubTreeStack, std::vector<Dali::Actor>& potentialRedundantSubRoots);
+ void PropagateAll(Dali::Internal::Actor& actorImpl, Dimension::Type dimension, RawActorList& topOfSubTreeStack, RawActorList& potentialRedundantSubRoots);
/**
* Queue an actor on the relayout container
* @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;
SlotDelegate<RelayoutController> 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<MemoryPoolRelayoutContainer> mRelayoutStack; ///< Stack for relayouting
- std::vector<Dali::Actor> mPotentialRedundantSubRoots; ///< Stack of Actor when RequestLayout comes. Keep it as member to avoid vector size reserving.
- std::vector<Dali::Actor> 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