(A11y) Let we make some way to do not create new Accessible
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / control / control-data-impl.cpp
index b8c811f..1202c26 100644 (file)
@@ -233,6 +233,23 @@ void MoveVisual(RegisteredVisualContainer::Iterator sourceIter, RegisteredVisual
 }
 
 /**
+ * Discard visual from source to visual factory.
+ */
+void DiscardVisual(RegisteredVisualContainer::Iterator sourceIter, RegisteredVisualContainer& source)
+{
+  Toolkit::Visual::Base visual = (*sourceIter)->visual;
+  if(visual)
+  {
+    if(Stage::IsInstalled())
+    {
+      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.
  * @param[in] actionName The action to perform.
@@ -586,68 +603,75 @@ Control::Impl::~Impl()
 
 Control::Impl& Control::Impl::Get(Internal::Control& internalControl)
 {
+  DALI_ASSERT_ALWAYS(Stage::IsCoreThread() && "Core is not installed. Might call this API from worker thread?");
+
   return *internalControl.mImpl;
 }
 
 const Control::Impl& Control::Impl::Get(const Internal::Control& internalControl)
 {
+  DALI_ASSERT_ALWAYS(Stage::IsCoreThread() && "Core is not installed. Might call this API from worker thread?");
+
   return *internalControl.mImpl;
 }
 
 void Control::Impl::CheckHighlightedObjectGeometry()
 {
-  auto accessible     = GetAccessibleObject();
-  auto lastPosition   = accessible->GetLastPosition();
-  auto accessibleRect = accessible->GetExtents(Dali::Accessibility::CoordinateType::WINDOW);
-  auto rect           = GetShowingGeometry(accessibleRect, accessible);
-
-  switch(mAccessibilityLastScreenRelativeMoveType)
+  auto accessible = GetAccessibleObject();
+  if(DALI_LIKELY(accessible))
   {
-    case Dali::Accessibility::ScreenRelativeMoveType::OUTSIDE:
-    {
-      if(IsShowingGeometryOnScreen(rect))
-      {
-        mAccessibilityLastScreenRelativeMoveType = Dali::Accessibility::ScreenRelativeMoveType::INSIDE;
-      }
-      break;
-    }
-    case Dali::Accessibility::ScreenRelativeMoveType::INSIDE:
+    auto lastPosition   = accessible->GetLastPosition();
+    auto accessibleRect = accessible->GetExtents(Dali::Accessibility::CoordinateType::WINDOW);
+    auto rect           = GetShowingGeometry(accessibleRect, accessible);
+
+    switch(mAccessibilityLastScreenRelativeMoveType)
     {
-      if(rect.width < 0 && !Dali::Equals(accessibleRect.x, lastPosition.x))
+      case Dali::Accessibility::ScreenRelativeMoveType::OUTSIDE:
       {
-        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;
+        if(IsShowingGeometryOnScreen(rect))
+        {
+          mAccessibilityLastScreenRelativeMoveType = Dali::Accessibility::ScreenRelativeMoveType::INSIDE;
+        }
+        break;
       }
-      // notify AT-clients on outgoing moves only
-      if(mAccessibilityLastScreenRelativeMoveType != Dali::Accessibility::ScreenRelativeMoveType::INSIDE)
+      case Dali::Accessibility::ScreenRelativeMoveType::INSIDE:
       {
-        accessible->EmitMovedOutOfScreen(mAccessibilityLastScreenRelativeMoveType);
+        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;
       }
-      break;
-    }
-    case Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_TOP_LEFT:
-    case Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_BOTTOM_RIGHT:
-    {
-      if(IsShowingGeometryOnScreen(rect))
+      case Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_TOP_LEFT:
+      case Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_BOTTOM_RIGHT:
       {
-        mAccessibilityLastScreenRelativeMoveType = Dali::Accessibility::ScreenRelativeMoveType::INSIDE;
+        if(IsShowingGeometryOnScreen(rect))
+        {
+          mAccessibilityLastScreenRelativeMoveType = Dali::Accessibility::ScreenRelativeMoveType::INSIDE;
+        }
+        else
+        {
+          mAccessibilityLastScreenRelativeMoveType = Dali::Accessibility::ScreenRelativeMoveType::OUTSIDE;
+        }
+        break;
       }
-      else
+      default:
       {
-        mAccessibilityLastScreenRelativeMoveType = Dali::Accessibility::ScreenRelativeMoveType::OUTSIDE;
+        break;
       }
-      break;
-    }
-    default:
-    {
-      break;
     }
-  }
 
-  accessible->SetLastPosition(Vector2(accessibleRect.x, accessibleRect.y));
+    accessible->SetLastPosition(Vector2(accessibleRect.x, accessibleRect.y));
+  }
 }
 
 void Control::Impl::RegisterAccessibilityPositionPropertyNotification()
@@ -715,6 +739,8 @@ void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base&
 
 void Control::Impl::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);
@@ -848,6 +874,8 @@ void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base&
 
 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))
   {
@@ -865,8 +893,9 @@ void Control::Impl::UnregisterVisual(Property::Index index)
     Actor self(mControlImpl.Self());
     Toolkit::GetImplementation((*iter)->visual).SetOffScene(self);
     (*iter)->pending = false;
-    (*iter)->visual.Reset();
-    mRemoveVisuals.Erase(iter);
+
+    // Discard removed visual. It will be destroyed at next Idle time.
+    DiscardVisual(iter, mRemoveVisuals);
   }
 }
 
