Split control data implementation(Code Refactoring) 87/318387/10
authorjmm <j0064423.lee@samsung.com>
Fri, 27 Sep 2024 08:53:32 +0000 (17:53 +0900)
committerjmm <j0064423.lee@samsung.com>
Wed, 16 Oct 2024 08:53:08 +0000 (17:53 +0900)
Change-Id: I4856e07a693ca7e0896c1a99a73014d58057aae6

dali-toolkit/devel-api/controls/control-accessible.cpp
dali-toolkit/devel-api/controls/control-devel.cpp
dali-toolkit/internal/controls/control/control-accessibility-data.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/control/control-accessibility-data.h [new file with mode: 0644]
dali-toolkit/internal/controls/control/control-data-impl.cpp
dali-toolkit/internal/controls/control/control-data-impl.h
dali-toolkit/internal/controls/control/control-debug.cpp
dali-toolkit/internal/controls/control/control-visual-data.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/control/control-visual-data.h [new file with mode: 0644]
dali-toolkit/internal/file.list
dali-toolkit/public-api/controls/control-impl.cpp

index 497aaf210cc745d9dbbc215541c55c3f0aa01898..c98b54fec3a74332d7f9ae42da43305e13d053e8 100644 (file)
@@ -30,7 +30,7 @@
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/devel-api/asset-manager/asset-manager.h>
-#include <dali-toolkit/internal/controls/control/control-data-impl.h>
+#include <dali-toolkit/internal/controls/control/control-accessibility-data.h>
 #include <dali-toolkit/internal/visuals/image/image-visual.h>
 #include <dali-toolkit/public-api/controls/control-impl.h>
 #include <dali-toolkit/public-api/controls/control.h>
@@ -236,13 +236,13 @@ std::string ControlAccessible::GetName() const
   Internal::Control::Impl& controlImpl     = Internal::Control::Impl::Get(internalControl);
   std::string              name;
 
-  if(!controlImpl.mAccessibilityGetNameSignal.Empty())
+  if(!controlImpl.mAccessibilityData->mAccessibilityGetNameSignal.Empty())
   {
-    controlImpl.mAccessibilityGetNameSignal.Emit(name);
+    controlImpl.mAccessibilityData->mAccessibilityGetNameSignal.Emit(name);
   }
-  else if(!controlImpl.mAccessibilityProps.name.empty())
+  else if(!controlImpl.mAccessibilityData->mAccessibilityProps.name.empty())
   {
-    name = controlImpl.mAccessibilityProps.name;
+    name = controlImpl.mAccessibilityData->mAccessibilityProps.name;
   }
   else if(auto raw = GetNameRaw(); !raw.empty())
   {
@@ -269,13 +269,13 @@ std::string ControlAccessible::GetDescription() const
   Internal::Control::Impl& controlImpl     = Internal::Control::Impl::Get(internalControl);
   std::string              description;
 
-  if(!controlImpl.mAccessibilityGetDescriptionSignal.Empty())
+  if(!controlImpl.mAccessibilityData->mAccessibilityGetDescriptionSignal.Empty())
   {
-    controlImpl.mAccessibilityGetDescriptionSignal.Emit(description);
+    controlImpl.mAccessibilityData->mAccessibilityGetDescriptionSignal.Emit(description);
   }
-  else if(!controlImpl.mAccessibilityProps.description.empty())
+  else if(!controlImpl.mAccessibilityData->mAccessibilityProps.description.empty())
   {
-    description = controlImpl.mAccessibilityProps.description;
+    description = controlImpl.mAccessibilityData->mAccessibilityProps.description;
   }
   else
   {
@@ -343,7 +343,7 @@ void ControlAccessible::ApplyAccessibilityProps(Dali::Accessibility::States& sta
   Internal::Control::Impl& controlImpl     = Internal::Control::Impl::Get(internalControl);
 
   // Apply states
-  const auto& props       = controlImpl.mAccessibilityProps;
+  const auto& props       = controlImpl.mAccessibilityData->mAccessibilityProps;
   states[State::ENABLED]  = props.states[AccessibilityState::ENABLED];
   states[State::SELECTED] = props.states[AccessibilityState::SELECTED];
   states[State::CHECKED]  = props.states[AccessibilityState::CHECKED];
@@ -443,7 +443,7 @@ bool ControlAccessible::IsHidden() const
   Internal::Control&       internalControl = Toolkit::Internal::GetImplementation(control);
   Internal::Control::Impl& controlImpl     = Internal::Control::Impl::Get(internalControl);
 
-  return controlImpl.mAccessibilityProps.isHidden;
+  return controlImpl.mAccessibilityData->mAccessibilityProps.isHidden;
 }
 
 bool ControlAccessible::GrabFocus()
@@ -472,7 +472,7 @@ void ControlAccessible::RegisterPositionPropertyNotification()
   auto                     control         = Dali::Toolkit::Control::DownCast(Self());
   Internal::Control&       internalControl = Toolkit::Internal::GetImplementation(control);
   Internal::Control::Impl& controlImpl     = Internal::Control::Impl::Get(internalControl);
-  controlImpl.RegisterAccessibilityPositionPropertyNotification();
+  controlImpl.mAccessibilityData->RegisterAccessibilityPositionPropertyNotification();
 }
 
 void ControlAccessible::UnregisterPositionPropertyNotification()
@@ -480,7 +480,7 @@ void ControlAccessible::UnregisterPositionPropertyNotification()
   auto                     control         = Dali::Toolkit::Control::DownCast(Self());
   Internal::Control&       internalControl = Toolkit::Internal::GetImplementation(control);
   Internal::Control::Impl& controlImpl     = Internal::Control::Impl::Get(internalControl);
-  controlImpl.UnregisterAccessibilityPositionPropertyNotification();
+  controlImpl.mAccessibilityData->UnregisterAccessibilityPositionPropertyNotification();
 }
 
 void ControlAccessible::RegisterPropertySetSignal()
@@ -488,9 +488,9 @@ void ControlAccessible::RegisterPropertySetSignal()
   auto                     control         = Dali::Toolkit::Control::DownCast(Self());
   Internal::Control&       internalControl = Toolkit::Internal::GetImplementation(control);
   Internal::Control::Impl& controlImpl     = Internal::Control::Impl::Get(internalControl);
-  controlImpl.RegisterAccessibilityPropertySetSignal();
+  controlImpl.mAccessibilityData->RegisterAccessibilityPropertySetSignal();
 
-  mStatesSnapshot = controlImpl.mAccessibilityProps.states;
+  mStatesSnapshot = controlImpl.mAccessibilityData->mAccessibilityProps.states;
 }
 
 void ControlAccessible::UnregisterPropertySetSignal()
@@ -498,7 +498,7 @@ void ControlAccessible::UnregisterPropertySetSignal()
   auto                     control         = Dali::Toolkit::Control::DownCast(Self());
   Internal::Control&       internalControl = Toolkit::Internal::GetImplementation(control);
   Internal::Control::Impl& controlImpl     = Internal::Control::Impl::Get(internalControl);
-  controlImpl.UnregisterAccessibilityPropertySetSignal();
+  controlImpl.mAccessibilityData->UnregisterAccessibilityPropertySetSignal();
 
   mStatesSnapshot = {};
 }
