82524657fdd115c804ff4816ed42700f99fb7fc6
[platform/core/uifw/dali-adaptor.git] / dali / internal / accessibility / bridge / bridge-collection.cpp
1 /*
2  * Copyright (c) 2021 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   mDbusServer.addInterface("/", desc, true);
34 }
35
36 Collection* BridgeCollection::FindSelf() const
37 {
38   auto self = BridgeBase::FindSelf();
39   assert(self);
40   auto collectionInterface = dynamic_cast<Collection*>(self);
41   if(!collectionInterface)
42   {
43     throw std::domain_error{"object " + self->GetAddress().ToString() + " doesn't have Collection interface"};
44   }
45   return collectionInterface;
46 }
47
48 enum
49 {
50   ATSPI_Collection_MATCH_INVALID,
51   ATSPI_Collection_MATCH_ALL,
52   ATSPI_Collection_MATCH_ANY,
53   ATSPI_Collection_MATCH_NONE,
54   ATSPI_Collection_MATCH_EMPTY,
55   ATSPI_Collection_MATCH_LAST_DEFINED,
56 };
57
58 struct BridgeCollection::Comparer
59 {
60   using Mode = MatchType;
61
62   enum class CompareFuncExit
63   {
64     FIRST_FOUND,
65     FIRST_NOT_FOUND
66   };
67
68   static Mode ConvertToMatchType(int32_t mode)
69   {
70     switch(mode)
71     {
72       case ATSPI_Collection_MATCH_INVALID:
73       {
74         return Mode::INVALID;
75       }
76       case ATSPI_Collection_MATCH_ALL:
77       {
78         return Mode::ALL;
79       }
80       case ATSPI_Collection_MATCH_ANY:
81       {
82         return Mode::ANY;
83       }
84       case ATSPI_Collection_MATCH_NONE:
85       {
86         return Mode::NONE;
87       }
88       case ATSPI_Collection_MATCH_EMPTY:
89       {
90         return Mode::EMPTY;
91       }
92     }
93     return Mode::INVALID;
94   }
95
96   struct ComparerInterfaces
97   {
98     std::unordered_set<std::string> object;
99     std::vector<std::string>        requested;
100     Mode                            mode = Mode::INVALID;
101
102     ComparerInterfaces(MatchRule* rule)
103     : mode(ConvertToMatchType(std::get<Index::InterfacesMatchType>(*rule)))
104     {
105       requested = {std::get<Index::Interfaces>(*rule).begin(), std::get<Index::Interfaces>(*rule).end()};
106     }
107
108     void Update(Accessible* obj)
109     {
110       object.clear();
111       for(auto& interface : obj->GetInterfaces())
112       {
113         object.insert(std::move(interface));
114       }
115     }
116
117     bool RequestEmpty() const
118     {
119       return requested.empty();
120     }
121
122     bool ObjectEmpty() const
123     {
124       return object.empty();
125     }
126
127     bool Compare(CompareFuncExit exit)
128     {
129       bool foundAny = false;
130       for(auto& iname : requested)
131       {
132         bool found = (object.find(iname) != object.end());
133         if(found)
134         {
135           foundAny = true;
136         }
137
138         if(found == (exit == CompareFuncExit::FIRST_FOUND))
139         {
140           return found;
141         }
142       }
143       return foundAny;
144     }
145   }; // ComparerInterfaces struct
146
147   struct ComparerAttributes
148   {
149     std::unordered_map<std::string, std::string> requested, object;
150     Mode                                         mode = Mode::INVALID;
151
152     ComparerAttributes(MatchRule* rule)
153     : mode(ConvertToMatchType(std::get<Index::AttributesMatchType>(*rule)))
154     {
155       requested = std::get<Index::Attributes>(*rule);
156     }
157
158     void Update(Accessible* obj)
159     {
160       object = obj->GetAttributes();
161     }
162
163     bool RequestEmpty() const
164     {
165       return requested.empty();
166     }
167
168     bool ObjectEmpty() const
169     {
170       return object.empty();
171     }
172
173     bool Compare(CompareFuncExit exit)
174     {
175       bool foundAny = false;
176       for(auto& iname : requested)
177       {
178         auto it    = object.find(iname.first);
179         bool found = it != object.end() && iname.second == it->second;
180         if(found)
181         {
182           foundAny = true;
183         }
184
185         if(found == (exit == CompareFuncExit::FIRST_FOUND))
186         {
187           return found;
188         }
189       }
190       return foundAny;
191     }
192   }; // ComparerAttributes struct
193
194   struct ComparerRoles
195   {
196     using Roles = BitSets<4, Role>;
197     Roles requested, object;
198     Mode  mode = Mode::INVALID;
199
200     ComparerRoles(MatchRule* rule)
201     : mode(ConvertToMatchType(std::get<Index::RolesMatchType>(*rule)))
202     {
203       requested = Roles{std::get<Index::Roles>(*rule)};
204     }
205
206     void Update(Accessible* obj)
207     {
208       object                 = {};
209       object[obj->GetRole()] = true;
210       assert(object);
211     }
212
213     bool RequestEmpty() const
214     {
215       return !requested;
216     }
217
218     bool ObjectEmpty() const
219     {
220       return !object;
221     }
222
223     bool Compare(CompareFuncExit exit)
224     {
225       switch(mode)
226       {
227         case Mode::INVALID:
228         {
229           return true;
230         }
231         case Mode::EMPTY:
232         case Mode::ALL:
233         {
234           return requested == (object & requested);
235         }
236         case Mode::ANY:
237         {
238           return bool(object & requested);
239         }
240         case Mode::NONE:
241         {
242           return bool(object & requested);
243         }
244       }
245       return false;
246     }
247   }; // ComparerRoles struct
248
249   struct ComparerStates
250   {
251     States requested, object;
252     Mode   mode = Mode::INVALID;
253
254     ComparerStates(MatchRule* rule)
255     : mode(ConvertToMatchType(std::get<Index::StatesMatchType>(*rule)))
256     {
257       requested = States{std::get<Index::States>(*rule)};
258     }
259
260     void Update(Accessible* obj)
261     {
262       object = obj->GetStates();
263     }
264
265     bool RequestEmpty() const
266     {
267       return !requested;
268     }
269
270     bool ObjectEmpty() const
271     {
272       return !object;
273     }
274
275     bool Compare(CompareFuncExit exit)
276     {
277       switch(mode)
278       {
279         case Mode::INVALID:
280         {
281           return true;
282         }
283         case Mode::EMPTY:
284         case Mode::ALL:
285         {
286           return requested == (object & requested);
287         }
288         case Mode::ANY:
289         {
290           return bool(object & requested);
291         }
292         case Mode::NONE:
293         {
294           return bool(object & requested);
295         }
296       }
297       return false;
298     }
299   }; // ComparerStates struct
300
301   template<typename T>
302   bool CompareFunc(T& cmp, Accessible* obj)
303   {
304     if(cmp.mode == Mode::INVALID)
305     {
306       return true;
307     }
308
309     cmp.Update(obj);
310     switch(cmp.mode)
311     {
312       case Mode::ANY:
313       {
314         if(cmp.RequestEmpty() || cmp.ObjectEmpty())
315         {
316           return false;
317         }
318         break;
319       }
320       case Mode::ALL:
321       {
322         if(cmp.RequestEmpty())
323         {
324           return true;
325         }
326         if(cmp.ObjectEmpty())
327         {
328           return false;
329         }
330         break;
331       }
332       case Mode::NONE:
333       {
334         if(cmp.RequestEmpty() || cmp.ObjectEmpty())
335         {
336           return true;
337         }
338         break;
339       }
340       case Mode::EMPTY:
341       {
342         if(cmp.RequestEmpty() && cmp.ObjectEmpty())
343         {
344           return true;
345         }
346         if(cmp.RequestEmpty() || cmp.ObjectEmpty())
347         {
348           return false;
349         }
350         break;
351       }
352       case Mode::INVALID:
353       {
354         return true;
355       }
356     }
357
358     switch(cmp.mode)
359     {
360       case Mode::EMPTY:
361       case Mode::ALL:
362       {
363         if(!cmp.Compare(CompareFuncExit::FIRST_NOT_FOUND))
364         {
365           return false;
366         }
367         break;
368       }
369       case Mode::ANY:
370       {
371         if(cmp.Compare(CompareFuncExit::FIRST_FOUND))
372         {
373           return true;
374         }
375         break;
376       }
377       case Mode::NONE:
378       {
379         if(cmp.Compare(CompareFuncExit::FIRST_FOUND))
380         {
381           return false;
382         }
383         break;
384       }
385       case Mode::INVALID:
386       {
387         return true;
388       }
389     }
390     switch(cmp.mode)
391     {
392       case Mode::EMPTY:
393       case Mode::ALL:
394       case Mode::NONE:
395       {
396         return true;
397       }
398       case Mode::ANY:
399       {
400         return false;
401       }
402       case Mode::INVALID:
403       {
404         return true;
405       }
406     }
407     return false;
408   }
409
410   ComparerInterfaces interface;
411   ComparerAttributes attribute;
412   ComparerRoles      role;
413   ComparerStates     state;
414
415   Comparer(MatchRule* mr)
416   : interface(mr),
417     attribute(mr),
418     role(mr),
419     state(mr)
420   {
421   }
422
423   bool operator()(Accessible* obj)
424   {
425     return CompareFunc(interface, obj) &&
426            CompareFunc(attribute, obj) &&
427            CompareFunc(role, obj) &&
428            CompareFunc(state, obj);
429   }
430 }; // BridgeCollection::Comparer struct
431
432 void BridgeCollection::VisitNodes(Accessible* obj, std::vector<Accessible*>& result, Comparer& cmp, size_t maxCount)
433 {
434   if(maxCount > 0 && result.size() >= maxCount)
435   {
436     return;
437   }
438
439   if(cmp(obj))
440   {
441     result.emplace_back(obj);
442   }
443
444   for(auto i = 0u; i < obj->GetChildCount(); ++i)
445   {
446     VisitNodes(obj->GetChildAtIndex(i), result, cmp, maxCount);
447   }
448 }
449
450 DBus::ValueOrError<std::vector<Accessible*> > BridgeCollection::GetMatches(MatchRule rule, uint32_t sortBy, int32_t count, bool traverse)
451 {
452   std::vector<Accessible*> res;
453   auto                     self    = BridgeBase::FindSelf();
454   auto                     matcher = Comparer{&rule};
455   VisitNodes(self, res, matcher, count);
456
457   switch(static_cast<SortOrder>(sortBy))
458   {
459     case SortOrder::CANONICAL:
460     {
461       break;
462     }
463
464     case SortOrder::REVERSE_CANONICAL:
465     {
466       std::reverse(res.begin(), res.end());
467       break;
468     }
469
470     default:
471     {
472       throw std::domain_error{"unsupported sorting order"};
473     }
474       //TODO: other cases
475   }
476
477   return res;
478 }