457db614b834815200ca41c4ec780a0125ec74b4
[platform/core/uifw/dali-csharp-binder.git] / dali-csharp-binder / src / nui-view-accessible.cpp
1 /*
2  * Copyright (c) 2022 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 "nui-view-accessible.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23
24 // INTERNAL INCLUDES
25 #include "control-devel-wrap.h"
26
27 using namespace Dali;
28 using namespace Dali::Toolkit;
29
30 using Interface = Accessibility::AtspiInterface;
31
32 namespace
33 {
34 void GetAttributesCallback(const char* key, const char* value, Accessibility::Attributes* attributes)
35 {
36   attributes->insert_or_assign(key, value);
37 }
38
39 using GetAttributesCallbackType = decltype(&GetAttributesCallback);
40
41 } // unnamed namespace
42
43 // Keep this structure layout binary compatible with the respective C# structure!
44 struct NUIViewAccessible::AccessibilityDelegate
45 {
46   AccessibilityDelegate() = delete;
47
48   // clang-format off
49   char*                 (*getName)                 (RefObject*);                   //  1
50   char*                 (*getDescription)          (RefObject*);                   //  2
51   bool                  (*doAction)                (RefObject*, const char*);      //  3
52   std::uint64_t         (*calculateStates)         (RefObject*, std::uint64_t);    //  4
53   int                   (*getActionCount)          (RefObject*);                   //  5
54   char*                 (*getActionName)           (RefObject*, int);              //  6
55   std::uint32_t         (*getInterfaces)           (RefObject*);                   //  7
56   double                (*getMinimum)              (RefObject*);                   //  8
57   double                (*getCurrent)              (RefObject*);                   //  9
58   double                (*getMaximum)              (RefObject*);                   // 10
59   bool                  (*setCurrent)              (RefObject*, double);           // 11
60   double                (*getMinimumIncrement)     (RefObject*);                   // 12
61   bool                  (*isScrollable)            (RefObject*);                   // 13
62   char*                 (*getText)                 (RefObject*, int, int);         // 14
63   int                   (*getCharacterCount)       (RefObject*);                   // 15
64   int                   (*getCursorOffset)         (RefObject*);                   // 16
65   bool                  (*setCursorOffset)         (RefObject*, int);              // 17
66   Accessibility::Range* (*getTextAtOffset)         (RefObject*, int, int);         // 18
67   Accessibility::Range* (*getRangeOfSelection)     (RefObject*, int);              // 19
68   bool                  (*removeSelection)         (RefObject*, int);              // 20
69   bool                  (*setRangeOfSelection)     (RefObject*, int, int, int);    // 21
70   bool                  (*copyText)                (RefObject*, int, int);         // 22
71   bool                  (*cutText)                 (RefObject*, int, int);         // 23
72   bool                  (*insertText)              (RefObject*, int, const char*); // 24
73   bool                  (*setTextContents)         (RefObject*, const char*);      // 25
74   bool                  (*deleteText)              (RefObject*, int, int);         // 26
75   bool                  (*scrollToChild)           (RefObject*, Actor*);           // 27
76   int                   (*getSelectedChildrenCount)(RefObject*);                   // 28
77   Actor*                (*getSelectedChild)        (RefObject*, int);              // 29
78   bool                  (*selectChild)             (RefObject*, int);              // 30
79   bool                  (*deselectSelectedChild)   (RefObject*, int);              // 31
80   bool                  (*isChildSelected)         (RefObject*, int);              // 32
81   bool                  (*selectAll)               (RefObject*);                   // 33
82   bool                  (*clearSelection)          (RefObject*);                   // 34
83   bool                  (*deselectChild)           (RefObject*, int);              // 35
84   Rect<int>*            (*getRangeExtents)         (RefObject*, int, int, int);    // 36
85   void                  (*getAttributes)           (RefObject*, GetAttributesCallbackType, Accessibility::Attributes*); // 37
86   // clang-format on
87 };
88
89 NUIViewAccessible::NUIViewAccessible(Actor actor)
90 : ControlAccessible(actor)
91 {
92   DALI_ASSERT_DEBUG(mTable);
93 }
94
95 void NUIViewAccessible::SetAccessibilityDelegate(const AccessibilityDelegate* accessibilityDelegate)
96 {
97   if(mTable)
98   {
99     DALI_LOG_ERROR("Overwriting global AccessibilityDelegate");
100   }
101
102   mTable = accessibilityDelegate;
103 }
104
105 std::string NUIViewAccessible::StealString(char* str)
106 {
107   std::string ret{};
108
109   if(str)
110   {
111     ret = {str};
112     free(str);
113   }
114
115   return ret;
116 }
117
118 template<typename T>
119 T NUIViewAccessible::StealObject(T* obj)
120 {
121   T ret{};
122
123   if(obj)
124   {
125     ret = std::move(*obj);
126     delete obj;
127   }
128
129   return ret;
130 }
131
132 template<Interface I, typename R, typename... Args>
133 R NUIViewAccessible::CallMethod(R (*method)(RefObject*, Args...), Args... args) const
134 {
135   DALI_ASSERT_DEBUG(method);
136   DALI_ASSERT_ALWAYS(GetInterfaces()[I]);
137
138   return method(Self().GetObjectPtr(), args...);
139 }
140
141 //
142 // Standard interfaces (Accessible, Action, Component)
143 //
144
145 std::string NUIViewAccessible::GetNameRaw() const
146 {
147   char* name = CallMethod<Interface::ACCESSIBLE>(mTable->getName);
148
149   return StealString(name);
150 }
151
152 std::string NUIViewAccessible::GetDescriptionRaw() const
153 {
154   char* description = CallMethod<Interface::ACCESSIBLE>(mTable->getDescription);
155
156   return StealString(description);
157 }
158
159 bool NUIViewAccessible::GrabHighlight()
160 {
161   bool ret = ControlAccessible::GrabHighlight();
162
163   if(ret)
164   {
165     // Note: Currently (2021-03-26), size negotiation between the default highlight frame
166     // and NUI Components is known to be broken (and possibly in other cases, too). Please
167     // remove this for GrabHighlight() when it is fixed.
168     auto size = Self().GetProperty<Vector2>(Actor::Property::SIZE);
169     mCurrentHighlightActor.GetHandle().SetProperty(Actor::Property::SIZE, size);
170   }
171
172   return ret;
173 }
174
175 std::string NUIViewAccessible::GetActionName(std::size_t index) const
176 {
177   char* name = CallMethod<Interface::ACTION>(mTable->getActionName, static_cast<int>(index));
178
179   return StealString(name);
180 }
181
182 std::size_t NUIViewAccessible::GetActionCount() const
183 {
184   int count = CallMethod<Interface::ACTION>(mTable->getActionCount);
185
186   return static_cast<std::size_t>(count);
187 }
188
189 bool NUIViewAccessible::DoAction(std::size_t index)
190 {
191   return DoAction(GetActionName(index));
192 }
193
194 bool NUIViewAccessible::DoAction(const std::string& name)
195 {
196   return CallMethod<Interface::ACTION>(mTable->doAction, name.c_str());
197 }
198
199 Accessibility::States NUIViewAccessible::CalculateStates()
200 {
201   std::uint64_t states = ControlAccessible::CalculateStates().GetRawData64();
202
203   states = CallMethod<Interface::ACCESSIBLE>(mTable->calculateStates, states);
204
205   return Accessibility::States{states};
206 }
207
208 Accessibility::Attributes NUIViewAccessible::GetAttributes() const
209 {
210   auto attributes = ControlAccessible::GetAttributes();
211
212   CallMethod<Interface::ACCESSIBLE>(mTable->getAttributes, &GetAttributesCallback, &attributes);
213
214   return attributes;
215 }
216
217 Property::Index NUIViewAccessible::GetNamePropertyIndex()
218 {
219   return Property::INVALID_INDEX;
220 }
221
222 Property::Index NUIViewAccessible::GetDescriptionPropertyIndex()
223 {
224   return Property::INVALID_INDEX;
225 }
226
227 bool NUIViewAccessible::IsScrollable() const
228 {
229   return CallMethod<Interface::COMPONENT>(mTable->isScrollable);
230 }
231
232 bool NUIViewAccessible::ScrollToChild(Actor child)
233 {
234   return CallMethod<Interface::ACCESSIBLE>(mTable->scrollToChild, new Actor(child));
235 }
236
237 Accessibility::AtspiInterfaces NUIViewAccessible::DoGetInterfaces() const
238 {
239   using Interfaces = Accessibility::AtspiInterfaces;
240
241   Interfaces baseInterfaces;
242   Interfaces extraInterfaces;
243
244   // These are always implemented
245   baseInterfaces[Interface::ACCESSIBLE] = true;
246   baseInterfaces[Interface::ACTION]     = true;
247   baseInterfaces[Interface::COLLECTION] = true;
248   baseInterfaces[Interface::COMPONENT]  = true;
249
250   // We cannot use CallMethod() here as that would cause recursion.
251   // Note that the result will be cached and subsequent calls to GetInterfaces()
252   // will not involve calling this virtual method or jumping into C# code.
253   extraInterfaces = Interfaces{mTable->getInterfaces(Self().GetObjectPtr())};
254
255   return baseInterfaces | extraInterfaces;
256 }
257
258 //
259 // Value interface
260 //
261
262 double NUIViewAccessible::GetMinimum() const
263 {
264   return CallMethod<Interface::VALUE>(mTable->getMinimum);
265 }
266
267 double NUIViewAccessible::GetCurrent() const
268 {
269   return CallMethod<Interface::VALUE>(mTable->getCurrent);
270 }
271
272 double NUIViewAccessible::GetMaximum() const
273 {
274   return CallMethod<Interface::VALUE>(mTable->getMaximum);
275 }
276
277 bool NUIViewAccessible::SetCurrent(double value)
278 {
279   return CallMethod<Interface::VALUE>(mTable->setCurrent, value);
280 }
281
282 double NUIViewAccessible::GetMinimumIncrement() const
283 {
284   return CallMethod<Interface::VALUE>(mTable->getMinimumIncrement);
285 }
286
287 //
288 // Text interface
289 //
290
291 std::string NUIViewAccessible::GetText(std::size_t startOffset, std::size_t endOffset) const
292 {
293   char* text = CallMethod<Interface::TEXT>(mTable->getText, static_cast<int>(startOffset), static_cast<int>(endOffset));
294
295   return StealString(text);
296 }
297
298 std::size_t NUIViewAccessible::GetCharacterCount() const
299 {
300   int count = CallMethod<Interface::TEXT>(mTable->getCharacterCount);
301
302   return static_cast<std::size_t>(count);
303 }
304
305 std::size_t NUIViewAccessible::GetCursorOffset() const
306 {
307   int offset = CallMethod<Interface::TEXT>(mTable->getCursorOffset);
308
309   return static_cast<std::size_t>(offset);
310 }
311
312 bool NUIViewAccessible::SetCursorOffset(std::size_t offset)
313 {
314   return CallMethod<Interface::TEXT>(mTable->setCursorOffset, static_cast<int>(offset));
315 }
316
317 Accessibility::Range NUIViewAccessible::GetTextAtOffset(std::size_t offset, Accessibility::TextBoundary boundary) const
318 {
319   Accessibility::Range* range = CallMethod<Interface::TEXT>(mTable->getTextAtOffset, static_cast<int>(offset), static_cast<int>(boundary));
320
321   return StealObject(range);
322 }
323
324 Accessibility::Range NUIViewAccessible::GetRangeOfSelection(std::size_t selectionIndex) const
325 {
326   Accessibility::Range* range = CallMethod<Interface::TEXT>(mTable->getRangeOfSelection, static_cast<int>(selectionIndex));
327
328   return StealObject(range);
329 }
330
331 bool NUIViewAccessible::RemoveSelection(std::size_t selectionIndex)
332 {
333   return CallMethod<Interface::TEXT>(mTable->removeSelection, static_cast<int>(selectionIndex));
334 }
335
336 bool NUIViewAccessible::SetRangeOfSelection(std::size_t selectionIndex, std::size_t startOffset, std::size_t endOffset)
337 {
338   return CallMethod<Interface::TEXT>(mTable->setRangeOfSelection, static_cast<int>(selectionIndex), static_cast<int>(startOffset), static_cast<int>(endOffset));
339 }
340
341 Rect<> NUIViewAccessible::GetRangeExtents(std::size_t startOffset, std::size_t endOffset, Accessibility::CoordinateType type)
342 {
343   auto      rectPtr = CallMethod<Interface::TEXT>(mTable->getRangeExtents, static_cast<int>(startOffset), static_cast<int>(endOffset), static_cast<int>(type));
344   Rect<int> rect    = StealObject(rectPtr);
345
346   return {(float)rect.x, (float)rect.y, (float)rect.width, (float)rect.height};
347 }
348
349 //
350 // EditableText interface
351 //
352
353 bool NUIViewAccessible::CopyText(std::size_t startPosition, std::size_t endPosition)
354 {
355   return CallMethod<Interface::EDITABLE_TEXT>(mTable->copyText, static_cast<int>(startPosition), static_cast<int>(endPosition));
356 }
357
358 bool NUIViewAccessible::CutText(std::size_t startPosition, std::size_t endPosition)
359 {
360   return CallMethod<Interface::EDITABLE_TEXT>(mTable->cutText, static_cast<int>(startPosition), static_cast<int>(endPosition));
361 }
362
363 bool NUIViewAccessible::InsertText(std::size_t startPosition, std::string text)
364 {
365   return CallMethod<Interface::EDITABLE_TEXT>(mTable->insertText, static_cast<int>(startPosition), text.c_str());
366 }
367
368 bool NUIViewAccessible::SetTextContents(std::string newContents)
369 {
370   return CallMethod<Interface::EDITABLE_TEXT>(mTable->setTextContents, newContents.c_str());
371 }
372
373 bool NUIViewAccessible::DeleteText(std::size_t startPosition, std::size_t endPosition)
374 {
375   return CallMethod<Interface::EDITABLE_TEXT>(mTable->deleteText, static_cast<int>(startPosition), static_cast<int>(endPosition));
376 }
377
378 //
379 // Selection interface
380 //
381
382 int NUIViewAccessible::GetSelectedChildrenCount() const
383 {
384   return CallMethod<Interface::SELECTION>(mTable->getSelectedChildrenCount);
385 }
386
387 Accessibility::Accessible* NUIViewAccessible::GetSelectedChild(int selectedChildIndex)
388 {
389   Actor* actor = CallMethod<Interface::SELECTION>(mTable->getSelectedChild, selectedChildIndex);
390
391   return actor ? Accessibility::Accessible::Get(*actor) : nullptr;
392 }
393
394 bool NUIViewAccessible::SelectChild(int childIndex)
395 {
396   return CallMethod<Interface::SELECTION>(mTable->selectChild, childIndex);
397 }
398
399 bool NUIViewAccessible::DeselectSelectedChild(int selectedChildIndex)
400 {
401   return CallMethod<Interface::SELECTION>(mTable->deselectSelectedChild, selectedChildIndex);
402 }
403
404 bool NUIViewAccessible::IsChildSelected(int childIndex) const
405 {
406   return CallMethod<Interface::SELECTION>(mTable->isChildSelected, childIndex);
407 }
408
409 bool NUIViewAccessible::SelectAll()
410 {
411   return CallMethod<Interface::SELECTION>(mTable->selectAll);
412 }
413
414 bool NUIViewAccessible::ClearSelection()
415 {
416   return CallMethod<Interface::SELECTION>(mTable->clearSelection);
417 }
418
419 bool NUIViewAccessible::DeselectChild(int childIndex)
420 {
421   return CallMethod<Interface::SELECTION>(mTable->deselectChild, childIndex);
422 }
423
424 #ifdef __cplusplus
425 extern "C" {
426 #endif
427
428 SWIGEXPORT char* SWIGSTDCALL CSharp_Dali_Accessibility_DuplicateString(const char* arg)
429 {
430   return strdup(arg);
431 }
432
433 SWIGEXPORT void SWIGSTDCALL CSharp_Dali_Accessibility_SetAccessibilityDelegate(const void* arg1_accessibilityDelegate, int arg2_accessibilityDelegateSize)
434 {
435   GUARD_ON_NULL_RET(arg1_accessibilityDelegate);
436
437   const auto* accessibilityDelegate     = static_cast<const NUIViewAccessible::AccessibilityDelegate*>(arg1_accessibilityDelegate);
438   auto        accessibilityDelegateSize = static_cast<std::size_t>(arg2_accessibilityDelegateSize);
439
440   try_catch(([&]() {
441     if(accessibilityDelegateSize != sizeof(*accessibilityDelegate))
442     {
443       DALI_LOG_ERROR("SetAccessibilityDelegate error: Marshal.SizeOf<AccessibilityDelegate>()[%zu] != sizeof(AccessibilityDelegate)[%zu]\n", accessibilityDelegateSize, sizeof(*accessibilityDelegate));
444       throw std::runtime_error("SetAccessibilityDelegate error: Marshal.SizeOf<AccessibilityDelegate>() != sizeof(AccessibilityDelegate)");
445     }
446
447     NUIViewAccessible::SetAccessibilityDelegate(accessibilityDelegate);
448     Accessibility::Bridge::GetCurrentBridge()->SetToolkitName("nui(dali)");
449   }));
450 }
451
452 #ifdef __cplusplus
453 } // extern "C"
454 #endif