2 * Copyright (c) 2023 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>
22 #include <dali/public-api/math/math-utils.h>
28 #include <dali/devel-api/atspi-interfaces/accessible.h>
29 #include <dali/devel-api/atspi-interfaces/component.h>
30 #include <dali/devel-api/atspi-interfaces/selection.h>
31 #include <dali/devel-api/atspi-interfaces/text.h>
32 #include <dali/devel-api/atspi-interfaces/value.h>
34 //comment out 2 lines below to get more logs
36 #define LOG() _LoggerEmpty()
38 using namespace Dali::Accessibility;
40 #define GET_NAVIGABLE_AT_POINT_MAX_RECURSION_DEPTH 10000
44 bool SortVertically(Component* lhs, Component* rhs)
46 auto leftRect = lhs->GetExtents(CoordinateType::WINDOW);
47 auto rightRect = rhs->GetExtents(CoordinateType::WINDOW);
49 return leftRect.y < rightRect.y;
52 bool SortHorizontally(Component* lhs, Component* rhs)
54 auto leftRect = lhs->GetExtents(CoordinateType::WINDOW);
55 auto rightRect = rhs->GetExtents(CoordinateType::WINDOW);
57 return leftRect.x < rightRect.x;
60 std::vector<std::vector<Component*>> SplitLines(const std::vector<Component*>& children)
62 // Find first with non-zero area
63 auto first = std::find_if(children.begin(), children.end(), [](Component* child) -> bool {
64 auto extents = child->GetExtents(CoordinateType::WINDOW);
65 return !Dali::EqualsZero(extents.height) && !Dali::EqualsZero(extents.width);
68 if(first == children.end())
73 std::vector<std::vector<Component*>> lines(1);
74 Dali::Rect<> lineRect = (*first)->GetExtents(CoordinateType::WINDOW);
78 for(auto it = first; it != children.end(); ++it)
82 rect = child->GetExtents(CoordinateType::WINDOW);
83 if(Dali::EqualsZero(rect.height) || Dali::EqualsZero(rect.width))
89 if(lineRect.y + (0.5 * lineRect.height) >= rect.y + (0.5 * rect.height))
92 lines.back().push_back(child);
99 lines.back().push_back(child);
106 static bool AcceptObjectCheckRelations(Component* obj)
108 auto relations = obj->GetRelationSet();
110 for(const auto& it : relations)
112 if(it.mRelationType == RelationType::CONTROLLED_BY)
120 static Component* GetScrollableParent(Accessible* obj)
124 obj = obj->GetParent();
125 auto comp = dynamic_cast<Component*>(obj);
126 if(comp && comp->IsScrollable())
134 static bool IsObjectItem(Component* obj)
140 auto role = obj->GetRole();
141 return role == Role::LIST_ITEM || role == Role::MENU_ITEM;
144 static bool IsObjectCollapsed(Component* obj)
150 const auto states = obj->GetStates();
151 return states[State::EXPANDABLE] && !states[State::EXPANDED];
154 static bool IsObjectZeroSize(Component* obj)
160 auto extents = obj->GetExtents(CoordinateType::WINDOW);
161 return Dali::EqualsZero(extents.height) || Dali::EqualsZero(extents.width);
164 static bool IsObjectAcceptable(Component* obj)
171 const auto states = obj->GetStates();
172 if(!states[State::VISIBLE])
176 if(!AcceptObjectCheckRelations(obj))
180 if(!states[State::HIGHLIGHTABLE])
185 if(GetScrollableParent(obj) != nullptr)
187 auto parent = dynamic_cast<Component*>(obj->GetParent());
191 return !IsObjectItem(obj) || !IsObjectCollapsed(parent);
196 if(IsObjectZeroSize(obj))
200 if(!states[State::SHOWING])
208 static bool IsObjectAcceptable(Accessible* obj)
210 auto component = dynamic_cast<Component*>(obj);
211 return IsObjectAcceptable(component);
214 static int32_t GetItemCountOfContainer(Accessible* obj, Dali::Accessibility::Role containerRole, Dali::Accessibility::Role itemRole, bool isDirectChild)
216 int32_t itemCount = 0;
217 if(obj && (!isDirectChild || obj->GetRole() == containerRole))
219 for(auto i = 0u; i < static_cast<size_t>(obj->GetChildCount()); ++i)
221 auto child = obj->GetChildAtIndex(i);
222 if(child && child->GetRole() == itemRole)
231 static int32_t GetItemCountOfFirstDescendantContainer(Accessible* obj, Dali::Accessibility::Role containerRole, Dali::Accessibility::Role itemRole, bool isDirectChild)
233 int32_t itemCount = 0;
234 itemCount = GetItemCountOfContainer(obj, containerRole, itemRole, isDirectChild);
235 if(itemCount > 0 || !obj)
240 for(auto i = 0u; i < static_cast<size_t>(obj->GetChildCount()); ++i)
242 auto child = obj->GetChildAtIndex(i);
243 itemCount = GetItemCountOfFirstDescendantContainer(child, containerRole, itemRole, isDirectChild);
252 static std::string GetComponentInfo(Component* obj)
259 std::ostringstream object;
260 auto extent = obj->GetExtents(CoordinateType::SCREEN);
261 object << "name: " << obj->GetName() << " extent: (" << extent.x << ", "
262 << extent.y << "), [" << extent.width << ", " << extent.height << "]";
266 static std::string MakeIndent(unsigned int maxRecursionDepth)
268 return std::string(GET_NAVIGABLE_AT_POINT_MAX_RECURSION_DEPTH - maxRecursionDepth, ' ');
271 static bool IsRoleAcceptableWhenNavigatingNextPrev(Accessible* obj)
277 auto role = obj->GetRole();
278 return role != Role::POPUP_MENU && role != Role::DIALOG;
281 static Accessible* FindNonDefunctChild(const std::vector<Component*>& children, unsigned int currentIndex, unsigned char forward)
283 unsigned int childrenCount = children.size();
284 for(; currentIndex < childrenCount; forward ? ++currentIndex : --currentIndex)
286 Accessible* object = children[currentIndex];
287 if(object && !object->GetStates()[State::DEFUNCT])
295 // The auxiliary method for Depth-First Search (DFS) algorithm to find non defunct child directionally
296 static Accessible* FindNonDefunctChildWithDepthFirstSearch(Accessible* node, const std::vector<Component*>& children, unsigned char forward)
303 auto childrenCount = children.size();
304 if(childrenCount > 0)
306 const bool isShowing = GetScrollableParent(node) == nullptr ? node->GetStates()[State::SHOWING] : true;
309 return FindNonDefunctChild(children, forward ? 0 : childrenCount - 1, forward);
315 static bool CheckChainEndWithAttribute(Accessible* obj, unsigned char forward)
322 auto attrs = obj->GetAttributes();
323 for(auto& attr : attrs)
325 if(attr.first == "relation_chain_end")
327 if((attr.second == "prev,end" && forward == 0) || (attr.second == "next,end" && forward == 1) || attr.second == "prev,next,end")
336 static std::vector<Component*> GetScrollableParents(Accessible* accessible)
338 std::vector<Component*> scrollableParents;
342 accessible = accessible->GetParent();
343 auto component = dynamic_cast<Component*>(accessible);
344 if(component && component->IsScrollable())
346 scrollableParents.push_back(component);
349 return scrollableParents;
352 static std::vector<Component*> GetNonDuplicatedScrollableParents(Accessible* child, Accessible* start)
354 auto scrollableParentsOfChild = GetScrollableParents(child);
355 auto scrollableParentsOfStart = GetScrollableParents(start);
357 // find the first different scrollable parent by comparing from top to bottom.
358 // since it can not be the same after that, there is no need to compare.
359 while(!scrollableParentsOfChild.empty() && !scrollableParentsOfStart.empty() && scrollableParentsOfChild.back() == scrollableParentsOfStart.back())
361 scrollableParentsOfChild.pop_back();
362 scrollableParentsOfStart.pop_back();
365 return scrollableParentsOfChild;
368 } // anonymous namespace
370 BridgeAccessible::BridgeAccessible()
374 void BridgeAccessible::RegisterInterfaces()
376 DBus::DBusInterfaceDescription desc{Accessible::GetInterfaceName(AtspiInterface::ACCESSIBLE)};
377 AddGetPropertyToInterface(desc, "ChildCount", &BridgeAccessible::GetChildCount);
378 AddGetPropertyToInterface(desc, "Name", &BridgeAccessible::GetName);
379 AddGetPropertyToInterface(desc, "Description", &BridgeAccessible::GetDescription);
380 AddGetPropertyToInterface(desc, "Parent", &BridgeAccessible::GetParent);
381 AddFunctionToInterface(desc, "GetRole", &BridgeAccessible::GetRole);
382 AddFunctionToInterface(desc, "GetRoleName", &BridgeAccessible::GetRoleName);
383 AddFunctionToInterface(desc, "GetLocalizedRoleName", &BridgeAccessible::GetLocalizedRoleName);
384 AddFunctionToInterface(desc, "GetState", &BridgeAccessible::GetStates);
385 AddFunctionToInterface(desc, "GetAttributes", &BridgeAccessible::GetAttributes);
386 AddFunctionToInterface(desc, "GetInterfaces", &BridgeAccessible::GetInterfacesAsStrings);
387 AddFunctionToInterface(desc, "GetChildAtIndex", &BridgeAccessible::GetChildAtIndex);
388 AddFunctionToInterface(desc, "GetChildren", &BridgeAccessible::GetChildren);
389 AddFunctionToInterface(desc, "GetIndexInParent", &BridgeAccessible::GetIndexInParent);
390 AddFunctionToInterface(desc, "GetNavigableAtPoint", &BridgeAccessible::GetNavigableAtPoint);
391 AddFunctionToInterface(desc, "GetNeighbor", &BridgeAccessible::GetNeighbor);
392 AddFunctionToInterface(desc, "GetDefaultLabelInfo", &BridgeAccessible::GetDefaultLabelInfo);
393 AddFunctionToInterface(desc, "DoGesture", &BridgeAccessible::DoGesture);
394 AddFunctionToInterface(desc, "GetReadingMaterial", &BridgeAccessible::GetReadingMaterial);
395 AddFunctionToInterface(desc, "GetRelationSet", &BridgeAccessible::GetRelationSet);
396 AddFunctionToInterface(desc, "SetListenPostRender", &BridgeAccessible::SetListenPostRender);
397 AddFunctionToInterface(desc, "GetNodeInfo", &BridgeAccessible::GetNodeInfo);
398 mDbusServer.addInterface("/", desc, true);
401 Accessible* BridgeAccessible::FindSelf() const
403 return FindCurrentObject();
406 Component* BridgeAccessible::GetObjectInRelation(Accessible* obj, RelationType relationType)
413 for(auto& relation : obj->GetRelationSet())
415 if(relation.mRelationType == relationType)
417 for(auto& target : relation.mTargets)
419 auto component = dynamic_cast<Component*>(target);
430 Component* BridgeAccessible::CalculateNavigableAccessibleAtPoint(Accessible* root, Point point, CoordinateType type, unsigned int maxRecursionDepth)
432 if(!root || maxRecursionDepth == 0)
437 auto rootComponent = dynamic_cast<Component*>(root);
438 LOG() << "CalculateNavigableAccessibleAtPoint: checking: " << MakeIndent(maxRecursionDepth) << GetComponentInfo(rootComponent);
440 if(rootComponent && !rootComponent->IsAccessibleContainingPoint(point, type))
445 auto children = root->GetChildren();
446 for(auto childIt = children.rbegin(); childIt != children.rend(); childIt++)
448 //check recursively all children first
449 auto result = CalculateNavigableAccessibleAtPoint(*childIt, point, type, maxRecursionDepth - 1);
458 //Found a candidate, all its children are already checked
459 auto controledBy = GetObjectInRelation(rootComponent, RelationType::CONTROLLED_BY);
462 controledBy = rootComponent;
465 if(controledBy->IsProxy() || IsObjectAcceptable(controledBy))
467 LOG() << "CalculateNavigableAccessibleAtPoint: found: " << MakeIndent(maxRecursionDepth) << GetComponentInfo(rootComponent);
474 BridgeAccessible::ReadingMaterialType BridgeAccessible::GetReadingMaterial()
476 auto self = FindSelf();
477 auto findObjectByRelationType = [this, &self](RelationType relationType) {
478 auto relations = self->GetRelationSet();
479 auto relation = std::find_if(relations.begin(),
481 [relationType](const Dali::Accessibility::Relation& relation) -> bool {
482 return relation.mRelationType == relationType;
484 return relations.end() != relation && !relation->mTargets.empty() ? relation->mTargets.back() : nullptr;
487 auto labellingObject = findObjectByRelationType(RelationType::LABELLED_BY);
488 std::string labeledByName = labellingObject ? labellingObject->GetName() : "";
490 auto describedByObject = findObjectByRelationType(RelationType::DESCRIBED_BY);
492 double currentValue = 0.0;
493 std::string currentValueText;
494 double minimumIncrement = 0.0;
495 double maximumValue = 0.0;
496 double minimumValue = 0.0;
497 auto* valueInterface = Value::DownCast(self);
500 currentValue = valueInterface->GetCurrent();
501 currentValueText = valueInterface->GetValueText();
502 minimumIncrement = valueInterface->GetMinimumIncrement();
503 maximumValue = valueInterface->GetMaximum();
504 minimumValue = valueInterface->GetMinimum();
507 int32_t firstSelectedChildIndex = -1;
508 int32_t selectedChildCount = 0;
509 auto* selfSelectionInterface = Selection::DownCast(self);
510 if(selfSelectionInterface)
512 selectedChildCount = selfSelectionInterface->GetSelectedChildrenCount();
513 auto firstSelectedChild = selfSelectionInterface->GetSelectedChild(0);
514 if(firstSelectedChild)
516 firstSelectedChildIndex = firstSelectedChild->GetIndexInParent();
520 auto childCount = static_cast<int32_t>(self->GetChildCount());
521 bool hasCheckBoxChild = false;
522 for(auto i = 0u; i < static_cast<size_t>(childCount); ++i)
524 auto child = self->GetChildAtIndex(i);
525 if(child->GetRole() == Role::CHECK_BOX)
527 hasCheckBoxChild = true;
532 auto attributes = self->GetAttributes();
533 auto itemCount = attributes.find("item_count");
534 auto atspiRole = self->GetRole();
535 int32_t listChildrenCount = 0;
536 if(itemCount != attributes.end())
538 // "item_count" gives manual control to the application, so it has priority
539 listChildrenCount = std::atoi(itemCount->second.c_str());
541 else if(atspiRole == Role::DIALOG)
543 listChildrenCount = GetItemCountOfFirstDescendantContainer(self, Role::LIST, Role::LIST_ITEM, true);
545 else if(atspiRole == Role::POPUP_MENU)
547 listChildrenCount = GetItemCountOfFirstDescendantContainer(self, Role::POPUP_MENU, Role::MENU_ITEM, false);
550 auto* textInterface = Text::DownCast(self);
551 std::string nameFromTextInterface = "";
554 nameFromTextInterface = textInterface->GetText(0, textInterface->GetCharacterCount());
557 auto name = self->GetName();
558 auto role = static_cast<uint32_t>(atspiRole);
559 auto states = self->GetStates();
560 auto localizedRoleName = self->GetLocalizedRoleName();
561 auto description = self->GetDescription();
562 auto indexInParent = static_cast<int32_t>(self->GetIndexInParent());
564 auto parent = self->GetParent();
565 auto parentRole = static_cast<uint32_t>(parent ? parent->GetRole() : Role{});
566 auto parentChildCount = parent ? static_cast<int32_t>(parent->GetChildCount()) : 0;
567 auto parentStateSet = parent ? parent->GetStates() : States{};
568 bool isSelectedInParent = false;
569 auto* parentSelectionInterface = Selection::DownCast(parent);
570 if(parentSelectionInterface)
572 isSelectedInParent = parentSelectionInterface->IsChildSelected(indexInParent);
579 nameFromTextInterface,
594 firstSelectedChildIndex,
603 BridgeAccessible::NodeInfoType BridgeAccessible::GetNodeInfo()
605 auto self = FindSelf();
606 auto roleName = self->GetRoleName();
607 auto name = self->GetName();
608 auto toolkitName = "dali";
609 auto attributes = self->GetAttributes();
610 auto states = self->GetStates();
612 auto* component = Component::DownCast(self);
613 Dali::Rect<> screenExtents = {0, 0, 0, 0};
614 Dali::Rect<> windowExtents = {0, 0, 0, 0};
617 screenExtents = component->GetExtents(CoordinateType::SCREEN);
618 windowExtents = component->GetExtents(CoordinateType::WINDOW);
621 auto* valueInterface = Value::DownCast(self);
622 double currentValue = 0.0;
623 double minimumIncrement = 0.0;
624 double maximumValue = 0.0;
625 double minimumValue = 0.0;
628 currentValue = valueInterface->GetCurrent();
629 minimumIncrement = valueInterface->GetMinimumIncrement();
630 maximumValue = valueInterface->GetMaximum();
631 minimumValue = valueInterface->GetMinimum();
640 {screenExtents.x, screenExtents.y, screenExtents.width, screenExtents.height},
641 {windowExtents.x, windowExtents.y, windowExtents.width, windowExtents.height},
648 DBus::ValueOrError<bool> BridgeAccessible::DoGesture(Dali::Accessibility::Gesture type, int32_t startPositionX, int32_t startPositionY, int32_t endPositionX, int32_t endPositionY, Dali::Accessibility::GestureState state, uint32_t eventTime)
650 // Please be aware of sending GestureInfo point in the different order with parameters
651 return FindSelf()->DoGesture(Dali::Accessibility::GestureInfo{type, startPositionX, endPositionX, startPositionY, endPositionY, state, eventTime});
654 DBus::ValueOrError<Accessible*, uint8_t, Accessible*> BridgeAccessible::GetNavigableAtPoint(int32_t x, int32_t y, uint32_t coordinateType)
656 Accessible* deputy = nullptr;
657 auto accessible = FindSelf();
658 auto cType = static_cast<CoordinateType>(coordinateType);
660 x -= mData->mExtentsOffset.first;
661 y -= mData->mExtentsOffset.second;
663 LOG() << "GetNavigableAtPoint: " << x << ", " << y << " type: " << coordinateType;
664 auto component = CalculateNavigableAccessibleAtPoint(accessible, {x, y}, cType, GET_NAVIGABLE_AT_POINT_MAX_RECURSION_DEPTH);
665 bool recurse = false;
668 recurse = component->IsProxy();
671 return {component, recurse, deputy};
674 Accessible* BridgeAccessible::GetCurrentlyHighlighted()
676 //TODO: add currently highlighted object
680 std::vector<Component*> BridgeAccessible::GetValidChildren(const std::vector<Accessible*>& children, Accessible* start)
687 std::vector<Component*> vec;
689 Dali::Rect<> scrollableParentExtents;
690 auto nonDuplicatedScrollableParents = GetNonDuplicatedScrollableParents(children.front(), start);
691 if(!nonDuplicatedScrollableParents.empty())
693 scrollableParentExtents = nonDuplicatedScrollableParents.front()->GetExtents(CoordinateType::WINDOW);
696 for(auto child : children)
698 auto* component = dynamic_cast<Component*>(child);
701 if(nonDuplicatedScrollableParents.empty() || scrollableParentExtents.Intersects(component->GetExtents(CoordinateType::WINDOW)))
703 vec.push_back(component);
711 void BridgeAccessible::SortChildrenFromTopLeft(std::vector<Dali::Accessibility::Component*>& children)
718 std::vector<Component*> sortedChildren;
720 std::sort(children.begin(), children.end(), &SortVertically);
722 for(auto& line : SplitLines(children))
724 std::sort(line.begin(), line.end(), &SortHorizontally);
725 sortedChildren.insert(sortedChildren.end(), line.begin(), line.end());
728 children = sortedChildren;
732 struct CycleDetection
734 CycleDetection(const T value)
736 mCurrentSearchSize(1),
741 bool Check(const T value)
750 mCurrentSearchSize <<= 1;
751 if(mCurrentSearchSize == 0)
753 return true; // UNDEFINED BEHAVIOR
755 mCounter = mCurrentSearchSize;
762 unsigned int mCurrentSearchSize;
763 unsigned int mCounter;
766 Accessible* BridgeAccessible::GetNextNonDefunctSibling(Accessible* obj, Accessible* start, unsigned char forward)
773 auto parent = obj->GetParent();
778 else if(parent->IsProxy())
783 auto children = GetValidChildren(parent->GetChildren(), start);
784 SortChildrenFromTopLeft(children);
786 unsigned int childrenCount = children.size();
787 if(childrenCount == 0)
792 unsigned int current = 0;
793 for(; current < childrenCount && children[current] != obj; ++current)
797 if(current >= childrenCount)
802 forward ? ++current : --current;
803 auto ret = FindNonDefunctChild(children, current, forward);
807 Accessible* BridgeAccessible::FindNonDefunctSibling(bool& areAllChildrenVisited, Accessible* node, Accessible* start, Accessible* root, unsigned char forward)
811 Accessible* sibling = GetNextNonDefunctSibling(node, start, forward);
815 areAllChildrenVisited = false; // Note that this is passed by non-const reference, so it is the caller that can determine whether this search exhausted all children.
819 node = node->GetParent();
820 if(node == nullptr || node == root)
825 // in backward traversing stop the walk up on parent
835 Accessible* BridgeAccessible::CalculateNeighbor(Accessible* root, Accessible* start, unsigned char forward, BridgeAccessible::NeighborSearchMode searchMode)
837 if(start && CheckChainEndWithAttribute(start, forward))
841 if(root && root->GetStates()[State::DEFUNCT])
845 if(start && start->GetStates()[State::DEFUNCT])
851 if(searchMode == BridgeAccessible::NeighborSearchMode::RECURSE_TO_OUTSIDE)
853 searchMode = BridgeAccessible::NeighborSearchMode::CONTINUE_AFTER_FAILED_RECURSION;
856 Accessible* node = start ? start : root;
862 // initialization of all-children-visited flag for start node - we assume
863 // that when we begin at start node and we navigate backward, then all children
864 // are visited, so navigation will ignore start's children and go to
865 // previous sibling available.
866 // Regarding condtion (start != root):
867 // The last object can be found only if areAllChildrenVisited is false.
868 // The start is same with root, when looking for the last object.
869 bool areAllChildrenVisited = (start != root) && (searchMode != BridgeAccessible::NeighborSearchMode::RECURSE_FROM_ROOT && !forward);
871 // true, if starting element should be ignored. this is only used in rare case of
872 // recursive search failing to find an object.
873 // consider tree, where element A on bus BUS_A has child B on bus BUS_B. when going "next" from
874 // element A algorithm has to descend into BUS_B and search element B and its children. this is done
875 // by returning to our caller object B with special flag set (meaning - continue the search from B on bus BUS_B).
876 // if next object will be found there (on BUS_B), then search ends. but if not, then our caller will find it out
877 // and will call us again with object A and flag searchMode set to NEIGHBOR_SEARCH_MODE_CONTINUE_AFTER_FAILED_RECURSING.
878 // this flag means, that object A was already checked previously and we should skip it and its children.
879 bool forceNext = (searchMode == BridgeAccessible::NeighborSearchMode::CONTINUE_AFTER_FAILED_RECURSION);
881 CycleDetection<Accessible*> cycleDetection(node);
884 if(node->GetStates()[State::DEFUNCT])
889 // always accept proxy object from different world
890 if(!forceNext && node->IsProxy())
895 auto children = GetValidChildren(node->GetChildren(), start);
896 SortChildrenFromTopLeft(children);
900 // 2. parent after all children in backward traversing
901 // 3. Nodes with roles: ATSPI_ROLE_PAGE_TAB, ATSPI_ROLE_POPUP_MENU and ATSPI_ROLE_DIALOG, only when looking for first or last element.
902 // Objects with those roles shouldnt be reachable, when navigating next / prev.
903 bool areAllChildrenVisitedOrMovingForward = (children.size() == 0 || forward || areAllChildrenVisited);
905 if(!forceNext && node != start && areAllChildrenVisitedOrMovingForward && IsObjectAcceptable(node))
907 if(start == NULL || IsRoleAcceptableWhenNavigatingNextPrev(node))
913 Accessible* nextRelatedInDirection = !forceNext ? GetObjectInRelation(node, forward ? RelationType::FLOWS_TO : RelationType::FLOWS_FROM) : nullptr;
914 if(nextRelatedInDirection && start && start->GetStates()[State::DEFUNCT])
916 nextRelatedInDirection = NULL;
919 unsigned char wantCycleDetection = 0;
920 if(nextRelatedInDirection)
922 node = nextRelatedInDirection;
923 wantCycleDetection = 1;
927 auto child = !forceNext && !areAllChildrenVisited ? FindNonDefunctChildWithDepthFirstSearch(node, children, forward) : nullptr;
930 wantCycleDetection = 1;
934 if(!forceNext && node == root)
938 areAllChildrenVisited = true;
939 child = FindNonDefunctSibling(areAllChildrenVisited, node, start, root, forward);
945 if(wantCycleDetection && cycleDetection.Check(node))
953 DBus::ValueOrError<Accessible*, uint8_t> BridgeAccessible::GetNeighbor(std::string rootPath, int32_t direction, int32_t searchMode)
955 auto start = FindSelf();
956 auto root = !rootPath.empty() ? Find(StripPrefix(rootPath)) : nullptr;
957 auto accessible = CalculateNeighbor(root, start, direction == 1, static_cast<NeighborSearchMode>(searchMode));
958 unsigned char recurse = 0;
961 recurse = accessible->IsProxy();
963 return {accessible, recurse};
966 Accessible* BridgeAccessible::GetParent()
968 // NOTE: currently bridge supports single application root element.
969 // only element set as application root might return nullptr from GetParent
970 // if you want more, then you need to change setApplicationRoot to
971 // add/remove ApplicationRoot and make roots a vector.
972 auto parent = FindSelf()->GetParent();
977 DBus::ValueOrError<std::vector<Accessible*>> BridgeAccessible::GetChildren()
979 return FindSelf()->GetChildren();
982 std::string BridgeAccessible::GetDescription()
984 return FindSelf()->GetDescription();
987 DBus::ValueOrError<uint32_t> BridgeAccessible::GetRole()
989 return static_cast<unsigned int>(FindSelf()->GetRole());
992 DBus::ValueOrError<std::string> BridgeAccessible::GetRoleName()
994 return FindSelf()->GetRoleName();
997 DBus::ValueOrError<std::string> BridgeAccessible::GetLocalizedRoleName()
999 return FindSelf()->GetLocalizedRoleName();
1002 DBus::ValueOrError<int32_t> BridgeAccessible::GetIndexInParent()
1004 return FindSelf()->GetIndexInParent();
1007 DBus::ValueOrError<std::array<uint32_t, 2>> BridgeAccessible::GetStates()
1009 return FindSelf()->GetStates().GetRawData();
1012 DBus::ValueOrError<std::unordered_map<std::string, std::string>> BridgeAccessible::GetAttributes()
1014 std::unordered_map<std::string, std::string> attributes = FindSelf()->GetAttributes();
1016 if(mIsScreenReaderSuppressed)
1018 attributes.insert({"suppress-screen-reader", "true"});
1024 DBus::ValueOrError<std::vector<std::string>> BridgeAccessible::GetInterfacesAsStrings()
1026 return FindSelf()->GetInterfacesAsStrings();
1029 int BridgeAccessible::GetChildCount()
1031 return FindSelf()->GetChildCount();
1034 DBus::ValueOrError<Accessible*> BridgeAccessible::GetChildAtIndex(int index)
1038 throw std::domain_error{"negative index (" + std::to_string(index) + ")"};
1040 return FindSelf()->GetChildAtIndex(static_cast<size_t>(index));
1043 std::string BridgeAccessible::GetName()
1045 return FindSelf()->GetName();
1048 DBus::ValueOrError<Accessible*, uint32_t, std::unordered_map<std::string, std::string>> BridgeAccessible::GetDefaultLabelInfo()
1050 auto* defaultLabel = GetDefaultLabel(FindSelf());
1051 DALI_ASSERT_DEBUG(defaultLabel);
1053 // By default, the text is taken from navigation context root's accessibility properties name and description.
1054 return {defaultLabel, static_cast<uint32_t>(defaultLabel->GetRole()), defaultLabel->GetAttributes()};
1057 DBus::ValueOrError<std::vector<BridgeAccessible::Relation>> BridgeAccessible::GetRelationSet()
1059 auto relations = FindSelf()->GetRelationSet();
1060 std::vector<BridgeAccessible::Relation> ret;
1062 for(auto& it : relations)
1064 ret.emplace_back(Relation{static_cast<uint32_t>(it.mRelationType), it.mTargets});
1070 DBus::ValueOrError<void> BridgeAccessible::SetListenPostRender(bool enabled)
1072 FindSelf()->SetListenPostRender(enabled);