[Tizen][AT-SPI] Move AccessibilityAttributes to Accessible
[platform/core/uifw/dali-adaptor.git] / dali / devel-api / adaptor-framework / actor-accessible.cpp
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/devel-api/adaptor-framework/actor-accessible.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/devel-api/actors/actor-devel.h>
23 #include <dali/public-api/object/type-info.h>
24
25 // INTERNAL INCLUDES
26 #include <dali/devel-api/adaptor-framework/window-devel.h>
27
28 namespace Dali::Accessibility
29 {
30 ActorAccessible::ActorAccessible(Actor actor)
31 : mSelf(actor),
32   mChildrenDirty{true} // to trigger the initial UpdateChildren()
33 {
34   // Select the right overload manually because Connect(this, &OnChildrenChanged) is ambiguous.
35   void (ActorAccessible::*handler)(Dali::Actor) = &ActorAccessible::OnChildrenChanged;
36
37   Dali::DevelActor::ChildAddedSignal(actor).Connect(this, handler);
38   Dali::DevelActor::ChildRemovedSignal(actor).Connect(this, handler);
39   Dali::DevelActor::ChildOrderChangedSignal(actor).Connect(this, handler);
40 }
41
42 std::string ActorAccessible::GetName() const
43 {
44   return Self().GetProperty<std::string>(Dali::Actor::Property::NAME);
45 }
46
47 std::string ActorAccessible::GetDescription() const
48 {
49   return {};
50 }
51
52 Accessible* ActorAccessible::GetParent()
53 {
54   if(IsOnRootLevel())
55   {
56     auto data = GetBridgeData();
57     return data->mBridge->GetApplication();
58   }
59
60   return Get(Self().GetParent());
61 }
62
63 std::size_t ActorAccessible::GetChildCount() const
64 {
65   // ActorAccessible is never stored in const memory and it is an implementation detail that
66   // children are recalculated lazily.
67   const_cast<ActorAccessible*>(this)->UpdateChildren();
68
69   return mChildren.size();
70 }
71
72 std::vector<Accessible*> ActorAccessible::GetChildren()
73 {
74   UpdateChildren();
75
76   return mChildren;
77 }
78
79 Accessible* ActorAccessible::GetChildAtIndex(std::size_t index)
80 {
81   auto childCount = GetChildCount(); // calls UpdateChildren()
82   if(DALI_UNLIKELY(index >= childCount))
83   {
84     throw std::domain_error{"invalid index " + std::to_string(index) + " for object with " + std::to_string(childCount) + " children"};
85   }
86
87   return mChildren[index];
88 }
89
90 std::size_t ActorAccessible::GetIndexInParent()
91 {
92   auto* parent = GetParent();
93
94   if(DALI_UNLIKELY(!parent))
95   {
96     throw std::domain_error{"can't call GetIndexInParent on object without parent"};
97   }
98
99   // Avoid calling parent->GetChildren() in order not to make an unnecessary copy
100   auto childCount = parent->GetChildCount();
101   for(auto i = 0u; i < childCount; ++i)
102   {
103     if(parent->GetChildAtIndex(i) == this)
104     {
105       return i;
106     }
107   }
108
109   throw std::domain_error{"actor is not a child of its parent"};
110 }
111
112 Dali::Actor ActorAccessible::GetInternalActor()
113 {
114   return Self();
115 }
116
117 ComponentLayer ActorAccessible::GetLayer() const
118 {
119   return ComponentLayer::WINDOW;
120 }
121
122 std::int16_t ActorAccessible::GetMdiZOrder() const
123 {
124   return 0;
125 }
126
127 double ActorAccessible::GetAlpha() const
128 {
129   return 0;
130 }
131
132 bool ActorAccessible::IsScrollable() const
133 {
134   return false;
135 }
136
137 Dali::Rect<> ActorAccessible::GetExtents(CoordinateType type) const
138 {
139   Dali::Actor actor                   = Self();
140   Vector2     screenPosition          = actor.GetProperty<Vector2>(Actor::Property::SCREEN_POSITION);
141   Vector3     size                    = actor.GetCurrentProperty<Vector3>(Actor::Property::SIZE) * actor.GetCurrentProperty<Vector3>(Actor::Property::WORLD_SCALE);
142   bool        positionUsesAnchorPoint = actor.GetProperty<bool>(Actor::Property::POSITION_USES_ANCHOR_POINT);
143   Vector3     anchorPointOffSet       = size * (positionUsesAnchorPoint ? actor.GetCurrentProperty<Vector3>(Actor::Property::ANCHOR_POINT) : AnchorPoint::TOP_LEFT);
144   Vector2     position                = Vector2(screenPosition.x - anchorPointOffSet.x, screenPosition.y - anchorPointOffSet.y);
145
146   if(type == CoordinateType::WINDOW)
147   {
148     return {position.x, position.y, size.x, size.y};
149   }
150   else // CoordinateType::SCREEN
151   {
152     auto window         = Dali::DevelWindow::Get(actor);
153     auto windowPosition = window.GetPosition();
154     return {position.x + windowPosition.GetX(), position.y + windowPosition.GetY(), size.x, size.y};
155   }
156 }
157
158 void ActorAccessible::OnChildrenChanged()
159 {
160   mChildrenDirty = true;
161 }
162
163 void ActorAccessible::OnChildrenChanged(Dali::Actor)
164 {
165   OnChildrenChanged();
166 }
167
168 void ActorAccessible::DoGetChildren(std::vector<Accessible*>& children)
169 {
170   auto self       = Self();
171   auto childCount = self.GetChildCount();
172
173   children.reserve(childCount);
174
175   for(auto i = 0u; i < childCount; ++i)
176   {
177     children.push_back(Accessible::Get(self.GetChildAt(i)));
178   }
179 }
180
181 void ActorAccessible::UpdateAttributes(Attributes& attributes) const
182 {
183   static const std::string classKey = "class";
184
185   Accessible::UpdateAttributes(attributes);
186
187   if(attributes.find(classKey) == attributes.end())
188   {
189     Dali::TypeInfo typeInfo;
190     Self().GetTypeInfo(typeInfo);
191     if(typeInfo)
192     {
193       attributes.emplace(classKey, typeInfo.GetName());
194     }
195   }
196 }
197
198 void ActorAccessible::UpdateChildren()
199 {
200   if(!mChildrenDirty)
201   {
202     return;
203   }
204
205   // Set to false before DoGetChildren() to prevent recursion
206   // in case DoGetChildren() does something strange.
207   mChildrenDirty = false;
208
209   mChildren.clear();
210   DoGetChildren(mChildren);
211
212   // Erase-remove idiom
213   // TODO (C++20): Replace with std::erase_if
214   auto it = std::remove_if(mChildren.begin(), mChildren.end(), [](const Accessible* child) {
215     return !child || child->IsHidden();
216   });
217   mChildren.erase(it, mChildren.end());
218   mChildren.shrink_to_fit();
219 }
220
221 } // namespace Dali::Accessibility