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