/*
- * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
// EXTERNAL INCLUDES
#include <algorithm>
-#include <iostream>
#include <unordered_set>
#include <vector>
using namespace Dali::Accessibility;
+namespace
+{
+/**
+ * @brief Enumeration used for quering Accessibility objects.
+ *
+ * Refer to MatchType enumeration.
+ */
+enum class AtspiCollection
+{
+ MATCH_INVALID,
+ MATCH_ALL,
+ MATCH_ANY,
+ MATCH_NONE,
+ MATCH_EMPTY,
+ MATCH_LAST_DEFINED,
+};
+} // anonymous namespace
+
void BridgeCollection::RegisterInterfaces()
{
- DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceCollection};
- AddFunctionToInterface( desc, "GetMatches", &BridgeCollection::GetMatches );
- dbusServer.addInterface( "/", desc, true );
+ DBus::DBusInterfaceDescription desc{Accessible::GetInterfaceName(AtspiInterface::COLLECTION)};
+ AddFunctionToInterface(desc, "GetMatches", &BridgeCollection::GetMatches);
+ AddFunctionToInterface(desc, "GetMatchesInMatches", &BridgeCollection::GetMatchesInMatches);
+
+ mDbusServer.addInterface("/", desc, true);
}
Collection* BridgeCollection::FindSelf() const
{
- auto s = BridgeBase::FindSelf();
- assert( s );
- auto s2 = dynamic_cast< Collection* >( s );
- if( !s2 )
- throw std::domain_error{"object " + s->GetAddress().ToString() + " doesn't have Collection interface"};
- return s2;
+ return FindCurrentObjectWithInterface<Dali::Accessibility::AtspiInterface::COLLECTION>();
}
-enum
-{
- ATSPI_Collection_MATCH_INVALID,
- ATSPI_Collection_MATCH_ALL,
- ATSPI_Collection_MATCH_ANY,
- ATSPI_Collection_MATCH_NONE,
- ATSPI_Collection_MATCH_EMPTY,
- ATSPI_Collection_MATCH_LAST_DEFINED,
-};
-
+/**
+ * @brief The BridgeCollection::Comparer structure.
+ *
+ * Once the data is de-serialized by DBusWrapper, the data of match rule is passed
+ * to Comparer type which do the comparison against a single accessible object.
+ */
struct BridgeCollection::Comparer
{
using Mode = MatchType;
+ /**
+ * @brief Enumeration to check the object is found first.
+ */
enum class CompareFuncExit
{
FIRST_FOUND,
FIRST_NOT_FOUND
};
- static Mode ConvertToMatchType( int32_t mode )
+ static Mode ConvertToMatchType(int32_t mode)
{
- switch( mode )
+ switch(mode)
{
- case ATSPI_Collection_MATCH_INVALID:
+ case static_cast<int32_t>(AtspiCollection::MATCH_INVALID):
{
return Mode::INVALID;
}
- case ATSPI_Collection_MATCH_ALL:
+ case static_cast<int32_t>(AtspiCollection::MATCH_ALL):
{
return Mode::ALL;
}
- case ATSPI_Collection_MATCH_ANY:
+ case static_cast<int32_t>(AtspiCollection::MATCH_ANY):
{
return Mode::ANY;
}
- case ATSPI_Collection_MATCH_NONE:
+ case static_cast<int32_t>(AtspiCollection::MATCH_NONE):
{
return Mode::NONE;
}
- case ATSPI_Collection_MATCH_EMPTY:
+ case static_cast<int32_t>(AtspiCollection::MATCH_EMPTY):
{
return Mode::EMPTY;
}
return Mode::INVALID;
}
+ /**
+ * @brief The ComparerInterfaces structure
+ */
struct ComparerInterfaces
{
- std::unordered_set< std::string > object;
- std::vector< std::string > requested;
- Mode mode = Mode::INVALID;
+ std::unordered_set<std::string> mObject;
+ std::vector<std::string> mRequested;
+ Mode mMode = Mode::INVALID;
- ComparerInterfaces( MatchRule* rule ) : mode( ConvertToMatchType( std::get< Index::InterfacesMatchType >( *rule ) ) )
+ ComparerInterfaces(MatchRule* rule)
+ : mMode(ConvertToMatchType(std::get<static_cast<std::size_t>(Index::INTERFACES_MATCH_TYPE)>(*rule)))
{
- requested = {std::get< Index::Interfaces >( *rule ).begin(), std::get< Index::Interfaces >( *rule ).end()};
+ mRequested = {std::get<static_cast<std::size_t>(Index::INTERFACES)>(*rule).begin(), std::get<static_cast<std::size_t>(Index::INTERFACES)>(*rule).end()};
}
- void Update( Accessible* obj )
+
+ void Update(Accessible* obj)
{
- object.clear();
- for( auto& q : obj->GetInterfaces() )
- object.insert( std::move( q ) );
+ mObject.clear();
+ for(auto& interface : obj->GetInterfacesAsStrings())
+ {
+ mObject.insert(std::move(interface));
+ }
}
- bool RequestEmpty() const { return requested.empty(); }
- bool ObjectEmpty() const { return object.empty(); }
- bool Compare( CompareFuncExit exit )
+
+ bool IsRequestEmpty() const
+ {
+ return mRequested.empty();
+ }
+
+ bool IsObjectEmpty() const
+ {
+ return mObject.empty();
+ }
+
+ bool Compare(CompareFuncExit exit)
{
bool foundAny = false;
- for( auto& iname : requested )
+ for(auto& iname : mRequested)
{
- bool found = ( object.find( iname ) != object.end() );
- if( found )
+ bool found = (mObject.find(iname) != mObject.end());
+ if(found)
+ {
foundAny = true;
- if( found == ( exit == CompareFuncExit::FIRST_FOUND ) )
+ }
+
+ if(found == (exit == CompareFuncExit::FIRST_FOUND))
+ {
return found;
+ }
}
return foundAny;
}
- };
+ }; // ComparerInterfaces struct
+
+ /**
+ * @brief The ComparerAttributes structure
+ */
struct ComparerAttributes
{
- std::unordered_map< std::string, std::string > requested, object;
- Mode mode = Mode::INVALID;
+ std::unordered_map<std::string, std::string> mRequested;
+ std::unordered_map<std::string, std::string> mObject;
+ Mode mMode = Mode::INVALID;
+
+ ComparerAttributes(MatchRule* rule)
+ : mMode(ConvertToMatchType(std::get<static_cast<std::size_t>(Index::ATTRIBUTES_MATCH_TYPE)>(*rule)))
+ {
+ mRequested = std::get<static_cast<std::size_t>(Index::ATTRIBUTES)>(*rule);
+ }
+
+ void Update(Accessible* obj)
+ {
+ mObject = obj->GetAttributes();
+ }
- ComparerAttributes( MatchRule* rule ) : mode( ConvertToMatchType( std::get< Index::AttributesMatchType >( *rule ) ) )
+ bool IsRequestEmpty() const
{
- requested = std::get< Index::Attributes >( *rule );
+ return mRequested.empty();
}
- void Update( Accessible* obj )
+
+ bool IsObjectEmpty() const
{
- object = obj->GetAttributes();
+ return mObject.empty();
}
- bool RequestEmpty() const { return requested.empty(); }
- bool ObjectEmpty() const { return object.empty(); }
- bool Compare( CompareFuncExit exit )
+
+ bool Compare(CompareFuncExit exit)
{
bool foundAny = false;
- for( auto& iname : requested )
+ for(auto& iname : mRequested)
{
- auto it = object.find( iname.first );
- bool found = it != object.end() && iname.second == it->second;
- if( found )
+ auto it = mObject.find(iname.first);
+ bool found = it != mObject.end() && iname.second == it->second;
+ if(found)
+ {
foundAny = true;
- if( found == ( exit == CompareFuncExit::FIRST_FOUND ) )
+ }
+
+ if(found == (exit == CompareFuncExit::FIRST_FOUND))
{
return found;
}
}
return foundAny;
}
- };
+ }; // ComparerAttributes struct
+
+ /**
+ * @brief The ComparerRoles structure
+ */
struct ComparerRoles
{
- using Roles = BitSets< 4, Role >;
- Roles requested, object;
- Mode mode = Mode::INVALID;
+ using Roles = EnumBitSet<Role, Role::MAX_COUNT>;
- ComparerRoles( MatchRule* rule ) : mode( ConvertToMatchType( std::get< Index::RolesMatchType >( *rule ) ) )
+ Roles mRequested;
+ Roles mObject;
+ Mode mMode = Mode::INVALID;
+
+ ComparerRoles(MatchRule* rule)
+ : mMode(ConvertToMatchType(std::get<static_cast<std::size_t>(Index::ROLES_MATCH_TYPE)>(*rule)))
+ {
+ mRequested = Roles{std::get<static_cast<std::size_t>(Index::ROLES)>(*rule)};
+ }
+
+ void Update(Accessible* obj)
{
- requested = Roles{std::get< Index::Roles >( *rule )};
+ mObject = {};
+ mObject[obj->GetRole()] = true;
+ assert(mObject);
}
- void Update( Accessible* obj )
+
+ bool IsRequestEmpty() const
{
- object = {};
- object[obj->GetRole()] = true;
- assert( object );
+ return !mRequested;
}
- bool RequestEmpty() const { return !requested; }
- bool ObjectEmpty() const { return !object; }
- bool Compare( CompareFuncExit exit )
+
+ bool IsObjectEmpty() const
{
- switch( mode )
+ return !mObject;
+ }
+
+ bool Compare(CompareFuncExit exit)
+ {
+ switch(mMode)
{
case Mode::INVALID:
{
case Mode::EMPTY:
case Mode::ALL:
{
- return requested == ( object & requested );
+ return mRequested == (mObject & mRequested);
}
case Mode::ANY:
{
- return bool( object & requested );
+ return bool(mObject & mRequested);
}
case Mode::NONE:
{
- return bool( object & requested );
+ return bool(mObject & mRequested);
}
}
return false;
}
- };
+ }; // ComparerRoles struct
+
+ /**
+ * @brief The ComparerStates structure
+ */
struct ComparerStates
{
- States requested, object;
- Mode mode = Mode::INVALID;
+ States mRequested;
+ States mObject;
+ Mode mMode = Mode::INVALID;
+
+ ComparerStates(MatchRule* rule)
+ : mMode(ConvertToMatchType(std::get<static_cast<std::size_t>(Index::STATES_MATCH_TYPE)>(*rule)))
+ {
+ mRequested = States{std::get<static_cast<std::size_t>(Index::STATES)>(*rule)};
+ }
+
+ void Update(Accessible* obj)
+ {
+ mObject = obj->GetStates();
+ }
- ComparerStates( MatchRule* rule ) : mode( ConvertToMatchType( std::get< Index::StatesMatchType >( *rule ) ) )
+ bool IsRequestEmpty() const
{
- requested = States{std::get< Index::States >( *rule )};
+ return !mRequested;
}
- void Update( Accessible* obj )
+
+ bool IsObjectEmpty() const
{
- object = obj->GetStates();
+ return !mObject;
}
- bool RequestEmpty() const { return !requested; }
- bool ObjectEmpty() const { return !object; }
- bool Compare( CompareFuncExit exit )
+
+ bool Compare(CompareFuncExit exit)
{
- switch( mode )
+ switch(mMode)
{
case Mode::INVALID:
{
case Mode::EMPTY:
case Mode::ALL:
{
- return requested == ( object & requested );
+ return mRequested == (mObject & mRequested);
}
case Mode::ANY:
{
- return bool( object & requested );
+ return bool(mObject & mRequested);
}
case Mode::NONE:
{
- return bool( object & requested );
+ return bool(mObject & mRequested);
}
}
return false;
}
- };
+ }; // ComparerStates struct
- template < typename T >
- bool compareFunc( T& cmp, Accessible* obj )
+ template<typename T>
+ bool CompareFunc(T& cmp, Accessible* obj)
{
- if( cmp.mode == Mode::INVALID )
+ if(cmp.mMode == Mode::INVALID)
+ {
return true;
- cmp.Update( obj );
- switch( cmp.mode )
+ }
+
+ cmp.Update(obj);
+ switch(cmp.mMode)
{
case Mode::ANY:
{
- if( cmp.RequestEmpty() || cmp.ObjectEmpty() )
+ if(cmp.IsRequestEmpty() || cmp.IsObjectEmpty())
+ {
return false;
+ }
break;
}
case Mode::ALL:
{
- if( cmp.RequestEmpty() )
+ if(cmp.IsRequestEmpty())
+ {
return true;
- if( cmp.ObjectEmpty() )
+ }
+ if(cmp.IsObjectEmpty())
+ {
return false;
+ }
break;
}
case Mode::NONE:
{
- if( cmp.RequestEmpty() || cmp.ObjectEmpty() )
+ if(cmp.IsRequestEmpty() || cmp.IsObjectEmpty())
+ {
return true;
+ }
break;
}
case Mode::EMPTY:
{
- if( cmp.RequestEmpty() && cmp.ObjectEmpty() )
+ if(cmp.IsRequestEmpty() && cmp.IsObjectEmpty())
+ {
return true;
- if( cmp.RequestEmpty() || cmp.ObjectEmpty() )
+ }
+ if(cmp.IsRequestEmpty() || cmp.IsObjectEmpty())
+ {
return false;
+ }
break;
}
case Mode::INVALID:
}
}
- switch( cmp.mode )
+ switch(cmp.mMode)
{
case Mode::EMPTY:
case Mode::ALL:
{
- if( !cmp.Compare( CompareFuncExit::FIRST_NOT_FOUND ) )
+ if(!cmp.Compare(CompareFuncExit::FIRST_NOT_FOUND))
+ {
return false;
+ }
break;
}
case Mode::ANY:
{
- if( cmp.Compare( CompareFuncExit::FIRST_FOUND ) )
+ if(cmp.Compare(CompareFuncExit::FIRST_FOUND))
+ {
return true;
+ }
break;
}
case Mode::NONE:
{
- if( cmp.Compare( CompareFuncExit::FIRST_FOUND ) )
+ if(cmp.Compare(CompareFuncExit::FIRST_FOUND))
+ {
return false;
+ }
break;
}
case Mode::INVALID:
return true;
}
}
- switch( cmp.mode )
+
+ switch(cmp.mMode)
{
case Mode::EMPTY:
case Mode::ALL:
return false;
}
- ComparerInterfaces ci;
- ComparerAttributes ca;
- ComparerRoles cr;
- ComparerStates cs;
+ Comparer(MatchRule* rule)
+ : mInterface(rule),
+ mAttribute(rule),
+ mRole(rule),
+ mState(rule)
+ {
+ }
- Comparer( MatchRule* mr ) : ci( mr ), ca( mr ), cr( mr ), cs( mr ) {}
+ bool operator()(Accessible* obj)
+ {
+ return CompareFunc(mInterface, obj) &&
+ CompareFunc(mAttribute, obj) &&
+ CompareFunc(mRole, obj) &&
+ CompareFunc(mState, obj);
+ }
- bool operator()( Accessible* obj )
+ bool IsShowing(Accessible* obj)
{
- return compareFunc( ci, obj ) &&
- compareFunc( ca, obj ) &&
- compareFunc( cr, obj ) &&
- compareFunc( cs, obj );
+ if (mState.mMode == Mode::NONE) return true;
+ mState.Update(obj);
+ if (mState.IsRequestEmpty() || mState.IsObjectEmpty()) return true;
+ if (!mState.mRequested[State::SHOWING] ) return true;
+ if (mState.mObject[State::SHOWING]) return true;
+
+ return false;
}
-};
-void BridgeCollection::VisitNodes( Accessible* obj, std::vector< Accessible* >& result, Comparer& cmp, size_t maxCount )
+ ComparerInterfaces mInterface;
+ ComparerAttributes mAttribute;
+ ComparerRoles mRole;
+ ComparerStates mState;
+}; // BridgeCollection::Comparer struct
+
+
+void BridgeCollection::VisitNodes(Accessible* obj, std::vector<Accessible*>& result, Comparer& comparer, size_t maxCount)
{
- if( maxCount > 0 && result.size() >= maxCount )
+ if(maxCount > 0 && result.size() >= maxCount)
+ {
+ return;
+ }
+
+ if(comparer(obj))
+ {
+ result.emplace_back(obj);
+ // the code below will never return for maxCount equal 0
+ if(result.size() == maxCount)
+ {
+ return;
+ }
+ }
+
+ if (!comparer.IsShowing(obj))
+ {
return;
+ }
- if( cmp( obj ) )
- result.emplace_back( obj );
+ for(auto i = 0u; i < obj->GetChildCount(); ++i)
+ {
+ VisitNodes(obj->GetChildAtIndex(i), result, comparer, maxCount);
+ }
+}
- for( auto i = 0u; i < obj->GetChildCount(); ++i )
- VisitNodes( obj->GetChildAtIndex( i ), result, cmp, maxCount );
+DBus::ValueOrError<std::vector<Accessible*> > BridgeCollection::GetMatches(MatchRule rule, uint32_t sortBy, int32_t count, bool traverse)
+{
+ std::vector<Accessible*> res;
+ auto self = BridgeBase::FindCurrentObject();
+ auto matcher = Comparer{&rule};
+ VisitNodes(self, res, matcher, count);
+
+ switch(static_cast<SortOrder>(sortBy))
+ {
+ case SortOrder::CANONICAL:
+ {
+ break;
+ }
+
+ case SortOrder::REVERSE_CANONICAL:
+ {
+ std::reverse(res.begin(), res.end());
+ break;
+ }
+
+ default:
+ {
+ throw std::domain_error{"unsupported sorting order"};
+ }
+ //TODO: other cases
+ }
+
+ return res;
}
-DBus::ValueOrError< std::vector< Accessible* > > BridgeCollection::GetMatches( MatchRule rule, uint32_t sortBy, int32_t count, bool traverse )
+DBus::ValueOrError<std::vector<Accessible*> > BridgeCollection::GetMatchesInMatches(MatchRule firstRule, MatchRule secondRule, uint32_t sortBy, int32_t firstCount, int32_t secondCount, bool traverse)
{
- std::vector< Accessible* > res;
- auto self = BridgeBase::FindSelf();
- auto matcher = Comparer{&rule};
- VisitNodes( self, res, matcher, count );
+ std::vector<Accessible*> res;
+ std::vector<Accessible*> firstRes;
+ std::vector<Accessible*> secondRes;
+ auto self = BridgeBase::FindCurrentObject();
+ auto firstMatcher = Comparer{&firstRule};
+ auto secondMatcher = Comparer{&secondRule};
+ VisitNodes(self, firstRes, firstMatcher, firstCount);
+
+ for (auto &obj : firstRes)
+ {
+ VisitNodes(obj, secondRes, secondMatcher, secondCount);
+
+ res.insert(res.end(), secondRes.begin(), secondRes.end());
+ secondRes.clear();
+ }
- switch( static_cast< SortOrder >( sortBy ) )
+ switch(static_cast<SortOrder>(sortBy))
{
case SortOrder::CANONICAL:
{
case SortOrder::REVERSE_CANONICAL:
{
- std::reverse( res.begin(), res.end() );
+ std::reverse(res.begin(), res.end());
break;
}