[dali_2.0.20] Merge branch 'devel/master'
[platform/core/uifw/dali-csharp-binder.git] / dali-csharp-binder / src / accessible-impl-nui.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 #include "control-devel_wrap.h"
18
19 #include <dali/devel-api/adaptor-framework/accessibility.h>
20 #include <dali/devel-api/adaptor-framework/accessibility-impl.h>
21 #include <stdexcept>
22
23 using namespace Dali::Toolkit::DevelControl;
24
25 namespace {
26
27 // Keep this structure layout binary compatible with the respective C# structure!
28 struct AccessibilityDelegate
29 {
30     char *(*getName)(); // 1
31     char *(*getDescription)(); // 2
32     bool (*doAction)(const char *); // 3
33     Dali::Accessibility::States *(*calculateStates)(); // 4
34     int (*getActionCount)(); // 5
35     char *(*getActionName)(int); // 6
36     bool (*shouldReportZeroChildren)(); // 7
37     double (*getMinimum)(); // 8
38     double (*getCurrent)(); // 9
39     double (*getMaximum)(); // 10
40     bool (*setCurrent)(double); // 11
41     double (*getMinimumIncrement)(); // 12
42     bool (*isScrollable)(); // 13
43     char *(*getText)(int, int); // 14
44     int (*getCharacterCount)(); // 15
45     int (*getCaretOffset)(); // 16
46     bool (*setCaretOffset)(int); // 17
47     Dali::Accessibility::Range *(*getTextAtOffset)(int, int); // 18
48     Dali::Accessibility::Range *(*getSelection)(int); // 19
49     bool (*removeSelection)(int); // 20
50     bool (*setSelection)(int, int, int); // 21
51     bool (*copyText)(int, int); // 22
52     bool (*cutText)(int, int); // 23
53 };
54
55 inline std::string stealString(char *str)
56 {
57     std::string ret{};
58
59     if (str)
60     {
61         ret = {str};
62         free(str);
63     }
64
65     return ret;
66 }
67
68 template <typename T>
69 inline T stealObject(T *obj)
70 {
71     T ret{};
72
73     if (obj)
74     {
75         ret = *obj;
76         delete obj;
77     }
78
79     return ret;
80 }
81
82 struct AccessibleImpl_NUI : public AccessibleImpl
83 {
84     // Points to memory managed from the C# side
85     const AccessibilityDelegate *v;
86
87     AccessibleImpl_NUI() = delete;
88     AccessibleImpl_NUI(const AccessibleImpl_NUI &) = delete;
89     AccessibleImpl_NUI(AccessibleImpl_NUI &&) = delete;
90
91     AccessibleImpl_NUI& operator=(const AccessibleImpl_NUI &) = delete;
92     AccessibleImpl_NUI& operator=(AccessibleImpl_NUI &&) = delete;
93
94     AccessibleImpl_NUI(Dali::Actor actor, Dali::Accessibility::Role role, const AccessibilityDelegate *vtable)
95     : AccessibleImpl(actor, role, false), v{vtable} {}
96
97     std::string GetNameRaw() override
98     {
99         std::string ret{};
100
101         if (v->getName)
102         {
103             ret = stealString(v->getName());
104         }
105
106         return ret;
107     }
108
109     std::string GetDescriptionRaw() override
110     {
111         std::string ret{};
112
113         if (v->getDescription)
114         {
115             ret = stealString(v->getDescription());
116         }
117
118         return ret;
119     }
120
121     std::string GetActionName(std::size_t index) override
122     {
123         std::string ret{};
124
125         if (v->getActionName)
126         {
127             ret = stealString(v->getActionName(static_cast<int>(index)));
128         }
129
130         return ret;
131     }
132
133     std::size_t GetActionCount() override
134     {
135         std::size_t ret{0};
136
137         if (v->getActionCount)
138         {
139             ret = static_cast<std::size_t>(v->getActionCount());
140         }
141
142         return ret;
143     }
144
145     bool DoAction(std::size_t index) override
146     {
147         return DoAction(GetActionName(index));
148     }
149
150     bool DoAction(const std::string &name) override
151     {
152         bool ret{false};
153
154         if (v->doAction)
155         {
156             ret = v->doAction(name.data());
157         }
158
159         return ret;
160     }
161
162     Dali::Accessibility::States CalculateStates() override
163     {
164         Dali::Accessibility::States ret{};
165
166         if (v->calculateStates)
167         {
168             ret = stealObject(v->calculateStates());
169         }
170
171         return ret;
172     }
173
174     Dali::Property::Index GetNamePropertyIndex() override
175     {
176         return Dali::Property::INVALID_INDEX;
177     }
178
179     Dali::Property::Index GetDescriptionPropertyIndex() override
180     {
181         return Dali::Property::INVALID_INDEX;
182     }
183
184     virtual bool ShouldReportZeroChildren()
185     {
186         bool ret{false};
187
188         if (v->shouldReportZeroChildren)
189         {
190             ret = v->shouldReportZeroChildren();
191         }
192
193         return ret;
194     }
195
196     std::size_t GetChildCount() override
197     {
198         bool highlighted = (self == Dali::Accessibility::Accessible::GetCurrentlyHighlightedActor());
199
200         if (ShouldReportZeroChildren())
201         {
202             std::size_t ret = 0;
203
204             // We still allow the highlight frame to be reported as a child of this actor
205             // even though its ShouldReportZeroChildren() method returned true.
206             ret += static_cast<std::size_t>(highlighted);
207
208             return ret;
209         }
210         else
211         {
212             return AccessibleImpl::GetChildCount();
213         }
214     }
215
216     Dali::Accessibility::Accessible *GetChildAtIndex(std::size_t index) override
217     {
218         bool highlighted = (self == Dali::Accessibility::Accessible::GetCurrentlyHighlightedActor());
219
220         if (ShouldReportZeroChildren())
221         {
222             if (highlighted && index == 0)
223             {
224                 return Dali::Accessibility::Accessible::Get(currentHighlightActor.GetHandle());
225             }
226             else
227             {
228                 // We should not end up here. When ShouldReportZeroChildren() returns true,
229                 // there are two possible cases:
230                 // (1) The actor is not highlighted, so GetChildCount() returns zero, and so
231                 // GetChildAtIndex() is not called.
232                 // (2) The actor is highlighted, so GetChildCount() returns one. The only valid
233                 // argument for GetChildAtIndex() is zero.
234                 throw std::domain_error{"Invalid index"};
235             }
236         }
237         else
238         {
239             return AccessibleImpl::GetChildAtIndex(index);
240         }
241     }
242
243     bool IsScrollable() override
244     {
245         bool ret{false};
246
247         if (v->isScrollable)
248         {
249             ret = v->isScrollable();
250         }
251
252         return ret;
253     }
254
255 #if 0
256     void EnsureChildVisible(Dali::Actor child) override;
257     void EnsureSelfVisible() override;
258 #endif
259 };
260
261 struct AccessibleImpl_NUI_Value : public AccessibleImpl_NUI,
262                                   public virtual Dali::Accessibility::Value
263 {
264     using AccessibleImpl_NUI::AccessibleImpl_NUI;
265
266     double GetMinimum() override
267     {
268         double ret{0.0};
269
270         if (v->getMinimum)
271         {
272             ret = v->getMinimum();
273         }
274
275         return ret;
276     }
277
278     double GetCurrent() override
279     {
280         double ret{0.0};
281
282         if (v->getCurrent)
283         {
284             ret = v->getCurrent();
285         }
286
287         return ret;
288     }
289
290     double GetMaximum() override
291     {
292         double ret{0.0};
293
294         if (v->getMaximum)
295         {
296             ret = v->getMaximum();
297         }
298
299         return ret;
300     }
301
302     bool SetCurrent(double val) override
303     {
304         bool ret{false};
305
306         if (v->setCurrent)
307         {
308             ret = v->setCurrent(val);
309         }
310
311         return ret;
312     }
313
314     double GetMinimumIncrement() override
315     {
316         double ret{0.0};
317
318         if (v->getMinimumIncrement)
319         {
320             ret = v->getMinimumIncrement();
321         }
322
323         return ret;
324     }
325 };
326
327 struct AccessibleImpl_NUI_EditableText : public AccessibleImpl_NUI,
328                                          public virtual Dali::Accessibility::Text,
329                                          public virtual Dali::Accessibility::EditableText
330 {
331     using AccessibleImpl_NUI::AccessibleImpl_NUI;
332
333     std::string GetText(std::size_t startOffset, std::size_t endOffset) override
334     {
335         std::string ret{};
336
337         if (v->getText)
338         {
339             ret = stealString(v->getText(static_cast<int>(startOffset), static_cast<int>(endOffset)));
340         }
341
342         return ret;
343     }
344
345     std::size_t GetCharacterCount() override
346     {
347         std::size_t ret{0};
348
349         if (v->getCharacterCount)
350         {
351             ret = static_cast<std::size_t>(v->getCharacterCount());
352         }
353
354         return ret;
355     }
356
357     std::size_t GetCaretOffset() override
358     {
359         std::size_t ret{0};
360
361         if (v->getCaretOffset)
362         {
363             ret = static_cast<std::size_t>(v->getCaretOffset());
364         }
365
366         return ret;
367     }
368
369     bool SetCaretOffset(std::size_t offset) override
370     {
371         bool ret{false};
372
373         if (v->setCaretOffset)
374         {
375             ret = v->setCaretOffset(static_cast<int>(offset));
376         }
377
378         return ret;
379     }
380
381     Dali::Accessibility::Range GetTextAtOffset(std::size_t offset, Dali::Accessibility::TextBoundary boundary) override
382     {
383         Dali::Accessibility::Range ret{};
384
385         if (v->getTextAtOffset)
386         {
387             ret = stealObject(v->getTextAtOffset(static_cast<int>(offset), static_cast<int>(boundary)));
388         }
389
390         return ret;
391     }
392
393     Dali::Accessibility::Range GetSelection(std::size_t selectionNum) override
394     {
395         Dali::Accessibility::Range ret{};
396
397         if (v->getSelection)
398         {
399             ret = stealObject(v->getSelection(static_cast<int>(selectionNum)));
400         }
401
402         return ret;
403     }
404
405     bool RemoveSelection(std::size_t selectionNum) override
406     {
407         bool ret{false};
408
409         if (v->removeSelection)
410         {
411             ret = v->removeSelection(static_cast<int>(selectionNum));
412         }
413
414         return ret;
415     }
416
417     bool SetSelection(std::size_t selectionNum, std::size_t startOffset, std::size_t endOffset) override
418     {
419         bool ret{false};
420
421         if (v->setSelection)
422         {
423             ret = v->setSelection(static_cast<int>(selectionNum), static_cast<int>(startOffset), static_cast<int>(endOffset));
424         }
425
426         return ret;
427     }
428
429     bool CopyText(std::size_t startPosition, std::size_t endPosition) override
430     {
431         bool ret{false};
432
433         if (v->copyText)
434         {
435             ret = v->copyText(static_cast<int>(startPosition), static_cast<int>(endPosition));
436         }
437
438         return ret;
439     }
440
441     bool CutText(std::size_t startPosition, std::size_t endPosition) override
442     {
443         bool ret{false};
444
445         if (v->cutText)
446         {
447             ret = v->cutText(static_cast<int>(startPosition), static_cast<int>(endPosition));
448         }
449
450         return ret;
451     }
452 };
453
454 enum {
455     IFACE_NONE = 0,
456     IFACE_VALUE = 1,
457     IFACE_EDITABLE_TEXT = 2,
458 };
459
460 } // anonymous namespace
461
462 extern "C" {
463
464 SWIGEXPORT void SWIGSTDCALL CSharp_Dali_Toolkit_DevelControl_SetAccessibilityConstructor_NUI
465     (void *arg1_self, int arg2_role, int arg3_iface, const void *arg4_vtable, int arg5_vtableSize)
466 {
467     GUARD_ON_NULL_RET(arg1_self);
468     GUARD_ON_NULL_RET(arg4_vtable);
469     try_catch([&]()
470     {
471         Dali::Actor self = *(Dali::Actor *)arg1_self;
472         auto role = static_cast<Dali::Accessibility::Role>(arg2_role);
473         int iface = arg3_iface;
474         const auto *vtable = static_cast<const AccessibilityDelegate *>(arg4_vtable);
475         auto vtableSize = static_cast<std::size_t>(arg5_vtableSize);
476
477         if (vtableSize != sizeof(*vtable))
478         {
479             throw std::runtime_error("SetAccessibilityConstructor_NUI interop error: Marshal.SizeOf<AccessibilityDelegate>() != sizeof(AccessibilityDelegate)");
480         }
481
482         SetAccessibilityConstructor(self, [=](Dali::Actor actor)
483         {
484             Dali::Accessibility::Accessible *accessible{};
485
486             switch (iface)
487             {
488             default:
489                 DALI_LOG_ERROR("SetAccessibilityConstructor_NUI error: unknown interface %d", iface);
490                 // fall-through
491             case IFACE_NONE:
492                 accessible = new AccessibleImpl_NUI(actor, role, vtable);
493                 break;
494             case IFACE_VALUE:
495                 accessible = new AccessibleImpl_NUI_Value(actor, role, vtable);
496                 break;
497             case IFACE_EDITABLE_TEXT:
498                 accessible = new AccessibleImpl_NUI_EditableText(actor, role, vtable);
499                 break;
500             }
501
502             return std::unique_ptr<Dali::Accessibility::Accessible>(accessible);
503         });
504     });
505 }
506
507 SWIGEXPORT char *SWIGSTDCALL CSharp_Dali_Toolkit_DevelControl_AccessibleImpl_NUI_DuplicateString(const char *arg)
508 {
509     return strdup(arg);
510 }
511
512 } // extern "C"