[Tizen][ATSPI] Accessibility initial implementation
[platform/core/uifw/dali-adaptor.git] / dali / dali-bridge / src / BridgeCollection.cpp
1 #include "BridgeCollection.hpp"
2 #include <algorithm>
3 #include <iostream>
4 #include <unordered_set>
5 #include <vector>
6
7 using namespace Dali::Accessibility;
8
9 void BridgeCollection::RegisterInterfaces()
10 {
11   DBus::DBusInterfaceDescription desc{ATSPI_DBUS_INTERFACE_COLLECTION};
12   AddFunctionToInterface( desc, "GetMatches", &BridgeCollection::GetMatches );
13   dbusServer.addInterface( "/", desc, true );
14 }
15
16 Collection* BridgeCollection::FindSelf() const
17 {
18   auto s = BridgeBase::FindSelf();
19   assert( s );
20   auto s2 = dynamic_cast< Collection* >( s );
21   if( !s2 )
22     throw AccessibleError{"object " + s->GetAddress().ToString() + " doesn't have Collection interface"};
23   return s2;
24 }
25
26 enum
27 {
28   ATSPI_Collection_MATCH_INVALID,
29   ATSPI_Collection_MATCH_ALL,
30   ATSPI_Collection_MATCH_ANY,
31   ATSPI_Collection_MATCH_NONE,
32   ATSPI_Collection_MATCH_EMPTY,
33   ATSPI_Collection_MATCH_LAST_DEFINED,
34 };
35
36 struct BridgeCollection::Comparer
37 {
38   using Mode = MatchType;
39
40   enum class CompareFuncExit
41   {
42     firstFound,
43     firstNotFound
44   };
45
46   static Mode ConvertToMatchType( int32_t mode )
47   {
48     switch( mode )
49     {
50       case ATSPI_Collection_MATCH_INVALID:
51       {
52         return Mode::Invalid;
53       }
54       case ATSPI_Collection_MATCH_ALL:
55       {
56         return Mode::All;
57       }
58       case ATSPI_Collection_MATCH_ANY:
59       {
60         return Mode::Any;
61       }
62       case ATSPI_Collection_MATCH_NONE:
63       {
64         return Mode::None;
65       }
66       case ATSPI_Collection_MATCH_EMPTY:
67       {
68         return Mode::Empty;
69       }
70     }
71     return Mode::Invalid;
72   }
73
74   struct ComparerInterfaces
75   {
76     std::unordered_set< std::string > object;
77     std::vector< std::string > requested;
78     Mode mode = Mode::Invalid;
79
80     ComparerInterfaces( MatchRule* rule ) : mode( ConvertToMatchType( std::get< Index::InterfacesMatchType >( *rule ) ) )
81     {
82       requested = {std::get< Index::Interfaces >( *rule ).begin(), std::get< Index::Interfaces >( *rule ).end()};
83     }
84     void Update( Accessible* obj )
85     {
86       object.clear();
87       for( auto& q : obj->GetInterfaces() )
88         object.insert( std::move( q ) );
89     }
90     bool RequestEmpty() const { return requested.empty(); }
91     bool ObjectEmpty() const { return object.empty(); }
92     bool Compare( CompareFuncExit exit )
93     {
94       bool foundAny = false;
95       for( auto& iname : requested )
96       {
97         bool found = ( object.find( iname ) != object.end() );
98         if( found )
99           foundAny = true;
100         if( found == ( exit == CompareFuncExit::firstFound ) )
101           return found;
102       }
103       return foundAny;
104     }
105   };
106   struct ComparerAttributes
107   {
108     std::unordered_map< std::string, std::string > requested, object;
109     Mode mode = Mode::Invalid;
110
111     ComparerAttributes( MatchRule* rule ) : mode( ConvertToMatchType( std::get< Index::AttributesMatchType >( *rule ) ) )
112     {
113       requested = std::get< Index::Attributes >( *rule );
114     }
115     void Update( Accessible* obj )
116     {
117       object = obj->GetAttributes();
118     }
119     bool RequestEmpty() const { return requested.empty(); }
120     bool ObjectEmpty() const { return object.empty(); }
121     bool Compare( CompareFuncExit exit )
122     {
123       bool foundAny = false;
124       for( auto& iname : requested )
125       {
126         auto it = object.find( iname.first );
127         bool found = it != object.end() && iname.second == it->second;
128         if( found )
129           foundAny = true;
130         if( found == ( exit == CompareFuncExit::firstFound ) )
131         {
132           return found;
133         }
134       }
135       return foundAny;
136     }
137   };
138   struct ComparerRoles
139   {
140     using Roles = BitStates< 4, Role >;
141     Roles requested, object;
142     Mode mode = Mode::Invalid;
143
144     ComparerRoles( MatchRule* rule ) : mode( ConvertToMatchType( std::get< Index::RolesMatchType >( *rule ) ) )
145     {
146       requested = Roles{std::get< Index::Roles >( *rule )};
147     }
148     void Update( Accessible* obj )
149     {
150       object = {};
151       object[obj->GetRole()] = true;
152       assert( object );
153     }
154     bool RequestEmpty() const { return !requested; }
155     bool ObjectEmpty() const { return !object; }
156     bool Compare( CompareFuncExit exit )
157     {
158       switch( mode )
159       {
160         case Mode::Invalid:
161         {
162           return true;
163         }
164         case Mode::Empty:
165         case Mode::All:
166         {
167           return requested == ( object & requested );
168         }
169         case Mode::Any:
170         {
171           return bool( object & requested );
172         }
173         case Mode::None:
174         {
175           return bool( object & requested );
176         }
177       }
178       return false;
179     }
180   };
181   struct ComparerStates
182   {
183     States requested, object;
184     Mode mode = Mode::Invalid;
185
186     ComparerStates( MatchRule* rule ) : mode( ConvertToMatchType( std::get< Index::StatesMatchType >( *rule ) ) )
187     {
188       requested = States{std::get< Index::States >( *rule )};
189     }
190     void Update( Accessible* obj )
191     {
192       object = obj->GetStates();
193     }
194     bool RequestEmpty() const { return !requested; }
195     bool ObjectEmpty() const { return !object; }
196     bool Compare( CompareFuncExit exit )
197     {
198       switch( mode )
199       {
200         case Mode::Invalid:
201         {
202           return true;
203         }
204         case Mode::Empty:
205         case Mode::All:
206         {
207           return requested == ( object & requested );
208         }
209         case Mode::Any:
210         {
211           return bool( object & requested );
212         }
213         case Mode::None:
214         {
215           return bool( object & requested );
216         }
217       }
218       return false;
219     }
220   };
221
222   template < typename T >
223   bool compareFunc( T& cmp, Accessible* obj )
224   {
225     if( cmp.mode == Mode::Invalid )
226       return true;
227     cmp.Update( obj );
228     switch( cmp.mode )
229     {
230       case Mode::Any:
231       {
232         if( cmp.RequestEmpty() || cmp.ObjectEmpty() )
233           return false;
234         break;
235       }
236       case Mode::All:
237       {
238         if( cmp.RequestEmpty() )
239           return true;
240         if( cmp.ObjectEmpty() )
241           return false;
242         break;
243       }
244       case Mode::None:
245       {
246         if( cmp.RequestEmpty() || cmp.ObjectEmpty() )
247           return true;
248         break;
249       }
250       case Mode::Empty:
251       {
252         if( cmp.RequestEmpty() && cmp.ObjectEmpty() )
253           return true;
254         if( cmp.RequestEmpty() || cmp.ObjectEmpty() )
255           return false;
256         break;
257       }
258       case Mode::Invalid:
259       {
260         return true;
261       }
262     }
263
264     switch( cmp.mode )
265     {
266       case Mode::Empty:
267       case Mode::All:
268       {
269         if( !cmp.Compare( CompareFuncExit::firstNotFound ) )
270           return false;
271         break;
272       }
273       case Mode::Any:
274       {
275         if( cmp.Compare( CompareFuncExit::firstFound ) )
276           return true;
277         break;
278       }
279       case Mode::None:
280       {
281         if( cmp.Compare( CompareFuncExit::firstFound ) )
282           return false;
283         break;
284       }
285       case Mode::Invalid:
286       {
287         return true;
288       }
289     }
290     switch( cmp.mode )
291     {
292       case Mode::Empty:
293       case Mode::All:
294       case Mode::None:
295       {
296         return true;
297       }
298       case Mode::Any:
299       {
300         return false;
301       }
302       case Mode::Invalid:
303       {
304         return true;
305       }
306     }
307     return false;
308   }
309
310   ComparerInterfaces ci;
311   ComparerAttributes ca;
312   ComparerRoles cr;
313   ComparerStates cs;
314
315   Comparer( MatchRule* mr ) : ci( mr ), ca( mr ), cr( mr ), cs( mr ) {}
316
317   bool operator()( Accessible* obj )
318   {
319     return compareFunc( ci, obj ) &&
320            compareFunc( ca, obj ) &&
321            compareFunc( cr, obj ) &&
322            compareFunc( cs, obj );
323   }
324 };
325
326 void BridgeCollection::VisitNodes( Accessible* obj, std::vector< Accessible* >& result, Comparer& cmp, size_t maxCount )
327 {
328   if( result.size() >= maxCount )
329     return;
330
331   if( cmp( obj ) )
332     result.emplace_back( obj );
333
334   for( auto i = 0u; i < obj->GetChildCount(); ++i )
335     VisitNodes( obj->GetChildAtIndex( i ), result, cmp, maxCount );
336 }
337
338 DBus::ValueOrError< std::vector< Accessible* > > BridgeCollection::GetMatches( MatchRule rule, uint32_t sortBy, int32_t count, bool traverse )
339 {
340   std::vector< Accessible* > res;
341   auto self = BridgeBase::FindSelf();
342   auto matcher = Comparer{&rule};
343   VisitNodes( self, res, matcher, count );
344
345   switch( static_cast< SortOrder >( sortBy ) )
346   {
347     case SortOrder::Canonical:
348     {
349       break;
350     }
351
352     case SortOrder::ReverseCanonical:
353     {
354       std::reverse( res.begin(), res.end() );
355       break;
356     }
357
358     default:
359     {
360       throw AccessibleError{"unsupported sorting order"};
361     }
362       //TODO: other cases
363   }
364
365   return res;
366 }