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