Merge "Add class for encoded image buffer" into devel/master
[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(CoordinateType::WINDOW);
38   auto rightRect = rhs->GetExtents(CoordinateType::WINDOW);
39
40   return leftRect.y < rightRect.y;
41 }
42
43 bool SortHorizontally(Component* lhs, Component* rhs)
44 {
45   auto leftRect  = lhs->GetExtents(CoordinateType::WINDOW);
46   auto rightRect = rhs->GetExtents(CoordinateType::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(CoordinateType::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(CoordinateType::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(CoordinateType::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 ObjectIsZeroSize(Component* obj)
168 {
169   if(!obj)
170     return false;
171   auto extents = obj->GetExtents(CoordinateType::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(ObjectIsZeroSize(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(CoordinateType::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, CoordinateType type, unsigned int maxRecursionDepth)
290 {
291   if(!root || maxRecursionDepth == 0)
292   {
293     return nullptr;
294   }
295
296   auto root_component = dynamic_cast<Component*>(root);
297   LOG() << "CalculateNavigableAccessibleAtPoint: checking: " << makeIndent(maxRecursionDepth) << objDump(root_component);
298
299   if(root_component && !root_component->IsAccessibleContainedAtPoint(p, type))
300   {
301     return nullptr;
302   }
303
304   auto children = root->GetChildren();
305   for(auto childIt = children.rbegin(); childIt != children.rend(); childIt++)
306   {
307     //check recursively all children first
308     auto result = CalculateNavigableAccessibleAtPoint(*childIt, p, type, maxRecursionDepth - 1);
309     if(result)
310     {
311       return result;
312     }
313   }
314
315   if(root_component)
316   {
317     //Found a candidate, all its children are already checked
318     auto controledBy = GetObjectInRelation(root_component, RelationType::CONTROLLED_BY);
319     if(!controledBy)
320     {
321       controledBy = root_component;
322     }
323
324     if(controledBy->IsProxy() || AcceptObject(controledBy))
325     {
326       LOG() << "CalculateNavigableAccessibleAtPoint: found:    " << makeIndent(maxRecursionDepth) << objDump(root_component);
327       return controledBy;
328     }
329   }
330   return nullptr;
331 }
332
333 BridgeAccessible::ReadingMaterialType BridgeAccessible::GetReadingMaterial()
334 {
335   auto self                     = FindSelf();
336   auto findObjectByRelationType = [this, &self](RelationType relationType) {
337     auto relations = self->GetRelationSet();
338     auto relation  = std::find_if(relations.begin(),
339                                  relations.end(),
340                                  [relationType](const Dali::Accessibility::Relation& relation) -> bool {
341                                    return relation.relationType == relationType;
342                                  });
343     return relations.end() != relation && !relation->targets.empty() ? Find(relation->targets.back()) : nullptr;
344   };
345
346   auto        labellingObject = findObjectByRelationType(RelationType::LABELLED_BY);
347   std::string labeledByName   = labellingObject ? labellingObject->GetName() : "";
348
349   auto describedByObject = findObjectByRelationType(RelationType::DESCRIBED_BY);
350
351   double currentValue     = 0.0;
352   double minimumIncrement = 0.0;
353   double maximumValue     = 0.0;
354   double minimumValue     = 0.0;
355   auto*  valueInterface   = dynamic_cast<Dali::Accessibility::Value*>(self);
356   if(valueInterface)
357   {
358     currentValue     = valueInterface->GetCurrent();
359     minimumIncrement = valueInterface->GetMinimumIncrement();
360     maximumValue     = valueInterface->GetMaximum();
361     minimumValue     = valueInterface->GetMinimum();
362   }
363
364   int32_t firstSelectedChildIndex = -1;
365   int32_t selectedChildCount      = 0;
366   auto*   selfSelectionInterface  = dynamic_cast<Dali::Accessibility::Selection*>(self);
367   if(selfSelectionInterface)
368   {
369     selectedChildCount      = selfSelectionInterface->GetSelectedChildrenCount();
370     auto firstSelectedChild = selfSelectionInterface->GetSelectedChild(0);
371     if(firstSelectedChild)
372     {
373       firstSelectedChildIndex = firstSelectedChild->GetIndexInParent();
374     }
375   }
376
377   auto childCount       = static_cast<int32_t>(self->GetChildCount());
378   bool hasCheckBoxChild = false;
379   for(auto i = 0u; i < static_cast<size_t>(childCount); ++i)
380   {
381     auto child = self->GetChildAtIndex(i);
382     if(child->GetRole() == Role::CHECK_BOX)
383     {
384       hasCheckBoxChild = true;
385       break;
386     }
387   }
388
389   auto    role              = static_cast<uint32_t>(self->GetRole());
390   int32_t listChildrenCount = 0;
391   if(role == static_cast<uint32_t>(Role::DIALOG))
392   {
393     listChildrenCount = GetItemCountOfFirstDescendantList(self);
394   }
395
396   auto*       textInterface         = dynamic_cast<Dali::Accessibility::Text*>(self);
397   std::string nameFromTextInterface = "";
398   if(textInterface)
399   {
400     nameFromTextInterface = textInterface->GetText(0, textInterface->GetCharacterCount());
401   }
402
403   auto description       = self->GetDescription();
404   auto attributes        = self->GetAttributes();
405   auto states            = self->GetStates();
406   auto name              = self->GetName();
407   auto localizedRoleName = self->GetLocalizedRoleName();
408   auto indexInParent     = static_cast<int32_t>(self->GetIndexInParent());
409
410   auto  parent                   = self->GetParent();
411   auto  parentRole               = static_cast<uint32_t>(parent ? parent->GetRole() : Role{});
412   auto  parentChildCount         = parent ? static_cast<int32_t>(parent->GetChildCount()) : 0;
413   auto  parentStateSet           = parent ? parent->GetStates() : States{};
414   bool  isSelectedInParent       = false;
415   auto* parentSelectionInterface = dynamic_cast<Dali::Accessibility::Selection*>(parent);
416   if(parentSelectionInterface)
417   {
418     isSelectedInParent = parentSelectionInterface->IsChildSelected(indexInParent);
419   }
420
421   return {
422     attributes,
423     name,
424     labeledByName,
425     nameFromTextInterface,
426     role,
427     states,
428     localizedRoleName,
429     childCount,
430     currentValue,
431     minimumIncrement,
432     maximumValue,
433     minimumValue,
434     description,
435     indexInParent,
436     isSelectedInParent,
437     hasCheckBoxChild,
438     listChildrenCount,
439     firstSelectedChildIndex,
440     parent,
441     parentStateSet,
442     parentChildCount,
443     parentRole,
444     selectedChildCount,
445     describedByObject};
446 }
447
448 void BridgeAccessible::SuppressScreenReader(bool suppress)
449 {
450   suppressScreenReader = suppress;
451 }
452
453 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)
454 {
455   return FindSelf()->DoGesture(Dali::Accessibility::GestureInfo{type, xBeg, xEnd, yBeg, yEnd, state, eventTime});
456 }
457
458 DBus::ValueOrError<Accessible*, uint8_t, Accessible*> BridgeAccessible::GetNavigableAtPoint(int32_t x, int32_t y, uint32_t coordinateType)
459 {
460   Accessible* deputy     = nullptr;
461   auto        accessible = FindSelf();
462   auto        cType      = static_cast<CoordinateType>(coordinateType);
463   LOG() << "GetNavigableAtPoint: " << x << ", " << y << " type: " << coordinateType;
464   auto component = CalculateNavigableAccessibleAtPoint(accessible, {x, y}, cType, GET_NAVIGABLE_AT_POINT_MAX_RECURSION_DEPTH);
465   bool recurse   = false;
466   if(component)
467   {
468     recurse = component->IsProxy();
469   }
470   //TODO: add deputy
471   return {component, recurse, deputy};
472 }
473
474 static bool CheckChainEndWithAttribute(Accessible* obj, unsigned char forward)
475 {
476   if(!obj)
477     return false;
478   auto attrs = obj->GetAttributes();
479   for(auto& attr : attrs)
480   {
481     if(attr.first == "relation_chain_end")
482     {
483       if((attr.second == "prev,end" && forward == 0) || (attr.second == "next,end" && forward == 1) || attr.second == "prev,next,end")
484       {
485         return true;
486       }
487     }
488   }
489   return false;
490 }
491
492 static Accessible* DeputyOfProxyInParentGet(Accessible* obj)
493 {
494   return nullptr;
495 }
496
497 Accessible* BridgeAccessible::GetCurrentlyHighlighted()
498 {
499   //TODO: add currently highlighted object
500   return nullptr;
501 }
502
503 std::vector<Accessible*> BridgeAccessible::ValidChildrenGet(const std::vector<Accessible*>& children, Accessible* start, Accessible* root)
504 {
505   std::vector<Component*> vec;
506   std::vector<Accessible*> ret;
507
508   for(auto child : children)
509   {
510     if(auto* component = dynamic_cast<Component*>(child); component)
511     {
512       vec.push_back(component);
513     }
514   }
515
516   std::sort(vec.begin(), vec.end(), &SortVertically);
517
518   for(auto& line : SplitLines(vec))
519   {
520     std::sort(line.begin(), line.end(), &SortHorizontally);
521     ret.insert(ret.end(), line.begin(), line.end());
522   }
523
524   return ret;
525 }
526
527 static bool DeputyIs(Accessible* obj)
528 {
529   //TODO: add deputy
530   return false;
531 }
532
533 static Accessible* ProxyInParentGet(Accessible* obj)
534 {
535   if(!obj)
536     return nullptr;
537   auto children = obj->GetChildren();
538   for(auto& child : children)
539   {
540     if(child->IsProxy())
541       return child;
542   }
543   return nullptr;
544 }
545
546 static bool ObjectRoleIsAcceptableWhenNavigatingNextPrev(Accessible* obj)
547 {
548   if(!obj)
549     return false;
550   auto role = obj->GetRole();
551   return role != Role::POPUP_MENU && role != Role::DIALOG;
552 }
553
554 template<class T>
555 struct CycleDetection
556 {
557   CycleDetection(const T value)
558   : key(value),
559     currentSearchSize(1),
560     counter(1)
561   {
562   }
563   bool check(const T value)
564   {
565     if(key == value)
566       return true;
567     if(--counter == 0)
568     {
569       currentSearchSize <<= 1;
570       if(currentSearchSize == 0)
571         return true; // UNDEFINED BEHAVIOR
572       counter = currentSearchSize;
573       key     = value;
574     }
575     return false;
576   }
577   T            key;
578   unsigned int currentSearchSize;
579   unsigned int counter;
580 };
581
582 static Accessible* FindNonDefunctChild(const std::vector<Accessible*>& children, unsigned int currentIndex, unsigned char forward)
583 {
584   unsigned int childrenCount = children.size();
585   for(; currentIndex < childrenCount; forward ? ++currentIndex : --currentIndex)
586   {
587     Accessible* n = children[currentIndex];
588     if(n && !n->GetStates()[State::DEFUNCT])
589       return n;
590   }
591   return nullptr;
592 }
593
594 static Accessible* DirectionalDepthFirstSearchTryNonDefunctChild(Accessible* node, const std::vector<Accessible*>& children, unsigned char forward)
595 {
596   if(!node)
597     return nullptr;
598   auto childrenCount = children.size();
599   if(childrenCount > 0)
600   {
601     const bool isShowing = GetScrollableParent(node) == nullptr ? node->GetStates()[State::SHOWING] : true;
602     if(isShowing)
603     {
604       return FindNonDefunctChild(children, forward ? 0 : childrenCount - 1, forward);
605     }
606   }
607   return nullptr;
608 }
609
610 Accessible* BridgeAccessible::GetNextNonDefunctSibling(Accessible* obj, Accessible* start, Accessible* root, unsigned char forward)
611 {
612   if(!obj)
613     return nullptr;
614   auto parent = obj->GetParent();
615   if(!parent)
616     return nullptr;
617
618   auto children = ValidChildrenGet(parent->GetChildren(), start, root);
619
620   unsigned int children_count = children.size();
621   if(children_count == 0)
622   {
623     return nullptr;
624   }
625   unsigned int current = 0;
626   for(; current < children_count && children[current] != obj; ++current)
627     ;
628   if(current >= children_count)
629   {
630     return nullptr;
631   }
632   forward ? ++current : --current;
633   auto ret = FindNonDefunctChild(children, current, forward);
634   return ret;
635 }
636
637 Accessible* BridgeAccessible::DirectionalDepthFirstSearchTryNonDefunctSibling(bool& all_children_visited, Accessible* node, Accessible* start, Accessible* root, unsigned char forward)
638 {
639   while(true)
640   {
641     Accessible* sibling = GetNextNonDefunctSibling(node, start, root, forward);
642     if(sibling)
643     {
644       node                 = sibling;
645       all_children_visited = false;
646       break;
647     }
648     // walk up...
649     node = node->GetParent();
650     if(node == nullptr || node == root)
651       return nullptr;
652
653     // in backward traversing stop the walk up on parent
654     if(!forward)
655       break;
656   }
657   return node;
658 }
659
660 Accessible* BridgeAccessible::CalculateNeighbor(Accessible* root, Accessible* start, unsigned char forward, BridgeAccessible::GetNeighborSearchMode search_mode)
661 {
662   if(start && CheckChainEndWithAttribute(start, forward))
663     return start;
664   if(root && root->GetStates()[State::DEFUNCT])
665     return NULL;
666   if(start && start->GetStates()[State::DEFUNCT])
667   {
668     start   = NULL;
669     forward = 1;
670   }
671
672   if(search_mode == BridgeAccessible::GetNeighborSearchMode::recurseToOutside)
673   {
674     // This only works if we navigate backward, and it is not possible to
675     // find in embedded process. In this case the deputy should be used */
676     return DeputyOfProxyInParentGet(start);
677   }
678
679   Accessible* node = start ? start : root;
680   if(!node)
681     return nullptr;
682
683   // initialization of all-children-visited flag for start node - we assume
684   // that when we begin at start node and we navigate backward, then all children
685   // are visited, so navigation will ignore start's children and go to
686   // previous sibling available.
687   // Regarding condtion (start != root):
688   // The last object can be found only if all_children_visited is false.
689   // The start is same with root, when looking for the last object.
690   bool all_children_visited = (start != root) && (search_mode != BridgeAccessible::GetNeighborSearchMode::recurseFromRoot && !forward);
691   // true, if starting element should be ignored. this is only used in rare case of
692   // recursive search failing to find an object.
693   // consider tree, where element A on bus BUS_A has child B on bus BUS_B. when going "next" from
694   // element A algorithm has to descend into BUS_B and search element B and its children. this is done
695   // by returning to our caller object B with special flag set (meaning - continue the search from B on bus BUS_B).
696   // if next object will be found there (on BUS_B), then search ends. but if not, then our caller will find it out
697   // and will call us again with object A and flag search_mode set to NEIGHBOR_SEARCH_MODE_CONTINUE_AFTER_FAILED_RECURSING.
698   // this flag means, that object A was already checked previously and we should skip it and its children.
699   bool force_next = (search_mode == BridgeAccessible::GetNeighborSearchMode::continueAfterFailedRecursion);
700
701   CycleDetection<Accessible*> cycleDetection(node);
702   while(node)
703   {
704     if(node->GetStates()[State::DEFUNCT])
705       return nullptr;
706
707     // always accept proxy object from different world
708     if(!force_next && node->IsProxy())
709       return node;
710
711     auto children = node->GetChildren();
712     children      = ValidChildrenGet(children, start, root);
713
714     // do accept:
715     // 1. not start node
716     // 2. parent after all children in backward traversing
717     // 3. Nodes with roles: ATSPI_ROLE_PAGE_TAB, ATSPI_ROLE_POPUP_MENU and ATSPI_ROLE_DIALOG, only when looking for first or last element.
718     //    Objects with those roles shouldnt be reachable, when navigating next / prev.
719     bool all_children_visited_or_moving_forward = (children.size() == 0 || forward || all_children_visited);
720     if(!force_next && node != start && all_children_visited_or_moving_forward && AcceptObject(node))
721     {
722       if(start == NULL || ObjectRoleIsAcceptableWhenNavigatingNextPrev(node))
723         return node;
724     }
725
726     Accessible* next_related_in_direction = !force_next ? GetObjectInRelation(node, forward ? RelationType::FLOWS_TO : RelationType::FLOWS_FROM) : nullptr;
727     // force_next means that the search_mode is NEIGHBOR_SEARCH_MODE_CONTINUE_AFTER_FAILED_RECURSING
728     // in this case the node is elm_layout which is parent of proxy object.
729     // There is an access object working for the proxy object, and the access
730     // object could have relation information. This relation information should
731     // be checked first before using the elm_layout as a node.
732     if(force_next && forward)
733     {
734       auto deputy = DeputyOfProxyInParentGet(node);
735       next_related_in_direction =
736         GetObjectInRelation(deputy, RelationType::FLOWS_TO);
737     }
738
739     if(next_related_in_direction && start && start->GetStates()[State::DEFUNCT])
740     {
741       next_related_in_direction = NULL;
742     }
743
744     unsigned char want_cycle_detection = 0;
745     if(next_related_in_direction)
746     {
747       // Check next_related_in_direction is deputy object
748       Accessible* parent;
749       if(!forward)
750       {
751         // If the prev object is deputy, then go to inside of its proxy first
752         if(DeputyIs(next_related_in_direction))
753         {
754           parent                    = next_related_in_direction->GetParent();
755           next_related_in_direction = ProxyInParentGet(parent);
756         }
757       }
758       else
759       {
760         // If current object is deputy, and it has relation next object,
761         // then do not use the relation next object, and use proxy first
762         if(DeputyIs(node))
763         {
764           parent                    = node->GetParent();
765           next_related_in_direction = ProxyInParentGet(parent);
766         }
767       }
768       node                 = next_related_in_direction;
769       want_cycle_detection = 1;
770     }
771     else
772     {
773       auto child = !force_next && !all_children_visited ? DirectionalDepthFirstSearchTryNonDefunctChild(node, children, forward) : nullptr;
774       if(child)
775       {
776         want_cycle_detection = 1;
777       }
778       else
779       {
780         if(!force_next && node == root)
781           return NULL;
782         all_children_visited = true;
783         child                = DirectionalDepthFirstSearchTryNonDefunctSibling(all_children_visited, node, start, root, forward);
784       }
785       node = child;
786     }
787     force_next = 0;
788     if(want_cycle_detection && cycleDetection.check(node))
789     {
790       return NULL;
791     }
792   }
793   return NULL;
794 }
795
796 DBus::ValueOrError<Accessible*, uint8_t> BridgeAccessible::GetNeighbor(std::string rootPath, int32_t direction, int32_t search_mode)
797 {
798   auto start               = FindSelf();
799   rootPath                 = StripPrefix(rootPath);
800   auto          root       = !rootPath.empty() ? Find(rootPath) : nullptr;
801   auto          accessible = CalculateNeighbor(root, start, direction == 1, static_cast<GetNeighborSearchMode>(search_mode));
802   unsigned char recurse    = 0;
803   if(accessible)
804   {
805     recurse = accessible->IsProxy();
806   }
807   return {accessible, recurse};
808 }
809
810 Accessible* BridgeAccessible::GetParent()
811 {
812   // NOTE: currently bridge supports single application root element.
813   // only element set as application root might return nullptr from GetParent
814   // if you want more, then you need to change setApplicationRoot to
815   // add/remove ApplicationRoot and make roots a vector.
816   auto p = FindSelf()->GetParent();
817
818   return p;
819 }
820 DBus::ValueOrError<std::vector<Accessible*>> BridgeAccessible::GetChildren()
821 {
822   return FindSelf()->GetChildren();
823 }
824 std::string BridgeAccessible::GetDescription()
825 {
826   return FindSelf()->GetDescription();
827 }
828 DBus::ValueOrError<uint32_t> BridgeAccessible::GetRole()
829 {
830   return static_cast<unsigned int>(FindSelf()->GetRole());
831 }
832 DBus::ValueOrError<std::string> BridgeAccessible::GetRoleName()
833 {
834   return FindSelf()->GetRoleName();
835 }
836 DBus::ValueOrError<std::string> BridgeAccessible::GetLocalizedRoleName()
837 {
838   return FindSelf()->GetLocalizedRoleName();
839 }
840 DBus::ValueOrError<int32_t> BridgeAccessible::GetIndexInParent()
841 {
842   return FindSelf()->GetIndexInParent();
843 }
844 DBus::ValueOrError<std::array<uint32_t, 2>> BridgeAccessible::GetStates()
845 {
846   return FindSelf()->GetStates().GetRawData();
847 }
848 DBus::ValueOrError<std::unordered_map<std::string, std::string>> BridgeAccessible::GetAttributes()
849 {
850   std::unordered_map<std::string, std::string> attributes = FindSelf()->GetAttributes();
851   if(suppressScreenReader)
852   {
853     attributes.insert({"suppress-screen-reader", "true"});
854   }
855
856   return attributes;
857 }
858 DBus::ValueOrError<std::vector<std::string>> BridgeAccessible::GetInterfaces()
859 {
860   return FindSelf()->GetInterfaces();
861 }
862 int BridgeAccessible::GetChildCount()
863 {
864   return FindSelf()->GetChildCount();
865 }
866 DBus::ValueOrError<Accessible*> BridgeAccessible::GetChildAtIndex(int index)
867 {
868   if(index < 0)
869     throw std::domain_error{"negative index (" + std::to_string(index) + ")"};
870   return FindSelf()->GetChildAtIndex(static_cast<size_t>(index));
871 }
872
873 std::string BridgeAccessible::GetName()
874 {
875   return FindSelf()->GetName();
876 }
877
878 DBus::ValueOrError<Accessible*, uint32_t, std::unordered_map<std::string, std::string>> BridgeAccessible::GetDefaultLabelInfo()
879 {
880   auto defaultLabel = FindSelf()->GetDefaultLabel();
881   return {defaultLabel, static_cast<uint32_t>(defaultLabel->GetRole()), defaultLabel->GetAttributes()};
882 }
883
884 DBus::ValueOrError<std::vector<BridgeAccessible::Relation>> BridgeAccessible::GetRelationSet()
885 {
886   auto                                    relations = FindSelf()->GetRelationSet();
887   std::vector<BridgeAccessible::Relation> ret;
888
889   for(auto& it : relations)
890     ret.emplace_back(Relation{static_cast<uint32_t>(it.relationType), it.targets});
891
892   return ret;
893 }