Merge "Modify ecore_wl2_window_geometry_set() with window rotation angle" into devel...
[platform/core/uifw/dali-adaptor.git] / dali / devel-api / adaptor-framework / accessibility-impl.cpp
1 /*
2  * Copyright 2020  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 // CLASS HEADER
18
19 // EXTERNAL INCLUDES
20 #include <dali/integration-api/debug.h>
21 #include <dali/public-api/actors/actor.h>
22 #include <dali/public-api/actors/layer.h>
23 #include <dali/public-api/object/base-object.h>
24 #include <dali/public-api/object/object-registry.h>
25 #include <dali/public-api/object/type-info.h>
26 #include <dali/public-api/object/type-registry-helper.h>
27 #include <dali/public-api/object/weak-handle.h>
28
29 // INTERNAL INCLUDES
30 #include <dali/devel-api/adaptor-framework/accessibility-impl.h>
31 #include <dali/internal/adaptor/common/adaptor-impl.h>
32 #include <dali/public-api/dali-adaptor-common.h>
33
34 using namespace Dali::Accessibility;
35 using namespace Dali;
36
37 const std::string& Dali::Accessibility::Address::GetBus() const
38 {
39   return mBus.empty() && Bridge::GetCurrentBridge() ? Bridge::GetCurrentBridge()->GetBusName() : mBus;
40 }
41
42 std::string EmptyAccessibleWithAddress::GetRoleName()
43 {
44   return "";
45 }
46
47 std::string Accessible::GetLocalizedRoleName()
48 {
49   return GetRoleName();
50 }
51
52 std::string Accessible::GetRoleName()
53 {
54   switch(GetRole())
55   {
56     case Role::INVALID:
57     {
58       return "invalid";
59     }
60     case Role::ACCELERATOR_LABEL:
61     {
62       return "accelerator label";
63     }
64     case Role::ALERT:
65     {
66       return "alert";
67     }
68     case Role::ANIMATION:
69     {
70       return "animation";
71     }
72     case Role::ARROW:
73     {
74       return "arrow";
75     }
76     case Role::CALENDAR:
77     {
78       return "calendar";
79     }
80     case Role::CANVAS:
81     {
82       return "canvas";
83     }
84     case Role::CHECK_BOX:
85     {
86       return "check box";
87     }
88     case Role::CHECK_MENU_ITEM:
89     {
90       return "check menu item";
91     }
92     case Role::COLOR_CHOOSER:
93     {
94       return "color chooser";
95     }
96     case Role::COLUMN_HEADER:
97     {
98       return "column header";
99     }
100     case Role::COMBO_BOX:
101     {
102       return "combo box";
103     }
104     case Role::DATE_EDITOR:
105     {
106       return "date editor";
107     }
108     case Role::DESKTOP_ICON:
109     {
110       return "desktop icon";
111     }
112     case Role::DESKTOP_FRAME:
113     {
114       return "desktop frame";
115     }
116     case Role::DIAL:
117     {
118       return "dial";
119     }
120     case Role::DIALOG:
121     {
122       return "dialog";
123     }
124     case Role::DIRECTORY_PANE:
125     {
126       return "directory pane";
127     }
128     case Role::DRAWING_AREA:
129     {
130       return "drawing area";
131     }
132     case Role::FILE_CHOOSER:
133     {
134       return "file chooser";
135     }
136     case Role::FILLER:
137     {
138       return "filler";
139     }
140     case Role::FOCUS_TRAVERSABLE:
141     {
142       return "focus traversable";
143     }
144     case Role::FONT_CHOOSER:
145     {
146       return "font chooser";
147     }
148     case Role::FRAME:
149     {
150       return "frame";
151     }
152     case Role::GLASS_PANE:
153     {
154       return "glass pane";
155     }
156     case Role::HTML_CONTAINER:
157     {
158       return "html container";
159     }
160     case Role::ICON:
161     {
162       return "icon";
163     }
164     case Role::IMAGE:
165     {
166       return "image";
167     }
168     case Role::INTERNAL_FRAME:
169     {
170       return "internal frame";
171     }
172     case Role::LABEL:
173     {
174       return "label";
175     }
176     case Role::LAYERED_PANE:
177     {
178       return "layered pane";
179     }
180     case Role::LIST:
181     {
182       return "list";
183     }
184     case Role::LIST_ITEM:
185     {
186       return "list item";
187     }
188     case Role::MENU:
189     {
190       return "menu";
191     }
192     case Role::MENU_BAR:
193     {
194       return "menu bar";
195     }
196     case Role::MENU_ITEM:
197     {
198       return "menu item";
199     }
200     case Role::OPTION_PANE:
201     {
202       return "option pane";
203     }
204     case Role::PAGE_TAB:
205     {
206       return "page tab";
207     }
208     case Role::PAGE_TAB_LIST:
209     {
210       return "page tab list";
211     }
212     case Role::PANEL:
213     {
214       return "panel";
215     }
216     case Role::PASSWORD_TEXT:
217     {
218       return "password text";
219     }
220     case Role::POPUP_MENU:
221     {
222       return "popup menu";
223     }
224     case Role::PROGRESS_BAR:
225     {
226       return "progress bar";
227     }
228     case Role::PUSH_BUTTON:
229     {
230       return "push button";
231     }
232     case Role::RADIO_BUTTON:
233     {
234       return "radio button";
235     }
236     case Role::RADIO_MENU_ITEM:
237     {
238       return "radio menu item";
239     }
240     case Role::ROOT_PANE:
241     {
242       return "root pane";
243     }
244     case Role::ROW_HEADER:
245     {
246       return "row header";
247     }
248     case Role::SCROLL_BAR:
249     {
250       return "scroll bar";
251     }
252     case Role::SCROLL_PANE:
253     {
254       return "scroll pane";
255     }
256     case Role::SEPARATOR:
257     {
258       return "separator";
259     }
260     case Role::SLIDER:
261     {
262       return "slider";
263     }
264     case Role::SPIN_BUTTON:
265     {
266       return "spin button";
267     }
268     case Role::SPLIT_PANE:
269     {
270       return "split pane";
271     }
272     case Role::STATUS_BAR:
273     {
274       return "status bar";
275     }
276     case Role::TABLE:
277     {
278       return "table";
279     }
280     case Role::TABLE_CELL:
281     {
282       return "table cell";
283     }
284     case Role::TABLE_COLUMN_HEADER:
285     {
286       return "table column header";
287     }
288     case Role::TABLE_ROW_HEADER:
289     {
290       return "table row header";
291     }
292     case Role::TEAROFF_MENU_ITEM:
293     {
294       return "tearoff menu item";
295     }
296     case Role::TERMINAL:
297     {
298       return "terminal";
299     }
300     case Role::TEXT:
301     {
302       return "text";
303     }
304     case Role::TOGGLE_BUTTON:
305     {
306       return "toggle button";
307     }
308     case Role::TOOL_BAR:
309     {
310       return "tool bar";
311     }
312     case Role::TOOL_TIP:
313     {
314       return "tool tip";
315     }
316     case Role::TREE:
317     {
318       return "tree";
319     }
320     case Role::TREE_TABLE:
321     {
322       return "tree table";
323     }
324     case Role::UNKNOWN:
325     {
326       return "unknown";
327     }
328     case Role::VIEWPORT:
329     {
330       return "viewport";
331     }
332     case Role::WINDOW:
333     {
334       return "window";
335     }
336     case Role::EXTENDED:
337     {
338       return "extended";
339     }
340     case Role::HEADER:
341     {
342       return "header";
343     }
344     case Role::FOOTER:
345     {
346       return "footer";
347     }
348     case Role::PARAGRAPH:
349     {
350       return "paragraph";
351     }
352     case Role::RULER:
353     {
354       return "ruler";
355     }
356     case Role::APPLICATION:
357     {
358       return "application";
359     }
360     case Role::AUTOCOMPLETE:
361     {
362       return "autocomplete";
363     }
364     case Role::EDITBAR:
365     {
366       return "edit bar";
367     }
368     case Role::EMBEDDED:
369     {
370       return "embedded";
371     }
372     case Role::ENTRY:
373     {
374       return "entry";
375     }
376     case Role::CHART:
377     {
378       return "chart";
379     }
380     case Role::CAPTION:
381     {
382       return "caution";
383     }
384     case Role::DOCUMENT_FRAME:
385     {
386       return "document frame";
387     }
388     case Role::HEADING:
389     {
390       return "heading";
391     }
392     case Role::PAGE:
393     {
394       return "page";
395     }
396     case Role::SECTION:
397     {
398       return "section";
399     }
400     case Role::REDUNDANT_OBJECT:
401     {
402       return "redundant object";
403     }
404     case Role::FORM:
405     {
406       return "form";
407     }
408     case Role::LINK:
409     {
410       return "link";
411     }
412     case Role::INPUT_METHOD_WINDOW:
413     {
414       return "input method window";
415     }
416     case Role::TABLE_ROW:
417     {
418       return "table row";
419     }
420     case Role::TREE_ITEM:
421     {
422       return "tree item";
423     }
424     case Role::DOCUMENT_SPREADSHEET:
425     {
426       return "document spreadsheet";
427     }
428     case Role::DOCUMENT_PRESENTATION:
429     {
430       return "document presentation";
431     }
432     case Role::DOCUMENT_TEXT:
433     {
434       return "document text";
435     }
436     case Role::DOCUMENT_WEB:
437     {
438       return "document web";
439     }
440     case Role::DOCUMENT_EMAIL:
441     {
442       return "document email";
443     }
444     case Role::COMMENT:
445     {
446       return "comment";
447     }
448     case Role::LIST_BOX:
449     {
450       return "list box";
451     }
452     case Role::GROUPING:
453     {
454       return "grouping";
455     }
456     case Role::IMAGE_MAP:
457     {
458       return "image map";
459     }
460     case Role::NOTIFICATION:
461     {
462       return "notification";
463     }
464     case Role::INFO_BAR:
465     {
466       return "info bar";
467     }
468     case Role::LEVEL_BAR:
469     {
470       return "level bar";
471     }
472     case Role::TITLE_BAR:
473     {
474       return "title bar";
475     }
476     case Role::BLOCK_QUOTE:
477     {
478       return "block quote";
479     }
480     case Role::AUDIO:
481     {
482       return "audio";
483     }
484     case Role::VIDEO:
485     {
486       return "video";
487     }
488     case Role::DEFINITION:
489     {
490       return "definition";
491     }
492     case Role::ARTICLE:
493     {
494       return "article";
495     }
496     case Role::LANDMARK:
497     {
498       return "landmark";
499     }
500     case Role::LOG:
501     {
502       return "log";
503     }
504     case Role::MARQUEE:
505     {
506       return "marquee";
507     }
508     case Role::MATH:
509     {
510       return "math";
511     }
512     case Role::RATING:
513     {
514       return "rating";
515     }
516     case Role::TIMER:
517     {
518       return "timer";
519     }
520     case Role::STATIC:
521     {
522       return "static";
523     }
524     case Role::MATH_FRACTION:
525     {
526       return "math fraction";
527     }
528     case Role::MATH_ROOT:
529     {
530       return "math root";
531     }
532     case Role::SUBSCRIPT:
533     {
534       return "subscript";
535     }
536     case Role::SUPERSCRIPT:
537     {
538       return "superscript";
539     }
540     case Role::MAX_COUNT:
541     {
542       break;
543     }
544   }
545   return "";
546 }
547
548 Dali::Actor Accessible::GetCurrentlyHighlightedActor()
549 {
550   return IsUp() ? Bridge::GetCurrentBridge()->data->currentlyHighlightedActor : Dali::Actor{};
551 }
552
553 void Accessible::SetCurrentlyHighlightedActor(Dali::Actor actor)
554 {
555   if(IsUp())
556   {
557     Bridge::GetCurrentBridge()->data->currentlyHighlightedActor = actor;
558   }
559 }
560
561 Dali::Actor Accessible::GetHighlightActor()
562 {
563   return IsUp() ? Bridge::GetCurrentBridge()->data->highlightActor : Dali::Actor{};
564 }
565
566 void Accessible::SetHighlightActor(Dali::Actor actor)
567 {
568   if(IsUp())
569   {
570     Bridge::GetCurrentBridge()->data->highlightActor = actor;
571   }
572 }
573
574 void Bridge::ForceDown()
575 {
576   auto highlighted = Accessible::GetCurrentlyHighlightedActor();
577   if(highlighted)
578   {
579     auto p = dynamic_cast<Component*>(Accessible::Get(highlighted));
580     if(p)
581     {
582       p->ClearHighlight();
583     }
584   }
585   data = {};
586 }
587
588 void Bridge::SetIsOnRootLevel(Accessible* o)
589 {
590   o->isOnRootLevel = true;
591 }
592
593 namespace
594 {
595 class NonControlAccessible : public virtual Accessible, public virtual Collection, public virtual Component
596 {
597 protected:
598   Dali::WeakHandle<Dali::Actor> self;
599   bool        root = false;
600
601   Dali::Actor Self()
602   {
603     auto handle = self.GetHandle();
604
605     // NonControlAccessible is deleted on ObjectDestroyedSignal
606     // for the respective actor (see `nonControlAccessibles`).
607     DALI_ASSERT_ALWAYS(handle);
608
609     return handle;
610   }
611
612 public:
613   NonControlAccessible(Dali::Actor actor, bool root)
614   : self(actor),
615     root(root)
616   {
617   }
618
619   Dali::Rect<> GetExtents(Dali::Accessibility::CoordType ctype) override
620   {
621     Dali::Actor actor = Self();
622     Vector2 screenPosition          = actor.GetProperty(Actor::Property::SCREEN_POSITION).Get<Vector2>();
623     Vector3 size                    = actor.GetCurrentProperty<Vector3>(Actor::Property::SIZE) * actor.GetCurrentProperty<Vector3>(Actor::Property::WORLD_SCALE);
624     bool    positionUsesAnchorPoint = actor.GetProperty(Actor::Property::POSITION_USES_ANCHOR_POINT).Get<bool>();
625     Vector3 anchorPointOffSet       = size * (positionUsesAnchorPoint ? actor.GetCurrentProperty<Vector3>(Actor::Property::ANCHOR_POINT) : AnchorPoint::TOP_LEFT);
626     Vector2 position                = Vector2(screenPosition.x - anchorPointOffSet.x, screenPosition.y - anchorPointOffSet.y);
627
628     return {position.x, position.y, size.x, size.y};
629   }
630   Dali::Accessibility::ComponentLayer GetLayer() override
631   {
632     return Dali::Accessibility::ComponentLayer::WINDOW;
633   }
634   int16_t GetMdiZOrder()
635   {
636     return 0;
637   }
638   double GetAlpha()
639   {
640     return 0;
641   }
642   bool GrabFocus() override
643   {
644     return false;
645   }
646   bool GrabHighlight() override
647   {
648     return false;
649   }
650   bool ClearHighlight() override
651   {
652     return false;
653   }
654   bool IsScrollable() override
655   {
656     return false;
657   }
658   std::string GetName() override
659   {
660     return Self().GetProperty<std::string>(Dali::Actor::Property::NAME);
661   }
662   std::string GetDescription() override
663   {
664     return "";
665   }
666   Accessible* GetParent() override
667   {
668     if(GetIsOnRootLevel())
669     {
670       auto b = GetBridgeData();
671       return b->bridge->GetApplication();
672     }
673     return Get(Self().GetParent());
674   }
675   size_t GetChildCount() override
676   {
677     return static_cast<size_t>(Self().GetChildCount());
678   }
679   Accessible* GetChildAtIndex(size_t index) override
680   {
681     auto s = static_cast<size_t>(Self().GetChildCount());
682     if(index >= s)
683     {
684       throw std::domain_error{"invalid index " + std::to_string(index) + " for object with " + std::to_string(s) + " children"};
685     }
686     return Get(Self().GetChildAt(static_cast<unsigned int>(index)));
687   }
688   size_t GetIndexInParent() override
689   {
690     auto parent = Self().GetParent();
691     if(!parent)
692     {
693       return 0;
694     }
695     auto size = static_cast<size_t>(parent.GetChildCount());
696     for(auto i = 0u; i < size; ++i)
697     {
698       if(parent.GetChildAt(i) == Self())
699       {
700         return i;
701       }
702     }
703     throw std::domain_error{"actor is not a child of it's parent"};
704   }
705   Role GetRole() override
706   {
707     return root ? Role::WINDOW : Role::REDUNDANT_OBJECT;
708   }
709   States GetStates() override
710   {
711     States s;
712     if(root)
713     {
714       s[State::ENABLED]   = true;
715       s[State::SENSITIVE] = true;
716       s[State::SHOWING]   = true;
717       s[State::VISIBLE]   = true;
718       s[State::ACTIVE]    = true;
719     }
720     else
721     {
722       auto t            = GetParent()->GetStates();
723       s[State::SHOWING] = t[State::SHOWING];
724       s[State::VISIBLE] = t[State::VISIBLE];
725     }
726     return s;
727   }
728   Attributes GetAttributes() override
729   {
730     Dali::TypeInfo type;
731     Self().GetTypeInfo(type);
732     return {
733       {"t", type.GetName()},
734     };
735   }
736
737   bool DoGesture(const GestureInfo& gestureInfo) override
738   {
739     return false;
740   }
741
742   std::vector<Relation> GetRelationSet() override
743   {
744     return {};
745   }
746 };
747
748 using NonControlAccessiblesType = std::unordered_map<const Dali::RefObject*, std::unique_ptr<NonControlAccessible> >;
749
750 NonControlAccessiblesType nonControlAccessibles;
751
752 std::function<Accessible*(Dali::Actor)> convertingFunctor = [](Dali::Actor) -> Accessible* {
753   return nullptr;
754 };
755
756 ObjectRegistry objectRegistry;
757 } // namespace
758
759 void Accessible::SetObjectRegistry(ObjectRegistry registry)
760 {
761   objectRegistry = registry;
762 }
763
764 void Accessible::RegisterControlAccessibilityGetter(std::function<Accessible*(Dali::Actor)> functor)
765 {
766   convertingFunctor = functor;
767 }
768
769 Accessible* Accessible::Get(Dali::Actor actor, bool root)
770 {
771   if(!actor)
772   {
773     return nullptr;
774   }
775   auto accessible = convertingFunctor(actor);
776   if(!accessible)
777   {
778     if(nonControlAccessibles.empty() && objectRegistry)
779     {
780       objectRegistry.ObjectDestroyedSignal().Connect([](const Dali::RefObject* obj) {
781         nonControlAccessibles.erase(obj);
782       });
783     }
784     auto it = nonControlAccessibles.emplace(&actor.GetBaseObject(), nullptr);
785     if(it.second)
786     {
787       it.first->second.reset(new NonControlAccessible(actor, root));
788     }
789     accessible = it.first->second.get();
790   }
791   return accessible;
792 }