Merge "Assign more texture format" into devel/graphics
[platform/core/uifw/dali-adaptor.git] / dali / internal / accessibility / bridge / bridge-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/internal/accessibility/bridge/bridge-accessible.h>
20
21 // EXTERNAL INCLUDES
22 #include <iostream>
23
24 //comment out 2 lines below to get more logs
25 #undef LOG
26 #define LOG() _LoggerEmpty()
27
28 using namespace Dali::Accessibility;
29
30 #define GET_NAVIGABLE_AT_POINT_MAX_RECURSION_DEPTH 10000
31
32 BridgeAccessible::BridgeAccessible()
33 {
34 }
35
36 void BridgeAccessible::RegisterInterfaces()
37 {
38   DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceAccessible};
39   AddGetPropertyToInterface(desc, "ChildCount", &BridgeAccessible::GetChildCount);
40   AddGetPropertyToInterface(desc, "Name", &BridgeAccessible::GetName);
41   AddGetPropertyToInterface(desc, "Description", &BridgeAccessible::GetDescription);
42   AddGetPropertyToInterface(desc, "Parent", &BridgeAccessible::GetParent);
43   AddFunctionToInterface(desc, "GetRole", &BridgeAccessible::GetRole);
44   AddFunctionToInterface(desc, "GetRoleName", &BridgeAccessible::GetRoleName);
45   AddFunctionToInterface(desc, "GetLocalizedRoleName", &BridgeAccessible::GetLocalizedRoleName);
46   AddFunctionToInterface(desc, "GetState", &BridgeAccessible::GetStates);
47   AddFunctionToInterface(desc, "GetAttributes", &BridgeAccessible::GetAttributes);
48   AddFunctionToInterface(desc, "GetInterfaces", &BridgeAccessible::GetInterfaces);
49   AddFunctionToInterface(desc, "GetChildAtIndex", &BridgeAccessible::GetChildAtIndex);
50   AddFunctionToInterface(desc, "GetChildren", &BridgeAccessible::GetChildren);
51   AddFunctionToInterface(desc, "GetIndexInParent", &BridgeAccessible::GetIndexInParent);
52   AddFunctionToInterface(desc, "GetNavigableAtPoint", &BridgeAccessible::GetNavigableAtPoint);
53   AddFunctionToInterface(desc, "GetNeighbor", &BridgeAccessible::GetNeighbor);
54   AddFunctionToInterface(desc, "GetDefaultLabelInfo", &BridgeAccessible::GetDefaultLabelInfo);
55   AddFunctionToInterface(desc, "DoGesture", &BridgeAccessible::DoGesture);
56   AddFunctionToInterface(desc, "GetReadingMaterial", &BridgeAccessible::GetReadingMaterial);
57   AddFunctionToInterface(desc, "GetRelationSet", &BridgeAccessible::GetRelationSet);
58   dbusServer.addInterface("/", desc, true);
59 }
60
61 static bool AcceptObjectCheckRole(Component* obj)
62 {
63   if(!obj)
64     return false;
65   switch(obj->GetRole())
66   {
67     case Role::APPLICATION:
68     case Role::FILLER:
69     case Role::SCROLL_PANE:
70     case Role::SPLIT_PANE:
71     case Role::WINDOW:
72     case Role::IMAGE:
73     case Role::IMAGE_MAP:
74     case Role::LIST:
75     case Role::ICON:
76     case Role::TOOL_BAR:
77     case Role::REDUNDANT_OBJECT:
78     case Role::COLOR_CHOOSER:
79     case Role::TREE_TABLE:
80     case Role::PAGE_TAB_LIST:
81     case Role::PAGE_TAB:
82     case Role::SPIN_BUTTON:
83     case Role::INPUT_METHOD_WINDOW:
84     case Role::EMBEDDED:
85     case Role::INVALID:
86     case Role::NOTIFICATION:
87     case Role::DATE_EDITOR:
88     case Role::TABLE:
89     {
90       return false;
91     }
92     default:
93     {
94       break;
95     }
96   }
97
98   return true;
99 }
100
101 static bool AcceptObjectCheckRelations(Component* obj)
102 {
103   auto r = obj->GetRelationSet();
104
105   for(const auto& it : r)
106     if(it.relationType == RelationType::CONTROLLED_BY)
107       return false;
108
109   return true;
110 }
111
112 static Component* GetScrollableParent(Accessible* obj)
113 {
114   while(obj)
115   {
116     obj       = obj->GetParent();
117     auto comp = dynamic_cast<Component*>(obj);
118     if(comp && comp->IsScrollable())
119       return comp;
120   }
121   return nullptr;
122 }
123
124 static bool ObjectIsItem(Component* obj)
125 {
126   if(!obj)
127     return false;
128   auto role = obj->GetRole();
129   return role == Role::LIST_ITEM || role == Role::MENU_ITEM;
130 }
131
132 static bool ObjectIsCollapsed(Component* obj)
133 {
134   if(!obj)
135     return false;
136   const auto states = obj->GetStates();
137   return states[State::EXPANDABLE] && !states[State::EXPANDED];
138 }
139
140 static bool OobjectIsZeroSize(Component* obj)
141 {
142   if(!obj)
143     return false;
144   auto extents = obj->GetExtents(CoordType::WINDOW);
145   return extents.height == 0 || extents.width == 0;
146 }
147
148 static bool AcceptObject(Component* obj)
149 {
150   if(!obj)
151     return false;
152   const auto states = obj->GetStates();
153   if(!states[State::VISIBLE])
154     return false;
155   if(!AcceptObjectCheckRole(obj))
156     return false;
157   if(!AcceptObjectCheckRelations(obj))
158     return false;
159   if(!states[State::HIGHLIGHTABLE])
160     return false;
161
162   if(GetScrollableParent(obj) != nullptr)
163   {
164     auto parent = dynamic_cast<Component*>(obj->GetParent());
165
166     if(parent)
167     {
168       return !ObjectIsItem(obj) || !ObjectIsCollapsed(parent);
169     }
170   }
171   else
172   {
173     if(OobjectIsZeroSize(obj))
174     {
175       return false;
176     }
177     if(!states[State::SHOWING])
178     {
179       return false;
180     }
181   }
182   return true;
183 }
184
185 static bool AcceptObject(Accessible* obj)
186 {
187   auto c = dynamic_cast<Component*>(obj);
188   return AcceptObject(c);
189 }
190
191 static std::string objDump(Component* obj)
192 {
193   if(!obj)
194     return "nullptr";
195   std::ostringstream o;
196   auto               e = obj->GetExtents(CoordType::SCREEN);
197   o << "name: " << obj->GetName() << " extent: (" << e.x << ", "
198     << e.y << "), [" << e.width << ", " << e.height << "]";
199   return o.str();
200 }
201
202 Component* BridgeAccessible::GetObjectInRelation(Accessible* obj, RelationType ralationType)
203 {
204   if(!obj)
205     return nullptr;
206   for(auto& relation : obj->GetRelationSet())
207   {
208     if(relation.relationType == ralationType)
209     {
210       for(auto& address : relation.targets)
211       {
212         auto component = dynamic_cast<Component*>(Find(address));
213         if(component)
214           return component;
215       }
216     }
217   }
218   return nullptr;
219 }
220
221 static std::string makeIndent(unsigned int maxRecursionDepth)
222 {
223   return std::string(GET_NAVIGABLE_AT_POINT_MAX_RECURSION_DEPTH - maxRecursionDepth, ' ');
224 }
225
226 Component* BridgeAccessible::CalculateNavigableAccessibleAtPoint(Accessible* root, Point p, CoordType cType, unsigned int maxRecursionDepth)
227 {
228   if(!root || maxRecursionDepth == 0)
229     return nullptr;
230   auto root_component = dynamic_cast<Component*>(root);
231   LOG() << "CalculateNavigableAccessibleAtPoint: checking: " << makeIndent(maxRecursionDepth) << objDump(root_component);
232
233   if(root_component && !root_component->Contains(p, cType))
234     return nullptr;
235
236   auto children = root->GetChildren();
237   for(auto childIt = children.rbegin(); childIt != children.rend(); childIt++)
238   {
239     //check recursively all children first
240     auto result = CalculateNavigableAccessibleAtPoint(*childIt, p, cType, maxRecursionDepth - 1);
241     if(result)
242       return result;
243   }
244   if(root_component)
245   {
246     //Found a candidate, all its children are already checked
247     auto controledBy = GetObjectInRelation(root_component, RelationType::CONTROLLED_BY);
248     if(!controledBy)
249       controledBy = root_component;
250
251     if(controledBy->IsProxy() || AcceptObject(controledBy))
252     {
253       LOG() << "CalculateNavigableAccessibleAtPoint: found:    " << makeIndent(maxRecursionDepth) << objDump(root_component);
254       return controledBy;
255     }
256   }
257   return nullptr;
258 }
259
260 BridgeAccessible::ReadingMaterialType BridgeAccessible::GetReadingMaterial()
261 {
262   auto        self          = FindSelf();
263   auto        attributes    = self->GetAttributes();
264   auto        name          = self->GetName();
265   std::string labeledByName = "";
266   std::string textIfceName  = "";
267   auto        role          = static_cast<uint32_t>(self->GetRole());
268   auto        states        = self->GetStates();
269   auto        localizedName = self->GetLocalizedRoleName();
270   auto        childCount    = static_cast<int32_t>(self->GetChildCount());
271
272   double currentValue     = 0.0;
273   double minimumIncrement = 0.0;
274   double maximumValue     = 0.0;
275   double minimumValue     = 0.0;
276
277   auto* value = dynamic_cast<Dali::Accessibility::Value*>(self);
278   if(value)
279   {
280     currentValue     = value->GetCurrent();
281     minimumIncrement = value->GetMinimumIncrement();
282     maximumValue     = value->GetMaximum();
283     minimumValue     = value->GetMinimum();
284   }
285
286   auto    description             = self->GetDescription();
287   auto    indexInParent           = static_cast<int32_t>(self->GetIndexInParent());
288   bool    isSelectedInParent      = false;
289   bool    hasCheckBoxChild        = false;
290   int32_t firstSelectedChildIndex = -1;
291   int32_t selectedChildCount      = 0;
292
293   for(auto i = 0u; i < static_cast<size_t>(childCount); ++i)
294   {
295     auto q = self->GetChildAtIndex(i);
296     auto s = q->GetStates();
297     if(s[State::SELECTABLE])
298     {
299       if(s[State::SELECTED])
300       {
301         ++selectedChildCount;
302         if(firstSelectedChildIndex < 0)
303           firstSelectedChildIndex = static_cast<int32_t>(i);
304       }
305     }
306     if(q->GetRole() == Role::CHECK_BOX)
307       hasCheckBoxChild = true;
308   }
309
310   int32_t     listChildrenCount = 0;
311   Accessible* parent            = self->GetParent();
312   auto        parentStateSet    = parent ? parent->GetStates() : States{};
313   auto        parentChildCount  = parent ? static_cast<int32_t>(parent->GetChildCount()) : 0;
314   auto        parentRole        = static_cast<uint32_t>(parent ? parent->GetRole() : Role{});
315   Accessible* describedByObject = nullptr;
316
317   return {
318     attributes,
319     name,
320     labeledByName,
321     textIfceName,
322     role,
323     states,
324     localizedName,
325     childCount,
326     currentValue,
327     minimumIncrement,
328     maximumValue,
329     minimumValue,
330     description,
331     indexInParent,
332     isSelectedInParent,
333     hasCheckBoxChild,
334     listChildrenCount,
335     firstSelectedChildIndex,
336     parent,
337     parentStateSet,
338     parentChildCount,
339     parentRole,
340     selectedChildCount,
341     describedByObject};
342 }
343
344 DBus::ValueOrError<bool> BridgeAccessible::DoGesture(Dali::Accessibility::Gesture type, int32_t xBeg, int32_t yBeg, int32_t xEnd, int32_t yEnd, Dali::Accessibility::GestureState state, uint32_t eventTime)
345 {
346   return FindSelf()->DoGesture(Dali::Accessibility::GestureInfo{type, xBeg, xEnd, yBeg, yEnd, state, eventTime});
347 }
348
349 DBus::ValueOrError<Accessible*, uint8_t, Accessible*> BridgeAccessible::GetNavigableAtPoint(int32_t x, int32_t y, uint32_t coordType)
350 {
351   Accessible* deputy     = nullptr;
352   auto        accessible = FindSelf();
353   auto        cType      = static_cast<CoordType>(coordType);
354   LOG() << "GetNavigableAtPoint: " << x << ", " << y << " type: " << coordType;
355   auto component = CalculateNavigableAccessibleAtPoint(accessible, {x, y}, cType, GET_NAVIGABLE_AT_POINT_MAX_RECURSION_DEPTH);
356   bool recurse   = false;
357   if(component)
358   {
359     recurse = component->IsProxy();
360   }
361   //TODO: add deputy
362   return {component, recurse, deputy};
363 }
364
365 static bool CheckChainEndWithAttribute(Accessible* obj, unsigned char forward)
366 {
367   if(!obj)
368     return false;
369   auto attrs = obj->GetAttributes();
370   for(auto& attr : attrs)
371   {
372     if(attr.first == "relation_chain_end")
373     {
374       if((attr.second == "prev,end" && forward == 0) || (attr.second == "next,end" && forward == 1) || attr.second == "prev,next,end")
375       {
376         return true;
377       }
378     }
379   }
380   return false;
381 }
382
383 static Accessible* DeputyOfProxyInParentGet(Accessible* obj)
384 {
385   return nullptr;
386 }
387
388 Accessible* BridgeAccessible::GetCurrentlyHighlighted()
389 {
390   //TODO: add currently highlighted object
391   return nullptr;
392 }
393
394 std::vector<Accessible*> BridgeAccessible::ValidChildrenGet(const std::vector<Accessible*>& children, Accessible* start, Accessible* root)
395 {
396   return children;
397 }
398
399 static bool DeputyIs(Accessible* obj)
400 {
401   //TODO: add deputy
402   return false;
403 }
404
405 static Accessible* ProxyInParentGet(Accessible* obj)
406 {
407   if(!obj)
408     return nullptr;
409   auto children = obj->GetChildren();
410   for(auto& child : children)
411   {
412     if(child->IsProxy())
413       return child;
414   }
415   return nullptr;
416 }
417
418 static bool ObjectRoleIsAcceptableWhenNavigatingNextPrev(Accessible* obj)
419 {
420   if(!obj)
421     return false;
422   auto role = obj->GetRole();
423   return role != Role::POPUP_MENU && role != Role::DIALOG;
424 }
425
426 template<class T>
427 struct CycleDetection
428 {
429   CycleDetection(const T value)
430   : key(value),
431     currentSearchSize(1),
432     counter(1)
433   {
434   }
435   bool check(const T value)
436   {
437     if(key == value)
438       return true;
439     if(--counter == 0)
440     {
441       currentSearchSize <<= 1;
442       if(currentSearchSize == 0)
443         return true; // UNDEFINED BEHAVIOR
444       counter = currentSearchSize;
445       key     = value;
446     }
447     return false;
448   }
449   T            key;
450   unsigned int currentSearchSize;
451   unsigned int counter;
452 };
453
454 static Accessible* FindNonDefunctChild(const std::vector<Accessible*>& children, unsigned int currentIndex, unsigned char forward)
455 {
456   unsigned int childrenCount = children.size();
457   for(; currentIndex < childrenCount; forward ? ++currentIndex : --currentIndex)
458   {
459     Accessible* n = children[currentIndex];
460     if(n && !n->GetStates()[State::DEFUNCT])
461       return n;
462   }
463   return nullptr;
464 }
465
466 static Accessible* DirectionalDepthFirstSearchTryNonDefunctChild(Accessible* node, const std::vector<Accessible*>& children, unsigned char forward)
467 {
468   if(!node)
469     return nullptr;
470   auto childrenCount = children.size();
471   if(childrenCount > 0)
472   {
473     const bool isShowing = GetScrollableParent(node) == nullptr ? node->GetStates()[State::SHOWING] : true;
474     if(isShowing)
475     {
476       return FindNonDefunctChild(children, forward ? 0 : childrenCount - 1, forward);
477     }
478   }
479   return nullptr;
480 }
481
482 Accessible* BridgeAccessible::GetNextNonDefunctSibling(Accessible* obj, Accessible* start, Accessible* root, unsigned char forward)
483 {
484   if(!obj)
485     return nullptr;
486   auto parent = obj->GetParent();
487   if(!parent)
488     return nullptr;
489
490   auto children = ValidChildrenGet(parent->GetChildren(), start, root);
491
492   unsigned int children_count = children.size();
493   if(children_count == 0)
494   {
495     return nullptr;
496   }
497   unsigned int current = 0;
498   for(; current < children_count && children[current] != obj; ++current)
499     ;
500   if(current >= children_count)
501   {
502     return nullptr;
503   }
504   forward ? ++current : --current;
505   auto ret = FindNonDefunctChild(children, current, forward);
506   return ret;
507 }
508
509 Accessible* BridgeAccessible::DirectionalDepthFirstSearchTryNonDefunctSibling(bool& all_children_visited, Accessible* node, Accessible* start, Accessible* root, unsigned char forward)
510 {
511   while(true)
512   {
513     Accessible* sibling = GetNextNonDefunctSibling(node, start, root, forward);
514     if(sibling)
515     {
516       node                 = sibling;
517       all_children_visited = false;
518       break;
519     }
520     // walk up...
521     node = node->GetParent();
522     if(node == nullptr || node == root)
523       return nullptr;
524
525     // in backward traversing stop the walk up on parent
526     if(!forward)
527       break;
528   }
529   return node;
530 }
531
532 Accessible* BridgeAccessible::CalculateNeighbor(Accessible* root, Accessible* start, unsigned char forward, BridgeAccessible::GetNeighborSearchMode search_mode)
533 {
534   if(start && CheckChainEndWithAttribute(start, forward))
535     return start;
536   if(root && root->GetStates()[State::DEFUNCT])
537     return NULL;
538   if(start && start->GetStates()[State::DEFUNCT])
539   {
540     start   = NULL;
541     forward = 1;
542   }
543
544   if(search_mode == BridgeAccessible::GetNeighborSearchMode::recurseToOutside)
545   {
546     // This only works if we navigate backward, and it is not possible to
547     // find in embedded process. In this case the deputy should be used */
548     return DeputyOfProxyInParentGet(start);
549   }
550
551   Accessible* node = start ? start : root;
552   if(!node)
553     return nullptr;
554
555   // initialization of all-children-visited flag for start node - we assume
556   // that when we begin at start node and we navigate backward, then all children
557   // are visited, so navigation will ignore start's children and go to
558   // previous sibling available.
559   // Regarding condtion (start != root):
560   // The last object can be found only if all_children_visited is false.
561   // The start is same with root, when looking for the last object.
562   bool all_children_visited = (start != root) && (search_mode != BridgeAccessible::GetNeighborSearchMode::recurseFromRoot && !forward);
563   // true, if starting element should be ignored. this is only used in rare case of
564   // recursive search failing to find an object.
565   // consider tree, where element A on bus BUS_A has child B on bus BUS_B. when going "next" from
566   // element A algorithm has to descend into BUS_B and search element B and its children. this is done
567   // by returning to our caller object B with special flag set (meaning - continue the search from B on bus BUS_B).
568   // if next object will be found there (on BUS_B), then search ends. but if not, then our caller will find it out
569   // and will call us again with object A and flag search_mode set to NEIGHBOR_SEARCH_MODE_CONTINUE_AFTER_FAILED_RECURSING.
570   // this flag means, that object A was already checked previously and we should skip it and its children.
571   bool force_next = (search_mode == BridgeAccessible::GetNeighborSearchMode::continueAfterFailedRecursion);
572
573   CycleDetection<Accessible*> cycleDetection(node);
574   while(node)
575   {
576     if(node->GetStates()[State::DEFUNCT])
577       return nullptr;
578
579     // always accept proxy object from different world
580     if(!force_next && node->IsProxy())
581       return node;
582
583     auto children = node->GetChildren();
584     children      = ValidChildrenGet(children, start, root);
585
586     // do accept:
587     // 1. not start node
588     // 2. parent after all children in backward traversing
589     // 3. Nodes with roles: ATSPI_ROLE_PAGE_TAB, ATSPI_ROLE_POPUP_MENU and ATSPI_ROLE_DIALOG, only when looking for first or last element.
590     //    Objects with those roles shouldnt be reachable, when navigating next / prev.
591     bool all_children_visited_or_moving_forward = (children.size() == 0 || forward || all_children_visited);
592     if(!force_next && node != start && all_children_visited_or_moving_forward && AcceptObject(node))
593     {
594       if(start == NULL || ObjectRoleIsAcceptableWhenNavigatingNextPrev(node))
595         return node;
596     }
597
598     Accessible* next_related_in_direction = !force_next ? GetObjectInRelation(node, forward ? RelationType::FLOWS_TO : RelationType::FLOWS_FROM) : nullptr;
599     // force_next means that the search_mode is NEIGHBOR_SEARCH_MODE_CONTINUE_AFTER_FAILED_RECURSING
600     // in this case the node is elm_layout which is parent of proxy object.
601     // There is an access object working for the proxy object, and the access
602     // object could have relation information. This relation information should
603     // be checked first before using the elm_layout as a node.
604     if(force_next && forward)
605     {
606       auto deputy = DeputyOfProxyInParentGet(node);
607       next_related_in_direction =
608         GetObjectInRelation(deputy, RelationType::FLOWS_TO);
609     }
610
611     if(next_related_in_direction && start && start->GetStates()[State::DEFUNCT])
612     {
613       next_related_in_direction = NULL;
614     }
615
616     unsigned char want_cycle_detection = 0;
617     if(next_related_in_direction)
618     {
619       // Check next_related_in_direction is deputy object
620       Accessible* parent;
621       if(!forward)
622       {
623         // If the prev object is deputy, then go to inside of its proxy first
624         if(DeputyIs(next_related_in_direction))
625         {
626           parent                    = next_related_in_direction->GetParent();
627           next_related_in_direction = ProxyInParentGet(parent);
628         }
629       }
630       else
631       {
632         // If current object is deputy, and it has relation next object,
633         // then do not use the relation next object, and use proxy first
634         if(DeputyIs(node))
635         {
636           parent                    = node->GetParent();
637           next_related_in_direction = ProxyInParentGet(parent);
638         }
639       }
640       node                 = next_related_in_direction;
641       want_cycle_detection = 1;
642     }
643     else
644     {
645       auto child = !force_next && !all_children_visited ? DirectionalDepthFirstSearchTryNonDefunctChild(node, children, forward) : nullptr;
646       if(child)
647       {
648         want_cycle_detection = 1;
649       }
650       else
651       {
652         if(!force_next && node == root)
653           return NULL;
654         all_children_visited = true;
655         child                = DirectionalDepthFirstSearchTryNonDefunctSibling(all_children_visited, node, start, root, forward);
656       }
657       node = child;
658     }
659     force_next = 0;
660     if(want_cycle_detection && cycleDetection.check(node))
661     {
662       return NULL;
663     }
664   }
665   return NULL;
666 }
667
668 DBus::ValueOrError<Accessible*, uint8_t> BridgeAccessible::GetNeighbor(std::string rootPath, int32_t direction, int32_t search_mode)
669 {
670   auto start               = FindSelf();
671   rootPath                 = StripPrefix(rootPath);
672   auto          root       = !rootPath.empty() ? Find(rootPath) : nullptr;
673   auto          accessible = CalculateNeighbor(root, start, direction == 1, static_cast<GetNeighborSearchMode>(search_mode));
674   unsigned char recurse    = 0;
675   if(accessible)
676   {
677     recurse = accessible->IsProxy();
678   }
679   return {accessible, recurse};
680 }
681
682 Accessible* BridgeAccessible::GetParent()
683 {
684   // NOTE: currently bridge supports single application root element.
685   // only element set as application root might return nullptr from GetParent
686   // if you want more, then you need to change setApplicationRoot to
687   // add/remove ApplicationRoot and make roots a vector.
688   auto p = FindSelf()->GetParent();
689   assert(p);
690   return p;
691 }
692 DBus::ValueOrError<std::vector<Accessible*>> BridgeAccessible::GetChildren()
693 {
694   return FindSelf()->GetChildren();
695 }
696 std::string BridgeAccessible::GetDescription()
697 {
698   return FindSelf()->GetDescription();
699 }
700 DBus::ValueOrError<uint32_t> BridgeAccessible::GetRole()
701 {
702   return static_cast<unsigned int>(FindSelf()->GetRole());
703 }
704 DBus::ValueOrError<std::string> BridgeAccessible::GetRoleName()
705 {
706   return FindSelf()->GetRoleName();
707 }
708 DBus::ValueOrError<std::string> BridgeAccessible::GetLocalizedRoleName()
709 {
710   return FindSelf()->GetLocalizedRoleName();
711 }
712 DBus::ValueOrError<int32_t> BridgeAccessible::GetIndexInParent()
713 {
714   return FindSelf()->GetIndexInParent();
715 }
716 DBus::ValueOrError<std::array<uint32_t, 2>> BridgeAccessible::GetStates()
717 {
718   return FindSelf()->GetStates().GetRawData();
719 }
720 DBus::ValueOrError<std::unordered_map<std::string, std::string>> BridgeAccessible::GetAttributes()
721 {
722   return FindSelf()->GetAttributes();
723 }
724 DBus::ValueOrError<std::vector<std::string>> BridgeAccessible::GetInterfaces()
725 {
726   return FindSelf()->GetInterfaces();
727 }
728 int BridgeAccessible::GetChildCount()
729 {
730   return FindSelf()->GetChildCount();
731 }
732 DBus::ValueOrError<Accessible*> BridgeAccessible::GetChildAtIndex(int index)
733 {
734   if(index < 0)
735     throw std::domain_error{"negative index (" + std::to_string(index) + ")"};
736   return FindSelf()->GetChildAtIndex(static_cast<size_t>(index));
737 }
738
739 std::string BridgeAccessible::GetName()
740 {
741   return FindSelf()->GetName();
742 }
743
744 DBus::ValueOrError<Accessible*, uint32_t, std::unordered_map<std::string, std::string>> BridgeAccessible::GetDefaultLabelInfo()
745 {
746   auto defaultLabel = FindSelf()->GetDefaultLabel();
747   return {defaultLabel, static_cast<uint32_t>(defaultLabel->GetRole()), defaultLabel->GetAttributes()};
748 }
749
750 DBus::ValueOrError<std::vector<BridgeAccessible::Relation>> BridgeAccessible::GetRelationSet()
751 {
752   auto                                    relations = FindSelf()->GetRelationSet();
753   std::vector<BridgeAccessible::Relation> ret;
754
755   for(auto& it : relations)
756     ret.emplace_back(Relation{static_cast<uint32_t>(it.relationType), it.targets});
757
758   return ret;
759 }