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