@@ -961,6 +990,8 @@ void Control::Impl::StartObservingVisual(Toolkit::Visual::Base& visual)
 
 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())
   {
@@ -995,7 +1026,9 @@ void Control::Impl::ResourceReady(Visual::Base& object)
     {
       Toolkit::GetImplementation((*visualToRemoveIter)->visual).SetOffScene(self);
     }
-    mRemoveVisuals.Erase(visualToRemoveIter);
+
+    // 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
@@ -1177,6 +1210,8 @@ void Control::Impl::AppendAccessibilityAttribute(const std::string& key, const s
 
 void Control::Impl::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value)
 {
+  DALI_ASSERT_ALWAYS(Stage::IsCoreThread() && "Core is not installed. Might call this API from worker thread?");
+
   Toolkit::Control control = Toolkit::Control::DownCast(BaseHandle(object));
 
   if(control)
@@ -1435,10 +1470,13 @@ void Control::Impl::SetProperty(BaseObject* object, Property::Index index, const
           controlImpl.mImpl->mAccessibilityHidden = hidden;
 
           auto* accessible = controlImpl.GetAccessibleObject();
-          auto* parent     = dynamic_cast<Dali::Accessibility::ActorAccessible*>(accessible->GetParent());
-          if(parent)
+          if(DALI_LIKELY(accessible))
           {
-            parent->OnChildrenChanged();
+            auto* parent = dynamic_cast<Dali::Accessibility::ActorAccessible*>(accessible->GetParent());
+            if(parent)
+            {
+              parent->OnChildrenChanged();
+            }
           }
         }
         break;
@@ -1477,6 +1515,8 @@ void Control::Impl::SetProperty(BaseObject* object, Property::Index index, const
 
 Property::Value Control::Impl::GetProperty(BaseObject* object, Property::Index index)
 {
+  DALI_ASSERT_ALWAYS(Stage::IsCoreThread() && "Core is not installed. Might call this API from worker thread?");
+
   Property::Value value;
 
   Toolkit::Control control = Toolkit::Control::DownCast(BaseHandle(object));
@@ -1848,6 +1888,8 @@ void Control::Impl::RecreateChangedVisuals(Dictionary<Property::Map>& stateVisua
 
 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)
@@ -1985,17 +2027,25 @@ void Control::Impl::OnSceneDisconnection()
 
   // 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
-  for(auto removalIter = mRemoveVisuals.Begin(), end = mRemoveVisuals.End(); removalIter != end; removalIter++)
+
+  if(!mRemoveVisuals.Empty())
   {
-    Toolkit::GetImplementation((*removalIter)->visual).SetOffScene(self);
+    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;
   }
-
-  mRemoveVisuals.Clear();
 }
 
 void Control::Impl::SetMargin(Extents margin)
@@ -2072,7 +2122,7 @@ Dali::Property Control::Impl::GetVisualProperty(Dali::Property::Index index, Dal
   if(visual)
   {
     Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
-    return visualImpl.GetPropertyObject(visualPropertyKey);
+    return visualImpl.GetPropertyObject(std::move(visualPropertyKey));
   }
 
   Handle handle;
@@ -2179,7 +2229,7 @@ bool Control::Impl::OnIdleCallback()
 
 Toolkit::DevelControl::ControlAccessible* Control::Impl::GetAccessibleObject()
 {
-  if(!mAccessibleObject)
+  if(mAccessibleCreatable && !mAccessibleObject)
   {
     mAccessibleObject.reset(mControlImpl.CreateAccessibleObject());
   }
@@ -2187,6 +2237,21 @@ Toolkit::DevelControl::ControlAccessible* Control::Impl::GetAccessibleObject()
   return mAccessibleObject.get();
 }
 
+bool Control::Impl::IsAccessibleCreated() const
+{
+  return !!mAccessibleObject;
+}
+
+void Control::Impl::EnableCreateAccessible(bool enable)
+{
+  mAccessibleCreatable = enable;
+}
+
+bool Control::Impl::IsCreateAccessibleEnabled() const
+{
+  return mAccessibleCreatable;
+}
+
 } // namespace Internal
 
 } // namespace Toolkit