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