b2e0f065ea6f495ec7eb6fb5a3ba7340220ed774
[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   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)
101     : mode(ConvertToMatchType(std::get<Index::InterfacesMatchType>(*rule)))
102     {
103       requested = {std::get<Index::Interfaces>(*rule).begin(), std::get<Index::Interfaces>(*rule).end()};
104     }
105     void Update(Accessible* obj)
106     {
107       object.clear();
108       for(auto& q : obj->GetInterfaces())
109         object.insert(std::move(q));
110     }
111     bool RequestEmpty() const
112     {
113       return requested.empty();
114     }
115     bool ObjectEmpty() const
116     {
117       return object.empty();
118     }
119     bool Compare(CompareFuncExit exit)
120     {
121       bool foundAny = false;
122       for(auto& iname : requested)
123       {
124         bool found = (object.find(iname) != object.end());
125         if(found)
126           foundAny = true;
127         if(found == (exit == CompareFuncExit::FIRST_FOUND))
128           return found;
129       }
130       return foundAny;
131     }
132   };
133   struct ComparerAttributes
134   {
135     std::unordered_map<std::string, std::string> requested, object;
136     Mode                                         mode = Mode::INVALID;
137
138     ComparerAttributes(MatchRule* rule)
139     : mode(ConvertToMatchType(std::get<Index::AttributesMatchType>(*rule)))
140     {
141       requested = std::get<Index::Attributes>(*rule);
142     }
143     void Update(Accessible* obj)
144     {
145       object = obj->GetAttributes();
146     }
147     bool RequestEmpty() const
148     {
149       return requested.empty();
150     }
151     bool ObjectEmpty() const
152     {
153       return object.empty();
154     }
155     bool Compare(CompareFuncExit exit)
156     {
157       bool foundAny = false;
158       for(auto& iname : requested)
159       {
160         auto it    = object.find(iname.first);
161         bool found = it != object.end() && iname.second == it->second;
162         if(found)
163           foundAny = true;
164         if(found == (exit == CompareFuncExit::FIRST_FOUND))
165         {
166           return found;
167         }
168       }
169       return foundAny;
170     }
171   };
172   struct ComparerRoles
173   {
174     using Roles = BitSets<4, Role>;
175     Roles requested, object;
176     Mode  mode = Mode::INVALID;
177
178     ComparerRoles(MatchRule* rule)
179     : mode(ConvertToMatchType(std::get<Index::RolesMatchType>(*rule)))
180     {
181       requested = Roles{std::get<Index::Roles>(*rule)};
182     }
183     void Update(Accessible* obj)
184     {
185       object                 = {};
186       object[obj->GetRole()] = true;
187       assert(object);
188     }
189     bool RequestEmpty() const
190     {
191       return !requested;
192     }
193     bool ObjectEmpty() const
194     {
195       return !object;
196     }
197     bool Compare(CompareFuncExit exit)
198     {
199       switch(mode)
200       {
201         case Mode::INVALID:
202         {
203           return true;
204         }
205         case Mode::EMPTY:
206         case Mode::ALL:
207         {
208           return requested == (object & requested);
209         }
210         case Mode::ANY:
211         {
212           return bool(object & requested);
213         }
214         case Mode::NONE:
215         {
216           return bool(object & requested);
217         }
218       }
219       return false;
220     }
221   };
222   struct ComparerStates
223   {
224     States requested, object;
225     Mode   mode = Mode::INVALID;
226
227     ComparerStates(MatchRule* rule)
228     : mode(ConvertToMatchType(std::get<Index::StatesMatchType>(*rule)))
229     {
230       requested = States{std::get<Index::States>(*rule)};
231     }
232     void Update(Accessible* obj)
233     {
234       object = obj->GetStates();
235     }
236     bool RequestEmpty() const
237     {
238       return !requested;
239     }
240     bool ObjectEmpty() const
241     {
242       return !object;
243     }
244     bool Compare(CompareFuncExit exit)
245     {
246       switch(mode)
247       {
248         case Mode::INVALID:
249         {
250           return true;
251         }
252         case Mode::EMPTY:
253         case Mode::ALL:
254         {
255           return requested == (object & requested);
256         }
257         case Mode::ANY:
258         {
259           return bool(object & requested);
260         }
261         case Mode::NONE:
262         {
263           return bool(object & requested);
264         }
265       }
266       return false;
267     }
268   };
269
270   template<typename T>
271   bool compareFunc(T& cmp, Accessible* obj)
272   {
273     if(cmp.mode == Mode::INVALID)
274       return true;
275     cmp.Update(obj);
276     switch(cmp.mode)
277     {
278       case Mode::ANY:
279       {
280         if(cmp.RequestEmpty() || cmp.ObjectEmpty())
281           return false;
282         break;
283       }
284       case Mode::ALL:
285       {
286         if(cmp.RequestEmpty())
287           return true;
288         if(cmp.ObjectEmpty())
289           return false;
290         break;
291       }
292       case Mode::NONE:
293       {
294         if(cmp.RequestEmpty() || cmp.ObjectEmpty())
295           return true;
296         break;
297       }
298       case Mode::EMPTY:
299       {
300         if(cmp.RequestEmpty() && cmp.ObjectEmpty())
301           return true;
302         if(cmp.RequestEmpty() || cmp.ObjectEmpty())
303           return false;
304         break;
305       }
306       case Mode::INVALID:
307       {
308         return true;
309       }
310     }
311
312     switch(cmp.mode)
313     {
314       case Mode::EMPTY:
315       case Mode::ALL:
316       {
317         if(!cmp.Compare(CompareFuncExit::FIRST_NOT_FOUND))
318           return false;
319         break;
320       }
321       case Mode::ANY:
322       {
323         if(cmp.Compare(CompareFuncExit::FIRST_FOUND))
324           return true;
325         break;
326       }
327       case Mode::NONE:
328       {
329         if(cmp.Compare(CompareFuncExit::FIRST_FOUND))
330           return false;
331         break;
332       }
333       case Mode::INVALID:
334       {
335         return true;
336       }
337     }
338     switch(cmp.mode)
339     {
340       case Mode::EMPTY:
341       case Mode::ALL:
342       case Mode::NONE:
343       {
344         return true;
345       }
346       case Mode::ANY:
347       {
348         return false;
349       }
350       case Mode::INVALID:
351       {
352         return true;
353       }
354     }
355     return false;
356   }
357
358   ComparerInterfaces ci;
359   ComparerAttributes ca;
360   ComparerRoles      cr;
361   ComparerStates     cs;
362
363   Comparer(MatchRule* mr)
364   : ci(mr),
365     ca(mr),
366     cr(mr),
367     cs(mr)
368   {
369   }
370
371   bool operator()(Accessible* obj)
372   {
373     return compareFunc(ci, obj) &&
374            compareFunc(ca, obj) &&
375            compareFunc(cr, obj) &&
376            compareFunc(cs, obj);
377   }
378 };
379
380 void BridgeCollection::VisitNodes(Accessible* obj, std::vector<Accessible*>& result, Comparer& cmp, size_t maxCount)
381 {
382   if(maxCount > 0 && result.size() >= maxCount)
383     return;
384
385   if(cmp(obj))
386     result.emplace_back(obj);
387
388   for(auto i = 0u; i < obj->GetChildCount(); ++i)
389     VisitNodes(obj->GetChildAtIndex(i), result, cmp, maxCount);
390 }
391
392 DBus::ValueOrError<std::vector<Accessible*> > BridgeCollection::GetMatches(MatchRule rule, uint32_t sortBy, int32_t count, bool traverse)
393 {
394   std::vector<Accessible*> res;
395   auto                     self    = BridgeBase::FindSelf();
396   auto                     matcher = Comparer{&rule};
397   VisitNodes(self, res, matcher, count);
398
399   switch(static_cast<SortOrder>(sortBy))
400   {
401     case SortOrder::CANONICAL:
402     {
403       break;
404     }
405
406     case SortOrder::REVERSE_CANONICAL:
407     {
408       std::reverse(res.begin(), res.end());
409       break;
410     }
411
412     default:
413     {
414       throw std::domain_error{"unsupported sorting order"};
415     }
416       //TODO: other cases
417   }
418
419   return res;
420 }