+ }
+
+ auto childrenCount = children.size();
+ if(childrenCount > 0)
+ {
+ const bool isShowing = GetScrollableParent(node) == nullptr ? node->GetStates()[State::SHOWING] : true;
+ if(isShowing)
+ {
+ return FindNonDefunctChild(children, forward ? 0 : childrenCount - 1, forward);
+ }
+ }
+ return nullptr;
+}
+
+static bool CheckChainEndWithAttribute(Accessible* obj, unsigned char forward)
+{
+ if(!obj)
+ {
+ return false;
+ }
+
+ auto attrs = obj->GetAttributes();
+ for(auto& attr : attrs)
+ {
+ if(attr.first == "relation_chain_end")
+ {
+ if((attr.second == "prev,end" && forward == 0) || (attr.second == "next,end" && forward == 1) || attr.second == "prev,next,end")
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static Accessible* GetDeputyOfProxyInParent(Accessible* obj)
+{
+ return nullptr;
+}
+
+static std::vector<Component*> GetScrollableParents(Accessible *accessible)
+{
+ std::vector<Component*> scrollableParents;
+
+ while(accessible)
+ {
+ accessible = accessible->GetParent();
+ auto component = dynamic_cast<Component*>(accessible);
+ if(component && component->IsScrollable())
+ {
+ scrollableParents.push_back(component);
+ }
+ }
+ return scrollableParents;
+}
+
+static std::vector<Component*> GetNonDuplicatedScrollableParents(Accessible *child, Accessible *start)
+{
+ auto scrollableParentsOfChild = GetScrollableParents(child);
+ auto scrollableParentsOfStart = GetScrollableParents(start);
+
+ // find the first different scrollable parent by comparing from top to bottom.
+ // since it can not be the same after that, there is no need to compare.
+ while(!scrollableParentsOfChild.empty() && !scrollableParentsOfStart.empty() && scrollableParentsOfChild.back() == scrollableParentsOfStart.back())
+ {
+ scrollableParentsOfChild.pop_back();
+ scrollableParentsOfStart.pop_back();
+ }
+
+ return scrollableParentsOfChild;
+}
+
+} // anonymous namespace
+
+
+BridgeAccessible::BridgeAccessible()
+{
+}
+
+void BridgeAccessible::RegisterInterfaces()
+{
+ DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceAccessible};
+ AddGetPropertyToInterface(desc, "ChildCount", &BridgeAccessible::GetChildCount);
+ AddGetPropertyToInterface(desc, "Name", &BridgeAccessible::GetName);
+ AddGetPropertyToInterface(desc, "Description", &BridgeAccessible::GetDescription);
+ AddGetPropertyToInterface(desc, "Parent", &BridgeAccessible::GetParent);
+ AddFunctionToInterface(desc, "GetRole", &BridgeAccessible::GetRole);
+ AddFunctionToInterface(desc, "GetRoleName", &BridgeAccessible::GetRoleName);
+ AddFunctionToInterface(desc, "GetLocalizedRoleName", &BridgeAccessible::GetLocalizedRoleName);
+ AddFunctionToInterface(desc, "GetState", &BridgeAccessible::GetStates);
+ AddFunctionToInterface(desc, "GetAttributes", &BridgeAccessible::GetAttributes);
+ AddFunctionToInterface(desc, "GetInterfaces", &BridgeAccessible::GetInterfaces);
+ AddFunctionToInterface(desc, "GetChildAtIndex", &BridgeAccessible::GetChildAtIndex);
+ AddFunctionToInterface(desc, "GetChildren", &BridgeAccessible::GetChildren);
+ AddFunctionToInterface(desc, "GetIndexInParent", &BridgeAccessible::GetIndexInParent);
+ AddFunctionToInterface(desc, "GetNavigableAtPoint", &BridgeAccessible::GetNavigableAtPoint);
+ AddFunctionToInterface(desc, "GetNeighbor", &BridgeAccessible::GetNeighbor);
+ AddFunctionToInterface(desc, "GetDefaultLabelInfo", &BridgeAccessible::GetDefaultLabelInfo);
+ AddFunctionToInterface(desc, "DoGesture", &BridgeAccessible::DoGesture);
+ AddFunctionToInterface(desc, "GetReadingMaterial", &BridgeAccessible::GetReadingMaterial);
+ AddFunctionToInterface(desc, "GetRelationSet", &BridgeAccessible::GetRelationSet);
+ mDbusServer.addInterface("/", desc, true);
+}
+
+Component* BridgeAccessible::GetObjectInRelation(Accessible* obj, RelationType relationType)
+{
+ if(!obj)
+ {
+ return nullptr;
+ }
+