@@ -631,10 +631,10 @@ bool ControlAccessible::DoGesture(const Dali::Accessibility::GestureInfo& gestur
   Internal::Control&       internalControl = Toolkit::Internal::GetImplementation(control);
   Internal::Control::Impl& controlImpl     = Internal::Control::Impl::Get(internalControl);
 
-  if(!controlImpl.mAccessibilityDoGestureSignal.Empty())
+  if(!controlImpl.mAccessibilityData->mAccessibilityDoGestureSignal.Empty())
   {
     auto ret = std::make_pair(gestureInfo, false);
-    controlImpl.mAccessibilityDoGestureSignal.Emit(ret);
+    controlImpl.mAccessibilityData->mAccessibilityDoGestureSignal.Emit(ret);
     return ret.second;
   }
 
index 72e7ab13c9436a9f9b8a33f0dea6246b1a4a69bb..49fd71dec77a3b488194f35ed5bad3eb752296fa 100644 (file)
@@ -24,7 +24,7 @@
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/devel-api/visual-factory/transition-data.h>
-#include <dali-toolkit/internal/controls/control/control-data-impl.h>
+#include <dali-toolkit/internal/controls/control/control-accessibility-data.h>
 #include <dali-toolkit/public-api/controls/control-impl.h>
 #include <dali-toolkit/public-api/controls/control.h>
 
@@ -142,59 +142,59 @@ Dali::Property GetVisualProperty(Control control, Dali::Property::Index index, D
 
 Toolkit::DevelControl::AccessibilityActivateSignalType& AccessibilityActivateSignal(Toolkit::Control control)
 {
-  return GetControlImplementation(control).mAccessibilityActivateSignal;
+  return GetControlImplementation(control).mAccessibilityData->mAccessibilityActivateSignal;
 }
 
 Toolkit::DevelControl::AccessibilityReadingSkippedSignalType& AccessibilityReadingSkippedSignal(Toolkit::Control control)
 {
-  return GetControlImplementation(control).mAccessibilityReadingSkippedSignal;
+  return GetControlImplementation(control).mAccessibilityData->mAccessibilityReadingSkippedSignal;
 }
 
 Toolkit::DevelControl::AccessibilityReadingPausedSignalType& AccessibilityReadingPausedSignal(Toolkit::Control control)
 {
-  return GetControlImplementation(control).mAccessibilityReadingPausedSignal;
+  return GetControlImplementation(control).mAccessibilityData->mAccessibilityReadingPausedSignal;
 }
 
 Toolkit::DevelControl::AccessibilityReadingResumedSignalType& AccessibilityReadingResumedSignal(Toolkit::Control control)
 {
-  return GetControlImplementation(control).mAccessibilityReadingResumedSignal;
+  return GetControlImplementation(control).mAccessibilityData->mAccessibilityReadingResumedSignal;
 }
 
 Toolkit::DevelControl::AccessibilityReadingCancelledSignalType& AccessibilityReadingCancelledSignal(Toolkit::Control control)
 {
-  return GetControlImplementation(control).mAccessibilityReadingCancelledSignal;
+  return GetControlImplementation(control).mAccessibilityData->mAccessibilityReadingCancelledSignal;
 }
 
 Toolkit::DevelControl::AccessibilityReadingStoppedSignalType& AccessibilityReadingStoppedSignal(Toolkit::Control control)
 {
-  return GetControlImplementation(control).mAccessibilityReadingStoppedSignal;
+  return GetControlImplementation(control).mAccessibilityData->mAccessibilityReadingStoppedSignal;
 }
 
 Toolkit::DevelControl::AccessibilityGetNameSignalType& AccessibilityGetNameSignal(Toolkit::Control control)
 {
-  return GetControlImplementation(control).mAccessibilityGetNameSignal;
+  return GetControlImplementation(control).mAccessibilityData->mAccessibilityGetNameSignal;
 }
 
 Toolkit::DevelControl::AccessibilityGetDescriptionSignalType& AccessibilityGetDescriptionSignal(Toolkit::Control control)
 {
-  return GetControlImplementation(control).mAccessibilityGetDescriptionSignal;
+  return GetControlImplementation(control).mAccessibilityData->mAccessibilityGetDescriptionSignal;
 }
 
 Toolkit::DevelControl::AccessibilityDoGestureSignalType& AccessibilityDoGestureSignal(Toolkit::Control control)
 {
-  return GetControlImplementation(control).mAccessibilityDoGestureSignal;
+  return GetControlImplementation(control).mAccessibilityData->mAccessibilityDoGestureSignal;
 }
 
 Toolkit::DevelControl::AccessibilityActionSignalType& AccessibilityActionSignal(Toolkit::Control control)
 {
-  return GetControlImplementation(control).mAccessibilityActionSignal;
+  return GetControlImplementation(control).mAccessibilityData->mAccessibilityActionSignal;
 }
 
 void AppendAccessibilityRelation(Toolkit::Control control, Dali::Actor destination, Dali::Accessibility::RelationType relation)
 {
   if(auto destinationAccessible = Accessibility::Accessible::Get(destination))
   {
-    GetControlImplementation(control).mAccessibilityProps.relations[relation].insert(destinationAccessible);
+    GetControlImplementation(control).mAccessibilityData->mAccessibilityProps.relations[relation].insert(destinationAccessible);
   }
 }
 
@@ -202,7 +202,7 @@ void RemoveAccessibilityRelation(Toolkit::Control control, Dali::Actor destinati
 {
   if(auto destinationAccessible = Accessibility::Accessible::Get(destination))
   {
-    auto& relations = GetControlImplementation(control).mAccessibilityProps.relations;
+    auto& relations = GetControlImplementation(control).mAccessibilityData->mAccessibilityProps.relations;
 
     relations[relation].erase(destinationAccessible);
 
@@ -215,7 +215,7 @@ void RemoveAccessibilityRelation(Toolkit::Control control, Dali::Actor destinati
 
 std::vector<Accessibility::Relation> GetAccessibilityRelations(Toolkit::Control control)
 {
-  const auto&                          relations = GetControlImplementation(control).mAccessibilityProps.relations;
+  const auto&                          relations = GetControlImplementation(control).mAccessibilityData->mAccessibilityProps.relations;
   std::vector<Accessibility::Relation> result;
 
   for(auto& relation : relations)
@@ -231,7 +231,7 @@ std::vector<Accessibility::Relation> GetAccessibilityRelations(Toolkit::Control
 
 void ClearAccessibilityRelations(Toolkit::Control control)
 {
-  GetControlImplementation(control).mAccessibilityProps.relations.clear();
+  GetControlImplementation(control).mAccessibilityData->mAccessibilityProps.relations.clear();
 }
 
 void AppendAccessibilityAttribute(Toolkit::Control control, const std::string& key, const std::string& value)
diff --git a/dali-toolkit/internal/controls/control/control-accessibility-data.cpp b/dali-toolkit/internal/controls/control/control-accessibility-data.cpp
new file mode 100644 (file)
index 0000000..0e1a7d4
--- /dev/null
@@ -0,0 +1,367 @@
+/*
+ * Copyright (c) 2024 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "control-accessibility-data.h"
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/object/type-registry-helper.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+namespace
+{
+static constexpr const char* READING_INFO_TYPE_NAME           = "name";
+static constexpr const char* READING_INFO_TYPE_ATTRIBUTE_NAME = "reading_info_type";
+static constexpr const char* READING_INFO_TYPE_ROLE           = "role";
+static constexpr const char* READING_INFO_TYPE_DESCRIPTION    = "description";
+static constexpr const char* READING_INFO_TYPE_STATE          = "state";
+static constexpr const char* READING_INFO_TYPE_SEPARATOR      = "|";
+
+Dali::Rect<> GetShowingGeometry(Dali::Rect<> rect, Dali::Toolkit::DevelControl::ControlAccessible* accessible)
+{
+  Rect<>  parentRect;
+  Vector2 currentPosition;
+  auto    parent = dynamic_cast<Toolkit::DevelControl::ControlAccessible*>(accessible->GetParent());
+
+  while(parent)
+  {
+    parentRect = parent->GetExtents(Dali::Accessibility::CoordinateType::WINDOW);
+
+    currentPosition.x = rect.x;
+    currentPosition.y = rect.y;
+
+    rect.x      = rect.x > parentRect.x ? rect.x : parentRect.x;
+    rect.y      = rect.y > parentRect.y ? rect.y : parentRect.y;
+    rect.width  = currentPosition.x + rect.width < parentRect.x + parentRect.width ? currentPosition.x + rect.width - rect.x : parentRect.x + parentRect.width - rect.x;
+    rect.height = currentPosition.y + rect.height < parentRect.y + parentRect.height ? currentPosition.y + rect.height - rect.y : parentRect.y + parentRect.height - rect.y;
+
+    if(rect.width < 0 || rect.height < 0)
+    {
+      return rect;
+    }
+
+    parent = dynamic_cast<Toolkit::DevelControl::ControlAccessible*>(parent->GetParent());
+  }
+
+  return rect;
+}
+static bool IsShowingGeometryOnScreen(Dali::Rect<> rect)
+{
+  return rect.width > 0 && rect.height > 0;
+}
+} // unnamed namespace
+
+Control::Impl::AccessibilityData::AccessibilityData(Control& controlImpl)
+: mAccessibilityGetNameSignal(),
+  mAccessibilityGetDescriptionSignal(),
+  mAccessibilityDoGestureSignal(),
+  mControlImpl(controlImpl),
+  mIsAccessibilityPositionPropertyNotificationSet(false),
+  mIsAccessibilityPropertySetSignalRegistered(false),
+  mAccessibleCreatable(true)
+{
+  Accessibility::Accessible::RegisterExternalAccessibleGetter([](Dali::Actor actor) -> std::pair<std::shared_ptr<Accessibility::Accessible>, bool> {
+    auto control = Toolkit::Control::DownCast(actor);
+    if(!control)
+    {
+      return {nullptr, true};
+    }
+
+    auto& controlImpl = Toolkit::Internal::GetImplementation(control);
+    if(controlImpl.mImpl->IsCreateAccessibleEnabled())
+    {
+      return {std::shared_ptr<DevelControl::ControlAccessible>(controlImpl.CreateAccessibleObject()), true};
+    }
+
+    return {nullptr, false};
+  });
+  mAccessibilityProps.states[DevelControl::AccessibilityState::ENABLED] = true;
+}
+
+void Control::Impl::AccessibilityData::AppendAccessibilityAttribute(const std::string& key, const std::string value)
+{
+  Property::Value* checkedValue = mAccessibilityProps.extraAttributes.Find(key);
+  if(checkedValue)
+  {
+    mAccessibilityProps.extraAttributes[key] = Property::Value(value);
+  }
+  else
+  {
+    mAccessibilityProps.extraAttributes.Insert(key, value);
+  }
+}
+
+void Control::Impl::AccessibilityData::CheckHighlightedObjectGeometry()
+{
+  auto accessible = GetAccessibleObject();
+  if(DALI_LIKELY(accessible))
+  {
+    auto lastPosition   = accessible->GetLastPosition();
+    auto accessibleRect = accessible->GetExtents(Dali::Accessibility::CoordinateType::WINDOW);
+    auto rect           = GetShowingGeometry(accessibleRect, accessible.get());
+
+    switch(mAccessibilityLastScreenRelativeMoveType)
+    {
+      case Dali::Accessibility::ScreenRelativeMoveType::OUTSIDE:
+      {
+        if(IsShowingGeometryOnScreen(rect))
+        {
+          mAccessibilityLastScreenRelativeMoveType = Dali::Accessibility::ScreenRelativeMoveType::INSIDE;
+        }
+        break;
+      }
+      case Dali::Accessibility::ScreenRelativeMoveType::INSIDE:
+      {
+        if(rect.width < 0 && !Dali::Equals(accessibleRect.x, lastPosition.x))
+        {
+          mAccessibilityLastScreenRelativeMoveType = (accessibleRect.x < lastPosition.x) ? Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_TOP_LEFT : Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_BOTTOM_RIGHT;
+        }
+        if(rect.height < 0 && !Dali::Equals(accessibleRect.y, lastPosition.y))
+        {
+          mAccessibilityLastScreenRelativeMoveType = (accessibleRect.y < lastPosition.y) ? Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_TOP_LEFT : Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_BOTTOM_RIGHT;
+        }
+        // notify AT-clients on outgoing moves only
+        if(mAccessibilityLastScreenRelativeMoveType != Dali::Accessibility::ScreenRelativeMoveType::INSIDE)
+        {
+          accessible->EmitMovedOutOfScreen(mAccessibilityLastScreenRelativeMoveType);
+        }
+        break;
+      }
+      case Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_TOP_LEFT:
+      case Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_BOTTOM_RIGHT:
+      {
+        if(IsShowingGeometryOnScreen(rect))
+        {
+          mAccessibilityLastScreenRelativeMoveType = Dali::Accessibility::ScreenRelativeMoveType::INSIDE;
+        }
+        else
+        {
+          mAccessibilityLastScreenRelativeMoveType = Dali::Accessibility::ScreenRelativeMoveType::OUTSIDE;
+        }
+        break;
+      }
+      default:
+      {
+        break;
+      }
+    }
+
+    accessible->SetLastPosition(Vector2(accessibleRect.x, accessibleRect.y));
+  }
+}
+
+void Control::Impl::AccessibilityData::RegisterAccessibilityPositionPropertyNotification()
+{
+  if(mIsAccessibilityPositionPropertyNotificationSet)
+  {
+    return;
+  }
+  // set default value until first move of object is detected
+  mAccessibilityLastScreenRelativeMoveType = Dali::Accessibility::ScreenRelativeMoveType::OUTSIDE;
+  // recalculate mAccessibilityLastScreenRelativeMoveType accordingly to the initial position
+  CheckHighlightedObjectGeometry();
+  mAccessibilityPositionNotification = mControlImpl.Self().AddPropertyNotification(Actor::Property::WORLD_POSITION, StepCondition(1.0f, 1.0f));
+  mAccessibilityPositionNotification.SetNotifyMode(PropertyNotification::NOTIFY_ON_CHANGED);
+  mAccessibilityPositionNotification.NotifySignal().Connect(this, [this](PropertyNotification&) { CheckHighlightedObjectGeometry(); });
+  mIsAccessibilityPositionPropertyNotificationSet = true;
+}
+
+void Control::Impl::AccessibilityData::UnregisterAccessibilityPositionPropertyNotification()
+{
+  mControlImpl.Self().RemovePropertyNotification(mAccessibilityPositionNotification);
+  mIsAccessibilityPositionPropertyNotificationSet = false;
+}
+
+void Control::Impl::AccessibilityData::RegisterAccessibilityPropertySetSignal()
+{
+  if(mIsAccessibilityPropertySetSignalRegistered)
+  {
+    return;
+  }
+  mControlImpl.Self().PropertySetSignal().Connect(this, &Control::Impl::AccessibilityData::OnAccessibilityPropertySet);
+  mIsAccessibilityPropertySetSignalRegistered = true;
+}
+
+void Control::Impl::AccessibilityData::UnregisterAccessibilityPropertySetSignal()
+{
+  if(!mIsAccessibilityPropertySetSignalRegistered)
+  {
+    return;
+  }
+  mControlImpl.Self().PropertySetSignal().Disconnect(this, &Control::Impl::AccessibilityData::OnAccessibilityPropertySet);
+  mIsAccessibilityPropertySetSignalRegistered = false;
+}
+
+void Control::Impl::AccessibilityData::OnAccessibilityPropertySet(Dali::Handle& handle, Dali::Property::Index index, const Dali::Property::Value& value)
+{
+  auto accessible = GetAccessibleObject();
+  if(DALI_LIKELY(accessible))
+  {
+    if(mAccessibilityGetNameSignal.Empty())
+    {
+      if(index == DevelControl::Property::ACCESSIBILITY_NAME || (mAccessibilityProps.name.empty() && index == accessible->GetNamePropertyIndex()))
+      {
+        accessible->Emit(Dali::Accessibility::ObjectPropertyChangeEvent::NAME);
+        return;
+      }
+    }
+
+    if(mAccessibilityGetDescriptionSignal.Empty())
+    {
+      if(index == DevelControl::Property::ACCESSIBILITY_DESCRIPTION || (mAccessibilityProps.description.empty() && index == accessible->GetDescriptionPropertyIndex()))
+      {
+        accessible->Emit(Dali::Accessibility::ObjectPropertyChangeEvent::DESCRIPTION);
+        return;
+      }
+    }
+
+    if(index == DevelControl::Property::ACCESSIBILITY_VALUE)
+    {
+      accessible->Emit(Dali::Accessibility::ObjectPropertyChangeEvent::VALUE);
+      return;
+    }
+
+    if(index == DevelControl::Property::ACCESSIBILITY_STATES)
+    {
+      accessible->OnStatePropertySet(mAccessibilityProps.states);
+      return;
+    }
+  }
+}
+
+Dali::Accessibility::ReadingInfoTypes Control::Impl::AccessibilityData::GetAccessibilityReadingInfoType() const
+{
+  std::string value{};
+  auto        place = mAccessibilityProps.extraAttributes.Find(READING_INFO_TYPE_ATTRIBUTE_NAME);
+  if(place)
+  {
+    place->Get(value);
+  }
+  else
+  {
+    Dali::Accessibility::ReadingInfoTypes types;
+    types[Dali::Accessibility::ReadingInfoType::NAME]        = true;
+    types[Dali::Accessibility::ReadingInfoType::ROLE]        = true;
+    types[Dali::Accessibility::ReadingInfoType::DESCRIPTION] = true;
+    types[Dali::Accessibility::ReadingInfoType::STATE]       = true;
+    return types;
+  }
+
+  if(value.empty())
+  {
+    return {};
+  }
+
+  Dali::Accessibility::ReadingInfoTypes types;
+
+  if(value.find(READING_INFO_TYPE_NAME) != std::string::npos)
+  {
+    types[Dali::Accessibility::ReadingInfoType::NAME] = true;
+  }
+  if(value.find(READING_INFO_TYPE_ROLE) != std::string::npos)
+  {
+    types[Dali::Accessibility::ReadingInfoType::ROLE] = true;
+  }
+  if(value.find(READING_INFO_TYPE_DESCRIPTION) != std::string::npos)
+  {
+    types[Dali::Accessibility::ReadingInfoType::DESCRIPTION] = true;
+  }
+  if(value.find(READING_INFO_TYPE_STATE) != std::string::npos)
+  {
+    types[Dali::Accessibility::ReadingInfoType::STATE] = true;
+  }
+
+  return types;
+}
+
+void Control::Impl::AccessibilityData::RemoveAccessibilityAttribute(const std::string& key)
+{
+  Property::Value* value = mAccessibilityProps.extraAttributes.Find(key);
+  if(value)
+  {
+    mAccessibilityProps.extraAttributes[key] = Property::Value();
+  }
+}
+
+void Control::Impl::AccessibilityData::ClearAccessibilityAttributes()
+{
+  mAccessibilityProps.extraAttributes.Clear();
+}
+
+void Control::Impl::AccessibilityData::SetAccessibilityReadingInfoType(const Dali::Accessibility::ReadingInfoTypes types)
+{
+  std::string value{};
+  if(types[Dali::Accessibility::ReadingInfoType::NAME])
+  {
+    value += READING_INFO_TYPE_NAME;
+  }
+  if(types[Dali::Accessibility::ReadingInfoType::ROLE])
+  {
+    if(!value.empty())
+    {
+      value += READING_INFO_TYPE_SEPARATOR;
+    }
+    value += READING_INFO_TYPE_ROLE;
+  }
+  if(types[Dali::Accessibility::ReadingInfoType::DESCRIPTION])
+  {
+    if(!value.empty())
+    {
+      value += READING_INFO_TYPE_SEPARATOR;
+    }
+    value += READING_INFO_TYPE_DESCRIPTION;
+  }
+  if(types[Dali::Accessibility::ReadingInfoType::STATE])
+  {
+    if(!value.empty())
+    {
+      value += READING_INFO_TYPE_SEPARATOR;
+    }
+    value += READING_INFO_TYPE_STATE;
+  }
+  AppendAccessibilityAttribute(READING_INFO_TYPE_ATTRIBUTE_NAME, value);
+}
+
+std::shared_ptr<Toolkit::DevelControl::ControlAccessible> Control::Impl::AccessibilityData::GetAccessibleObject()
+{
+  return std::dynamic_pointer_cast<DevelControl::ControlAccessible>(Accessibility::Accessible::GetOwningPtr(mControlImpl.Self()));
+}
+
+bool Control::Impl::AccessibilityData::IsAccessibleCreated() const
+{
+  return !!Accessibility::Bridge::GetCurrentBridge()->GetAccessible(mControlImpl.Self());
+}
+
+void Control::Impl::AccessibilityData::EnableCreateAccessible(bool enable)
+{
+  mAccessibleCreatable = enable;
+}
+
+bool Control::Impl::AccessibilityData::IsCreateAccessibleEnabled() const
+{
+  return mAccessibleCreatable;
+}
+
+} // namespace Internal
+} // namespace Toolkit
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/control/control-accessibility-data.h b/dali-toolkit/internal/controls/control/control-accessibility-data.h
new file mode 100644 (file)
index 0000000..271eef2
--- /dev/null
@@ -0,0 +1,159 @@
+#ifndef DALI_TOOLKIT_CONTROL_ACCESSIBILITY_DATA_H
+#define DALI_TOOLKIT_CONTROL_ACCESSIBILITY_DATA_H
+
+/*
+ * Copyright (c) 2024 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/internal/controls/control/control-data-impl.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+// private inner class
+class Control::Impl::AccessibilityData : public ConnectionTracker
+{
+  friend class Toolkit::DevelControl::ControlAccessible;
+
+public:
+  // Constructor
+  AccessibilityData(Control& controlImpl);
+
+  /**
+   * @copydoc Dali::Toolkit::Internal::Control::Impl::AppendAccessibilityAttribute()
+   */
+  void AppendAccessibilityAttribute(const std::string& key, const std::string value);
+
+  /**
+   * @copydoc Dali::Toolkit::Internal::Control::Impl::RemoveAccessibilityAttribute()
+   */
+  void RemoveAccessibilityAttribute(const std::string& key);
+
+  /**
+   * @copydoc Dali::Toolkit::Internal::Control::Impl::ClearAccessibilityAttributes()
+   */
+  void ClearAccessibilityAttributes();
+
+  /**
+   * @copydoc Dali::Toolkit::Internal::Control::Impl::SetAccessibilityReadingInfoType()
+   */
+  void SetAccessibilityReadingInfoType(const Dali::Accessibility::ReadingInfoTypes types);
+
+  /**
+   * @copydoc Dali::Toolkit::Internal::Control::Impl::GetAccessibilityReadingInfoType()
+   */
+  Dali::Accessibility::ReadingInfoTypes GetAccessibilityReadingInfoType() const;
+
+  /**
+   * @copydoc Dali::Toolkit::Internal::Control::Impl::CheckHighlightedObjectGeometry()
+   */
+  void CheckHighlightedObjectGeometry();
+
+  /**
+   * @copydoc Dali::Toolkit::Internal::Control::Impl::RegisterAccessibilityPositionPropertyNotification()
+   */
+  void RegisterAccessibilityPositionPropertyNotification();
+
+  /**
+   * @copydoc Dali::Toolkit::Internal::Control::Impl::UnregisterAccessibilityPositionPropertyNotification()
+   */
+  void UnregisterAccessibilityPositionPropertyNotification();
+
+  /**
+   * @copydoc Dali::Toolkit::Internal::Control::Impl::RegisterAccessibilityPropertySetSignal()
+   */
+  void RegisterAccessibilityPropertySetSignal();
+
+  /**
+   * @copydoc Dali::Toolkit::Internal::Control::Impl::UnregisterAccessibilityPropertySetSignal()
+   */
+  void UnregisterAccessibilityPropertySetSignal();
+
+  /**
+   * @copydoc Dali::Toolkit::Internal::Control::Impl::OnAccessibilityPropertySet()
+   */
+  void OnAccessibilityPropertySet(Dali::Handle& handle, Dali::Property::Index index, const Dali::Property::Value& value);
+
+  /**
+   * @copydoc Dali::Toolkit::Internal::Control::Impl::GetAccessibleObject()
+   */
+  std::shared_ptr<Toolkit::DevelControl::ControlAccessible> GetAccessibleObject();
+
+  /**
+   * @copydoc Dali::Toolkit::Internal::Control::Impl::IsAccessibleCreated()
+   */
+  bool IsAccessibleCreated() const;
+
+  /**
+   * @copydoc Dali::Toolkit::Internal::Control::Impl::EnableCreateAccessible()
+   */
+  void EnableCreateAccessible(bool enable);
+
+  /**
+   * @copydoc Dali::Toolkit::Internal::Control::Impl::IsCreateAccessibleEnabled()
+   */
+  bool IsCreateAccessibleEnabled() const;
+
+public:
+  Toolkit::DevelControl::AccessibilityActivateSignalType         mAccessibilityActivateSignal;
+  Toolkit::DevelControl::AccessibilityReadingSkippedSignalType   mAccessibilityReadingSkippedSignal;
+  Toolkit::DevelControl::AccessibilityReadingPausedSignalType    mAccessibilityReadingPausedSignal;
+  Toolkit::DevelControl::AccessibilityReadingResumedSignalType   mAccessibilityReadingResumedSignal;
+  Toolkit::DevelControl::AccessibilityReadingCancelledSignalType mAccessibilityReadingCancelledSignal;
+  Toolkit::DevelControl::AccessibilityReadingStoppedSignalType   mAccessibilityReadingStoppedSignal;
+
+  Toolkit::DevelControl::AccessibilityGetNameSignalType        mAccessibilityGetNameSignal;
+  Toolkit::DevelControl::AccessibilityGetDescriptionSignalType mAccessibilityGetDescriptionSignal;
+  Toolkit::DevelControl::AccessibilityDoGestureSignalType      mAccessibilityDoGestureSignal;
+
+  Toolkit::DevelControl::AccessibilityActionSignalType mAccessibilityActionSignal;
+
+  struct AccessibilityProps
+  {
+    std::string                                                                       name{};
+    std::string                                                                       description{};
+    std::string                                                                       value{};
+    std::string                                                                       automationId{};
+    int32_t                                                                           role{static_cast<int32_t>(DevelControl::AccessibilityRole::NONE)};
+    DevelControl::AccessibilityStates                                                 states{};
+    std::map<Dali::Accessibility::RelationType, std::set<Accessibility::Accessible*>> relations;
+    Property::Map                                                                     extraAttributes{};
+    TriStateProperty                                                                  isHighlightable{TriStateProperty::AUTO};
+    bool                                                                              isHidden{false};
+    bool                                                                              isScrollable{false};
+    bool                                                                              isModal{false};
+  } mAccessibilityProps;
+
+private:
+  // Accessibility - notification for highlighted object to check if it is showing.
+  Dali::PropertyNotification                  mAccessibilityPositionNotification;
+  Dali::Accessibility::ScreenRelativeMoveType mAccessibilityLastScreenRelativeMoveType{Accessibility::ScreenRelativeMoveType::OUTSIDE};
+
+  Control& mControlImpl;
+
+  bool mIsAccessibilityPositionPropertyNotificationSet : 1;
+  bool mIsAccessibilityPropertySetSignalRegistered : 1;
+  bool mAccessibleCreatable : 1;
+};
+} // namespace Internal
+} // namespace Toolkit
+} // namespace Dali
+#endif // DALI_TOOLKIT_CONTROL_ACCESSIBILITY_DATA_H
index fe933d9ee6d0fe945a9f2c72380a3dfd6e00be5a..1cd01b0c09e2c0dc1fabe68456c0319d59f20ecc 100644 (file)
@@ -17,6 +17,8 @@
 
 // CLASS HEADER
 #include "control-data-impl.h"
+#include "control-accessibility-data.h"
+#include "control-visual-data.h"
 
 // EXTERNAL INCLUDES
 #include <dali-toolkit/public-api/controls/control-impl.h>
 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
 #include <dali-toolkit/devel-api/controls/control-devel.h>
 #include <dali-toolkit/devel-api/controls/control-wrapper-impl.h>
-#include <dali-toolkit/devel-api/visuals/visual-actions-devel.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
 #include <dali-toolkit/internal/styling/style-manager-impl.h>
+#include <dali-toolkit/internal/visuals/transition-data-impl.h>
 #include <dali-toolkit/internal/visuals/visual-base-impl.h>
-#include <dali-toolkit/internal/visuals/visual-string-constants.h>
-#include <dali-toolkit/public-api/align-enumerations.h>
 #include <dali-toolkit/public-api/controls/image-view/image-view.h>
 #include <dali-toolkit/public-api/focus-manager/keyboard-focus-manager.h>
-#include <dali-toolkit/public-api/visuals/image-visual-properties.h>
-#include <dali-toolkit/public-api/visuals/visual-properties.h>
-
-namespace
-{
-const char* READING_INFO_TYPE_NAME           = "name";
-const char* READING_INFO_TYPE_ROLE           = "role";
-const char* READING_INFO_TYPE_DESCRIPTION    = "description";
-const char* READING_INFO_TYPE_STATE          = "state";
-const char* READING_INFO_TYPE_ATTRIBUTE_NAME = "reading_info_type";
-const char* READING_INFO_TYPE_SEPARATOR      = "|";
-} // namespace
 
 namespace Dali
 {
@@ -77,180 +66,13 @@ const Scripting::StringEnum ControlStateTable[] = {
   {"DISABLED", Toolkit::DevelControl::DISABLED},
 };
 const unsigned int ControlStateTableCount = sizeof(ControlStateTable) / sizeof(ControlStateTable[0]);
-const Vector4      FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
 
 namespace
 {
 #if defined(DEBUG_ENABLED)
-Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_CONTROL_VISUALS");
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_CONTROL_DATA");
 #endif
 
-template<typename T>
-void Remove(Dictionary<T>& keyValues, const std::string& name)
-{
-  keyValues.Remove(name);
-}
-
-void Remove(DictionaryKeys& keys, const std::string& name)
-{
-  DictionaryKeys::iterator iter = std::find(keys.begin(), keys.end(), name);
-  if(iter != keys.end())
-  {
-    keys.erase(iter);
-  }
-}
-
-/**
- *  Finds visual in given array, returning true if found along with the iterator for that visual as a out parameter
- */
-bool FindVisual(Property::Index targetIndex, const RegisteredVisualContainer& visuals, RegisteredVisualContainer::Iterator& iter)
-{
-  for(iter = visuals.Begin(); iter != visuals.End(); iter++)
-  {
-    if((*iter)->index == targetIndex)
-    {
-      return true;
-    }
-  }
-  return false;
-}
-
-/**
- *  Finds visual in given array, returning true if found along with the iterator for that visual as a out parameter
- */
-bool FindVisual(std::string visualName, const RegisteredVisualContainer& visuals, RegisteredVisualContainer::Iterator& iter)
-{
-  for(iter = visuals.Begin(); iter != visuals.End(); iter++)
-  {
-    Toolkit::Visual::Base visual = (*iter)->visual;
-    if(visual && visual.GetName() == visualName)
-    {
-      return true;
-    }
-  }
-  return false;
-}
-
-/**
- *  Finds visual in given array, returning true if found along with the iterator for that visual as a out parameter
- */
-bool FindVisual(const Toolkit::Visual::Base findVisual, const RegisteredVisualContainer& visuals, RegisteredVisualContainer::Iterator& iter)
-{
-  for(iter = visuals.Begin(); iter != visuals.End(); iter++)
-  {
-    Toolkit::Visual::Base visual = (*iter)->visual;
-    if(visual && visual == findVisual)
-    {
-      return true;
-    }
-  }
-  return false;
-}
-
-/**
- *  Finds internal visual in given array, returning true if found along with the iterator for that visual as a out parameter
- */
-bool FindVisual(const Visual::Base& findInternalVisual, const RegisteredVisualContainer& visuals, RegisteredVisualContainer::Iterator& iter)
-{
-  for(iter = visuals.Begin(); iter != visuals.End(); iter++)
-  {
-    Visual::Base& visual = Toolkit::GetImplementation((*iter)->visual);
-    if((&visual == &findInternalVisual))
-    {
-      return true;
-    }
-  }
-  return false;
-}
-
-void FindChangableVisuals(Dictionary<Property::Map>& stateVisualsToAdd,
-                          Dictionary<Property::Map>& stateVisualsToChange,
-                          DictionaryKeys&            stateVisualsToRemove)
-{
-  DictionaryKeys copyOfStateVisualsToRemove = stateVisualsToRemove;
-
-  for(DictionaryKeys::iterator iter = copyOfStateVisualsToRemove.begin();
-      iter != copyOfStateVisualsToRemove.end();
-      ++iter)
-  {
-    const std::string& visualName = (*iter);
-    Property::Map*     toMap      = stateVisualsToAdd.Find(visualName);
-    if(toMap)
-    {
-      stateVisualsToChange.Add(visualName, *toMap);
-      stateVisualsToAdd.Remove(visualName);
-      Remove(stateVisualsToRemove, visualName);
-    }
-  }
-}
-
-Toolkit::Visual::Base GetVisualByName(
-  const RegisteredVisualContainer& visuals,
-  const std::string&               visualName)
-{
-  Toolkit::Visual::Base visualHandle;
-
-  RegisteredVisualContainer::Iterator iter;
-  for(iter = visuals.Begin(); iter != visuals.End(); iter++)
-  {
-    Toolkit::Visual::Base visual = (*iter)->visual;
-    if(visual && visual.GetName() == visualName)
-    {
-      visualHandle = visual;
-      break;
-    }
-  }
-  return visualHandle;
-}
-
-Toolkit::Visual::Base GetVisualByIndex(
-  const RegisteredVisualContainer& visuals,
-  Property::Index                  index)
-{
-  Toolkit::Visual::Base visualHandle;
-
-  RegisteredVisualContainer::Iterator iter;
-  for(iter = visuals.Begin(); iter != visuals.End(); iter++)
-  {
-    if((*iter)->index == index)
-    {
-      visualHandle = (*iter)->visual;
-      break;
-    }
-  }
-  return visualHandle;
-}
-
-/**
- * Move visual from source to destination container
- */
-void MoveVisual(RegisteredVisualContainer::Iterator sourceIter, RegisteredVisualContainer& source, RegisteredVisualContainer& destination)
-{
-  Toolkit::Visual::Base visual = (*sourceIter)->visual;
-  if(visual)
-  {
-    RegisteredVisual* rv = source.Release(sourceIter);
-    destination.PushBack(rv);
-  }
-}
-
-/**
- * Discard visual from source to visual factory.
- */
-void DiscardVisual(RegisteredVisualContainer::Iterator sourceIter, RegisteredVisualContainer& source)
-{
-  Toolkit::Visual::Base visual = (*sourceIter)->visual;
-  if(visual)
-  {
-    if(DALI_LIKELY(Dali::Adaptor::IsAvailable()))
-    {
-      Toolkit::VisualFactory::Get().DiscardVisual(visual);
-    }
-  }
-
-  source.Erase(sourceIter);
-}
-
 /**
  * Performs actions as requested using the action name.
  * @param[in] object The object on which to perform the action.
@@ -399,15 +221,6 @@ bool DoLegacyAccessibilityAction(BaseObject* object, const std::string& actionNa
   return PerformLegacyAccessibilityAction(control, actionName);
 }
 
-/**
- * Connects a callback function with the object's signals.
- * @param[in] object The object providing the signal.
- * @param[in] tracker Used to disconnect the signal.
- * @param[in] signalName The signal to connect to.
- * @param[in] functor A newly allocated FunctorDelegate.
- * @return True if the signal was connected.
- * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
- */
 const char* SIGNAL_KEY_EVENT              = "keyEvent";
 const char* SIGNAL_KEY_INPUT_FOCUS_GAINED = "keyInputFocusGained";
 const char* SIGNAL_KEY_INPUT_FOCUS_LOST   = "keyInputFocusLost";
@@ -418,6 +231,16 @@ const char* SIGNAL_LONG_PRESSED           = "longPressed";
 const char* SIGNAL_GET_NAME               = "getName";
 const char* SIGNAL_GET_DESCRIPTION        = "getDescription";
 const char* SIGNAL_DO_GESTURE             = "doGesture";
+
+/**
+ * Connects a callback function with the object's signals.
+ * @param[in] object The object providing the signal.
+ * @param[in] tracker Used to disconnect the signal.
+ * @param[in] signalName The signal to connect to.
+ * @param[in] functor A newly allocated FunctorDelegate.
+ * @return True if the signal was connected.
+ * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
+ */
 static bool DoConnectSignal(BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor)
 {
   Dali::BaseHandle handle(object);
@@ -517,58 +340,6 @@ TypeAction registerAction9(typeRegistration, ACTION_ACCESSIBILITY_READING_RESUME
 
 DALI_TYPE_REGISTRATION_END()
 
-/**
- * @brief Iterate through given container and setOffScene any visual found
- *
- * @param[in] container Container of visuals
- * @param[in] parent Parent actor to remove visuals from
- */
-void SetVisualsOffScene(const RegisteredVisualContainer& container, Actor parent)
-{
-  for(auto iter = container.Begin(), end = container.End(); iter != end; iter++)
-  {
-    if((*iter)->visual)
-    {
-      DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::SetOffScene Setting visual(%d) off stage\n", (*iter)->index);
-      Toolkit::GetImplementation((*iter)->visual).SetOffScene(parent);
-    }
-  }
-}
-
-Dali::Rect<> GetShowingGeometry(Dali::Rect<> rect, Dali::Toolkit::DevelControl::ControlAccessible* accessible)
-{
-  Rect<>  parentRect;
-  Vector2 currentPosition;
-  auto    parent = dynamic_cast<Toolkit::DevelControl::ControlAccessible*>(accessible->GetParent());
-
-  while(parent)
-  {
-    parentRect = parent->GetExtents(Dali::Accessibility::CoordinateType::WINDOW);
-
-    currentPosition.x = rect.x;
-    currentPosition.y = rect.y;
-
-    rect.x      = rect.x > parentRect.x ? rect.x : parentRect.x;
-    rect.y      = rect.y > parentRect.y ? rect.y : parentRect.y;
-    rect.width  = currentPosition.x + rect.width < parentRect.x + parentRect.width ? currentPosition.x + rect.width - rect.x : parentRect.x + parentRect.width - rect.x;
-    rect.height = currentPosition.y + rect.height < parentRect.y + parentRect.height ? currentPosition.y + rect.height - rect.y : parentRect.y + parentRect.height - rect.y;
-
-    if(rect.width < 0 || rect.height < 0)
-    {
-      return rect;
-    }
-
-    parent = dynamic_cast<Toolkit::DevelControl::ControlAccessible*>(parent->GetParent());
-  }
-
-  return rect;
-}
-
-static bool IsShowingGeometryOnScreen(Dali::Rect<> rect)
-{
-  return rect.width > 0 && rect.height > 0;
-}
-
 } // unnamed namespace
 
 // clang-format off
@@ -608,6 +379,8 @@ Control::Impl::Impl(Control& controlImpl)
 : mControlImpl(controlImpl),
   mState(Toolkit::DevelControl::NORMAL),
   mSubStateName(""),
+  mAccessibilityData(nullptr),
+  mVisualData(nullptr),
   mLeftFocusableActorId(-1),
   mRightFocusableActorId(-1),
   mUpFocusableActorId(-1),
@@ -624,10 +397,6 @@ Control::Impl::Impl(Control& controlImpl)
   mKeyInputFocusGainedSignal(),
   mKeyInputFocusLostSignal(),
   mResourceReadySignal(),
-  mVisualEventSignal(),
-  mAccessibilityGetNameSignal(),
-  mAccessibilityGetDescriptionSignal(),
-  mAccessibilityDoGestureSignal(),
   mPinchGestureDetector(),
   mPanGestureDetector(),
   mTapGestureDetector(),
@@ -643,43 +412,13 @@ Control::Impl::Impl(Control& controlImpl)
   mDispatchKeyEvents(true),
   mProcessorRegistered(false)
 {
-  Accessibility::Accessible::RegisterExternalAccessibleGetter([](Dali::Actor actor) -> std::pair<std::shared_ptr<Accessibility::Accessible>, bool> {
-    auto control = Toolkit::Control::DownCast(actor);
-    if(!control)
-    {
-      return {nullptr, true};
-    }
-
-    auto& controlImpl = Toolkit::Internal::GetImplementation(control);
-    if(controlImpl.mImpl->IsCreateAccessibleEnabled())
-    {
-      return {std::shared_ptr<DevelControl::ControlAccessible>(controlImpl.CreateAccessibleObject()), true};
-    }
-
-    return {nullptr, false};
-  });
-  mAccessibilityProps.states[DevelControl::AccessibilityState::ENABLED] = true;
+  mAccessibilityData = new AccessibilityData(mControlImpl);
+  mVisualData        = new VisualData(*this);
 }
 
 Control::Impl::~Impl()
 {
-  while(!mVisuals.Empty())
-  {
-    auto iter = mVisuals.End() - 1u;
-    StopObservingVisual((*iter)->visual);
-
-    // Discard removed visual. It will be destroyed at next Idle time.
-    DiscardVisual(iter, mVisuals);
-  }
-
-  while(!mRemoveVisuals.Empty())
-  {
-    auto removalIter = mRemoveVisuals.End() - 1u;
-    StopObservingVisual((*removalIter)->visual);
-
-    // Discard removed visual. It will be destroyed at next Idle time.
-    DiscardVisual(removalIter, mRemoveVisuals);
-  }
+  mVisualData->ClearVisuals();
 
   // All gesture detectors will be destroyed so no need to disconnect.
   delete mStartingPinchScale;
@@ -695,6 +434,9 @@ Control::Impl::~Impl()
     // Removes the callback from the callback manager in case the control is destroyed before the callback is executed.
     Adaptor::Get().RemoveIdle(mIdleCallback);
   }
+
+  delete mAccessibilityData;
+  delete mVisualData;
 }
 
 Control::Impl& Control::Impl::Get(Internal::Control& internalControl)
@@ -711,550 +453,97 @@ const Control::Impl& Control::Impl::Get(const Internal::Control& internalControl
   return *internalControl.mImpl;
 }
 
-void Control::Impl::CheckHighlightedObjectGeometry()
+// Gesture Detection Methods
+void Control::Impl::PinchDetected(Actor actor, const PinchGesture& pinch)
 {
-  auto accessible = GetAccessibleObject();
-  if(DALI_LIKELY(accessible))
-  {
-    auto lastPosition   = accessible->GetLastPosition();
-    auto accessibleRect = accessible->GetExtents(Dali::Accessibility::CoordinateType::WINDOW);
-    auto rect           = GetShowingGeometry(accessibleRect, accessible.get());
-
-    switch(mAccessibilityLastScreenRelativeMoveType)
-    {
-      case Dali::Accessibility::ScreenRelativeMoveType::OUTSIDE:
-      {
-        if(IsShowingGeometryOnScreen(rect))
-        {
-          mAccessibilityLastScreenRelativeMoveType = Dali::Accessibility::ScreenRelativeMoveType::INSIDE;
-        }
-        break;
-      }
-      case Dali::Accessibility::ScreenRelativeMoveType::INSIDE:
-      {
-        if(rect.width < 0 && !Dali::Equals(accessibleRect.x, lastPosition.x))
-        {
-          mAccessibilityLastScreenRelativeMoveType = (accessibleRect.x < lastPosition.x) ? Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_TOP_LEFT : Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_BOTTOM_RIGHT;
-        }
-        if(rect.height < 0 && !Dali::Equals(accessibleRect.y, lastPosition.y))
-        {
-          mAccessibilityLastScreenRelativeMoveType = (accessibleRect.y < lastPosition.y) ? Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_TOP_LEFT : Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_BOTTOM_RIGHT;
-        }
-        // notify AT-clients on outgoing moves only
-        if(mAccessibilityLastScreenRelativeMoveType != Dali::Accessibility::ScreenRelativeMoveType::INSIDE)
-        {
-          accessible->EmitMovedOutOfScreen(mAccessibilityLastScreenRelativeMoveType);
-        }
-        break;
-      }
-      case Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_TOP_LEFT:
-      case Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_BOTTOM_RIGHT:
-      {
-        if(IsShowingGeometryOnScreen(rect))
-        {
-          mAccessibilityLastScreenRelativeMoveType = Dali::Accessibility::ScreenRelativeMoveType::INSIDE;
-        }
-        else
-        {
-          mAccessibilityLastScreenRelativeMoveType = Dali::Accessibility::ScreenRelativeMoveType::OUTSIDE;
-        }
-        break;
-      }
-      default:
-      {
-        break;
-      }
-    }
-
-    accessible->SetLastPosition(Vector2(accessibleRect.x, accessibleRect.y));
-  }
+  mControlImpl.OnPinch(pinch);
 }
 
-void Control::Impl::RegisterAccessibilityPositionPropertyNotification()
+void Control::Impl::PanDetected(Actor actor, const PanGesture& pan)
 {
-  if(mIsAccessibilityPositionPropertyNotificationSet)
-  {
-    return;
-  }
-  // set default value until first move of object is detected
-  mAccessibilityLastScreenRelativeMoveType = Dali::Accessibility::ScreenRelativeMoveType::OUTSIDE;
-  // recalculate mAccessibilityLastScreenRelativeMoveType accordingly to the initial position
-  CheckHighlightedObjectGeometry();
-  mAccessibilityPositionNotification = mControlImpl.Self().AddPropertyNotification(Actor::Property::WORLD_POSITION, StepCondition(1.0f, 1.0f));
-  mAccessibilityPositionNotification.SetNotifyMode(PropertyNotification::NOTIFY_ON_CHANGED);
-  mAccessibilityPositionNotification.NotifySignal().Connect(this, [this](PropertyNotification&) { CheckHighlightedObjectGeometry(); });
-  mIsAccessibilityPositionPropertyNotificationSet = true;
+  mControlImpl.OnPan(pan);
 }
 
-void Control::Impl::UnregisterAccessibilityPositionPropertyNotification()
+void Control::Impl::TapDetected(Actor actor, const TapGesture& tap)
 {
-  mControlImpl.Self().RemovePropertyNotification(mAccessibilityPositionNotification);
-  mIsAccessibilityPositionPropertyNotificationSet = false;
+  mControlImpl.OnTap(tap);
 }
 
-void Control::Impl::RegisterAccessibilityPropertySetSignal()
+void Control::Impl::LongPressDetected(Actor actor, const LongPressGesture& longPress)
 {
-  if(mIsAccessibilityPropertySetSignalRegistered)
-  {
-    return;
-  }
-  mControlImpl.Self().PropertySetSignal().Connect(this, &Control::Impl::OnAccessibilityPropertySet);
-  mIsAccessibilityPropertySetSignalRegistered = true;
+  mControlImpl.OnLongPress(longPress);
 }
 
-void Control::Impl::UnregisterAccessibilityPropertySetSignal()
+void Control::Impl::ResourceReady()
 {
-  if(!mIsAccessibilityPropertySetSignalRegistered)
+  DALI_ASSERT_ALWAYS(Stage::IsCoreThread() && "Core is not installed. Might call this API from worker thread?");
+
+  // Emit signal if all enabled visuals registered by the control are ready or there are no visuals.
+  if(mVisualData->IsResourceReady())
   {
-    return;
+    EmitResourceReadySignal();
   }
-  mControlImpl.Self().PropertySetSignal().Disconnect(this, &Control::Impl::OnAccessibilityPropertySet);
-  mIsAccessibilityPropertySetSignalRegistered = false;
 }
 
-void Control::Impl::OnAccessibilityPropertySet(Dali::Handle& handle, Dali::Property::Index index, const Dali::Property::Value& value)
+void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual)
 {
-  auto accessible = GetAccessibleObject();
-  if(DALI_LIKELY(accessible))
-  {
-    if(mAccessibilityGetNameSignal.Empty())
-    {
-      if(index == DevelControl::Property::ACCESSIBILITY_NAME || (mAccessibilityProps.name.empty() && index == accessible->GetNamePropertyIndex()))
-      {
-        accessible->Emit(Dali::Accessibility::ObjectPropertyChangeEvent::NAME);
-        return;
-      }
-    }
-
-    if(mAccessibilityGetDescriptionSignal.Empty())
-    {
-      if(index == DevelControl::Property::ACCESSIBILITY_DESCRIPTION || (mAccessibilityProps.description.empty() && index == accessible->GetDescriptionPropertyIndex()))
-      {
-        accessible->Emit(Dali::Accessibility::ObjectPropertyChangeEvent::DESCRIPTION);
-        return;
-      }
-    }
-
-    if(index == DevelControl::Property::ACCESSIBILITY_VALUE)
-    {
-      accessible->Emit(Dali::Accessibility::ObjectPropertyChangeEvent::VALUE);
-      return;
-    }
+  mVisualData->RegisterVisual(index, visual);
+}
 
-    if(index == DevelControl::Property::ACCESSIBILITY_STATES)
-    {
-      accessible->OnStatePropertySet(mAccessibilityProps.states);
-      return;
-    }
-  }
+void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, int depthIndex)
+{
+  mVisualData->RegisterVisual(index, visual, depthIndex);
 }
 
-// Gesture Detection Methods
-void Control::Impl::PinchDetected(Actor actor, const PinchGesture& pinch)
+void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, bool enabled)
 {
-  mControlImpl.OnPinch(pinch);
+  mVisualData->RegisterVisual(index, visual, enabled);
 }
 
-void Control::Impl::PanDetected(Actor actor, const PanGesture& pan)
+void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, bool enabled, int depthIndex)
 {
-  mControlImpl.OnPan(pan);
+  mVisualData->RegisterVisual(index, visual, enabled, depthIndex);
 }
 
-void Control::Impl::TapDetected(Actor actor, const TapGesture& tap)
+void Control::Impl::UnregisterVisual(Property::Index index)
 {
-  mControlImpl.OnTap(tap);
+  mVisualData->UnregisterVisual(index);
 }
 
-void Control::Impl::LongPressDetected(Actor actor, const LongPressGesture& longPress)
+Toolkit::Visual::Base Control::Impl::GetVisual(Property::Index index) const
 {
-  mControlImpl.OnLongPress(longPress);
+  return mVisualData->GetVisual(index);
 }
 
-void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual)
+bool Control::Impl::IsResourceReady() const
 {
-  RegisterVisual(index, visual, VisualState::ENABLED, DepthIndexValue::NOT_SET);
+  return mVisualData->IsResourceReady();
 }
 
-void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, int depthIndex)
+void Control::Impl::OnSceneDisconnection()
 {
-  RegisterVisual(index, visual, VisualState::ENABLED, DepthIndexValue::SET, depthIndex);
+  Actor self = mControlImpl.Self();
+  mVisualData->ClearScene(self);
 }
 
