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