[dali_2.3.25] Merge branch 'devel/master'
[platform/core/uifw/dali-adaptor.git] / dali / internal / accessibility / bridge / bridge-base.h
1 #ifndef DALI_INTERNAL_ACCESSIBILITY_BRIDGE_BASE_H
2 #define DALI_INTERNAL_ACCESSIBILITY_BRIDGE_BASE_H
3
4 /*
5  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  */
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/actors/layer.h>
23 #include <dali/public-api/dali-adaptor-version.h>
24 #include <dali/public-api/object/weak-handle.h>
25 #include <dali/public-api/signals/connection-tracker.h>
26 #include <memory>
27 #include <tuple>
28
29 // INTERNAL INCLUDES
30 #include <dali/devel-api/adaptor-framework/proxy-accessible.h>
31 #include <dali/devel-api/adaptor-framework/window-devel.h>
32 #include <dali/devel-api/atspi-interfaces/accessible.h>
33 #include <dali/devel-api/atspi-interfaces/application.h>
34 #include <dali/devel-api/atspi-interfaces/collection.h>
35 #include <dali/devel-api/atspi-interfaces/socket.h>
36 #include <dali/internal/accessibility/bridge/accessibility-common.h>
37
38 /**
39  * @brief The ApplicationAccessible class is to define Accessibility Application.
40  */
41 class ApplicationAccessible : public virtual Dali::Accessibility::Accessible,
42                               public virtual Dali::Accessibility::Application,
43                               public virtual Dali::Accessibility::Collection,
44                               public virtual Dali::Accessibility::Component,
45                               public virtual Dali::Accessibility::Socket
46 {
47 public:
48   Dali::Accessibility::ProxyAccessible          mParent;
49   std::vector<Dali::Accessibility::Accessible*> mChildren;
50   std::string                                   mName;
51   std::string                                   mToolkitName{"dali"};
52   bool                                          mIsEmbedded{false};
53
54   std::string GetName() const override
55   {
56     return mName;
57   }
58
59   std::string GetDescription() const override
60   {
61     return "";
62   }
63
64   Dali::Accessibility::Accessible* GetParent() override
65   {
66     return &mParent;
67   }
68
69   size_t GetChildCount() const override
70   {
71     return mChildren.size();
72   }
73
74   std::vector<Dali::Accessibility::Accessible*> GetChildren() override
75   {
76     return mChildren;
77   }
78
79   Dali::Accessibility::Accessible* GetChildAtIndex(size_t index) override
80   {
81     auto size = mChildren.size();
82     if(index >= size)
83     {
84       throw std::domain_error{"invalid index " + std::to_string(index) + " for object with " + std::to_string(size) + " children"};
85     }
86     return mChildren[index];
87   }
88
89   size_t GetIndexInParent() override
90   {
91     if(mIsEmbedded)
92     {
93       return 0u;
94     }
95
96     throw std::domain_error{"can't call GetIndexInParent on application object"};
97   }
98
99   Dali::Accessibility::Role GetRole() const override
100   {
101     return Dali::Accessibility::Role::APPLICATION;
102   }
103
104   Dali::Accessibility::States GetStates() override
105   {
106     Dali::Accessibility::States result;
107
108     for(auto* child : mChildren)
109     {
110       result = result | child->GetStates();
111     }
112
113     // The Application object should never have the SENSITIVE state
114     result[Dali::Accessibility::State::SENSITIVE] = false;
115
116     return result;
117   }
118
119   Dali::Accessibility::Attributes GetAttributes() const override
120   {
121     return {};
122   }
123
124   /**
125    * @brief Gets the Accessible object from the window.
126    *
127    * @param[in] window The window to find
128    * @return Null if mChildren is empty, otherwise the Accessible object
129    * @note Currently, the default window would be returned when mChildren is not empty.
130    */
131   Dali::Accessibility::Accessible* GetWindowAccessible(Dali::Window window)
132   {
133     if(mChildren.empty())
134     {
135       return nullptr;
136     }
137
138     Dali::Layer rootLayer = window.GetRootLayer();
139
140     // Find a child which is related to the window.
141     for(auto i = 0u; i < mChildren.size(); ++i)
142     {
143       if(rootLayer == mChildren[i]->GetInternalActor())
144       {
145         return mChildren[i];
146       }
147     }
148
149     // If can't find its children, return the default window.
150     return mChildren[0];
151   }
152
153   bool DoGesture(const Dali::Accessibility::GestureInfo& gestureInfo) override
154   {
155     return false;
156   }
157
158   std::vector<Dali::Accessibility::Relation> GetRelationSet() override
159   {
160     return {};
161   }
162
163   Dali::Actor GetInternalActor() const override
164   {
165     return Dali::Actor{};
166   }
167
168   Dali::Accessibility::Address GetAddress() const override
169   {
170     return {"", "root"};
171   }
172
173   // Application
174
175   std::string GetToolkitName() const override
176   {
177     return mToolkitName;
178   }
179
180   std::string GetVersion() const override
181   {
182     return std::to_string(Dali::ADAPTOR_MAJOR_VERSION) + "." + std::to_string(Dali::ADAPTOR_MINOR_VERSION);
183   }
184
185   // Socket
186
187   Dali::Accessibility::Address Embed(Dali::Accessibility::Address plug) override
188   {
189     mIsEmbedded = true;
190     mParent.SetAddress(plug);
191
192     return GetAddress();
193   }
194
195   void Unembed(Dali::Accessibility::Address plug) override
196   {
197     if(mParent.GetAddress() == plug)
198     {
199       mIsEmbedded = false;
200       mParent.SetAddress({});
201       Dali::Accessibility::Bridge::GetCurrentBridge()->SetExtentsOffset(0, 0);
202     }
203   }
204
205   void SetOffset(std::int32_t x, std::int32_t y) override
206   {
207     if(!mIsEmbedded)
208     {
209       return;
210     }
211
212     Dali::Accessibility::Bridge::GetCurrentBridge()->SetExtentsOffset(x, y);
213   }
214
215   // Component
216
217   Dali::Rect<> GetExtents(Dali::Accessibility::CoordinateType type) const override
218   {
219     using limits = std::numeric_limits<float>;
220
221     float minX = limits::max();
222     float minY = limits::max();
223     float maxX = limits::min();
224     float maxY = limits::min();
225
226     for(Dali::Accessibility::Accessible* child : mChildren)
227     {
228       auto* component = Dali::Accessibility::Component::DownCast(child);
229       if(!component)
230       {
231         continue;
232       }
233
234       auto extents = component->GetExtents(type);
235
236       minX = std::min(minX, extents.x);
237       minY = std::min(minY, extents.y);
238       maxX = std::max(maxX, extents.x + extents.width);
239       maxY = std::max(maxY, extents.y + extents.height);
240     }
241
242     return {minX, minY, maxX - minX, maxY - minY};
243   }
244
245   Dali::Accessibility::ComponentLayer GetLayer() const override
246   {
247     return Dali::Accessibility::ComponentLayer::WINDOW;
248   }
249
250   std::int16_t GetMdiZOrder() const override
251   {
252     return 0;
253   }
254
255   bool GrabFocus() override
256   {
257     return false;
258   }
259
260   double GetAlpha() const override
261   {
262     return 0.0;
263   }
264
265   bool GrabHighlight() override
266   {
267     return false;
268   }
269
270   bool ClearHighlight() override
271   {
272     return false;
273   }
274
275   bool IsScrollable() const override
276   {
277     return false;
278   }
279 };
280
281 /**
282  * @brief Enumeration for CoalescableMessages.
283  */
284 enum class CoalescableMessages
285 {
286   BOUNDS_CHANGED, ///< Bounds changed
287   SET_OFFSET, ///< Set offset
288   POST_RENDER, ///< Post render
289   STATE_CHANGED_BEGIN = 500, ///< State changed (begin of reserved range)
290   STATE_CHANGED_END   = STATE_CHANGED_BEGIN + 99, ///< State changed (end of reserved range)
291   PROPERTY_CHANGED_BEGIN, ///< Property changed (begin of reserved range)
292   PROPERTY_CHANGED_END = PROPERTY_CHANGED_BEGIN + 99, ///< Property changed (end of reserved range)
293 };
294
295 // Custom specialization of std::hash
296 namespace std
297 {
298 template<>
299 struct hash<std::pair<CoalescableMessages, Dali::Accessibility::Accessible*>>
300 {
301   size_t operator()(std::pair<CoalescableMessages, Dali::Accessibility::Accessible*> value) const
302   {
303     return (static_cast<size_t>(value.first) * 131) ^ reinterpret_cast<size_t>(value.second);
304   }
305 };
306 } // namespace std
307
308 /**
309  * @brief The BridgeBase class is basic class for Bridge functions.
310  */
311 class BridgeBase : public Dali::Accessibility::Bridge, public Dali::ConnectionTracker
312 {
313   std::unordered_map<std::pair<CoalescableMessages, Dali::Accessibility::Accessible*>, std::tuple<unsigned int, unsigned int, std::function<void()>>> mCoalescableMessages;
314
315   /**
316    * @brief Removes all CoalescableMessages using Tick signal.
317    *
318    * @return False if mCoalescableMessages is empty, otherwise true.
319    */
320   bool TickCoalescableMessages();
321
322 public:
323   /**
324    * @brief Adds CoalescableMessages, Accessible, and delay time to mCoalescableMessages.
325    *
326    * @param[in] kind CoalescableMessages enum value
327    * @param[in] obj Accessible object
328    * @param[in] delay The delay time
329    * @param[in] functor The function to be called // NEED TO UPDATE!
330    */
331   void AddCoalescableMessage(CoalescableMessages kind, Dali::Accessibility::Accessible* obj, float delay, std::function<void()> functor);
332
333   /**
334    * @brief Callback when the visibility of the window is changed.
335    *
336    * @param[in] window The window to be changed
337    * @param[in] visible The visibility of the window
338    */
339   void OnWindowVisibilityChanged(Dali::Window window, bool visible);
340
341   /**
342    * @brief Callback when the window focus is changed.
343    *
344    * @param[in] window The window whose focus is changed
345    * @param[in] focusIn Whether the focus is in/out
346    */
347   void OnWindowFocusChanged(Dali::Window window, bool focusIn);
348
349   /**
350    * @copydoc Dali::Accessibility::Bridge::GetBusName()
351    */
352   const std::string& GetBusName() const override;
353
354   /**
355    * @copydoc Dali::Accessibility::Bridge::AddTopLevelWindow()
356    */
357   void AddTopLevelWindow(Dali::Accessibility::Accessible* windowAccessible) override;
358
359   /**
360    * @copydoc Dali::Accessibility::Bridge::RemoveTopLevelWindow()
361    */
362   void RemoveTopLevelWindow(Dali::Accessibility::Accessible* windowAccessible) override;
363
364   /**
365    * @copydoc Dali::Accessibility::Bridge::RegisterDefaultLabel()
366    */
367   void RegisterDefaultLabel(Dali::Accessibility::Accessible* object) override;
368
369   /**
370    * @copydoc Dali::Accessibility::Bridge::UnregisterDefaultLabel()
371    */
372   void UnregisterDefaultLabel(Dali::Accessibility::Accessible* object) override;
373
374   /**
375    * @copydoc Dali::Accessibility::Bridge::GetDefaultLabel()
376    */
377   Dali::Accessibility::Accessible* GetDefaultLabel(Dali::Accessibility::Accessible* root) const override;
378
379   /**
380    * @copydoc Dali::Accessibility::Bridge::GetApplication()
381    */
382   Dali::Accessibility::Accessible* GetApplication() const override
383   {
384     return &mApplication;
385   }
386
387   /**
388    * @brief Adds function to dbus interface.
389    */
390   template<typename SELF, typename... RET, typename... ARGS>
391   void AddFunctionToInterface(
392     DBus::DBusInterfaceDescription& desc, const std::string& funcName, DBus::ValueOrError<RET...> (SELF::*funcPtr)(ARGS...))
393   {
394     if(auto self = dynamic_cast<SELF*>(this))
395       desc.addMethod<DBus::ValueOrError<RET...>(ARGS...)>(
396         funcName,
397         [=](ARGS... args) -> DBus::ValueOrError<RET...> {
398           try
399           {
400             return (self->*funcPtr)(std::move(args)...);
401           }
402           catch(std::domain_error& e)
403           {
404             return DBus::Error{e.what()};
405           }
406         });
407   }
408
409   /**
410    * @brief Adds 'Get' property to dbus interface.
411    */
412   template<typename T, typename SELF>
413   void AddGetPropertyToInterface(DBus::DBusInterfaceDescription& desc,
414                                  const std::string&              funcName,
415                                  T (SELF::*funcPtr)())
416   {
417     if(auto self = dynamic_cast<SELF*>(this))
418       desc.addProperty<T>(funcName,
419                           [=]() -> DBus::ValueOrError<T> {
420                             try
421                             {
422                               return (self->*funcPtr)();
423                             }
424                             catch(std::domain_error& e)
425                             {
426                               return DBus::Error{e.what()};
427                             }
428                           },
429                           {});
430   }
431
432   /**
433    * @brief Adds 'Set' property to dbus interface.
434    */
435   template<typename T, typename SELF>
436   void AddSetPropertyToInterface(DBus::DBusInterfaceDescription& desc,
437                                  const std::string&              funcName,
438                                  void (SELF::*funcPtr)(T))
439   {
440     if(auto self = dynamic_cast<SELF*>(this))
441       desc.addProperty<T>(funcName, {}, [=](T t) -> DBus::ValueOrError<void> {
442         try
443         {
444           (self->*funcPtr)(std::move(t));
445           return {};
446         }
447         catch(std::domain_error& e)
448         {
449           return DBus::Error{e.what()};
450         }
451       });
452   }
453
454   /**
455    * @brief Adds 'Set' and 'Get' properties to dbus interface.
456    */
457   template<typename T, typename T1, typename SELF>
458   void AddGetSetPropertyToInterface(DBus::DBusInterfaceDescription& desc,
459                                     const std::string&              funcName,
460                                     T1 (SELF::*funcPtrGet)(),
461                                     DBus::ValueOrError<void> (SELF::*funcPtrSet)(T))
462   {
463     if(auto self = dynamic_cast<SELF*>(this))
464       desc.addProperty<T>(
465         funcName,
466         [=]() -> DBus::ValueOrError<T> {
467           try
468           {
469             return (self->*funcPtrGet)();
470           }
471           catch(std::domain_error& e)
472           {
473             return DBus::Error{e.what()};
474           }
475         },
476         [=](T t) -> DBus::ValueOrError<void> {
477           try
478           {
479             (self->*funcPtrSet)(std::move(t));
480             return {};
481           }
482           catch(std::domain_error& e)
483           {
484             return DBus::Error{e.what()};
485           }
486         });
487   }
488
489   /**
490    * @brief Adds 'Get' and 'Set' properties to dbus interface.
491    */
492   template<typename T, typename T1, typename SELF>
493   void AddGetSetPropertyToInterface(DBus::DBusInterfaceDescription& desc,
494                                     const std::string&              funcName,
495                                     T1 (SELF::*funcPtrGet)(),
496                                     void (SELF::*funcPtrSet)(T))
497   {
498     if(auto self = dynamic_cast<SELF*>(this))
499       desc.addProperty<T>(
500         funcName,
501         [=]() -> DBus::ValueOrError<T> {
502           try
503           {
504             return (self->*funcPtrGet)();
505           }
506           catch(std::domain_error& e)
507           {
508             return DBus::Error{e.what()};
509           }
510         },
511         [=](T t) -> DBus::ValueOrError<void> {
512           try
513           {
514             (self->*funcPtrSet)(std::move(t));
515             return {};
516           }
517           catch(std::domain_error& e)
518           {
519             return DBus::Error{e.what()};
520           }
521         });
522   }
523
524   /**
525    * @brief Gets the string of the path excluding the specified prefix.
526    *
527    * @param path The path to get
528    * @return The string stripped of the specific prefix
529    */
530   static std::string StripPrefix(const std::string& path);
531
532   /**
533    * @brief Finds the Accessible object according to the path.
534    *
535    * @param[in] path The path for Accessible object
536    * @return The Accessible object corresponding to the path
537    */
538   Dali::Accessibility::Accessible* Find(const std::string& path) const;
539
540   /**
541    * @brief Finds the Accessible object with the given address.
542    *
543    * @param[in] ptr The unique Address of the object
544    * @return The Accessible object corresponding to the path
545    */
546   Dali::Accessibility::Accessible* Find(const Dali::Accessibility::Address& ptr) const;
547
548   /**
549    * @brief Returns the target object of the currently executed DBus method call.
550    *
551    * @return The Accessible object
552    * @note When a DBus method is called on some object, this target object (`currentObject`) is temporarily saved by the bridge,
553    * because DBus handles the invocation target separately from the method arguments.
554    * We then use the saved object inside the 'glue' method (e.g. BridgeValue::GetMinimum)
555    * to call the equivalent method on the respective C++ object (this could be ScrollBar::AccessibleImpl::GetMinimum in the example given).
556    */
557   Dali::Accessibility::Accessible* FindCurrentObject() const;
558
559   /**
560    * @brief Returns the target object of the currently executed DBus method call.
561    *
562    * This method tries to downcast the return value of FindCurrentObject() to the requested type,
563    * issuing an error reply to the DBus caller if the requested type is not implemented. Whether
564    * a given type is implemented is decided based on the return value of Accessible::GetInterfaces()
565    * for the current object.
566    *
567    * @tparam I The requested AT-SPI interface
568    * @return The Accessible object (cast to a more derived type)
569    *
570    * @see FindCurrentObject()
571    * @see Dali::Accessibility::AtspiInterface
572    * @see Dali::Accessibility::AtspiInterfaceType
573    * @see Dali::Accessibility::Accessible::GetInterfaces()
574    */
575   template<Dali::Accessibility::AtspiInterface I>
576   auto* FindCurrentObjectWithInterface() const
577   {
578     using Type = Dali::Accessibility::AtspiInterfaceType<I>;
579
580     Type* result;
581     auto* currentObject = FindCurrentObject();
582     DALI_ASSERT_DEBUG(currentObject); // FindCurrentObject() throws domain_error
583
584     if(!(result = Dali::Accessibility::Accessible::DownCast<I>(currentObject)))
585     {
586       std::stringstream s;
587
588       s << "Object " << currentObject->GetAddress().ToString();
589       s << " does not implement ";
590       s << Dali::Accessibility::Accessible::GetInterfaceName(I);
591
592       throw std::domain_error{s.str()};
593     }
594
595     return result;
596   }
597
598   /**
599    * @copydoc Dali::Accessibility::Bridge::FindByPath()
600    */
601   Dali::Accessibility::Accessible* FindByPath(const std::string& name) const override;
602
603   /**
604    * @copydoc Dali::Accessibility::Bridge::SetApplicationName()
605    */
606   void SetApplicationName(std::string name) override
607   {
608     mApplication.mName = std::move(name);
609   }
610
611   /**
612    * @copydoc Dali::Accessibility::Bridge::SetToolkitName()
613    */
614   void SetToolkitName(std::string_view toolkitName) override
615   {
616     mApplication.mToolkitName = std::string{toolkitName};
617   }
618
619 protected:
620   // We use a weak handle in order not to keep a window alive forever if someone forgets to UnregisterDefaultLabel()
621   using DefaultLabelType  = std::pair<Dali::WeakHandle<Dali::Window>, Dali::Accessibility::Accessible*>;
622   using DefaultLabelsType = std::list<DefaultLabelType>;
623
624   mutable ApplicationAccessible mApplication;
625   DefaultLabelsType             mDefaultLabels;
626   bool                          mIsScreenReaderSuppressed = false;
627
628 private:
629   /**
630    * @brief Sets an ID.
631    * @param[in] id An ID (integer value)
632    */
633   void SetId(int id);
634
635   /**
636    * @brief Gets the ID.
637    * @return The ID to be set
638    */
639   int GetId();
640
641   /**
642    * @brief Update registered events.
643    */
644   void UpdateRegisteredEvents();
645
646   using CacheElementType = std::tuple<
647     Dali::Accessibility::Address,
648     Dali::Accessibility::Address,
649     Dali::Accessibility::Address,
650     std::vector<Dali::Accessibility::Address>,
651     std::vector<std::string>,
652     std::string,
653     Dali::Accessibility::Role,
654     std::string,
655     std::array<uint32_t, 2>>;
656
657   /**
658    * @brief Gets Items  // NEED TO UPDATE!
659    *
660    * @return
661    */
662   DBus::ValueOrError<std::vector<CacheElementType>> GetItems();
663
664   /**
665    * @brief Creates CacheElement.
666    *
667    * CreateCacheElement method works for GetItems which is a part of ATSPI protocol.
668    * ATSPI client library (libatspi from at-spi2-core) depending on cacheing policy configuration uses GetItems
669    * to pre-load entire accessible tree from application to its own cache in single dbus call.
670    * Otherwise the particular nodes in a tree are cached lazily when client library tries to access them.
671    * @param item Accessible to get information
672    * @return The elements to be cached
673    */
674   CacheElementType CreateCacheElement(Dali::Accessibility::Accessible* item);
675
676   /**
677    * @brief Removes expired elements from the default label collection.
678    */
679   void CompressDefaultLabels();
680
681   /**
682    * @brief Gets the window to which this accessible belongs (or an empty handle).
683    *
684    * @param accessible The accessible
685    * @return The window
686    */
687   static Dali::WeakHandle<Dali::Window> GetWindow(Dali::Accessibility::Accessible* accessible);
688
689 protected:
690   BridgeBase();
691   virtual ~BridgeBase();
692
693   /**
694    * @copydoc Dali::Accessibility::Bridge::ForceUp()
695    */
696   ForceUpResult ForceUp() override;
697
698   /**
699    * @copydoc Dali::Accessibility::Bridge::ForceDown()
700    */
701   void ForceDown() override;
702
703   DBus::DBusServer           mDbusServer;
704   DBusWrapper::ConnectionPtr mConnectionPtr;
705   int                        mId = 0;
706   DBus::DBusClient           mRegistry;
707   bool                       IsBoundsChangedEventAllowed{false};
708 };
709
710 #endif // DALI_INTERNAL_ACCESSIBILITY_BRIDGE_BASE_H