-void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, bool enabled)
+void Control::Impl::EnableReadyTransitionOverriden(Toolkit::Visual::Base& visual, bool enable)
 {
-  RegisterVisual(index, visual, (enabled ? VisualState::ENABLED : VisualState::DISABLED), DepthIndexValue::NOT_SET);
+  mVisualData->EnableReadyTransitionOverriden(visual, enable);
 }
 
-void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, bool enabled, int depthIndex)
+void Control::Impl::EnableVisual(Property::Index index, bool enable)
 {
-  RegisterVisual(index, visual, (enabled ? VisualState::ENABLED : VisualState::DISABLED), DepthIndexValue::SET, depthIndex);
+  mVisualData->EnableVisual(index, enable);
 }
 
-void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, VisualState::Type enabled, DepthIndexValue::Type depthIndexValueSet, int depthIndex)
+bool Control::Impl::IsVisualEnabled(Property::Index index) const
 {
-  DALI_ASSERT_ALWAYS(Stage::IsCoreThread() && "Core is not installed. Might call this API from worker thread?");
-
-  DALI_LOG_INFO(gLogFilter, Debug::Concise, "RegisterVisual:%d \n", index);
-
-  bool  visualReplaced(false);
-  Actor self = mControlImpl.Self();
-
-  // Set the depth index, if not set by caller this will be either the current visual depth, max depth of all visuals
-  // or zero.
-  int requiredDepthIndex = visual.GetDepthIndex();
-
-  if(depthIndexValueSet == DepthIndexValue::SET)
-  {
-    requiredDepthIndex = depthIndex;
-  }
-
-  // Change the depth index value automatically if the visual has DepthIndex to AUTO_INDEX
-  // or if RegisterVisual set DepthIndex to AUTO_INDEX.
-  const bool requiredDepthIndexChanged = (requiredDepthIndex == DepthIndex::AUTO_INDEX);
-
-  // Visual replacement, existing visual should only be removed from stage when replacement ready.
-  if(!mVisuals.Empty())
-  {
-    RegisteredVisualContainer::Iterator registeredVisualsiter;
-    // Check if visual (index) is already registered, this is the current visual.
-    if(FindVisual(index, mVisuals, registeredVisualsiter))
-    {
-      Toolkit::Visual::Base& currentRegisteredVisual = (*registeredVisualsiter)->visual;
-      if(currentRegisteredVisual)
-      {
-        // Store current visual depth index as may need to set the replacement visual to same depth
-        const int currentDepthIndex = (*registeredVisualsiter)->visual.GetDepthIndex();
-
-        // No longer required to know if the replaced visual's resources are ready
-        StopObservingVisual(currentRegisteredVisual);
-
-        // If control staged and visual enabled then visuals will be swapped once ready
-        if(self.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE) && enabled)
-        {
-          // Check if visual is currently in the process of being replaced ( is in removal container )
-          RegisteredVisualContainer::Iterator visualQueuedForRemoval;
-          if(FindVisual(index, mRemoveVisuals, visualQueuedForRemoval))
-          {
-            // Visual with same index is already in removal container so current visual pending
-            // Only the the last requested visual will be displayed so remove current visual which is staged but not ready.
-            Toolkit::GetImplementation(currentRegisteredVisual).SetOffScene(self);
-            mVisuals.Erase(registeredVisualsiter);
-          }
-          else
-          {
-            // current visual not already in removal container so add now.
-            DALI_LOG_INFO(gLogFilter, Debug::Verbose, "RegisterVisual Move current registered visual to removal Queue: %d \n", index);
-            MoveVisual(registeredVisualsiter, mVisuals, mRemoveVisuals);
-          }
-        }
-        else
-        {
-          // Control not staged or visual disabled so can just erase from registered visuals and new visual will be added later.
-          mVisuals.Erase(registeredVisualsiter);
-        }
-
-        // If the visual have a depth index as AUTO_INDEX and the new visual does not have a depth index applied to it, then use the previously set depth-index for this index
-        if(requiredDepthIndexChanged)
-        {
-          requiredDepthIndex = currentDepthIndex;
-          DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Use replaced visual index. VisualDepthIndex AUTO_INDEX set as: %d\n", requiredDepthIndex);
-        }
-      }
-
-      visualReplaced = true;
-    }
-  }
-
-  // If not set, set the name of the visual to the same name as the control's property.
-  // ( If the control has been type registered )
-  if(visual.GetName().empty())
-  {
-    // returns empty string if index is not found as long as index is not -1
-    std::string visualName = self.GetPropertyName(index);
-    if(!visualName.empty())
-    {
-      DALI_LOG_INFO(gLogFilter, Debug::Concise, "Setting visual name for property %d to %s\n", index, visualName.c_str());
-      visual.SetName(visualName);
-    }
-  }
-
-  if(!visualReplaced) // New registration entry
-  {
-    // If we have more than one visual and the visual have a depth index as AUTO_INDEX, then set it to be the highest
-    if((mVisuals.Size() > 0) && requiredDepthIndexChanged)
-    {
-      int maxDepthIndex = static_cast<int>(DepthIndex::CONTENT) - 1; // Start at DepthIndex::CONTENT if maxDepth index belongs to a background or no visuals have been added yet.
-
-      RegisteredVisualContainer::ConstIterator       iter;
-      const RegisteredVisualContainer::ConstIterator endIter = mVisuals.End();
-      for(iter = mVisuals.Begin(); iter != endIter; iter++)
-      {
-        const int visualDepthIndex = (*iter)->visual.GetDepthIndex();
-        if(visualDepthIndex > maxDepthIndex)
-        {
-          maxDepthIndex = visualDepthIndex;
-        }
-      }
-      requiredDepthIndex = ++maxDepthIndex; // Add one to the current maximum depth index so that our added visual appears on top.
-      DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Use top of all visuals. VisualDepthIndex AUTO_INDEX set as: %d\n", requiredDepthIndex);
-    }
-  }
-
-  if(visual)
-  {
-    // If required depth index still DepthIndex::AUTO_INDEX, Make it as DepthIndex::CONTENT now
-    if(requiredDepthIndex == static_cast<int>(DepthIndex::AUTO_INDEX))
-    {
-      requiredDepthIndex = static_cast<int>(DepthIndex::CONTENT);
-      DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Some strange cases. VisualDepthIndex AUTO_INDEX set as: %d\n", requiredDepthIndex);
-    }
-
-    // Set determined depth index
-    visual.SetDepthIndex(requiredDepthIndex);
-
-    // Monitor when the visual resources are ready
-    StartObservingVisual(visual);
-
-    DALI_LOG_INFO(gLogFilter, Debug::Concise, "New Visual registration index[%d] depth[%d]\n", index, requiredDepthIndex);
-    RegisteredVisual* newRegisteredVisual = new RegisteredVisual(index, visual, (enabled == VisualState::ENABLED ? true : false), (visualReplaced && enabled));
-    mVisuals.PushBack(newRegisteredVisual);
-
-    Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
-    // Put on stage if enabled and the control is already on the stage
-    if((enabled == VisualState::ENABLED) && self.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
-    {
-      visualImpl.SetOnScene(self);
-    }
-    else if(enabled && visualImpl.IsResourceReady()) // When not being staged, check if visual already 'ResourceReady' before it was Registered. ( Resource may have been loaded already )
-    {
-      ResourceReady(visualImpl);
-    }
-  }
-
-  DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::RegisterVisual() Registered %s(%d), enabled:%s\n", visual.GetName().c_str(), index, enabled ? "true" : "false");
-}
-
-void Control::Impl::UnregisterVisual(Property::Index index)
-{
-  DALI_ASSERT_ALWAYS(Stage::IsCoreThread() && "Core is not installed. Might call this API from worker thread?");
-
-  RegisteredVisualContainer::Iterator iter;
-  if(FindVisual(index, mVisuals, iter))
-  {
-    // stop observing visual
-    StopObservingVisual((*iter)->visual);
-
-    Actor self(mControlImpl.Self());
-    Toolkit::GetImplementation((*iter)->visual).SetOffScene(self);
-    (*iter)->visual.Reset();
-    mVisuals.Erase(iter);
-  }
-
-  if(FindVisual(index, mRemoveVisuals, iter))
-  {
-    Actor self(mControlImpl.Self());
-    Toolkit::GetImplementation((*iter)->visual).SetOffScene(self);
-    (*iter)->pending = false;
-
-    // Discard removed visual. It will be destroyed at next Idle time.
-    DiscardVisual(iter, mRemoveVisuals);
-  }
-}
-
-Toolkit::Visual::Base Control::Impl::GetVisual(Property::Index index) const
-{
-  RegisteredVisualContainer::Iterator iter;
-  if(FindVisual(index, mVisuals, iter))
-  {
-    return (*iter)->visual;
-  }
-
-  return Toolkit::Visual::Base();
-}
-
-void Control::Impl::EnableVisual(Property::Index index, bool enable)
-{
-  DALI_LOG_INFO(gLogFilter, Debug::General, "Control::EnableVisual(%d, %s)\n", index, enable ? "T" : "F");
-
-  RegisteredVisualContainer::Iterator iter;
-  if(FindVisual(index, mVisuals, iter))
-  {
-    if((*iter)->enabled == enable)
-    {
-      DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::EnableVisual Visual %s(%d) already %s\n", (*iter)->visual.GetName().c_str(), index, enable ? "enabled" : "disabled");
-      return;
-    }
-
-    (*iter)->enabled  = enable;
-    Actor parentActor = mControlImpl.Self();
-    if(mControlImpl.Self().GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE)) // If control not on Scene then Visual will be added when SceneConnection is called.
-    {
-      if(enable)
-      {
-        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::EnableVisual Setting %s(%d) on stage \n", (*iter)->visual.GetName().c_str(), index);
-        Toolkit::GetImplementation((*iter)->visual).SetOnScene(parentActor);
-      }
-      else
-      {
-        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::EnableVisual Setting %s(%d) off stage \n", (*iter)->visual.GetName().c_str(), index);
-        Toolkit::GetImplementation((*iter)->visual).SetOffScene(parentActor); // No need to call if control not staged.
-      }
-    }
-  }
-  else
-  {
-    DALI_LOG_WARNING("Control::EnableVisual(%d, %s) FAILED - NO SUCH VISUAL\n", index, enable ? "T" : "F");
-  }
-}
-
-bool Control::Impl::IsVisualEnabled(Property::Index index) const
-{
-  RegisteredVisualContainer::Iterator iter;
-  if(FindVisual(index, mVisuals, iter))
-  {
-    return (*iter)->enabled;
-  }
-  return false;
-}
-
-void Control::Impl::EnableReadyTransitionOverriden(Toolkit::Visual::Base& visual, bool enable)
-{
-  DALI_LOG_INFO(gLogFilter, Debug::General, "Control::EnableReadyTransitionOverriden(%p, %s)\n", visual, enable ? "T" : "F");
-
-  RegisteredVisualContainer::Iterator iter;
-  if(FindVisual(visual, mVisuals, iter))
-  {
-    if((*iter)->overideReadyTransition == enable)
-    {
-      DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::EnableReadyTransitionOverriden Visual %s(%p) already %s\n", (*iter)->visual.GetName().c_str(), visual, enable ? "enabled" : "disabled");
-      return;
-    }
-
-    (*iter)->overideReadyTransition = enable;
-  }
-}
-
-void Control::Impl::StopObservingVisual(Toolkit::Visual::Base& visual)
-{
-  Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
-
-  // Stop observing the visual
-  visualImpl.RemoveEventObserver(*this);
-}
-
-void Control::Impl::StartObservingVisual(Toolkit::Visual::Base& visual)
-{
-  Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
-
-  // start observing the visual for events
-  visualImpl.AddEventObserver(*this);
-}
-
-void Control::Impl::ResourceReady()
-{
-  DALI_ASSERT_ALWAYS(Stage::IsCoreThread() && "Core is not installed. Might call this API from worker thread?");
-
-  // Emit signal if all enabled visuals registered by the control are ready or there are no visuals.
-  if(IsResourceReady())
-  {
-    EmitResourceReadySignal();
-  }
-}
-
-// Called by a Visual when it's resource is ready
-void Control::Impl::ResourceReady(Visual::Base& object)
-{
-  DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::Impl::ResourceReady() replacements pending[%d]\n", mRemoveVisuals.Count());
-
-  Actor self = mControlImpl.Self();
-
-  RegisteredVisualContainer::Iterator registeredIter;
-
-  // A resource is ready, find resource in the registered visuals container and get its index
-  if(!FindVisual(object, mVisuals, registeredIter))
-  {
-    return;
-  }
-
-  RegisteredVisualContainer::Iterator visualToRemoveIter;
-  // Find visual with the same index in the removal container
-  // Set if off stage as it's replacement is now ready.
-  // Remove if from removal list as now removed from stage.
-  // Set Pending flag on the ready visual to false as now ready.
-  if(FindVisual((*registeredIter)->index, mRemoveVisuals, visualToRemoveIter))
-  {
-    (*registeredIter)->pending = false;
-    if(!((*visualToRemoveIter)->overideReadyTransition))
-    {
-      Toolkit::GetImplementation((*visualToRemoveIter)->visual).SetOffScene(self);
-    }
-
-    // Discard removed visual. It will be destroyed at next Idle time.
-    DiscardVisual(visualToRemoveIter, mRemoveVisuals);
-  }
-
-  // A visual is ready so control may need relayouting if staged
-  RelayoutRequest(object);
-
-  // Called by a Visual when it's resource is ready
-  if(((*registeredIter)->enabled))
-  {
-    ResourceReady();
-  }
-}
-
-void Control::Impl::NotifyVisualEvent(Visual::Base& object, Property::Index signalId)
-{
-  for(auto registeredIter = mVisuals.Begin(), end = mVisuals.End(); registeredIter != end; ++registeredIter)
-  {
-    Internal::Visual::Base& registeredVisualImpl = Toolkit::GetImplementation((*registeredIter)->visual);
-    if(&object == &registeredVisualImpl)
-    {
-      Dali::Toolkit::Control handle(mControlImpl.GetOwner());
-      mVisualEventSignal.Emit(handle, (*registeredIter)->index, signalId);
-      break;
-    }
-  }
-}
-
-void Control::Impl::RelayoutRequest(Visual::Base& object)
-{
-  if(mControlImpl.Self().GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
-  {
-    mControlImpl.RelayoutRequest();
-  }
-}
-
-bool Control::Impl::IsResourceReady() const
-{
-  // Iterate through and check all the enabled visuals are ready
-  for(auto visualIter = mVisuals.Begin();
-      visualIter != mVisuals.End();
-      ++visualIter)
-  {
-    const Toolkit::Visual::Base   visual     = (*visualIter)->visual;
-    const Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
-
-    // one of the enabled visuals is not ready
-    if(!visualImpl.IsResourceReady() && (*visualIter)->enabled)
-    {
-      return false;
-    }
-  }
-  return true;
-}
+  return mVisualData->IsVisualEnabled(index);
+}
 
 Toolkit::Visual::ResourceStatus Control::Impl::GetVisualResourceStatus(Property::Index index) const
 {
-  RegisteredVisualContainer::Iterator iter;
-  if(FindVisual(index, mVisuals, iter))
-  {
-    const Toolkit::Visual::Base   visual     = (*iter)->visual;
-    const Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
-    return visualImpl.GetResourceStatus();
-  }
-
-  return Toolkit::Visual::ResourceStatus::PREPARING;
+  return mVisualData->GetVisualResourceStatus(index);
 }
 
 void Control::Impl::AddTransitions(Dali::Animation&               animation,
@@ -1270,7 +559,7 @@ void Control::Impl::AddTransitions(Dali::Animation&               animation,
   {
     TransitionData::Animator* animator = (*iter);
 
-    Toolkit::Visual::Base visual = GetVisualByName(mVisuals, animator->objectName);
+    Toolkit::Visual::Base visual = mVisualData->GetVisual(animator->objectName);
     if(visual)
     {
 #if defined(DEBUG_ENABLED)
@@ -1327,46 +616,25 @@ void Control::Impl::AddTransitions(Dali::Animation&               animation,
   }
 }
 
-Dali::Animation Control::Impl::CreateTransition(const Toolkit::TransitionData& transitionData)
-{
-  Dali::Animation transition;
-
-  if(transitionData.Count() > 0)
-  {
-    AddTransitions(transition, transitionData, true);
-  }
-  return transition;
-}
-
 void Control::Impl::DoAction(Dali::Property::Index visualIndex, Dali::Property::Index actionId, const Dali::Property::Value attributes)
 {
-  RegisteredVisualContainer::Iterator iter;
-  if(FindVisual(visualIndex, mVisuals, iter))
-  {
-    Toolkit::GetImplementation((*iter)->visual).DoAction(actionId, attributes);
-  }
+  mVisualData->DoAction(visualIndex, actionId, attributes);
 }
 
 void Control::Impl::DoActionExtension(Dali::Property::Index visualIndex, Dali::Property::Index actionId, Dali::Any attributes)
 {
-  RegisteredVisualContainer::Iterator iter;
-  if(FindVisual(visualIndex, mVisuals, iter))
-  {
-    Toolkit::GetImplementation((*iter)->visual).DoActionExtension(actionId, attributes);
-  }
+  mVisualData->DoActionExtension(visualIndex, actionId, attributes);
 }
 
-void Control::Impl::AppendAccessibilityAttribute(const std::string& key, const std::string value)
+Dali::Animation Control::Impl::CreateTransition(const Toolkit::TransitionData& transitionData)
 {
-  Property::Value* checkedValue = mAccessibilityProps.extraAttributes.Find(key);
-  if(checkedValue)
-  {
-    mAccessibilityProps.extraAttributes[key] = Property::Value(value);
-  }
-  else
+  Dali::Animation transition;
+
+  if(transitionData.Count() > 0)
   {
-    mAccessibilityProps.extraAttributes.Insert(key, value);
+    AddTransitions(transition, transitionData, true);
   }
+  return transition;
 }
 
 void Control::Impl::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value)
@@ -1492,7 +760,7 @@ void Control::Impl::SetProperty(BaseObject* object, Property::Index index, const
           Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual(url, ImageDimensions());
           if(visual)
           {
-            controlImpl.mImpl->RegisterVisual(Toolkit::Control::Property::BACKGROUND, visual, DepthIndex::BACKGROUND);
+            controlImpl.mImpl->mVisualData->RegisterVisual(Toolkit::Control::Property::BACKGROUND, visual, DepthIndex::BACKGROUND);
           }
         }
         else if(value.Get(color))
@@ -1558,7 +826,7 @@ void Control::Impl::SetProperty(BaseObject* object, Property::Index index, const
         std::string name;
         if(value.Get(name))
         {
-          controlImpl.mImpl->mAccessibilityProps.name = std::move(name);
+          controlImpl.mImpl->mAccessibilityData->mAccessibilityProps.name = std::move(name);
         }
         break;
       }
@@ -1568,7 +836,7 @@ void Control::Impl::SetProperty(BaseObject* object, Property::Index index, const
         std::string text;
         if(value.Get(text))
         {
-          controlImpl.mImpl->mAccessibilityProps.description = std::move(text);
+          controlImpl.mImpl->mAccessibilityData->mAccessibilityProps.description = std::move(text);
         }
         break;
       }
@@ -1578,7 +846,7 @@ void Control::Impl::SetProperty(BaseObject* object, Property::Index index, const
         int32_t role;
         if(value.Get(role))
         {
-          controlImpl.mImpl->mAccessibilityProps.role = role;
+          controlImpl.mImpl->mAccessibilityData->mAccessibilityProps.role = role;
         }
         break;
       }
@@ -1588,7 +856,7 @@ void Control::Impl::SetProperty(BaseObject* object, Property::Index index, const
         bool highlightable;
         if(value.Get(highlightable))
         {
-          controlImpl.mImpl->mAccessibilityProps.isHighlightable = highlightable ? TriStateProperty::TRUE : TriStateProperty::FALSE;
+          controlImpl.mImpl->mAccessibilityData->mAccessibilityProps.isHighlightable = highlightable ? TriStateProperty::TRUE : TriStateProperty::FALSE;
         }
         break;
       }
@@ -1598,7 +866,7 @@ void Control::Impl::SetProperty(BaseObject* object, Property::Index index, const
         const Property::Map* map = value.GetMap();
         if(map && !map->Empty())
         {
-          controlImpl.mImpl->mAccessibilityProps.extraAttributes = *map;
+          controlImpl.mImpl->mAccessibilityData->mAccessibilityProps.extraAttributes = *map;
         }
         break;
       }
@@ -1618,7 +886,7 @@ void Control::Impl::SetProperty(BaseObject* object, Property::Index index, const
         bool hidden;
         if(value.Get(hidden))
         {
-          controlImpl.mImpl->mAccessibilityProps.isHidden = hidden;
+          controlImpl.mImpl->mAccessibilityData->mAccessibilityProps.isHidden = hidden;
 
           auto accessible = controlImpl.GetAccessibleObject();
           if(DALI_LIKELY(accessible))
@@ -1656,7 +924,7 @@ void Control::Impl::SetProperty(BaseObject* object, Property::Index index, const
         std::string automationId;
         if(value.Get(automationId))
         {
-          controlImpl.mImpl->mAccessibilityProps.automationId = std::move(automationId);
+          controlImpl.mImpl->mAccessibilityData->mAccessibilityProps.automationId = std::move(automationId);
         }
         break;
       }
@@ -1666,7 +934,7 @@ void Control::Impl::SetProperty(BaseObject* object, Property::Index index, const
         std::string accessibilityValue;
         if(value.Get(accessibilityValue))
         {
-          controlImpl.mImpl->mAccessibilityProps.value = std::move(accessibilityValue);
+          controlImpl.mImpl->mAccessibilityData->mAccessibilityProps.value = std::move(accessibilityValue);
         }
         break;
       }
@@ -1676,7 +944,7 @@ void Control::Impl::SetProperty(BaseObject* object, Property::Index index, const
         bool isScrollable;
         if(value.Get(isScrollable))
         {
-          controlImpl.mImpl->mAccessibilityProps.isScrollable = isScrollable;
+          controlImpl.mImpl->mAccessibilityData->mAccessibilityProps.isScrollable = isScrollable;
         }
         break;
       }
@@ -1686,7 +954,7 @@ void Control::Impl::SetProperty(BaseObject* object, Property::Index index, const
         int32_t states;
         if(value.Get(states))
         {
-          controlImpl.mImpl->mAccessibilityProps.states = Toolkit::DevelControl::AccessibilityStates{static_cast<uint32_t>(states)};
+          controlImpl.mImpl->mAccessibilityData->mAccessibilityProps.states = Toolkit::DevelControl::AccessibilityStates{static_cast<uint32_t>(states)};
         }
         break;
       }
@@ -1696,7 +964,7 @@ void Control::Impl::SetProperty(BaseObject* object, Property::Index index, const
         bool isModal;
         if(value.Get(isModal))
         {
-          controlImpl.mImpl->mAccessibilityProps.isModal = isModal;
+          controlImpl.mImpl->mAccessibilityData->mAccessibilityProps.isModal = isModal;
         }
         break;
       }
@@ -1769,7 +1037,7 @@ Property::Value Control::Impl::GetProperty(BaseObject* object, Property::Index i
       case Toolkit::Control::Property::BACKGROUND:
       {
         Property::Map         map;
-        Toolkit::Visual::Base visual = controlImpl.mImpl->GetVisual(Toolkit::Control::Property::BACKGROUND);
+        Toolkit::Visual::Base visual = controlImpl.mImpl->mVisualData->GetVisual(Toolkit::Control::Property::BACKGROUND);
         if(visual)
         {
           visual.CreatePropertyMap(map);
@@ -1805,7 +1073,7 @@ Property::Value Control::Impl::GetProperty(BaseObject* object, Property::Index i
       case Toolkit::DevelControl::Property::SHADOW:
       {
         Property::Map         map;
-        Toolkit::Visual::Base visual = controlImpl.mImpl->GetVisual(Toolkit::DevelControl::Property::SHADOW);
+        Toolkit::Visual::Base visual = controlImpl.mImpl->mVisualData->GetVisual(Toolkit::DevelControl::Property::SHADOW);
         if(visual)
         {
           visual.CreatePropertyMap(map);
@@ -1817,31 +1085,31 @@ Property::Value Control::Impl::GetProperty(BaseObject* object, Property::Index i
 
       case Toolkit::DevelControl::Property::ACCESSIBILITY_NAME:
       {
-        value = controlImpl.mImpl->mAccessibilityProps.name;
+        value = controlImpl.mImpl->mAccessibilityData->mAccessibilityProps.name;
         break;
       }
 
       case Toolkit::DevelControl::Property::ACCESSIBILITY_DESCRIPTION:
       {
-        value = controlImpl.mImpl->mAccessibilityProps.description;
+        value = controlImpl.mImpl->mAccessibilityData->mAccessibilityProps.description;
         break;
       }
 
       case Toolkit::DevelControl::Property::ACCESSIBILITY_ROLE:
       {
-        value = controlImpl.mImpl->mAccessibilityProps.role;
+        value = controlImpl.mImpl->mAccessibilityData->mAccessibilityProps.role;
         break;
       }
 
       case Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE:
       {
-        value = controlImpl.mImpl->mAccessibilityProps.isHighlightable == TriStateProperty::TRUE ? true : false;
+        value = controlImpl.mImpl->mAccessibilityData->mAccessibilityProps.isHighlightable == TriStateProperty::TRUE ? true : false;
         break;
       }
 
       case Toolkit::DevelControl::Property::ACCESSIBILITY_ATTRIBUTES:
       {
-        value = controlImpl.mImpl->mAccessibilityProps.extraAttributes;
+        value = controlImpl.mImpl->mAccessibilityData->mAccessibilityProps.extraAttributes;
         break;
       }
 
@@ -1853,7 +1121,7 @@ Property::Value Control::Impl::GetProperty(BaseObject* object, Property::Index i
 
       case Toolkit::DevelControl::Property::ACCESSIBILITY_HIDDEN:
       {
-        value = controlImpl.mImpl->mAccessibilityProps.isHidden;
+        value = controlImpl.mImpl->mAccessibilityData->mAccessibilityProps.isHidden;
         break;
       }
 
@@ -1871,31 +1139,31 @@ Property::Value Control::Impl::GetProperty(BaseObject* object, Property::Index i
 
       case Toolkit::DevelControl::Property::AUTOMATION_ID:
       {
-        value = controlImpl.mImpl->mAccessibilityProps.automationId;
+        value = controlImpl.mImpl->mAccessibilityData->mAccessibilityProps.automationId;
         break;
       }
 
       case Toolkit::DevelControl::Property::ACCESSIBILITY_VALUE:
       {
-        value = controlImpl.mImpl->mAccessibilityProps.value;
+        value = controlImpl.mImpl->mAccessibilityData->mAccessibilityProps.value;
         break;
       }
 
       case Toolkit::DevelControl::Property::ACCESSIBILITY_SCROLLABLE:
       {
-        value = controlImpl.mImpl->mAccessibilityProps.isScrollable;
+        value = controlImpl.mImpl->mAccessibilityData->mAccessibilityProps.isScrollable;
         break;
       }
 
       case Toolkit::DevelControl::Property::ACCESSIBILITY_STATES:
       {
-        value = static_cast<int32_t>(controlImpl.mImpl->mAccessibilityProps.states.GetRawData32());
+        value = static_cast<int32_t>(controlImpl.mImpl->mAccessibilityData->mAccessibilityProps.states.GetRawData32());
         break;
       }
 
       case Toolkit::DevelControl::Property::ACCESSIBILITY_IS_MODAL:
       {
-        value = controlImpl.mImpl->mAccessibilityProps.isModal;
+        value = controlImpl.mImpl->mAccessibilityData->mAccessibilityProps.isModal;
         break;
       }
     }
@@ -1904,253 +1172,6 @@ Property::Value Control::Impl::GetProperty(BaseObject* object, Property::Index i
   return value;
 }
 
-void Control::Impl::RemoveAccessibilityAttribute(const std::string& key)
-{
-  Property::Value* value = mAccessibilityProps.extraAttributes.Find(key);
-  if(value)
-  {
-    mAccessibilityProps.extraAttributes[key] = Property::Value();
-  }
-}
-
-void Control::Impl::ClearAccessibilityAttributes()
-{
-  mAccessibilityProps.extraAttributes.Clear();
-}
-
-void Control::Impl::SetAccessibilityReadingInfoType(const Dali::Accessibility::ReadingInfoTypes types)
-{
-  std::string value{};
-  if(types[Dali::Accessibility::ReadingInfoType::NAME])
-  {
-    value += READING_INFO_TYPE_NAME;
-  }
-  if(types[Dali::Accessibility::ReadingInfoType::ROLE])
-  {
-    if(!value.empty())
-    {
-      value += READING_INFO_TYPE_SEPARATOR;
-    }
-    value += READING_INFO_TYPE_ROLE;
-  }
-  if(types[Dali::Accessibility::ReadingInfoType::DESCRIPTION])
-  {
-    if(!value.empty())
-    {
-      value += READING_INFO_TYPE_SEPARATOR;
-    }
-    value += READING_INFO_TYPE_DESCRIPTION;
-  }
-  if(types[Dali::Accessibility::ReadingInfoType::STATE])
-  {
-    if(!value.empty())
-    {
-      value += READING_INFO_TYPE_SEPARATOR;
-    }
-    value += READING_INFO_TYPE_STATE;
-  }
-  AppendAccessibilityAttribute(READING_INFO_TYPE_ATTRIBUTE_NAME, value);
-}
-
-Dali::Accessibility::ReadingInfoTypes Control::Impl::GetAccessibilityReadingInfoType() const
-{
-  std::string value{};
-  auto        place = mAccessibilityProps.extraAttributes.Find(READING_INFO_TYPE_ATTRIBUTE_NAME);
-  if(place)
-  {
-    place->Get(value);
-  }
-  else
-  {
-    Dali::Accessibility::ReadingInfoTypes types;
-    types[Dali::Accessibility::ReadingInfoType::NAME]        = true;
-    types[Dali::Accessibility::ReadingInfoType::ROLE]        = true;
-    types[Dali::Accessibility::ReadingInfoType::DESCRIPTION] = true;
-    types[Dali::Accessibility::ReadingInfoType::STATE]       = true;
-    return types;
-  }
-
-  if(value.empty())
-  {
-    return {};
-  }
-
-  Dali::Accessibility::ReadingInfoTypes types;
-
-  if(value.find(READING_INFO_TYPE_NAME) != std::string::npos)
-  {
-    types[Dali::Accessibility::ReadingInfoType::NAME] = true;
-  }
-  if(value.find(READING_INFO_TYPE_ROLE) != std::string::npos)
-  {
-    types[Dali::Accessibility::ReadingInfoType::ROLE] = true;
-  }
-  if(value.find(READING_INFO_TYPE_DESCRIPTION) != std::string::npos)
-  {
-    types[Dali::Accessibility::ReadingInfoType::DESCRIPTION] = true;
-  }
-  if(value.find(READING_INFO_TYPE_STATE) != std::string::npos)
-  {
-    types[Dali::Accessibility::ReadingInfoType::STATE] = true;
-  }
-
-  return types;
-}
-
-void Control::Impl::CopyInstancedProperties(RegisteredVisualContainer& visuals, Dictionary<Property::Map>& instancedProperties)
-{
-  for(RegisteredVisualContainer::Iterator iter = visuals.Begin(); iter != visuals.End(); iter++)
-  {
-    if((*iter)->visual)
-    {
-      Property::Map instanceMap;
-      Toolkit::GetImplementation((*iter)->visual).CreateInstancePropertyMap(instanceMap);
-      instancedProperties.Add((*iter)->visual.GetName(), instanceMap);
-    }
-  }
-}
-
-void Control::Impl::RemoveVisual(RegisteredVisualContainer& visuals, const std::string& visualName)
-{
-  Actor self(mControlImpl.Self());
-
-  for(RegisteredVisualContainer::Iterator visualIter = visuals.Begin();
-      visualIter != visuals.End();
-      ++visualIter)
-  {
-    Toolkit::Visual::Base visual = (*visualIter)->visual;
-    if(visual && visual.GetName() == visualName)
-    {
-      Toolkit::GetImplementation(visual).SetOffScene(self);
-      (*visualIter)->visual.Reset();
-      visuals.Erase(visualIter);
-      break;
-    }
-  }
-}
-
-void Control::Impl::RemoveVisuals(RegisteredVisualContainer& visuals, DictionaryKeys& removeVisuals)
-{
-  Actor self(mControlImpl.Self());
-  for(DictionaryKeys::iterator iter = removeVisuals.begin(); iter != removeVisuals.end(); ++iter)
-  {
-    const std::string visualName = *iter;
-    RemoveVisual(visuals, visualName);
-  }
-}
-
-void Control::Impl::RecreateChangedVisuals(Dictionary<Property::Map>& stateVisualsToChange,
-                                           Dictionary<Property::Map>& instancedProperties)
-{
-  Dali::CustomActor handle(mControlImpl.GetOwner());
-  for(Dictionary<Property::Map>::iterator iter = stateVisualsToChange.Begin();
-      iter != stateVisualsToChange.End();
-      ++iter)
-  {
-    const std::string&   visualName = (*iter).key;
-    const Property::Map& toMap      = (*iter).entry;
-
-    Actor                               self = mControlImpl.Self();
-    RegisteredVisualContainer::Iterator registeredVisualsiter;
-    // Check if visual (visualName) is already registered, this is the current visual.
-    if(FindVisual(visualName, mVisuals, registeredVisualsiter))
-    {
-      Toolkit::Visual::Base& visual = (*registeredVisualsiter)->visual;
-      if(visual)
-      {
-        // No longer required to know if the replaced visual's resources are ready
-        StopObservingVisual(visual);
-
-        // If control staged then visuals will be swapped once ready
-        if(self.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
-        {
-          // Check if visual is currently in the process of being replaced ( is in removal container )
-          RegisteredVisualContainer::Iterator visualQueuedForRemoval;
-          if(FindVisual(visualName, mRemoveVisuals, visualQueuedForRemoval))
-          {
-            // Visual with same visual name is already in removal container so current visual pending
-            // Only the the last requested visual will be displayed so remove current visual which is staged but not ready.
-            Toolkit::GetImplementation(visual).SetOffScene(self);
-            (*registeredVisualsiter)->visual.Reset();
-            mVisuals.Erase(registeredVisualsiter);
-          }
-          else
-          {
-            // current visual not already in removal container so add now.
-            DALI_LOG_INFO(gLogFilter, Debug::Verbose, "RegisterVisual Move current registered visual to removal Queue: %s \n", visualName.c_str());
-            MoveVisual(registeredVisualsiter, mVisuals, mRemoveVisuals);
-          }
-        }
-        else
-        {
-          // Control not staged or visual disabled so can just erase from registered visuals and new visual will be added later.
-          (*registeredVisualsiter)->visual.Reset();
-          mVisuals.Erase(registeredVisualsiter);
-        }
-      }
-
-      const Property::Map* instancedMap = instancedProperties.FindConst(visualName);
-      Style::ApplyVisual(handle, visualName, toMap, instancedMap);
-    }
-  }
-}
-
-void Control::Impl::ReplaceStateVisualsAndProperties(const StylePtr oldState, const StylePtr newState, const std::string& subState)
-{
-  DALI_ASSERT_ALWAYS(Stage::IsCoreThread() && "Core is not installed. Might call this API from worker thread?");
-
-  // Collect all old visual names
-  DictionaryKeys stateVisualsToRemove;
-  if(oldState)
-  {
-    oldState->visuals.GetKeys(stateVisualsToRemove);
-    if(!subState.empty())
-    {
-      const StylePtr* oldSubState = oldState->subStates.FindConst(subState);
-      if(oldSubState)
-      {
-        DictionaryKeys subStateVisualsToRemove;
-        (*oldSubState)->visuals.GetKeys(subStateVisualsToRemove);
-        Merge(stateVisualsToRemove, subStateVisualsToRemove);
-      }
-    }
-  }
-
-  // Collect all new visual properties
-  Dictionary<Property::Map> stateVisualsToAdd;
-  if(newState)
-  {
-    stateVisualsToAdd = newState->visuals;
-    if(!subState.empty())
-    {
-      const StylePtr* newSubState = newState->subStates.FindConst(subState);
-      if(newSubState)
-      {
-        stateVisualsToAdd.Merge((*newSubState)->visuals);
-      }
-    }
-  }
-
-  // If a name is in both add/remove, move it to change list.
-  Dictionary<Property::Map> stateVisualsToChange;
-  FindChangableVisuals(stateVisualsToAdd, stateVisualsToChange, stateVisualsToRemove);
-
-  // Copy instanced properties (e.g. text label) of current visuals
-  Dictionary<Property::Map> instancedProperties;
-  CopyInstancedProperties(mVisuals, instancedProperties);
-
-  // For each visual in remove list, remove from mVisuals
-  RemoveVisuals(mVisuals, stateVisualsToRemove);
-
-  // For each visual in add list, create and add to mVisuals
-  Dali::CustomActor handle(mControlImpl.GetOwner());
-  Style::ApplyVisuals(handle, stateVisualsToAdd, instancedProperties);
-
-  // For each visual in change list, if it requires a new visual,
-  // remove old visual, create and add to mVisuals
-  RecreateChangedVisuals(stateVisualsToChange, instancedProperties);
-}
-
 void Control::Impl::SetState(DevelControl::State newState, bool withTransitions)
 {
   DevelControl::State oldState = mState;
@@ -2180,7 +1201,7 @@ void Control::Impl::SetState(DevelControl::State newState, bool withTransitions)
         if(oldStateStyle && newStateStyle)
         {
           // Only change if both state styles exist
-          ReplaceStateVisualsAndProperties(*oldStateStyle, *newStateStyle, mSubStateName);
+          mVisualData->ReplaceStateVisualsAndProperties(*oldStateStyle, *newStateStyle, mSubStateName);
         }
       }
     }
@@ -2213,7 +1234,7 @@ void Control::Impl::SetSubState(const std::string& subStateName, bool withTransi
           if(oldStateStyle && newStateStyle)
           {
             std::string empty;
-            ReplaceStateVisualsAndProperties(*oldStateStyle, *newStateStyle, empty);
+            mVisualData->ReplaceStateVisualsAndProperties(*oldStateStyle, *newStateStyle, empty);
           }
         }
       }
@@ -2223,40 +1244,6 @@ void Control::Impl::SetSubState(const std::string& subStateName, bool withTransi
   }
 }
 
-void Control::Impl::OnSceneDisconnection()
-{
-  Actor self = mControlImpl.Self();
-
-  // Any visuals set for replacement but not yet ready should still be registered.
-  // Reason: If a request was made to register a new visual but the control removed from scene before visual was ready
-  // then when this control appears back on stage it should use that new visual.
-
-  // Iterate through all registered visuals and set off scene
-  SetVisualsOffScene(mVisuals, self);
-
-  // Visuals pending replacement can now be taken out of the removal list and set off scene
-  // Iterate through all replacement visuals and add to a move queue then set off scene
-
-  if(!mRemoveVisuals.Empty())
-  {
-    std::reverse(mRemoveVisuals.Begin(), mRemoveVisuals.End());
-
-    while(!mRemoveVisuals.Empty())
-    {
-      auto removalIter = mRemoveVisuals.End() - 1u;
-      Toolkit::GetImplementation((*removalIter)->visual).SetOffScene(self);
-
-      // Discard removed visual. It will be destroyed at next Idle time.
-      DiscardVisual(removalIter, mRemoveVisuals);
-    }
-  }
-
-  for(auto replacedIter = mVisuals.Begin(), end = mVisuals.End(); replacedIter != end; replacedIter++)
-  {
-    (*replacedIter)->pending = false;
-  }
-}
-
 void Control::Impl::SetMargin(Extents margin)
 {
   mControlImpl.mImpl->mMargin = margin;
@@ -2283,6 +1270,11 @@ Extents Control::Impl::GetPadding() const
   return mControlImpl.mImpl->mPadding;
 }
 
+DevelControl::VisualEventSignalType& Control::Impl::VisualEventSignal()
+{
+  return mVisualData->VisualEventSignal();
+}
+
 void Control::Impl::SetInputMethodContext(InputMethodContext& inputMethodContext)
 {
   mInputMethodContext = inputMethodContext;
@@ -2299,9 +1291,79 @@ bool Control::Impl::FilterKeyEvent(const KeyEvent& event)
   return consumed;
 }
 
-DevelControl::VisualEventSignalType& Control::Impl::VisualEventSignal()
+void Control::Impl::AppendAccessibilityAttribute(const std::string& key, const std::string value)
+{
+  mAccessibilityData->AppendAccessibilityAttribute(key, value);
+}
+
+void Control::Impl::RemoveAccessibilityAttribute(const std::string& key)
+{
+  mAccessibilityData->RemoveAccessibilityAttribute(key);
+}
+
+void Control::Impl::ClearAccessibilityAttributes()
 {
-  return mVisualEventSignal;
+  mAccessibilityData->ClearAccessibilityAttributes();
+}
+
+void Control::Impl::SetAccessibilityReadingInfoType(const Dali::Accessibility::ReadingInfoTypes types)
+{
+  mAccessibilityData->SetAccessibilityReadingInfoType(types);
+}
+
+Dali::Accessibility::ReadingInfoTypes Control::Impl::GetAccessibilityReadingInfoType() const
+{
+  return mAccessibilityData->GetAccessibilityReadingInfoType();
+}
+
+void Control::Impl::CheckHighlightedObjectGeometry()
+{
+  mAccessibilityData->CheckHighlightedObjectGeometry();
+}
+
+void Control::Impl::RegisterAccessibilityPositionPropertyNotification()
+{
+  mAccessibilityData->RegisterAccessibilityPositionPropertyNotification();
+}
+
+void Control::Impl::UnregisterAccessibilityPositionPropertyNotification()
+{
+  mAccessibilityData->UnregisterAccessibilityPositionPropertyNotification();
+}
+
+void Control::Impl::RegisterAccessibilityPropertySetSignal()
+{
+  mAccessibilityData->RegisterAccessibilityPropertySetSignal();
+}
+
+void Control::Impl::UnregisterAccessibilityPropertySetSignal()
+{
+  mAccessibilityData->UnregisterAccessibilityPropertySetSignal();
+}
+
+void Control::Impl::OnAccessibilityPropertySet(Dali::Handle& handle, Dali::Property::Index index, const Dali::Property::Value& value)
+{
+  mAccessibilityData->OnAccessibilityPropertySet(handle, index, value);
+}
+
+bool Control::Impl::IsAccessibleCreated() const
+{
+  return mAccessibilityData->IsAccessibleCreated();
+}
+
+void Control::Impl::EnableCreateAccessible(bool enable)
+{
+  mAccessibilityData->EnableCreateAccessible(enable);
+}
+
+bool Control::Impl::IsCreateAccessibleEnabled() const
+{
+  return mAccessibilityData->IsCreateAccessibleEnabled();
+}
+
+void Control::Impl::ApplyFittingMode(const Vector2& size)
+{
+  mVisualData->ApplyFittingMode(size);
 }
 
 void Control::Impl::SetShadow(const Property::Map& map)
@@ -2311,7 +1373,7 @@ void Control::Impl::SetShadow(const Property::Map& map)
 
   if(visual)
   {
-    mControlImpl.mImpl->RegisterVisual(Toolkit::DevelControl::Property::SHADOW, visual, DepthIndex::BACKGROUND_EFFECT);
+    mControlImpl.mImpl->mVisualData->RegisterVisual(Toolkit::DevelControl::Property::SHADOW, visual, DepthIndex::BACKGROUND_EFFECT);
 
     mControlImpl.RelayoutRequest();
   }
@@ -2319,7 +1381,7 @@ void Control::Impl::SetShadow(const Property::Map& map)
 
 void Control::Impl::ClearShadow()
 {
-  mControlImpl.mImpl->UnregisterVisual(Toolkit::DevelControl::Property::SHADOW);
+  mControlImpl.mImpl->mVisualData->UnregisterVisual(Toolkit::DevelControl::Property::SHADOW);
 
   // Trigger a size negotiation request that may be needed when unregistering a visual.
   mControlImpl.RelayoutRequest();
@@ -2327,15 +1389,7 @@ void Control::Impl::ClearShadow()
 
 Dali::Property Control::Impl::GetVisualProperty(Dali::Property::Index index, Dali::Property::Key visualPropertyKey)
 {
-  Toolkit::Visual::Base visual = GetVisualByIndex(mVisuals, index);
-  if(visual)
-  {
-    Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
-    return visualImpl.GetPropertyObject(std::move(visualPropertyKey));
-  }
-
-  Handle handle;
-  return Dali::Property(handle, Property::INVALID_INDEX);
+  return mVisualData->GetVisualProperty(index, visualPropertyKey);
 }
 
 void Control::Impl::CreateTransitions(std::vector<std::pair<Dali::Property::Index, Dali::Property::Map>>& sourceProperties,
@@ -2367,18 +1421,7 @@ void Control::Impl::CreateTransitions(std::vector<std::pair<Dali::Property::Inde
 
 void Control::Impl::UpdateVisualProperties(const std::vector<std::pair<Dali::Property::Index, Dali::Property::Map>>& properties)
 {
-  for(auto&& data : properties)
-  {
-    if(data.first == Toolkit::Control::Property::BACKGROUND)
-    {
-      DoAction(Toolkit::Control::Property::BACKGROUND, DevelVisual::Action::UPDATE_PROPERTY, data.second);
-    }
-    else if(data.first == Toolkit::DevelControl::Property::SHADOW)
-    {
-      DoAction(Toolkit::DevelControl::Property::SHADOW, DevelVisual::Action::UPDATE_PROPERTY, data.second);
-    }
-  }
-  mControlImpl.OnUpdateVisualProperties(properties);
+  mVisualData->UpdateVisualProperties(properties);
 }
 
 void Control::Impl::EmitResourceReadySignal()
@@ -2446,205 +1489,7 @@ bool Control::Impl::OnIdleCallback()
 
 std::shared_ptr<Toolkit::DevelControl::ControlAccessible> Control::Impl::GetAccessibleObject()
 {
-  return std::dynamic_pointer_cast<DevelControl::ControlAccessible>(Accessibility::Accessible::GetOwningPtr(mControlImpl.Self()));
-}
-
-bool Control::Impl::IsAccessibleCreated() const
-{
-  return !!Accessibility::Bridge::GetCurrentBridge()->GetAccessible(mControlImpl.Self());
-}
-
-void Control::Impl::EnableCreateAccessible(bool enable)
-{
-  mAccessibleCreatable = enable;
-}
-
-bool Control::Impl::IsCreateAccessibleEnabled() const
-{
-  return mAccessibleCreatable;
-}
-
-void Control::Impl::ApplyFittingMode(const Vector2& size)
-{
-  Actor self = mControlImpl.Self();
-  for(RegisteredVisualContainer::Iterator iter = mVisuals.Begin(); iter != mVisuals.End(); iter++)
-  {
-    // Check whether the visual is empty and enabled
-    if((*iter)->visual && (*iter)->enabled)
-    {
-      Internal::Visual::Base& visualImpl = Toolkit::GetImplementation((*iter)->visual);
-
-      // If the current visual is using the transform property map, fittingMode will not be applied.
-      if(visualImpl.IsIgnoreFittingMode())
-      {
-        continue;
-      }
-
-      Visual::FittingMode fittingMode  = visualImpl.GetFittingMode();
-      Property::Map       transformMap = Property::Map();
-
-      // If the fittingMode is DONT_CARE, we don't need to apply fittingMode, just Set empty transformMap
-      if(fittingMode == Visual::FittingMode::DONT_CARE)
-      {
-        if(visualImpl.GetType() != Toolkit::Visual::Type::TEXT)
-        {
-          ((*iter)->visual).SetTransformAndSize(transformMap, size);
-        }
-        continue;
-      }
-
-      Extents padding = self.GetProperty<Extents>(Toolkit::Control::Property::PADDING);
-
-      bool zeroPadding = (padding == Extents());
-
-      Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>(
-        self.GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>());
-      if(Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection)
-      {
-        std::swap(padding.start, padding.end);
-      }
-
-      // remove padding from the size to know how much is left for the visual
-      Vector2 finalSize   = size - Vector2(padding.start + padding.end, padding.top + padding.bottom);
-      Vector2 finalOffset = Vector2(padding.start, padding.top);
-
-      // Reset PIXEL_AREA after using OVER_FIT_KEEP_ASPECT_RATIO
-      if(visualImpl.IsPixelAreaSetForFittingMode())
-      {
-        visualImpl.SetPixelAreaForFittingMode(FULL_TEXTURE_RECT);
-      }
-
-      if((!zeroPadding) || // If padding is not zero
-         (fittingMode != Visual::FittingMode::FILL))
-      {
-        visualImpl.SetTransformMapUsageForFittingMode(true);
-
-        Vector2 naturalSize;
-        // NaturalSize will not be used for FILL fitting mode, which is default.
-        // Skip GetNaturalSize
-        if(fittingMode != Visual::FittingMode::FILL)
-        {
-          ((*iter)->visual).GetNaturalSize(naturalSize);
-        }
-
-        // If FittingMode use FIT_WIDTH or FIT_HEIGTH, it need to change proper fittingMode
-        if(fittingMode == Visual::FittingMode::FIT_WIDTH || fittingMode == Visual::FittingMode::FIT_HEIGHT)
-        {
-          const float widthRatio  = !Dali::EqualsZero(naturalSize.width) ? (finalSize.width / naturalSize.width) : 0.0f;
-          const float heightRatio = !Dali::EqualsZero(naturalSize.height) ? (finalSize.height / naturalSize.height) : 0.0f;
-          if(widthRatio < heightRatio)
-          {
-            // Final size has taller form than natural size.
-            fittingMode = (fittingMode == Visual::FittingMode::FIT_WIDTH) ? Visual::FittingMode::FIT_KEEP_ASPECT_RATIO : Visual::FittingMode::OVER_FIT_KEEP_ASPECT_RATIO;
-          }
-          else
-          {
-            // Final size has wider form than natural size.
-            fittingMode = (fittingMode == Visual::FittingMode::FIT_WIDTH) ? Visual::FittingMode::OVER_FIT_KEEP_ASPECT_RATIO : Visual::FittingMode::FIT_KEEP_ASPECT_RATIO;
-          }
-        }
-
-        // Calculate size for fittingMode
-        switch(fittingMode)
-        {
-          case Visual::FittingMode::FIT_KEEP_ASPECT_RATIO:
-          {
-            auto availableVisualSize = finalSize;
-
-            // scale to fit the padded area
-            finalSize = naturalSize * std::min((!Dali::EqualsZero(naturalSize.width) ? (availableVisualSize.width / naturalSize.width) : 0),
-                                               (!Dali::EqualsZero(naturalSize.height) ? (availableVisualSize.height / naturalSize.height) : 0));
-
-            // calculate final offset within the padded area
-            finalOffset += (availableVisualSize - finalSize) * .5f;
-
-            // populate the transform map
-            transformMap.Add(Toolkit::Visual::Transform::Property::OFFSET, finalOffset)
-              .Add(Toolkit::Visual::Transform::Property::SIZE, finalSize);
-            break;
-          }
-          case Visual::FittingMode::OVER_FIT_KEEP_ASPECT_RATIO:
-          {
-            auto availableVisualSize = finalSize;
-            finalSize                = naturalSize * std::max((!Dali::EqualsZero(naturalSize.width) ? (availableVisualSize.width / naturalSize.width) : 0.0f),
-                                               (!Dali::EqualsZero(naturalSize.height) ? (availableVisualSize.height / naturalSize.height) : 0.0f));
-
-            auto originalOffset = finalOffset;
-
-            if(!visualImpl.IsPixelAreaSetForFittingMode() && !Dali::EqualsZero(finalSize.width) && !Dali::EqualsZero(finalSize.height))
-            {
-              float   x           = abs((availableVisualSize.width - finalSize.width) / finalSize.width) * .5f;
-              float   y           = abs((availableVisualSize.height - finalSize.height) / finalSize.height) * .5f;
-              float   widthRatio  = 1.f - abs((availableVisualSize.width - finalSize.width) / finalSize.width);
-              float   heightRatio = 1.f - abs((availableVisualSize.height - finalSize.height) / finalSize.height);
-              Vector4 pixelArea   = Vector4(x, y, widthRatio, heightRatio);
-              visualImpl.SetPixelAreaForFittingMode(pixelArea);
-            }
-
-            // populate the transform map
-            transformMap.Add(Toolkit::Visual::Transform::Property::OFFSET, originalOffset)
-              .Add(Toolkit::Visual::Transform::Property::SIZE, availableVisualSize);
-            break;
-          }
-          case Visual::FittingMode::CENTER:
-          {
-            auto availableVisualSize = finalSize;
-            if(availableVisualSize.width > naturalSize.width && availableVisualSize.height > naturalSize.height)
-            {
-              finalSize = naturalSize;
-            }
-            else
-            {
-              finalSize = naturalSize * std::min((!Dali::EqualsZero(naturalSize.width) ? (availableVisualSize.width / naturalSize.width) : 0.0f),
-                                                 (!Dali::EqualsZero(naturalSize.height) ? (availableVisualSize.height / naturalSize.height) : 0.0f));
-            }
-
-            finalOffset += (availableVisualSize - finalSize) * .5f;
-
-            // populate the transform map
-            transformMap.Add(Toolkit::Visual::Transform::Property::OFFSET, finalOffset)
-              .Add(Toolkit::Visual::Transform::Property::SIZE, finalSize);
-            break;
-          }
-          case Visual::FittingMode::FILL:
-          {
-            transformMap.Add(Toolkit::Visual::Transform::Property::OFFSET, finalOffset)
-              .Add(Toolkit::Visual::Transform::Property::SIZE, finalSize);
-            break;
-          }
-          case Visual::FittingMode::FIT_WIDTH:
-          case Visual::FittingMode::FIT_HEIGHT:
-          case Visual::FittingMode::DONT_CARE:
-          {
-            // This FittingMode already converted
-            break;
-          }
-        }
-
-        // Set extra value for applying transformMap
-        transformMap.Add(Toolkit::Visual::Transform::Property::OFFSET_POLICY,
-                         Vector2(Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE))
-          .Add(Toolkit::Visual::Transform::Property::ORIGIN, Toolkit::Align::TOP_BEGIN)
-          .Add(Toolkit::Visual::Transform::Property::ANCHOR_POINT, Toolkit::Align::TOP_BEGIN)
-          .Add(Toolkit::Visual::Transform::Property::SIZE_POLICY,
-               Vector2(Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE));
-      }
-      else if(visualImpl.IsTransformMapSetForFittingMode() && zeroPadding) // Reset offset to zero only if padding applied previously
-      {
-        visualImpl.SetTransformMapUsageForFittingMode(false);
-
-        // Reset the transform map
-        transformMap.Add(Toolkit::Visual::Transform::Property::OFFSET, Vector2::ZERO)
-          .Add(Toolkit::Visual::Transform::Property::OFFSET_POLICY,
-               Vector2(Toolkit::Visual::Transform::Policy::RELATIVE, Toolkit::Visual::Transform::Policy::RELATIVE))
-          .Add(Toolkit::Visual::Transform::Property::SIZE, Vector2::ONE)
-          .Add(Toolkit::Visual::Transform::Property::SIZE_POLICY,
-               Vector2(Toolkit::Visual::Transform::Policy::RELATIVE, Toolkit::Visual::Transform::Policy::RELATIVE));
-      }
-
-      ((*iter)->visual).SetTransformAndSize(transformMap, size);
-    }
-  }
+  return mAccessibilityData->GetAccessibleObject();
 }
 
 void Control::Impl::RegisterProcessorOnce()
@@ -2659,7 +1504,7 @@ void Control::Impl::RegisterProcessorOnce()
 void Control::Impl::Process(bool postProcessor)
 {
   // Call ApplyFittingMode
-  ApplyFittingMode(mSize);
+  mVisualData->ApplyFittingMode(mSize);
   mProcessorRegistered = false;
 }
 
index f3ce3d264d084b73f1507f30eab1b4f6159c4ca0..b789cca38ce1000012c26ee72da6253b7f03349c 100644 (file)
 #include <string>
 
 // INTERNAL INCLUDES
-#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
 #include <dali-toolkit/devel-api/controls/control-devel.h>
-#include <dali-toolkit/devel-api/visual-factory/visual-base.h>
-#include <dali-toolkit/internal/builder/dictionary.h>
-#include <dali-toolkit/internal/builder/style.h>
 #include <dali-toolkit/internal/controls/tooltip/tooltip.h>
-#include <dali-toolkit/internal/visuals/visual-event-observer.h>
 #include <dali-toolkit/public-api/controls/control-impl.h>
 #include <dali-toolkit/public-api/controls/render-effects/render-effect.h>
-#include <dali-toolkit/public-api/visuals/visual-properties.h>
-#include <dali/devel-api/common/owner-container.h>
 #include <dali/integration-api/debug.h>
 #include <map>
 #include <memory>
@@ -48,29 +41,6 @@ namespace Toolkit
 {
 namespace Internal
 {
-/**
-  * Struct used to store Visual within the control, index is a unique key for each visual.
-  */
-struct RegisteredVisual
-{
-  Property::Index       index;
-  Toolkit::Visual::Base visual;
-  bool                  enabled : 1;
-  bool                  pending : 1;
-  bool                  overideReadyTransition : 1;
-
-  RegisteredVisual(Property::Index aIndex, Toolkit::Visual::Base& aVisual, bool aEnabled, bool aPendingReplacement)
-  : index(aIndex),
-    visual(aVisual),
-    enabled(aEnabled),
-    pending(aPendingReplacement),
-    overideReadyTransition(false)
-  {
-  }
-};
-
-typedef Dali::OwnerContainer<RegisteredVisual*> RegisteredVisualContainer;
-
 enum class TriStateProperty
 {
   AUTO = 0,
@@ -81,9 +51,11 @@ enum class TriStateProperty
 /**
  * @brief Holds the Implementation for the internal control class
  */
-class Control::Impl : public ConnectionTracker, public Visual::EventObserver, public Integration::Processor
+class Control::Impl : public ConnectionTracker, public Integration::Processor
 {
-  friend class Toolkit::DevelControl::ControlAccessible;
+private:
+  class AccessibilityData;
+  class VisualData;
 
 public:
   /**
@@ -142,27 +114,6 @@ public:
    */
   void ResourceReady();
 
-  /**
-   * @brief Called when a resource is ready.
-   * @param[in] object The visual whose resources are ready
-   * @note Overriding method in Visual::EventObserver.
-   */
-  void ResourceReady(Visual::Base& object) override;
-
-  /**
-   * @brief Called when an event occurs.
-   * @param[in] object The visual whose events occur
-   * @param[in] signalId The signal to emit. See Visual to find supported signals
-   * @note Overriding method in Visual::EventObserver.
-   */
-  void NotifyVisualEvent(Visual::Base& object, Property::Index signalId) override;
-
-  /**
-   * @brief Called when the visual needs relayout request.
-   * @param[in] object The visual who requests relayout
-   */
-  void RelayoutRequest(Visual::Base& object) override;
-
   /**
    * @copydoc Dali::Toolkit::DevelControl::RegisterVisual()
    */
@@ -193,16 +144,6 @@ public:
    */
   Toolkit::Visual::Base GetVisual(Property::Index index) const;
 
-  /**
-   * @copydoc Dali::Toolkit::DevelControl::EnableVisual()
-   */
-  void EnableVisual(Property::Index index, bool enable);
-
-  /**
-   * @copydoc Dali::Toolkit::DevelControl::IsVisualEnabled()
-   */
-  bool IsVisualEnabled(Property::Index index) const;
-
   /**
    * @brief Sets the given visual to be ready transition
    *
@@ -213,16 +154,14 @@ public:
   void EnableReadyTransitionOverriden(Toolkit::Visual::Base& visual, bool enable);
 
   /**
-   * @brief Stops observing the given visual.
-   * @param[in] visual The visual to stop observing
+   * @copydoc Dali::Toolkit::DevelControl::EnableVisual()
    */
-  void StopObservingVisual(Toolkit::Visual::Base& visual);
+  void EnableVisual(Property::Index index, bool enable);
 
   /**
-   * @brief Starts observing the given visual.
-   * @param[in] visual The visual to start observing
+   * @copydoc Dali::Toolkit::DevelControl::IsVisualEnabled()
    */
-  void StartObservingVisual(Toolkit::Visual::Base& visual);
+  bool IsVisualEnabled(Property::Index index) const;
 
   /**
    * @copydoc Dali::Toolkit::DevelControl::GetVisualResourceStatus()
@@ -284,47 +223,6 @@ public:
    */
   void SetSubState(const std::string& subStateName, bool withTransitions = true);
 
-  /**
-   * @brief Replaces visuals and properties from the old state to the new state.
-   * @param[in] oldState The old state
-   * @param[in] newState The new state
-   * @param[in] subState The current sub state
-   */
-  void ReplaceStateVisualsAndProperties(const StylePtr oldState, const StylePtr newState, const std::string& subState);
-
-  /**
-   * @brief Removes a visual from the control's container.
-   * @param[in] visuals The container of visuals
-   * @param[in] visualName The name of the visual to remove
-   */
-  void RemoveVisual(RegisteredVisualContainer& visuals, const std::string& visualName);
-
-  /**
-   * @brief Removes several visuals from the control's container.
-   * @param[in] visuals The container of visuals
-   * @param[in] removeVisuals The visuals to remove
-   */
-  void RemoveVisuals(RegisteredVisualContainer& visuals, DictionaryKeys& removeVisuals);
-
-  /**
-   * @brief Copies the visual properties that are specific to the control instance into the instancedProperties container.
-   * @param[in] visuals The control's visual container
-   * @param[out] instancedProperties The instanced properties are added to this container
-   */
-  void CopyInstancedProperties(RegisteredVisualContainer& visuals, Dictionary<Property::Map>& instancedProperties);
-
-  /**
-   * @brief On state change, ensures visuals are moved or created appropriately.
-   *
-   * Go through the list of visuals that are common to both states.
-   * If they are different types, or are both image types with different
-   * URLs, then the existing visual needs moving and the new visual needs creating
-   *
-   * @param[in] stateVisualsToChange The visuals to change
-   * @param[in] instancedProperties The instanced properties @see CopyInstancedProperties
-   */
-  void RecreateChangedVisuals(Dictionary<Property::Map>& stateVisualsToChange, Dictionary<Property::Map>& instancedProperties);
-
   /**
    * @brief Whether the resource is ready
    * @return True if the resource is read.
@@ -433,7 +331,7 @@ public:
 
   /**
    * @brief Retrieves source and destination visual properties for the Transition of this Control.
-   * The properties of this Control will be transitioned from the propeties of source Control to that of destination control.
+   * The properties of this Control will be transitioned from the properties of source Control to that of destination Control.
    * If a property value is different between source and destination Control,
    * the property information of each Control will be included in sourceProperties and destinationProperties.
    *
@@ -507,50 +405,10 @@ protected: // From processor-interface
   }
 
 private:
-  /**
-   * Used as an alternative to boolean so that it is obvious whether a visual is enabled/disabled.
-   */
-  struct VisualState
-  {
-    enum Type
-    {
-      DISABLED = 0, ///< Visual disabled.
-      ENABLED  = 1  ///< Visual enabled.
-    };
-  };
-
-  /**
-   * Used as an alternative to boolean so that it is obvious whether a visual's depth value has been set or not by the caller.
-   */
-  struct DepthIndexValue
-  {
-    enum Type
-    {
-      NOT_SET = 0, ///< Visual depth value not set by caller.
-      SET     = 1  ///< Visual depth value set by caller.
-    };
-  };
-
-  /**
-   * @brief Adds the visual to the list of registered visuals.
-   * @param[in] index The Property index of the visual, used to reference visual
-   * @param[in,out] visual The visual to register, which can be altered in this function
-   * @param[in] enabled false if derived class wants to control when visual is set on stage
-   * @param[in] depthIndexValueSet Set to true if the depthIndex has actually been set manually
-   * @param[in] depthIndex The visual's depth-index is set to this. If the depth-index is set to DepthIndex::Ranges::AUTO_INDEX,
-   *                       the actual depth-index of visual will be determind automatically (Use previous visuals depth-index, or placed on top of all other visuals.)
-   *                       Otherwise, the visual's depth-index is set to clamped value, between DepthIndex::Ranges::MINIMUM_DEPTH_INDEX and DepthIndex::Ranges::MAXIMUM_DEPTH_INDEX.
-   *
-   * @note Registering a visual with an index that already has a registered visual will replace it. The replacement will
-   *       occur once the replacement visual is ready (loaded).
-   */
-  void RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, VisualState::Type enabled, DepthIndexValue::Type depthIndexValueSet, int depthIndex = static_cast<int>(Toolkit::DepthIndex::AUTO_INDEX));
-
   /**
    * @brief Emits the resource ready signal.
    */
   void EmitResourceReadySignal();
-
   /**
    * @brief Callbacks called on idle.
    *
@@ -597,6 +455,9 @@ public:
   DevelControl::State mState;
   std::string         mSubStateName;
 
+  AccessibilityData* mAccessibilityData;
+  VisualData*        mVisualData;
+
   int mLeftFocusableActorId;             ///< Actor ID of Left focusable control.
   int mRightFocusableActorId;            ///< Actor ID of Right focusable control.
   int mUpFocusableActorId;               ///< Actor ID of Up focusable control.
@@ -604,7 +465,6 @@ public:
   int mClockwiseFocusableActorId;        ///< Actor ID of Clockwise focusable control.
   int mCounterClockwiseFocusableActorId; ///< Actor ID of Counter clockwise focusable control.
 
-  RegisteredVisualContainer                 mVisuals; ///< Stores visuals needed by the control, non trivial type so std::vector used.
   std::string                               mStyleName;
   Vector4                                   mBackgroundColor;    ///< The color of the background visual
   RenderEffect                              mRenderEffect;       ///< The render effect on this control
@@ -616,39 +476,6 @@ public:
   Toolkit::Control::KeyInputFocusSignalType mKeyInputFocusGainedSignal;
   Toolkit::Control::KeyInputFocusSignalType mKeyInputFocusLostSignal;
   Toolkit::Control::ResourceReadySignalType mResourceReadySignal;
-  DevelControl::VisualEventSignalType       mVisualEventSignal;
-
-  // Accessibility
-  Toolkit::DevelControl::AccessibilityActivateSignalType         mAccessibilityActivateSignal;
-  Toolkit::DevelControl::AccessibilityReadingSkippedSignalType   mAccessibilityReadingSkippedSignal;
-  Toolkit::DevelControl::AccessibilityReadingPausedSignalType    mAccessibilityReadingPausedSignal;
-  Toolkit::DevelControl::AccessibilityReadingResumedSignalType   mAccessibilityReadingResumedSignal;
-  Toolkit::DevelControl::AccessibilityReadingCancelledSignalType mAccessibilityReadingCancelledSignal;
-  Toolkit::DevelControl::AccessibilityReadingStoppedSignalType   mAccessibilityReadingStoppedSignal;
-
-  Toolkit::DevelControl::AccessibilityGetNameSignalType        mAccessibilityGetNameSignal;
-  Toolkit::DevelControl::AccessibilityGetDescriptionSignalType mAccessibilityGetDescriptionSignal;
-  Toolkit::DevelControl::AccessibilityDoGestureSignalType      mAccessibilityDoGestureSignal;
-
-  Toolkit::DevelControl::AccessibilityActionSignalType mAccessibilityActionSignal;
-
-  struct AccessibilityProps
-  {
-    std::string                                                                       name{};
-    std::string                                                                       description{};
-    std::string                                                                       value{};
-    std::string                                                                       automationId{};
-    int32_t                                                                           role{static_cast<int32_t>(DevelControl::AccessibilityRole::NONE)};
-    DevelControl::AccessibilityStates                                                 states{};
-    std::map<Dali::Accessibility::RelationType, std::set<Accessibility::Accessible*>> relations;
-    Property::Map                                                                     extraAttributes{};
-    TriStateProperty                                                                  isHighlightable{TriStateProperty::AUTO};
-    bool                                                                              isHidden{false};
-    bool                                                                              isScrollable{false};
-    bool                                                                              isModal{false};
-  } mAccessibilityProps;
-
-  bool mAccessibleCreatable = true;
 
   // Gesture Detection
   PinchGestureDetector     mPinchGestureDetector;
@@ -670,8 +497,6 @@ public:
   bool             mDispatchKeyEvents : 1;                ///< Whether the actor emits key event signals
   bool             mProcessorRegistered : 1;              ///< Whether the processor is registered.
 
-  RegisteredVisualContainer mRemoveVisuals; ///< List of visuals that are being replaced by another visual once ready
-
   // Properties - these need to be members of Internal::Control::Impl as they access private methods/data of Internal::Control and Internal::Control::Impl.
   static const PropertyRegistration PROPERTY_1;
   static const PropertyRegistration PROPERTY_2;
@@ -703,13 +528,6 @@ public:
   static const PropertyRegistration PROPERTY_28;
   static const PropertyRegistration PROPERTY_29;
   static const PropertyRegistration PROPERTY_30;
-
-private:
-  // Accessibility - notification for highlighted object to check if it is showing.
-  bool                                        mIsAccessibilityPositionPropertyNotificationSet{false};
-  bool                                        mIsAccessibilityPropertySetSignalRegistered{false};
-  Dali::PropertyNotification                  mAccessibilityPositionNotification;
-  Dali::Accessibility::ScreenRelativeMoveType mAccessibilityLastScreenRelativeMoveType{Accessibility::ScreenRelativeMoveType::OUTSIDE};
 };
 
 } // namespace Internal
index 9a9c08fe171898e79df66b6bc439aa53f9940ad2..7f87f8852c59917bad85880868a5110f9c923029 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
@@ -16,6 +16,7 @@
 
 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
 #include <dali-toolkit/internal/controls/control/control-debug.h>
+#include <dali-toolkit/internal/controls/control/control-visual-data.h>
 #include <dali-toolkit/internal/visuals/visual-base-impl.h>
 #include <dali-toolkit/public-api/controls/control-impl.h>
 #include <dali/integration-api/debug.h>
@@ -292,9 +293,9 @@ std::string DumpControl(const Internal::Control& control)
   }
   oss << "\"id\":\"" << control.Self().GetProperty<int>(Actor::Property::ID) << "\",\n";
   oss << "\"registeredVisuals\":\n"
-      << controlData.mVisuals << ",\n";
+      << controlData.mVisualData->mVisuals << ",\n";
   oss << "\"removeVisuals\":\n"
-      << controlData.mRemoveVisuals << ",\n";
+      << controlData.mVisualData->mRemoveVisuals << ",\n";
   oss << "\"rendererCount\":" << control.Self().GetRendererCount() << ",\n";
   oss << "\"properties\":\n{\n";
   DumpProperties(oss, control.Self()) << "}\n";
diff --git a/dali-toolkit/internal/controls/control/control-visual-data.cpp b/dali-toolkit/internal/controls/control/control-visual-data.cpp
new file mode 100644 (file)
index 0000000..5eaa4c4
--- /dev/null
@@ -0,0 +1,1059 @@
+/*
+ * Copyright (c) 2024 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "control-visual-data.h"
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/common/stage.h>
+#include <dali/integration-api/adaptor-framework/adaptor.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/visuals/visual-actions-devel.h>
+#include <dali-toolkit/internal/visuals/visual-base-impl.h>
+#include <dali-toolkit/internal/visuals/visual-string-constants.h>
+#include <dali-toolkit/public-api/align-enumerations.h>
+#include <dali-toolkit/public-api/visuals/image-visual-properties.h>
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+namespace
+{
+const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_CONTROL_VISUALS");
+#endif
+
+template<typename T>
+void Remove(Dictionary<T>& keyValues, const std::string& name)
+{
+  keyValues.Remove(name);
+}
+
+void Remove(DictionaryKeys& keys, const std::string& name)
+{
+  DictionaryKeys::iterator iter = std::find(keys.begin(), keys.end(), name);
+  if(iter != keys.end())
+  {
+    keys.erase(iter);
+  }
+}
+
+/**
+ *  Finds visual in given array, returning true if found along with the iterator for that visual as a out parameter
+ */
+bool FindVisual(Property::Index targetIndex, const RegisteredVisualContainer& visuals, RegisteredVisualContainer::Iterator& iter)
+{
+  for(iter = visuals.Begin(); iter != visuals.End(); iter++)
+  {
+    if((*iter)->index == targetIndex)
+    {
+      return true;
+    }
+  }
+  return false;
+}
+
+/**
+ *  Finds visual in given array, returning true if found along with the iterator for that visual as a out parameter
+ */
+bool FindVisual(std::string visualName, const RegisteredVisualContainer& visuals, RegisteredVisualContainer::Iterator& iter)
+{
+  for(iter = visuals.Begin(); iter != visuals.End(); iter++)
+  {
+    Toolkit::Visual::Base visual = (*iter)->visual;
+    if(visual && visual.GetName() == visualName)
+    {
+      return true;
+    }
+  }
+  return false;
+}
+
+/**
+ *  Finds visual in given array, returning true if found along with the iterator for that visual as a out parameter
+ */
+bool FindVisual(const Toolkit::Visual::Base findVisual, const RegisteredVisualContainer& visuals, RegisteredVisualContainer::Iterator& iter)
+{
+  for(iter = visuals.Begin(); iter != visuals.End(); iter++)
+  {
+    Toolkit::Visual::Base visual = (*iter)->visual;
+    if(visual && visual == findVisual)
+    {
+      return true;
+    }
+  }
+  return false;
+}
+
+/**
+ *  Finds internal visual in given array, returning true if found along with the iterator for that visual as a out parameter
+ */
+bool FindVisual(const Visual::Base& findInternalVisual, const RegisteredVisualContainer& visuals, RegisteredVisualContainer::Iterator& iter)
+{
+  for(iter = visuals.Begin(); iter != visuals.End(); iter++)
+  {
+    Visual::Base& visual = Toolkit::GetImplementation((*iter)->visual);
+    if((&visual == &findInternalVisual))
+    {
+      return true;
+    }
+  }
+  return false;
+}
+
+void FindChangableVisuals(Dictionary<Property::Map>& stateVisualsToAdd,
+                          Dictionary<Property::Map>& stateVisualsToChange,
+                          DictionaryKeys&            stateVisualsToRemove)
+{
+  DictionaryKeys copyOfStateVisualsToRemove = stateVisualsToRemove;
+
+  for(DictionaryKeys::iterator iter = copyOfStateVisualsToRemove.begin();
+      iter != copyOfStateVisualsToRemove.end();
+      ++iter)
+  {
+    const std::string& visualName = (*iter);
+    Property::Map*     toMap      = stateVisualsToAdd.Find(visualName);
+    if(toMap)
+    {
+      stateVisualsToChange.Add(visualName, *toMap);
+      stateVisualsToAdd.Remove(visualName);
+      Remove(stateVisualsToRemove, visualName);
+    }
+  }
+}
+
+Toolkit::Visual::Base GetVisualByName(
+  const RegisteredVisualContainer& visuals,
+  const std::string&               visualName)
+{
+  Toolkit::Visual::Base visualHandle;
+
+  RegisteredVisualContainer::Iterator iter;
+  for(iter = visuals.Begin(); iter != visuals.End(); iter++)
+  {
+    Toolkit::Visual::Base visual = (*iter)->visual;
+    if(visual && visual.GetName() == visualName)
+    {
+      visualHandle = visual;
+      break;
+    }
+  }
+  return visualHandle;
+}
+
+Toolkit::Visual::Base GetVisualByIndex(
+  const RegisteredVisualContainer& visuals,
+  Property::Index                  index)
+{
+  Toolkit::Visual::Base visualHandle;
+
+  RegisteredVisualContainer::Iterator iter;
+  for(iter = visuals.Begin(); iter != visuals.End(); iter++)
+  {
+    if((*iter)->index == index)
+    {
+      visualHandle = (*iter)->visual;
+      break;
+    }
+  }
+  return visualHandle;
+}
+
+/**
+ * Move visual from source to destination container
+ */
+void MoveVisual(RegisteredVisualContainer::Iterator sourceIter, RegisteredVisualContainer& source, RegisteredVisualContainer& destination)
+{
+  Toolkit::Visual::Base visual = (*sourceIter)->visual;
+  if(visual)
+  {
+    RegisteredVisual* rv = source.Release(sourceIter);
+    destination.PushBack(rv);
+  }
+}
+
+/**
+ * Discard visual from source to visual factory.
+ */
+void DiscardVisual(RegisteredVisualContainer::Iterator sourceIter, RegisteredVisualContainer& source)
+{
+  Toolkit::Visual::Base visual = (*sourceIter)->visual;
+  if(visual)
+  {
+    if(DALI_LIKELY(Dali::Adaptor::IsAvailable()))
+    {
+      Toolkit::VisualFactory::Get().DiscardVisual(visual);
+    }
+  }
+
+  source.Erase(sourceIter);
+}
+
+/**
+ * @brief Iterate through given container and setOffScene any visual found
+ *
+ * @param[in] container Container of visuals
+ * @param[in] parent Parent actor to remove visuals from
+ */
+void SetVisualsOffScene(const RegisteredVisualContainer& container, Actor parent)
+{
+  for(auto iter = container.Begin(), end = container.End(); iter != end; iter++)
+  {
+    if((*iter)->visual)
+    {
+      DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::SetOffScene Setting visual(%d) off stage\n", (*iter)->index);
+      Toolkit::GetImplementation((*iter)->visual).SetOffScene(parent);
+    }
+  }
+}
+} // unnamed namespace
+
+Control::Impl::VisualData::VisualData(Control::Impl& outer)
+: mVisualEventSignal(),
+  mOuter(outer)
+{
+}
+
+Control::Impl::VisualData::~VisualData()
+{
+}
+
+void Control::Impl::VisualData::ClearScene(Actor parent)
+{
+  SetVisualsOffScene(mVisuals, parent);
+
+  if(!mRemoveVisuals.Empty())
+  {
+    std::reverse(mRemoveVisuals.Begin(), mRemoveVisuals.End());
+
+    while(!mRemoveVisuals.Empty())
+    {
+      auto removalIter = mRemoveVisuals.End() - 1u;
+      Toolkit::GetImplementation((*removalIter)->visual).SetOffScene(parent);
+
+      // Discard removed visual. It will be destroyed at next Idle time.
+      DiscardVisual(removalIter, mRemoveVisuals);
+    }
+  }
+
+  for(auto replacedIter = mVisuals.Begin(), end = mVisuals.End(); replacedIter != end; replacedIter++)
+  {
+    (*replacedIter)->pending = false;
+  }
+}
+
+// Called by a Visual when it's resource is ready
+void Control::Impl::VisualData::ResourceReady(Visual::Base& object)
+{
+  DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::Impl::VisualData::ResourceReady() replacements pending[%d]\n", mRemoveVisuals.Count());
+
+  Actor self = mOuter.mControlImpl.Self();
+
+  RegisteredVisualContainer::Iterator registeredIter;
+
+  // A resource is ready, find resource in the registered visuals container and get its index
+  if(!FindVisual(object, mVisuals, registeredIter))
+  {
+    return;
+  }
+
+  RegisteredVisualContainer::Iterator visualToRemoveIter;
+  // Find visual with the same index in the removal container
+  // Set if off stage as it's replacement is now ready.
+  // Remove if from removal list as now removed from stage.
+  // Set Pending flag on the ready visual to false as now ready.
+  if(FindVisual((*registeredIter)->index, mRemoveVisuals, visualToRemoveIter))
+  {
+    (*registeredIter)->pending = false;
+    if(!((*visualToRemoveIter)->overideReadyTransition))
+    {
+      Toolkit::GetImplementation((*visualToRemoveIter)->visual).SetOffScene(self);
+    }
+
+    // Discard removed visual. It will be destroyed at next Idle time.
+    DiscardVisual(visualToRemoveIter, mRemoveVisuals);
+  }
+
+  // A visual is ready so control may need relayouting if staged
+  RelayoutRequest(object);
+
+  // Called by a Visual when it's resource is ready
+  if(((*registeredIter)->enabled))
+  {
+    mOuter.ResourceReady();
+  }
+}
+
+void Control::Impl::VisualData::NotifyVisualEvent(Visual::Base& object, Property::Index signalId)
+{
+  for(auto registeredIter = mVisuals.Begin(), end = mVisuals.End(); registeredIter != end; ++registeredIter)
+  {
+    Internal::Visual::Base& registeredVisualImpl = Toolkit::GetImplementation((*registeredIter)->visual);
+    if(&object == &registeredVisualImpl)
+    {
+      Dali::Toolkit::Control handle(mOuter.mControlImpl.GetOwner());
+      mVisualEventSignal.Emit(handle, (*registeredIter)->index, signalId);
+      break;
+    }
+  }
+}
+
+void Control::Impl::VisualData::RelayoutRequest(Visual::Base& object)
+{
+  if(mOuter.mControlImpl.Self().GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
+  {
+    mOuter.mControlImpl.RelayoutRequest();
+  }
+}
+
+bool Control::Impl::VisualData::IsResourceReady() const
+{
+  // Iterate through and check all the enabled visuals are ready
+  for(auto visualIter = mVisuals.Begin();
+      visualIter != mVisuals.End();
+      ++visualIter)
+  {
+    const Toolkit::Visual::Base   visual     = (*visualIter)->visual;
+    const Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
+
+    // one of the enabled visuals is not ready
+    if(!visualImpl.IsResourceReady() && (*visualIter)->enabled)
+    {
+      return false;
+    }
+  }
+  return true;
+}
+
+Toolkit::Visual::ResourceStatus Control::Impl::VisualData::GetVisualResourceStatus(Property::Index index) const
+{
+  RegisteredVisualContainer::Iterator iter;
+  if(FindVisual(index, mVisuals, iter))
+  {
+    const Toolkit::Visual::Base   visual     = (*iter)->visual;
+    const Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
+    return visualImpl.GetResourceStatus();
+  }
+
+  return Toolkit::Visual::ResourceStatus::PREPARING;
+}
+
+void Control::Impl::VisualData::CopyInstancedProperties(RegisteredVisualContainer& visuals, Dictionary<Property::Map>& instancedProperties)
+{
+  for(RegisteredVisualContainer::Iterator iter = visuals.Begin(); iter != visuals.End(); iter++)
+  {
+    if((*iter)->visual)
+    {
+      Property::Map instanceMap;
+      Toolkit::GetImplementation((*iter)->visual).CreateInstancePropertyMap(instanceMap);
+      instancedProperties.Add((*iter)->visual.GetName(), instanceMap);
+    }
+  }
+}
+
+void Control::Impl::VisualData::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual)
+{
+  RegisterVisual(index, visual, VisualState::ENABLED, DepthIndexValue::NOT_SET);
+}
+
+void Control::Impl::VisualData::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, int depthIndex)
+{
+  RegisterVisual(index, visual, VisualState::ENABLED, DepthIndexValue::SET, depthIndex);
+}
+
+void Control::Impl::VisualData::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, bool enabled)
+{
+  RegisterVisual(index, visual, (enabled ? VisualState::ENABLED : VisualState::DISABLED), DepthIndexValue::NOT_SET);
+}
+
+void Control::Impl::VisualData::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, bool enabled, int depthIndex)
+{
+  RegisterVisual(index, visual, (enabled ? VisualState::ENABLED : VisualState::DISABLED), DepthIndexValue::SET, depthIndex);
+}
+
+void Control::Impl::VisualData::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, VisualState::Type enabled, DepthIndexValue::Type depthIndexValueSet, int depthIndex)
+{
+  DALI_ASSERT_ALWAYS(Stage::IsCoreThread() && "Core is not installed. Might call this API from worker thread?");
+
+  DALI_LOG_INFO(gLogFilter, Debug::Concise, "RegisterVisual:%d \n", index);
+
+  bool  visualReplaced(false);
+  Actor self = mOuter.mControlImpl.Self();
+
+  // Set the depth index, if not set by caller this will be either the current visual depth, max depth of all visuals
+  // or zero.
+  int requiredDepthIndex = visual.GetDepthIndex();
+
+  if(depthIndexValueSet == DepthIndexValue::SET)
+  {
+    requiredDepthIndex = depthIndex;
+  }
+
+  // Change the depth index value automatically if the visual has DepthIndex to AUTO_INDEX
+  // or if RegisterVisual set DepthIndex to AUTO_INDEX.
+  const bool requiredDepthIndexChanged = (requiredDepthIndex == DepthIndex::AUTO_INDEX);
+
+  // Visual replacement, existing visual should only be removed from stage when replacement ready.
+  if(!mVisuals.Empty())
+  {
+    RegisteredVisualContainer::Iterator registeredVisualsiter;
+    // Check if visual (index) is already registered, this is the current visual.
+    if(FindVisual(index, mVisuals, registeredVisualsiter))
+    {
+      Toolkit::Visual::Base& currentRegisteredVisual = (*registeredVisualsiter)->visual;
+      if(currentRegisteredVisual)
+      {
+        // Store current visual depth index as may need to set the replacement visual to same depth
+        const int currentDepthIndex = (*registeredVisualsiter)->visual.GetDepthIndex();
+
+        // No longer required to know if the replaced visual's resources are ready
+        StopObservingVisual(currentRegisteredVisual);
+
+        // If control staged and visual enabled then visuals will be swapped once ready
+        if(self.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE) && enabled)
+        {
+          // Check if visual is currently in the process of being replaced ( is in removal container )
+          RegisteredVisualContainer::Iterator visualQueuedForRemoval;
+          if(FindVisual(index, mRemoveVisuals, visualQueuedForRemoval))
+          {
+            // Visual with same index is already in removal container so current visual pending
+            // Only the the last requested visual will be displayed so remove current visual which is staged but not ready.
+            Toolkit::GetImplementation(currentRegisteredVisual).SetOffScene(self);
+            mVisuals.Erase(registeredVisualsiter);
+          }
+          else
+          {
+            // current visual not already in removal container so add now.
+            DALI_LOG_INFO(gLogFilter, Debug::Verbose, "RegisterVisual Move current registered visual to removal Queue: %d \n", index);
+            MoveVisual(registeredVisualsiter, mVisuals, mRemoveVisuals);
+          }
+        }
+        else
+        {
+          // Control not staged or visual disabled so can just erase from registered visuals and new visual will be added later.
+          mVisuals.Erase(registeredVisualsiter);
+        }
+
+        // If the visual have a depth index as AUTO_INDEX and the new visual does not have a depth index applied to it, then use the previously set depth-index for this index
+        if(requiredDepthIndexChanged)
+        {
+          requiredDepthIndex = currentDepthIndex;
+          DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Use replaced visual index. VisualDepthIndex AUTO_INDEX set as: %d\n", requiredDepthIndex);
+        }
+      }
+
+      visualReplaced = true;
+    }
+  }
+
+  // If not set, set the name of the visual to the same name as the control's property.
+  // ( If the control has been type registered )
+  if(visual.GetName().empty())
+  {
+    // returns empty string if index is not found as long as index is not -1
+    std::string visualName = self.GetPropertyName(index);
+    if(!visualName.empty())
+    {
+      DALI_LOG_INFO(gLogFilter, Debug::Concise, "Setting visual name for property %d to %s\n", index, visualName.c_str());
+      visual.SetName(visualName);
+    }
+  }
+
+  if(!visualReplaced) // New registration entry
+  {
+    // If we have more than one visual and the visual have a depth index as AUTO_INDEX, then set it to be the highest
+    if((mVisuals.Size() > 0) && requiredDepthIndexChanged)
+    {
+      int maxDepthIndex = static_cast<int>(DepthIndex::CONTENT) - 1; // Start at DepthIndex::CONTENT if maxDepth index belongs to a background or no visuals have been added yet.
+
+      RegisteredVisualContainer::ConstIterator       iter;
+      const RegisteredVisualContainer::ConstIterator endIter = mVisuals.End();
+      for(iter = mVisuals.Begin(); iter != endIter; iter++)
+      {
+        const int visualDepthIndex = (*iter)->visual.GetDepthIndex();
+        if(visualDepthIndex > maxDepthIndex)
+        {
+          maxDepthIndex = visualDepthIndex;
+        }
+      }
+      requiredDepthIndex = ++maxDepthIndex; // Add one to the current maximum depth index so that our added visual appears on top.
+      DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Use top of all visuals. VisualDepthIndex AUTO_INDEX set as: %d\n", requiredDepthIndex);
+    }
+  }
+
+  if(visual)
+  {
+    // If required depth index still DepthIndex::AUTO_INDEX, Make it as DepthIndex::CONTENT now
+    if(requiredDepthIndex == static_cast<int>(DepthIndex::AUTO_INDEX))
+    {
+      requiredDepthIndex = static_cast<int>(DepthIndex::CONTENT);
+      DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Some strange cases. VisualDepthIndex AUTO_INDEX set as: %d\n", requiredDepthIndex);
+    }
+
+    // Set determined depth index
+    visual.SetDepthIndex(requiredDepthIndex);
+
+    // Monitor when the visual resources are ready
+    StartObservingVisual(visual);
+
+    DALI_LOG_INFO(gLogFilter, Debug::Concise, "New Visual registration index[%d] depth[%d]\n", index, requiredDepthIndex);
+    RegisteredVisual* newRegisteredVisual = new RegisteredVisual(index, visual, (enabled == VisualState::ENABLED ? true : false), (visualReplaced && enabled));
+    mVisuals.PushBack(newRegisteredVisual);
+
+    Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
+    // Put on stage if enabled and the control is already on the stage
+    if((enabled == VisualState::ENABLED) && self.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
+    {
+      visualImpl.SetOnScene(self);
+    }
+    else if(enabled && visualImpl.IsResourceReady()) // When not being staged, check if visual already 'ResourceReady' before it was Registered. ( Resource may have been loaded already )
+    {
+      ResourceReady(visualImpl);
+    }
+  }
+
+  DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::RegisterVisual() Registered %s(%d), enabled:%s\n", visual.GetName().c_str(), index, enabled ? "true" : "false");
+}
+
+void Control::Impl::VisualData::UnregisterVisual(Property::Index index)
+{
+  DALI_ASSERT_ALWAYS(Stage::IsCoreThread() && "Core is not installed. Might call this API from worker thread?");
+
+  RegisteredVisualContainer::Iterator iter;
+  if(FindVisual(index, mVisuals, iter))
+  {
+    // stop observing visual
+    StopObservingVisual((*iter)->visual);
+
+    Actor self(mOuter.mControlImpl.Self());
+    Toolkit::GetImplementation((*iter)->visual).SetOffScene(self);
+    (*iter)->visual.Reset();
+    mVisuals.Erase(iter);
+  }
+
+  if(FindVisual(index, mRemoveVisuals, iter))
+  {
+    Actor self(mOuter.mControlImpl.Self());
+    Toolkit::GetImplementation((*iter)->visual).SetOffScene(self);
+    (*iter)->pending = false;
+
+    // Discard removed visual. It will be destroyed at next Idle time.
+    DiscardVisual(iter, mRemoveVisuals);
+  }
+}
+
+Toolkit::Visual::Base Control::Impl::VisualData::GetVisual(Property::Index index) const
+{
+  RegisteredVisualContainer::Iterator iter;
+  if(FindVisual(index, mVisuals, iter))
+  {
+    return (*iter)->visual;
+  }
+
+  return Toolkit::Visual::Base();
+}
+
+Toolkit::Visual::Base Control::Impl::VisualData::GetVisual(const std::string& name) const
+{
+  return GetVisualByName(mVisuals, name);
+}
+
+void Control::Impl::VisualData::EnableVisual(Property::Index index, bool enable)
+{
+  DALI_LOG_INFO(gLogFilter, Debug::General, "Control::EnableVisual(%d, %s)\n", index, enable ? "T" : "F");
+
+  RegisteredVisualContainer::Iterator iter;
+  if(FindVisual(index, mVisuals, iter))
+  {
+    if((*iter)->enabled == enable)
+    {
+      DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::EnableVisual Visual %s(%d) already %s\n", (*iter)->visual.GetName().c_str(), index, enable ? "enabled" : "disabled");
+      return;
+    }
+
+    (*iter)->enabled  = enable;
+    Actor parentActor = mOuter.mControlImpl.Self();
+    if(mOuter.mControlImpl.Self().GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE)) // If control not on Scene then Visual will be added when SceneConnection is called.
+    {
+      if(enable)
+      {
+        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::EnableVisual Setting %s(%d) on stage \n", (*iter)->visual.GetName().c_str(), index);
+        Toolkit::GetImplementation((*iter)->visual).SetOnScene(parentActor);
+      }
+      else
+      {
+        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::EnableVisual Setting %s(%d) off stage \n", (*iter)->visual.GetName().c_str(), index);
+        Toolkit::GetImplementation((*iter)->visual).SetOffScene(parentActor); // No need to call if control not staged.
+      }
+    }
+  }
+  else
+  {
+    DALI_LOG_WARNING("Control::EnableVisual(%d, %s) FAILED - NO SUCH VISUAL\n", index, enable ? "T" : "F");
+  }
+}
+
+void Control::Impl::VisualData::EnableReadyTransitionOverriden(Toolkit::Visual::Base& visual, bool enable)
+{
+  DALI_LOG_INFO(gLogFilter, Debug::General, "Control::EnableReadyTransitionOverriden(%p, %s)\n", visual, enable ? "T" : "F");
+
+  RegisteredVisualContainer::Iterator iter;
+  if(FindVisual(visual, mVisuals, iter))
+  {
+    if((*iter)->overideReadyTransition == enable)
+    {
+      DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::EnableReadyTransitionOverriden Visual %s(%p) already %s\n", (*iter)->visual.GetName().c_str(), visual, enable ? "enabled" : "disabled");
+      return;
+    }
+
+    (*iter)->overideReadyTransition = enable;
+  }
+}
+
+bool Control::Impl::VisualData::IsVisualEnabled(Property::Index index) const
+{
+  RegisteredVisualContainer::Iterator iter;
+  if(FindVisual(index, mVisuals, iter))
+  {
+    return (*iter)->enabled;
+  }
+  return false;
+}
+
+void Control::Impl::VisualData::RemoveVisual(RegisteredVisualContainer& visuals, const std::string& visualName)
+{
+  Actor self(mOuter.mControlImpl.Self());
+
+  for(RegisteredVisualContainer::Iterator visualIter = visuals.Begin();
+      visualIter != visuals.End();
+      ++visualIter)
+  {
+    Toolkit::Visual::Base visual = (*visualIter)->visual;
+    if(visual && visual.GetName() == visualName)
+    {
+      Toolkit::GetImplementation(visual).SetOffScene(self);
+      (*visualIter)->visual.Reset();
+      visuals.Erase(visualIter);
+      break;
+    }
+  }
+}
+
+void Control::Impl::VisualData::RemoveVisuals(RegisteredVisualContainer& visuals, DictionaryKeys& removeVisuals)
+{
+  Actor self(mOuter.mControlImpl.Self());
+  for(DictionaryKeys::iterator iter = removeVisuals.begin(); iter != removeVisuals.end(); ++iter)
+  {
+    const std::string visualName = *iter;
+    RemoveVisual(visuals, visualName);
+  }
+}
+
+void Control::Impl::VisualData::RecreateChangedVisuals(Dictionary<Property::Map>& stateVisualsToChange,
+                                                       Dictionary<Property::Map>& instancedProperties)
+{
+  Dali::CustomActor handle(mOuter.mControlImpl.GetOwner());
+  for(Dictionary<Property::Map>::iterator iter = stateVisualsToChange.Begin();
+      iter != stateVisualsToChange.End();
+      ++iter)
+  {
+    const std::string&   visualName = (*iter).key;
+    const Property::Map& toMap      = (*iter).entry;
+
+    Actor                               self = mOuter.mControlImpl.Self();
+    RegisteredVisualContainer::Iterator registeredVisualsiter;
+    // Check if visual (visualName) is already registered, this is the current visual.
+    if(FindVisual(visualName, mVisuals, registeredVisualsiter))
+    {
+      Toolkit::Visual::Base& visual = (*registeredVisualsiter)->visual;
+      if(visual)
+      {
+        // No longer required to know if the replaced visual's resources are ready
+        StopObservingVisual(visual);
+
+        // If control staged then visuals will be swapped once ready
+        if(self.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
+        {
+          // Check if visual is currently in the process of being replaced ( is in removal container )
+          RegisteredVisualContainer::Iterator visualQueuedForRemoval;
+          if(FindVisual(visualName, mRemoveVisuals, visualQueuedForRemoval))
+          {
+            // Visual with same visual name is already in removal container so current visual pending
+            // Only the the last requested visual will be displayed so remove current visual which is staged but not ready.
+            Toolkit::GetImplementation(visual).SetOffScene(self);
+            (*registeredVisualsiter)->visual.Reset();
+            mVisuals.Erase(registeredVisualsiter);
+          }
+          else
+          {
+            // current visual not already in removal container so add now.
+            DALI_LOG_INFO(gLogFilter, Debug::Verbose, "RegisterVisual Move current registered visual to removal Queue: %s \n", visualName.c_str());
+            MoveVisual(registeredVisualsiter, mVisuals, mRemoveVisuals);
+          }
+        }
+        else
+        {
+          // Control not staged or visual disabled so can just erase from registered visuals and new visual will be added later.
+          (*registeredVisualsiter)->visual.Reset();
+          mVisuals.Erase(registeredVisualsiter);
+        }
+      }
+
+      const Property::Map* instancedMap = instancedProperties.FindConst(visualName);
+      Style::ApplyVisual(handle, visualName, toMap, instancedMap);
+    }
+  }
+}
+
+void Control::Impl::VisualData::ReplaceStateVisualsAndProperties(const StylePtr oldState, const StylePtr newState, const std::string& subState)
+{
+  DALI_ASSERT_ALWAYS(Stage::IsCoreThread() && "Core is not installed. Might call this API from worker thread?");
+
+  // Collect all old visual names
+  DictionaryKeys stateVisualsToRemove;
+  if(oldState)
+  {
+    oldState->visuals.GetKeys(stateVisualsToRemove);
+    if(!subState.empty())
+    {
+      const StylePtr* oldSubState = oldState->subStates.FindConst(subState);
+      if(oldSubState)
+      {
+        DictionaryKeys subStateVisualsToRemove;
+        (*oldSubState)->visuals.GetKeys(subStateVisualsToRemove);
+        Merge(stateVisualsToRemove, subStateVisualsToRemove);
+      }
+    }
+  }
+
+  // Collect all new visual properties
+  Dictionary<Property::Map> stateVisualsToAdd;
+  if(newState)
+  {
+    stateVisualsToAdd = newState->visuals;
+    if(!subState.empty())
+    {
+      const StylePtr* newSubState = newState->subStates.FindConst(subState);
+      if(newSubState)
+      {
+        stateVisualsToAdd.Merge((*newSubState)->visuals);
+      }
+    }
+  }
+
+  // If a name is in both add/remove, move it to change list.
+  Dictionary<Property::Map> stateVisualsToChange;
+  FindChangableVisuals(stateVisualsToAdd, stateVisualsToChange, stateVisualsToRemove);
+
+  // Copy instanced properties (e.g. text label) of current visuals
+  Dictionary<Property::Map> instancedProperties;
+  CopyInstancedProperties(mVisuals, instancedProperties);
+
+  // For each visual in remove list, remove from mVisuals
+  RemoveVisuals(mVisuals, stateVisualsToRemove);
+
+  // For each visual in add list, create and add to mVisuals
+  Dali::CustomActor handle(mOuter.mControlImpl.GetOwner());
+  Style::ApplyVisuals(handle, stateVisualsToAdd, instancedProperties);
+
+  // For each visual in change list, if it requires a new visual,
+  // remove old visual, create and add to mVisuals
+  RecreateChangedVisuals(stateVisualsToChange, instancedProperties);
+}
+
+DevelControl::VisualEventSignalType& Control::Impl::VisualData::VisualEventSignal()
+{
+  return mVisualEventSignal;
+}
+
+void Control::Impl::VisualData::DoAction(Dali::Property::Index visualIndex, Dali::Property::Index actionId, const Dali::Property::Value attributes)
+{
+  RegisteredVisualContainer::Iterator iter;
+  if(FindVisual(visualIndex, mVisuals, iter))
+  {
+    Toolkit::GetImplementation((*iter)->visual).DoAction(actionId, attributes);
+  }
+}
+
+void Control::Impl::VisualData::DoActionExtension(Dali::Property::Index visualIndex, Dali::Property::Index actionId, Dali::Any attributes)
+{
+  RegisteredVisualContainer::Iterator iter;
+  if(FindVisual(visualIndex, mVisuals, iter))
+  {
+    Toolkit::GetImplementation((*iter)->visual).DoActionExtension(actionId, attributes);
+  }
+}
+
+void Control::Impl::VisualData::ClearVisuals()
+{
+  while(!mVisuals.Empty())
+  {
+    auto iter = mVisuals.End() - 1u;
+    StopObservingVisual((*iter)->visual);
+
+    // Discard removed visual. It will be destroyed at next Idle time.
+    DiscardVisual(iter, mVisuals);
+  }
+
+  while(!mRemoveVisuals.Empty())
+  {
+    auto removalIter = mRemoveVisuals.End() - 1u;
+    StopObservingVisual((*removalIter)->visual);
+
+    // Discard removed visual. It will be destroyed at next Idle time.
+    DiscardVisual(removalIter, mRemoveVisuals);
+  }
+}
+
+Dali::Property Control::Impl::VisualData::GetVisualProperty(Dali::Property::Index index, Dali::Property::Key visualPropertyKey)
+{
+  Toolkit::Visual::Base visual = GetVisualByIndex(mVisuals, index);
+  if(visual)
+  {
+    Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
+    return visualImpl.GetPropertyObject(std::move(visualPropertyKey));
+  }
+
+  Handle handle;
+  return Dali::Property(handle, Property::INVALID_INDEX);
+}
+
+void Control::Impl::VisualData::StopObservingVisual(Toolkit::Visual::Base& visual)
+{
+  Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
+
+  // Stop observing the visual
+  visualImpl.RemoveEventObserver(*this);
+}
+
+void Control::Impl::VisualData::StartObservingVisual(Toolkit::Visual::Base& visual)
+{
+  Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
+
+  // start observing the visual for events
+  visualImpl.AddEventObserver(*this);
+}
+
+void Control::Impl::VisualData::UpdateVisualProperties(const std::vector<std::pair<Dali::Property::Index, Dali::Property::Map>>& properties)
+{
+  for(auto&& data : properties)
+  {
+    if(data.first == Toolkit::Control::Property::BACKGROUND)
+    {
+      DoAction(Toolkit::Control::Property::BACKGROUND, DevelVisual::Action::UPDATE_PROPERTY, data.second);
+    }
+    else if(data.first == Toolkit::DevelControl::Property::SHADOW)
+    {
+      DoAction(Toolkit::DevelControl::Property::SHADOW, DevelVisual::Action::UPDATE_PROPERTY, data.second);
+    }
+  }
+  mOuter.mControlImpl.OnUpdateVisualProperties(properties);
+}
+
+void Control::Impl::VisualData::ApplyFittingMode(const Vector2& size)
+{
+  Actor self = mOuter.mControlImpl.Self();
+  for(RegisteredVisualContainer::Iterator iter = mVisuals.Begin(); iter != mVisuals.End(); iter++)
+  {
+    // Check whether the visual is empty and enabled
+    if((*iter)->visual && (*iter)->enabled)
+    {
+      Internal::Visual::Base& visualImpl = Toolkit::GetImplementation((*iter)->visual);
+
+      // If the current visual is using the transform property map, fittingMode will not be applied.
+      if(visualImpl.IsIgnoreFittingMode())
+      {
+        continue;
+      }
+
+      Visual::FittingMode fittingMode  = visualImpl.GetFittingMode();
+      Property::Map       transformMap = Property::Map();
+
+      // If the fittingMode is DONT_CARE, we don't need to apply fittingMode, just Set empty transformMap
+      if(fittingMode == Visual::FittingMode::DONT_CARE)
+      {
+        if(visualImpl.GetType() != Toolkit::Visual::Type::TEXT)
+        {
+          ((*iter)->visual).SetTransformAndSize(transformMap, size);
+        }
+        continue;
+      }
+
+      Extents padding = self.GetProperty<Extents>(Toolkit::Control::Property::PADDING);
+
+      bool zeroPadding = (padding == Extents());
+
+      Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>(
+        self.GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>());
+      if(Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection)
+      {
+        std::swap(padding.start, padding.end);
+      }
+
+      // remove padding from the size to know how much is left for the visual
+      Vector2 finalSize   = size - Vector2(padding.start + padding.end, padding.top + padding.bottom);
+      Vector2 finalOffset = Vector2(padding.start, padding.top);
+
+      // Reset PIXEL_AREA after using OVER_FIT_KEEP_ASPECT_RATIO
+      if(visualImpl.IsPixelAreaSetForFittingMode())
+      {
+        visualImpl.SetPixelAreaForFittingMode(FULL_TEXTURE_RECT);
+      }
+
+      if((!zeroPadding) || // If padding is not zero
+         (fittingMode != Visual::FittingMode::FILL))
+      {
+        visualImpl.SetTransformMapUsageForFittingMode(true);
+
+        Vector2 naturalSize;
+        // NaturalSize will not be used for FILL fitting mode, which is default.
+        // Skip GetNaturalSize
+        if(fittingMode != Visual::FittingMode::FILL)
+        {
+          ((*iter)->visual).GetNaturalSize(naturalSize);
+        }
+
+        // If FittingMode use FIT_WIDTH or FIT_HEIGTH, it need to change proper fittingMode
+        if(fittingMode == Visual::FittingMode::FIT_WIDTH || fittingMode == Visual::FittingMode::FIT_HEIGHT)
+        {
+          const float widthRatio  = !Dali::EqualsZero(naturalSize.width) ? (finalSize.width / naturalSize.width) : 0.0f;
+          const float heightRatio = !Dali::EqualsZero(naturalSize.height) ? (finalSize.height / naturalSize.height) : 0.0f;
+          if(widthRatio < heightRatio)
+          {
+            // Final size has taller form than natural size.
+            fittingMode = (fittingMode == Visual::FittingMode::FIT_WIDTH) ? Visual::FittingMode::FIT_KEEP_ASPECT_RATIO : Visual::FittingMode::OVER_FIT_KEEP_ASPECT_RATIO;
+          }
+          else
+          {
+            // Final size has wider form than natural size.
+            fittingMode = (fittingMode == Visual::FittingMode::FIT_WIDTH) ? Visual::FittingMode::OVER_FIT_KEEP_ASPECT_RATIO : Visual::FittingMode::FIT_KEEP_ASPECT_RATIO;
+          }
+        }
+
+        // Calculate size for fittingMode
+        switch(fittingMode)
+        {
+          case Visual::FittingMode::FIT_KEEP_ASPECT_RATIO:
+          {
+            auto availableVisualSize = finalSize;
+
+            // scale to fit the padded area
+            finalSize = naturalSize * std::min((!Dali::EqualsZero(naturalSize.width) ? (availableVisualSize.width / naturalSize.width) : 0),
+                                               (!Dali::EqualsZero(naturalSize.height) ? (availableVisualSize.height / naturalSize.height) : 0));
+
+            // calculate final offset within the padded area
+            finalOffset += (availableVisualSize - finalSize) * .5f;
+
+            // populate the transform map
+            transformMap.Add(Toolkit::Visual::Transform::Property::OFFSET, finalOffset)
+              .Add(Toolkit::Visual::Transform::Property::SIZE, finalSize);
+            break;
+          }
+          case Visual::FittingMode::OVER_FIT_KEEP_ASPECT_RATIO:
+          {
+            auto availableVisualSize = finalSize;
+            finalSize                = naturalSize * std::max((!Dali::EqualsZero(naturalSize.width) ? (availableVisualSize.width / naturalSize.width) : 0.0f),
+                                               (!Dali::EqualsZero(naturalSize.height) ? (availableVisualSize.height / naturalSize.height) : 0.0f));
+
+            auto originalOffset = finalOffset;
+
+            if(!visualImpl.IsPixelAreaSetForFittingMode() && !Dali::EqualsZero(finalSize.width) && !Dali::EqualsZero(finalSize.height))
+            {
+              float   x           = abs((availableVisualSize.width - finalSize.width) / finalSize.width) * .5f;
+              float   y           = abs((availableVisualSize.height - finalSize.height) / finalSize.height) * .5f;
+              float   widthRatio  = 1.f - abs((availableVisualSize.width - finalSize.width) / finalSize.width);
+              float   heightRatio = 1.f - abs((availableVisualSize.height - finalSize.height) / finalSize.height);
+              Vector4 pixelArea   = Vector4(x, y, widthRatio, heightRatio);
+              visualImpl.SetPixelAreaForFittingMode(pixelArea);
+            }
+
+            // populate the transform map
+            transformMap.Add(Toolkit::Visual::Transform::Property::OFFSET, originalOffset)
+              .Add(Toolkit::Visual::Transform::Property::SIZE, availableVisualSize);
+            break;
+          }
+          case Visual::FittingMode::CENTER:
+          {
+            auto availableVisualSize = finalSize;
+            if(availableVisualSize.width > naturalSize.width && availableVisualSize.height > naturalSize.height)
+            {
+              finalSize = naturalSize;
+            }
+            else
+            {
+              finalSize = naturalSize * std::min((!Dali::EqualsZero(naturalSize.width) ? (availableVisualSize.width / naturalSize.width) : 0.0f),
+                                                 (!Dali::EqualsZero(naturalSize.height) ? (availableVisualSize.height / naturalSize.height) : 0.0f));
+            }
+
+            finalOffset += (availableVisualSize - finalSize) * .5f;
+
+            // populate the transform map
+            transformMap.Add(Toolkit::Visual::Transform::Property::OFFSET, finalOffset)
+              .Add(Toolkit::Visual::Transform::Property::SIZE, finalSize);
+            break;
+          }
+          case Visual::FittingMode::FILL:
+          {
+            transformMap.Add(Toolkit::Visual::Transform::Property::OFFSET, finalOffset)
+              .Add(Toolkit::Visual::Transform::Property::SIZE, finalSize);
+            break;
+          }
+          case Visual::FittingMode::FIT_WIDTH:
+          case Visual::FittingMode::FIT_HEIGHT:
+          case Visual::FittingMode::DONT_CARE:
+          {
+            // This FittingMode already converted
+            break;
+          }
+        }
+
+        // Set extra value for applying transformMap
+        transformMap.Add(Toolkit::Visual::Transform::Property::OFFSET_POLICY,
+                         Vector2(Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE))
+          .Add(Toolkit::Visual::Transform::Property::ORIGIN, Toolkit::Align::TOP_BEGIN)
+          .Add(Toolkit::Visual::Transform::Property::ANCHOR_POINT, Toolkit::Align::TOP_BEGIN)
+          .Add(Toolkit::Visual::Transform::Property::SIZE_POLICY,
+               Vector2(Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE));
+      }
+      else if(visualImpl.IsTransformMapSetForFittingMode() && zeroPadding) // Reset offset to zero only if padding applied previously
+      {
+        visualImpl.SetTransformMapUsageForFittingMode(false);
+
+        // Reset the transform map
+        transformMap.Add(Toolkit::Visual::Transform::Property::OFFSET, Vector2::ZERO)
+          .Add(Toolkit::Visual::Transform::Property::OFFSET_POLICY,
+               Vector2(Toolkit::Visual::Transform::Policy::RELATIVE, Toolkit::Visual::Transform::Policy::RELATIVE))
+          .Add(Toolkit::Visual::Transform::Property::SIZE, Vector2::ONE)
+          .Add(Toolkit::Visual::Transform::Property::SIZE_POLICY,
+               Vector2(Toolkit::Visual::Transform::Policy::RELATIVE, Toolkit::Visual::Transform::Policy::RELATIVE));
+      }
+
+      ((*iter)->visual).SetTransformAndSize(transformMap, size);
+    }
+  }
+}
+
+} // namespace Internal
+} // namespace Toolkit
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/control/control-visual-data.h b/dali-toolkit/internal/controls/control/control-visual-data.h
new file mode 100644 (file)
index 0000000..e29c7f1
--- /dev/null
@@ -0,0 +1,305 @@
+#ifndef DALI_TOOLKIT_CONTROL_DATA_VISUAL_DATA_H
+#define DALI_TOOLKIT_CONTROL_DATA_VISUAL_DATA_H
+
+/*
+ * Copyright (c) 2024 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-base.h>
+#include <dali-toolkit/internal/builder/dictionary.h>
+#include <dali-toolkit/internal/builder/style.h>
+#include <dali-toolkit/internal/visuals/visual-event-observer.h>
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali/devel-api/common/owner-container.h>
+
+#include <dali-toolkit/internal/controls/control/control-data-impl.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+/**
+  * @brief Struct used to store Visual within the control, index is a unique key for each visual.
+  */
+struct RegisteredVisual
+{
+  Property::Index       index;
+  Toolkit::Visual::Base visual;
+  bool                  enabled : 1;
+  bool                  pending : 1;
+  bool                  overideReadyTransition : 1;
+
+  RegisteredVisual(Property::Index aIndex, Toolkit::Visual::Base& aVisual, bool aEnabled, bool aPendingReplacement)
+  : index(aIndex),
+    visual(aVisual),
+    enabled(aEnabled),
+    pending(aPendingReplacement),
+    overideReadyTransition(false)
+  {
+  }
+};
+
+typedef Dali::OwnerContainer<RegisteredVisual*> RegisteredVisualContainer;
+
+// private inner class
+class Control::Impl::VisualData : public Visual::EventObserver
+{
+public:
+  // Constructor
+  VisualData(Control::Impl& outer);
+
+  // Destructor
+  ~VisualData();
+
+  /**
+   * @brief Called when a resource is ready.
+   * @param[in] object The visual whose resources are ready
+   * @note Overriding method in Visual::EventObserver.
+   */
+  void ResourceReady(Visual::Base& object) override;
+
+  /**
+   * @brief Called when an event occurs.
+   * @param[in] object The visual whose events occur
+   * @param[in] signalId The signal to emit. See Visual to find supported signals
+   * @note Overriding method in Visual::EventObserver.
+   */
+  void NotifyVisualEvent(Visual::Base& object, Property::Index signalId) override;
+
+  /**
+   * @brief Called when the visual needs relayout request.
+   * @param[in] object The visual who requests relayout
+   */
+  void RelayoutRequest(Visual::Base& object) override;
+
+  /**
+   * @copydoc Dali::Toolkit::Internal::Control::Impl::IsResourceReady()
+   */
+  bool IsResourceReady() const;
+
+  /**
+   * @copydoc Dali::Toolkit::Internal::Control::Impl::EnableReadyTransitionOverriden()
+   */
+  void EnableReadyTransitionOverriden(Toolkit::Visual::Base& visual, bool enable);
+
+  /**
+   * @copydoc Dali::Toolkit::Internal::Control::Impl::GetVisualResourceStatus()
+   */
+  Toolkit::Visual::ResourceStatus GetVisualResourceStatus(Property::Index index) const;
+
+  /**
+   * @brief Copies the visual properties that are specific to the control instance into the instancedProperties container.
+   * @param[in] visuals The control's visual container
+   * @param[out] instancedProperties The instanced properties are added to this container
+   */
+  void CopyInstancedProperties(RegisteredVisualContainer& visuals, Dictionary<Property::Map>& instancedProperties);
+
+  /**
+   * @copydoc Dali::Toolkit::Internal::Control::Impl::RegisterVisual()
+   */
+  void RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual);
+
+  /**
+   * @copydoc Dali::Toolkit::Internal::Control::Impl::RegisterVisual()
+   */
+  void RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, int depthIndex);
+
+  /**
+   * @copydoc Dali::Toolkit::Internal::Control::Impl::RegisterVisual()
+   */
+  void RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, bool enabled);
+
+  /**
+   * @copydoc Dali::Toolkit::Internal::Control::Impl::RegisterVisual()
+   */
+  void RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, bool enabled, int depthIndex);
+
+  /**
+   * @copydoc Dali::Toolkit::Internal::Control::Impl::UnregisterVisual()
+   */
+  void UnregisterVisual(Property::Index index);
+
+  /**
+   * @copydoc Dali::Toolkit::Internal::Control::Impl::GetVisual()
+   */
+  Toolkit::Visual::Base GetVisual(Property::Index index) const;
+
+  /**
+   * @brief Get visual by its name
+   * @param[in] name Name of visual
+   */
+  Toolkit::Visual::Base GetVisual(const std::string& name) const;
+
+  /**
+   * @copydoc Dali::Toolkit::Internal::Control::Impl::GetVisualProperty()
+   */
+  Dali::Property GetVisualProperty(Dali::Property::Index index, Dali::Property::Key visualPropertyKey);
+
+  /**
+   * @copydoc Dali::Toolkit::Internal::Control::Impl::EnableVisual()
+   */
+  void EnableVisual(Property::Index index, bool enable);
+
+  /**
+   * @copydoc Dali::Toolkit::Internal::Control::Impl::IsVisualEnabled()
+   */
+  bool IsVisualEnabled(Property::Index index) const;
+
+  /**
+   * @brief Removes a visual from the control's container.
+   * @param[in] visuals The container of visuals
+   * @param[in] visualName The name of the visual to remove
+   */
+  void RemoveVisual(RegisteredVisualContainer& visuals, const std::string& visualName);
+
+  /**
+   * @brief Removes several visuals from the control's container.
+   * @param[in] visuals The container of visuals
+   * @param[in] removeVisuals The visuals to remove
+   */
+  void RemoveVisuals(RegisteredVisualContainer& visuals, DictionaryKeys& removeVisuals);
+
+  /**
+   * @brief On state change, ensures visuals are moved or created appropriately.
+   *
+   * Go through the list of visuals that are common to both states.
+   * If they are different types, or are both image types with different
+   * URLs, then the existing visual needs moving and the new visual needs creating
+   *
+   * @param[in] stateVisualsToChange The visuals to change
+   * @param[in] instancedProperties The instanced properties @see CopyInstancedProperties
+   */
+  void RecreateChangedVisuals(Dictionary<Property::Map>& stateVisualsToChange, Dictionary<Property::Map>& instancedProperties);
+
+  /**
+   * @brief Replaces visuals and properties from the old state to the new state.
+   * @param[in] oldState The old state
+   * @param[in] newState The new state
+   * @param[in] subState The current sub state
+   */
+  void ReplaceStateVisualsAndProperties(const StylePtr oldState, const StylePtr newState, const std::string& subState);
+
+  /**
+   * @copydoc Dali::Toolkit::Internal::Control::Impl::DoAction()
+   */
+  void DoAction(Dali::Property::Index visualIndex, Dali::Property::Index actionId, const Dali::Property::Value attributes);
+
+  /**
+   * @copydoc Dali::Toolkit::Internal::Control::Impl::DoActionExtension()
+   */
+  void DoActionExtension(Dali::Property::Index visualIndex, Dali::Property::Index actionId, Dali::Any attributes);
+
+  /**
+   * @copydoc Dali::Toolkit::Internal::Control::Impl::VisualEventSignal()
+   */
+  DevelControl::VisualEventSignalType& VisualEventSignal();
+
+  /**
+   * @brief Any visuals set for replacement but not yet ready should still be registered.
+   * Reason: If a request was made to register a new visual but the control removed from scene before visual was ready
+   * then when this control appears back on stage it should use that new visual.
+   *
+   * After all registered visuals are set off scene,
+   * visuals pending replacement can be taken out of the removal list and set off scene.
+   * Iterate through all replacement visuals and add to a move queue then set off scene.
+   *
+   * @param[in] parent Parent actor to remove visuals from
+   */
+  void ClearScene(Actor parent);
+
+  /**
+   * @brief Clear visuals.
+   */
+  void ClearVisuals();
+
+  /**
+   * @copydoc Dali::Toolkit::Internal::Control::Impl::ApplyFittingMode()
+   */
+  void ApplyFittingMode(const Vector2& size);
+
+  /**
+   * @brief Stops observing the given visual.
+   * @param[in] visual The visual to stop observing
+   */
+  void StopObservingVisual(Toolkit::Visual::Base& visual);
+
+  /**
+   * @brief Starts observing the given visual.
+   * @param[in] visual The visual to start observing
+   */
+  void StartObservingVisual(Toolkit::Visual::Base& visual);
+
+  /**
+   * @copydoc Dali::Toolkit::Internal::Control::Impl::UpdateVisualProperties()
+   */
+  void UpdateVisualProperties(const std::vector<std::pair<Dali::Property::Index, Dali::Property::Map>>& properties);
+
+private:
+  /**
+   * Used as an alternative to boolean so that it is obvious whether a visual is enabled/disabled.
+   */
+  struct VisualState
+  {
+    enum Type
+    {
+      DISABLED = 0, ///< Visual disabled.
+      ENABLED  = 1  ///< Visual enabled.
+    };
+  };
+
+  /**
+   * Used as an alternative to boolean so that it is obvious whether a visual's depth value has been set or not by the caller.
+   */
+  struct DepthIndexValue
+  {
+    enum Type
+    {
+      NOT_SET = 0, ///< Visual depth value not set by caller.
+      SET     = 1  ///< Visual depth value set by caller.
+    };
+  };
+
+  /**
+   * @brief Adds the visual to the list of registered visuals.
+   * @param[in] index The Property index of the visual, used to reference visual
+   * @param[in,out] visual The visual to register, which can be altered in this function
+   * @param[in] enabled false if derived class wants to control when visual is set on stage
+   * @param[in] depthIndexValueSet Set to true if the depthIndex has actually been set manually
+   * @param[in] depthIndex The visual's depth-index is set to this. If the depth-index is set to DepthIndex::Ranges::AUTO_INDEX,
+   *                       the actual depth-index of visual will be determind automatically (Use previous visuals depth-index, or placed on top of all other visuals.)
+   *                       Otherwise, the visual's depth-index is set to clamped value, between DepthIndex::Ranges::MINIMUM_DEPTH_INDEX and DepthIndex::Ranges::MAXIMUM_DEPTH_INDEX.
+   *
+   * @note Registering a visual with an index that already has a registered visual will replace it. The replacement will
+   *       occur once the replacement visual is ready (loaded).
+   */
+  void RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, VisualState::Type enabled, DepthIndexValue::Type depthIndexValueSet, int depthIndex = static_cast<int>(Toolkit::DepthIndex::AUTO_INDEX));
+
+public:
+  RegisteredVisualContainer           mVisuals; ///< Stores visuals needed by the control, non trivial type so std::vector used.
+  DevelControl::VisualEventSignalType mVisualEventSignal;
+  RegisteredVisualContainer           mRemoveVisuals; ///< List of visuals that are being replaced by another visual once ready
+private:
+  Control::Impl& mOuter;
+};
+} // namespace Internal
+} // namespace Toolkit
+} // namespace Dali
+#endif // DALI_TOOLKIT_CONTROL_DATA_VISUAL_DATA_H
index 0753d01aae363a1e73c780118fb961d74a9d7f28..d13e3b559b1ce55b029630e5dc639fc556f42c00 100644 (file)
@@ -82,6 +82,8 @@ SET( toolkit_src_files
    ${toolkit_src_dir}/controls/canvas-view/canvas-view-impl.cpp
    ${toolkit_src_dir}/controls/canvas-view/canvas-view-rasterize-task.cpp
    ${toolkit_src_dir}/controls/control/control-data-impl.cpp
+   ${toolkit_src_dir}/controls/control/control-accessibility-data.cpp
+   ${toolkit_src_dir}/controls/control/control-visual-data.cpp
    ${toolkit_src_dir}/controls/control/control-debug.cpp
    ${toolkit_src_dir}/controls/control/control-renderers.cpp
    ${toolkit_src_dir}/controls/effects-view/effects-view-impl.cpp
index f96731c46f619dc8a7b570287da341962a4a2174..fcf65500225d271732ccb0f272566e68186c933c 100644 (file)
@@ -38,6 +38,7 @@
 #include <dali-toolkit/devel-api/visuals/color-visual-properties-devel.h>
 #include <dali-toolkit/devel-api/visuals/visual-actions-devel.h>
 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
+#include <dali-toolkit/internal/controls/control/control-visual-data.h>
 #include <dali-toolkit/internal/controls/render-effects/render-effect-impl.h>
 #include <dali-toolkit/internal/styling/style-manager-impl.h>
 #include <dali-toolkit/internal/visuals/color/color-visual.h>
@@ -77,7 +78,7 @@ void CreateClippingRenderer(Control& controlImpl)
   {
     Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get(controlImpl);
 
-    if(clippingMode == ClippingMode::CLIP_CHILDREN && controlDataImpl.mVisuals.Empty() && self.GetRendererCount() == 0u)
+    if(clippingMode == ClippingMode::CLIP_CHILDREN && controlDataImpl.mVisualData->mVisuals.Empty() && self.GetRendererCount() == 0u)
     {
       controlImpl.SetBackgroundColor(Color::TRANSPARENT);
     }
@@ -573,11 +574,11 @@ void Control::EmitKeyInputFocusSignal(bool focusGained)
 
 void Control::OnSceneConnection(int depth)
 {
-  DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::OnSceneConnection number of registered visuals(%d)\n", mImpl->mVisuals.Size());
+  DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::OnSceneConnection number of registered visuals(%d)\n", mImpl->mVisualData->mVisuals.Size());
 
   Actor self(Self());
 
-  for(RegisteredVisualContainer::Iterator iter = mImpl->mVisuals.Begin(); iter != mImpl->mVisuals.End(); iter++)
+  for(RegisteredVisualContainer::Iterator iter = mImpl->mVisualData->mVisuals.Begin(); iter != mImpl->mVisualData->mVisuals.End(); iter++)
   {
     // Check whether the visual is empty and enabled
     if((*iter)->visual && (*iter)->enabled)