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