2 * Copyright (c) 2021 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/internal/accessibility/bridge/bridge-accessible.h>
25 //comment out 2 lines below to get more logs
27 #define LOG() _LoggerEmpty()
29 using namespace Dali::Accessibility;
31 #define GET_NAVIGABLE_AT_POINT_MAX_RECURSION_DEPTH 10000
35 bool SortVertically(Component* lhs, Component* rhs)
37 auto leftRect = lhs->GetExtents(CoordinateType::WINDOW);
38 auto rightRect = rhs->GetExtents(CoordinateType::WINDOW);
40 return leftRect.y < rightRect.y;
43 bool SortHorizontally(Component* lhs, Component* rhs)
45 auto leftRect = lhs->GetExtents(CoordinateType::WINDOW);
46 auto rightRect = rhs->GetExtents(CoordinateType::WINDOW);
48 return leftRect.x < rightRect.x;
51 std::vector<std::vector<Component*>> SplitLines(const std::vector<Component*>& children)
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;
59 if(first == children.end())
64 std::vector<std::vector<Component*>> lines(1);
65 Dali::Rect<> lineRect = (*first)->GetExtents(CoordinateType::WINDOW);
69 for(auto it = first; it != children.end(); ++it)
73 rect = child->GetExtents(CoordinateType::WINDOW);
74 if(rect.height == 0.0f || rect.width == 0.0f)
80 if(lineRect.y + (0.25 * lineRect.height) >= rect.y)
83 lines.back().push_back(child);
90 lines.back().push_back(child);
97 } // anonymous namespace
99 BridgeAccessible::BridgeAccessible()
103 void BridgeAccessible::RegisterInterfaces()
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);
128 static bool AcceptObjectCheckRelations(Component* obj)
130 auto r = obj->GetRelationSet();
132 for(const auto& it : r)
133 if(it.relationType == RelationType::CONTROLLED_BY)
139 static Component* GetScrollableParent(Accessible* obj)
143 obj = obj->GetParent();
144 auto comp = dynamic_cast<Component*>(obj);
145 if(comp && comp->IsScrollable())
151 static bool ObjectIsItem(Component* obj)
155 auto role = obj->GetRole();
156 return role == Role::LIST_ITEM || role == Role::MENU_ITEM;
159 static bool ObjectIsCollapsed(Component* obj)
163 const auto states = obj->GetStates();
164 return states[State::EXPANDABLE] && !states[State::EXPANDED];
167 static bool ObjectIsZeroSize(Component* obj)
171 auto extents = obj->GetExtents(CoordinateType::WINDOW);
172 return extents.height == 0 || extents.width == 0;
175 static bool AcceptObject(Component* obj)
179 const auto states = obj->GetStates();
180 if(!states[State::VISIBLE])
182 if(!AcceptObjectCheckRelations(obj))
184 if(!states[State::HIGHLIGHTABLE])
187 if(GetScrollableParent(obj) != nullptr)
189 auto parent = dynamic_cast<Component*>(obj->GetParent());
193 return !ObjectIsItem(obj) || !ObjectIsCollapsed(parent);
198 if(ObjectIsZeroSize(obj))
202 if(!states[State::SHOWING])
210 static bool AcceptObject(Accessible* obj)
212 auto c = dynamic_cast<Component*>(obj);
213 return AcceptObject(c);
216 static int32_t GetItemCountOfList(Accessible* obj)
218 int32_t itemCount = 0;
219 if(obj && obj->GetRole() == Role::LIST)
221 for(auto i = 0u; i < static_cast<size_t>(obj->GetChildCount()); ++i)
223 auto child = obj->GetChildAtIndex(i);
224 if(child && child->GetRole() == Role::LIST_ITEM)
233 static int32_t GetItemCountOfFirstDescendantList(Accessible* obj)
235 int32_t itemCount = 0;
236 itemCount = GetItemCountOfList(obj);
237 if(itemCount > 0 || !obj)
242 for(auto i = 0u; i < static_cast<size_t>(obj->GetChildCount()); ++i)
244 auto child = obj->GetChildAtIndex(i);
245 itemCount = GetItemCountOfFirstDescendantList(child);
254 static std::string objDump(Component* obj)
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 << "]";
265 Component* BridgeAccessible::GetObjectInRelation(Accessible* obj, RelationType ralationType)
269 for(auto& relation : obj->GetRelationSet())
271 if(relation.relationType == ralationType)
273 for(auto& address : relation.targets)
275 auto component = dynamic_cast<Component*>(Find(address));
284 static std::string makeIndent(unsigned int maxRecursionDepth)
286 return std::string(GET_NAVIGABLE_AT_POINT_MAX_RECURSION_DEPTH - maxRecursionDepth, ' ');
289 Component* BridgeAccessible::CalculateNavigableAccessibleAtPoint(Accessible* root, Point p, CoordinateType type, unsigned int maxRecursionDepth)
291 if(!root || maxRecursionDepth == 0)
296 auto root_component = dynamic_cast<Component*>(root);
297 LOG() << "CalculateNavigableAccessibleAtPoint: checking: " << makeIndent(maxRecursionDepth) << objDump(root_component);
299 if(root_component && !root_component->IsAccessibleContainedAtPoint(p, type))
304 auto children = root->GetChildren();
305 for(auto childIt = children.rbegin(); childIt != children.rend(); childIt++)
307 //check recursively all children first
308 auto result = CalculateNavigableAccessibleAtPoint(*childIt, p, type, maxRecursionDepth - 1);
317 //Found a candidate, all its children are already checked
318 auto controledBy = GetObjectInRelation(root_component, RelationType::CONTROLLED_BY);
321 controledBy = root_component;
324 if(controledBy->IsProxy() || AcceptObject(controledBy))
326 LOG() << "CalculateNavigableAccessibleAtPoint: found: " << makeIndent(maxRecursionDepth) << objDump(root_component);
333 BridgeAccessible::ReadingMaterialType BridgeAccessible::GetReadingMaterial()
335 auto self = FindSelf();
336 auto findObjectByRelationType = [this, &self](RelationType relationType) {
337 auto relations = self->GetRelationSet();
338 auto relation = std::find_if(relations.begin(),
340 [relationType](const Dali::Accessibility::Relation& relation) -> bool {
341 return relation.relationType == relationType;
343 return relations.end() != relation && !relation->targets.empty() ? Find(relation->targets.back()) : nullptr;
346 auto labellingObject = findObjectByRelationType(RelationType::LABELLED_BY);
347 std::string labeledByName = labellingObject ? labellingObject->GetName() : "";
349 auto describedByObject = findObjectByRelationType(RelationType::DESCRIBED_BY);
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);
358 currentValue = valueInterface->GetCurrent();
359 minimumIncrement = valueInterface->GetMinimumIncrement();
360 maximumValue = valueInterface->GetMaximum();
361 minimumValue = valueInterface->GetMinimum();
364 int32_t firstSelectedChildIndex = -1;
365 int32_t selectedChildCount = 0;
366 auto* selfSelectionInterface = dynamic_cast<Dali::Accessibility::Selection*>(self);
367 if(selfSelectionInterface)
369 selectedChildCount = selfSelectionInterface->GetSelectedChildrenCount();
370 auto firstSelectedChild = selfSelectionInterface->GetSelectedChild(0);
371 if(firstSelectedChild)
373 firstSelectedChildIndex = firstSelectedChild->GetIndexInParent();
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)
381 auto child = self->GetChildAtIndex(i);
382 if(child->GetRole() == Role::CHECK_BOX)
384 hasCheckBoxChild = true;
389 auto role = static_cast<uint32_t>(self->GetRole());
390 int32_t listChildrenCount = 0;
391 if(role == static_cast<uint32_t>(Role::DIALOG))
393 listChildrenCount = GetItemCountOfFirstDescendantList(self);
396 auto* textInterface = dynamic_cast<Dali::Accessibility::Text*>(self);
397 std::string nameFromTextInterface = "";
400 nameFromTextInterface = textInterface->GetText(0, textInterface->GetCharacterCount());
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());
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)
418 isSelectedInParent = parentSelectionInterface->IsChildSelected(indexInParent);
425 nameFromTextInterface,
439 firstSelectedChildIndex,
448 void BridgeAccessible::SuppressScreenReader(bool suppress)
450 suppressScreenReader = suppress;
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)
455 return FindSelf()->DoGesture(Dali::Accessibility::GestureInfo{type, xBeg, xEnd, yBeg, yEnd, state, eventTime});
458 DBus::ValueOrError<Accessible*, uint8_t, Accessible*> BridgeAccessible::GetNavigableAtPoint(int32_t x, int32_t y, uint32_t coordinateType)
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;
468 recurse = component->IsProxy();
471 return {component, recurse, deputy};
474 static bool CheckChainEndWithAttribute(Accessible* obj, unsigned char forward)
478 auto attrs = obj->GetAttributes();
479 for(auto& attr : attrs)
481 if(attr.first == "relation_chain_end")
483 if((attr.second == "prev,end" && forward == 0) || (attr.second == "next,end" && forward == 1) || attr.second == "prev,next,end")
492 static Accessible* DeputyOfProxyInParentGet(Accessible* obj)
497 Accessible* BridgeAccessible::GetCurrentlyHighlighted()
499 //TODO: add currently highlighted object
503 std::vector<Accessible*> BridgeAccessible::ValidChildrenGet(const std::vector<Accessible*>& children, Accessible* start, Accessible* root)
505 std::vector<Component*> vec;
506 std::vector<Accessible*> ret;
508 for(auto child : children)
510 if(auto* component = dynamic_cast<Component*>(child); component)
512 vec.push_back(component);
516 std::sort(vec.begin(), vec.end(), &SortVertically);
518 for(auto& line : SplitLines(vec))
520 std::sort(line.begin(), line.end(), &SortHorizontally);
521 ret.insert(ret.end(), line.begin(), line.end());
527 static bool DeputyIs(Accessible* obj)
533 static Accessible* ProxyInParentGet(Accessible* obj)
537 auto children = obj->GetChildren();
538 for(auto& child : children)
546 static bool ObjectRoleIsAcceptableWhenNavigatingNextPrev(Accessible* obj)
550 auto role = obj->GetRole();
551 return role != Role::POPUP_MENU && role != Role::DIALOG;
555 struct CycleDetection
557 CycleDetection(const T value)
559 currentSearchSize(1),
563 bool check(const T value)
569 currentSearchSize <<= 1;
570 if(currentSearchSize == 0)
571 return true; // UNDEFINED BEHAVIOR
572 counter = currentSearchSize;
578 unsigned int currentSearchSize;
579 unsigned int counter;
582 static Accessible* FindNonDefunctChild(const std::vector<Accessible*>& children, unsigned int currentIndex, unsigned char forward)
584 unsigned int childrenCount = children.size();
585 for(; currentIndex < childrenCount; forward ? ++currentIndex : --currentIndex)
587 Accessible* n = children[currentIndex];
588 if(n && !n->GetStates()[State::DEFUNCT])
594 static Accessible* DirectionalDepthFirstSearchTryNonDefunctChild(Accessible* node, const std::vector<Accessible*>& children, unsigned char forward)
598 auto childrenCount = children.size();
599 if(childrenCount > 0)
601 const bool isShowing = GetScrollableParent(node) == nullptr ? node->GetStates()[State::SHOWING] : true;
604 return FindNonDefunctChild(children, forward ? 0 : childrenCount - 1, forward);
610 Accessible* BridgeAccessible::GetNextNonDefunctSibling(Accessible* obj, Accessible* start, Accessible* root, unsigned char forward)
614 auto parent = obj->GetParent();
618 auto children = ValidChildrenGet(parent->GetChildren(), start, root);
620 unsigned int children_count = children.size();
621 if(children_count == 0)
625 unsigned int current = 0;
626 for(; current < children_count && children[current] != obj; ++current)
628 if(current >= children_count)
632 forward ? ++current : --current;
633 auto ret = FindNonDefunctChild(children, current, forward);
637 Accessible* BridgeAccessible::DirectionalDepthFirstSearchTryNonDefunctSibling(bool& all_children_visited, Accessible* node, Accessible* start, Accessible* root, unsigned char forward)
641 Accessible* sibling = GetNextNonDefunctSibling(node, start, root, forward);
645 all_children_visited = false;
649 node = node->GetParent();
650 if(node == nullptr || node == root)
653 // in backward traversing stop the walk up on parent
660 Accessible* BridgeAccessible::CalculateNeighbor(Accessible* root, Accessible* start, unsigned char forward, BridgeAccessible::GetNeighborSearchMode search_mode)
662 if(start && CheckChainEndWithAttribute(start, forward))
664 if(root && root->GetStates()[State::DEFUNCT])
666 if(start && start->GetStates()[State::DEFUNCT])
672 if(search_mode == BridgeAccessible::GetNeighborSearchMode::recurseToOutside)
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);
679 Accessible* node = start ? start : root;
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);
701 CycleDetection<Accessible*> cycleDetection(node);
704 if(node->GetStates()[State::DEFUNCT])
707 // always accept proxy object from different world
708 if(!force_next && node->IsProxy())
711 auto children = node->GetChildren();
712 children = ValidChildrenGet(children, start, root);
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))
722 if(start == NULL || ObjectRoleIsAcceptableWhenNavigatingNextPrev(node))
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)
734 auto deputy = DeputyOfProxyInParentGet(node);
735 next_related_in_direction =
736 GetObjectInRelation(deputy, RelationType::FLOWS_TO);
739 if(next_related_in_direction && start && start->GetStates()[State::DEFUNCT])
741 next_related_in_direction = NULL;
744 unsigned char want_cycle_detection = 0;
745 if(next_related_in_direction)
747 // Check next_related_in_direction is deputy object
751 // If the prev object is deputy, then go to inside of its proxy first
752 if(DeputyIs(next_related_in_direction))
754 parent = next_related_in_direction->GetParent();
755 next_related_in_direction = ProxyInParentGet(parent);
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
764 parent = node->GetParent();
765 next_related_in_direction = ProxyInParentGet(parent);
768 node = next_related_in_direction;
769 want_cycle_detection = 1;
773 auto child = !force_next && !all_children_visited ? DirectionalDepthFirstSearchTryNonDefunctChild(node, children, forward) : nullptr;
776 want_cycle_detection = 1;
780 if(!force_next && node == root)
782 all_children_visited = true;
783 child = DirectionalDepthFirstSearchTryNonDefunctSibling(all_children_visited, node, start, root, forward);
788 if(want_cycle_detection && cycleDetection.check(node))
796 DBus::ValueOrError<Accessible*, uint8_t> BridgeAccessible::GetNeighbor(std::string rootPath, int32_t direction, int32_t search_mode)
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;
805 recurse = accessible->IsProxy();
807 return {accessible, recurse};
810 Accessible* BridgeAccessible::GetParent()
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();
820 DBus::ValueOrError<std::vector<Accessible*>> BridgeAccessible::GetChildren()
822 return FindSelf()->GetChildren();
824 std::string BridgeAccessible::GetDescription()
826 return FindSelf()->GetDescription();
828 DBus::ValueOrError<uint32_t> BridgeAccessible::GetRole()
830 return static_cast<unsigned int>(FindSelf()->GetRole());
832 DBus::ValueOrError<std::string> BridgeAccessible::GetRoleName()
834 return FindSelf()->GetRoleName();
836 DBus::ValueOrError<std::string> BridgeAccessible::GetLocalizedRoleName()
838 return FindSelf()->GetLocalizedRoleName();
840 DBus::ValueOrError<int32_t> BridgeAccessible::GetIndexInParent()
842 return FindSelf()->GetIndexInParent();
844 DBus::ValueOrError<std::array<uint32_t, 2>> BridgeAccessible::GetStates()
846 return FindSelf()->GetStates().GetRawData();
848 DBus::ValueOrError<std::unordered_map<std::string, std::string>> BridgeAccessible::GetAttributes()
850 std::unordered_map<std::string, std::string> attributes = FindSelf()->GetAttributes();
851 if(suppressScreenReader)
853 attributes.insert({"suppress-screen-reader", "true"});
858 DBus::ValueOrError<std::vector<std::string>> BridgeAccessible::GetInterfaces()
860 return FindSelf()->GetInterfaces();
862 int BridgeAccessible::GetChildCount()
864 return FindSelf()->GetChildCount();
866 DBus::ValueOrError<Accessible*> BridgeAccessible::GetChildAtIndex(int index)
869 throw std::domain_error{"negative index (" + std::to_string(index) + ")"};
870 return FindSelf()->GetChildAtIndex(static_cast<size_t>(index));
873 std::string BridgeAccessible::GetName()
875 return FindSelf()->GetName();
878 DBus::ValueOrError<Accessible*, uint32_t, std::unordered_map<std::string, std::string>> BridgeAccessible::GetDefaultLabelInfo()
880 auto defaultLabel = FindSelf()->GetDefaultLabel();
881 return {defaultLabel, static_cast<uint32_t>(defaultLabel->GetRole()), defaultLabel->GetAttributes()};
884 DBus::ValueOrError<std::vector<BridgeAccessible::Relation>> BridgeAccessible::GetRelationSet()
886 auto relations = FindSelf()->GetRelationSet();
887 std::vector<BridgeAccessible::Relation> ret;
889 for(auto& it : relations)
890 ret.emplace_back(Relation{static_cast<uint32_t>(it.relationType), it.targets});