2 * Copyright 2020 Samsung Electronics Co., Ltd
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
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 <string_view>
26 #include <unordered_map>
29 #include <dali/devel-api/adaptor-framework/accessibility-bridge.h>
30 #include <dali/devel-api/adaptor-framework/actor-accessible.h>
31 #include <dali/devel-api/adaptor-framework/proxy-accessible.h>
32 #include <dali/devel-api/adaptor-framework/window-devel.h>
33 #include <dali/devel-api/atspi-interfaces/accessible.h>
34 #include <dali/devel-api/atspi-interfaces/action.h>
35 #include <dali/devel-api/atspi-interfaces/application.h>
36 #include <dali/devel-api/atspi-interfaces/collection.h>
37 #include <dali/devel-api/atspi-interfaces/component.h>
38 #include <dali/devel-api/atspi-interfaces/editable-text.h>
39 #include <dali/devel-api/atspi-interfaces/hyperlink.h>
40 #include <dali/devel-api/atspi-interfaces/hypertext.h>
41 #include <dali/devel-api/atspi-interfaces/selection.h>
42 #include <dali/devel-api/atspi-interfaces/socket.h>
43 #include <dali/devel-api/atspi-interfaces/text.h>
44 #include <dali/devel-api/atspi-interfaces/value.h>
45 #include <dali/internal/adaptor/common/adaptor-impl.h>
46 #include <dali/public-api/dali-adaptor-common.h>
48 using namespace Dali::Accessibility;
51 const std::string& Dali::Accessibility::Address::GetBus() const
53 return mBus.empty() && Bridge::GetCurrentBridge() ? Bridge::GetCurrentBridge()->GetBusName() : mBus;
56 std::string Accessible::GetLocalizedRoleName() const
61 std::string Accessible::GetRoleName() const
63 static const std::unordered_map<Role, std::string_view> roleMap{
64 {Role::INVALID, "invalid"},
65 {Role::ACCELERATOR_LABEL, "accelerator label"},
66 {Role::ALERT, "alert"},
67 {Role::ANIMATION, "animation"},
68 {Role::ARROW, "arrow"},
69 {Role::CALENDAR, "calendar"},
70 {Role::CANVAS, "canvas"},
71 {Role::CHECK_BOX, "check box"},
72 {Role::CHECK_MENU_ITEM, "check menu item"},
73 {Role::COLOR_CHOOSER, "color chooser"},
74 {Role::COLUMN_HEADER, "column header"},
75 {Role::COMBO_BOX, "combo box"},
76 {Role::DATE_EDITOR, "date editor"},
77 {Role::DESKTOP_ICON, "desktop icon"},
78 {Role::DESKTOP_FRAME, "desktop frame"},
80 {Role::DIALOG, "dialog"},
81 {Role::DIRECTORY_PANE, "directory pane"},
82 {Role::DRAWING_AREA, "drawing area"},
83 {Role::FILE_CHOOSER, "file chooser"},
84 {Role::FILLER, "filler"},
85 {Role::FOCUS_TRAVERSABLE, "focus traversable"},
86 {Role::FONT_CHOOSER, "font chooser"},
87 {Role::FRAME, "frame"},
88 {Role::GLASS_PANE, "glass pane"},
89 {Role::HTML_CONTAINER, "html container"},
91 {Role::IMAGE, "image"},
92 {Role::INTERNAL_FRAME, "internal frame"},
93 {Role::LABEL, "label"},
94 {Role::LAYERED_PANE, "layered pane"},
96 {Role::LIST_ITEM, "list item"},
98 {Role::MENU_BAR, "menu bar"},
99 {Role::MENU_ITEM, "menu item"},
100 {Role::OPTION_PANE, "option pane"},
101 {Role::PAGE_TAB, "page tab"},
102 {Role::PAGE_TAB_LIST, "page tab list"},
103 {Role::PANEL, "panel"},
104 {Role::PASSWORD_TEXT, "password text"},
105 {Role::POPUP_MENU, "popup menu"},
106 {Role::PROGRESS_BAR, "progress bar"},
107 {Role::PUSH_BUTTON, "push button"},
108 {Role::RADIO_BUTTON, "radio button"},
109 {Role::RADIO_MENU_ITEM, "radio menu item"},
110 {Role::ROOT_PANE, "root pane"},
111 {Role::ROW_HEADER, "row header"},
112 {Role::SCROLL_BAR, "scroll bar"},
113 {Role::SCROLL_PANE, "scroll pane"},
114 {Role::SEPARATOR, "separator"},
115 {Role::SLIDER, "slider"},
116 {Role::SPIN_BUTTON, "spin button"},
117 {Role::SPLIT_PANE, "split pane"},
118 {Role::STATUS_BAR, "status bar"},
119 {Role::TABLE, "table"},
120 {Role::TABLE_CELL, "table cell"},
121 {Role::TABLE_COLUMN_HEADER, "table column header"},
122 {Role::TABLE_ROW_HEADER, "table row header"},
123 {Role::TEAROFF_MENU_ITEM, "tearoff menu item"},
124 {Role::TERMINAL, "terminal"},
125 {Role::TEXT, "text"},
126 {Role::TOGGLE_BUTTON, "toggle button"},
127 {Role::TOOL_BAR, "tool bar"},
128 {Role::TOOL_TIP, "tool tip"},
129 {Role::TREE, "tree"},
130 {Role::TREE_TABLE, "tree table"},
131 {Role::UNKNOWN, "unknown"},
132 {Role::VIEWPORT, "viewport"},
133 {Role::WINDOW, "window"},
134 {Role::EXTENDED, "extended"},
135 {Role::HEADER, "header"},
136 {Role::FOOTER, "footer"},
137 {Role::PARAGRAPH, "paragraph"},
138 {Role::RULER, "ruler"},
139 {Role::APPLICATION, "application"},
140 {Role::AUTOCOMPLETE, "autocomplete"},
141 {Role::EDITBAR, "edit bar"},
142 {Role::EMBEDDED, "embedded"},
143 {Role::ENTRY, "entry"},
144 {Role::CHART, "chart"},
145 {Role::CAPTION, "caution"},
146 {Role::DOCUMENT_FRAME, "document frame"},
147 {Role::HEADING, "heading"},
148 {Role::PAGE, "page"},
149 {Role::SECTION, "section"},
150 {Role::REDUNDANT_OBJECT, "redundant object"},
151 {Role::FORM, "form"},
152 {Role::LINK, "link"},
153 {Role::INPUT_METHOD_WINDOW, "input method window"},
154 {Role::TABLE_ROW, "table row"},
155 {Role::TREE_ITEM, "tree item"},
156 {Role::DOCUMENT_SPREADSHEET, "document spreadsheet"},
157 {Role::DOCUMENT_PRESENTATION, "document presentation"},
158 {Role::DOCUMENT_TEXT, "document text"},
159 {Role::DOCUMENT_WEB, "document web"},
160 {Role::DOCUMENT_EMAIL, "document email"},
161 {Role::COMMENT, "comment"},
162 {Role::LIST_BOX, "list box"},
163 {Role::GROUPING, "grouping"},
164 {Role::IMAGE_MAP, "image map"},
165 {Role::NOTIFICATION, "notification"},
166 {Role::INFO_BAR, "info bar"},
167 {Role::LEVEL_BAR, "level bar"},
168 {Role::TITLE_BAR, "title bar"},
169 {Role::BLOCK_QUOTE, "block quote"},
170 {Role::AUDIO, "audio"},
171 {Role::VIDEO, "video"},
172 {Role::DEFINITION, "definition"},
173 {Role::ARTICLE, "article"},
174 {Role::LANDMARK, "landmark"},
176 {Role::MARQUEE, "marquee"},
177 {Role::MATH, "math"},
178 {Role::RATING, "rating"},
179 {Role::TIMER, "timer"},
180 {Role::STATIC, "static"},
181 {Role::MATH_FRACTION, "math fraction"},
182 {Role::MATH_ROOT, "math root"},
183 {Role::SUBSCRIPT, "subscript"},
184 {Role::SUPERSCRIPT, "superscript"},
187 auto it = roleMap.find(GetRole());
189 if(it == roleMap.end())
194 return std::string{it->second};
197 AtspiInterfaces Accessible::GetInterfaces() const
201 mInterfaces = DoGetInterfaces();
202 DALI_ASSERT_DEBUG(mInterfaces); // There has to be at least AtspiInterface::ACCESSIBLE
208 std::vector<std::string> Accessible::GetInterfacesAsStrings() const
210 std::vector<std::string> ret;
211 AtspiInterfaces interfaces = GetInterfaces();
213 for(std::size_t i = 0u; i < static_cast<std::size_t>(AtspiInterface::MAX_COUNT); ++i)
215 auto interface = static_cast<AtspiInterface>(i);
217 if(interfaces[interface])
219 auto name = GetInterfaceName(interface);
221 DALI_ASSERT_DEBUG(!name.empty());
222 ret.emplace_back(std::move(name));
229 AtspiInterfaces Accessible::DoGetInterfaces() const
231 AtspiInterfaces interfaces;
233 interfaces[AtspiInterface::ACCESSIBLE] = true;
234 interfaces[AtspiInterface::ACTION] = dynamic_cast<const Action*>(this);
235 interfaces[AtspiInterface::APPLICATION] = dynamic_cast<const Application*>(this);
236 interfaces[AtspiInterface::COLLECTION] = dynamic_cast<const Collection*>(this);
237 interfaces[AtspiInterface::COMPONENT] = dynamic_cast<const Component*>(this);
238 interfaces[AtspiInterface::EDITABLE_TEXT] = dynamic_cast<const EditableText*>(this);
239 interfaces[AtspiInterface::HYPERLINK] = dynamic_cast<const Hyperlink*>(this);
240 interfaces[AtspiInterface::HYPERTEXT] = dynamic_cast<const Hypertext*>(this);
241 interfaces[AtspiInterface::SELECTION] = dynamic_cast<const Selection*>(this);
242 interfaces[AtspiInterface::SOCKET] = dynamic_cast<const Socket*>(this);
243 interfaces[AtspiInterface::TEXT] = dynamic_cast<const Text*>(this);
244 interfaces[AtspiInterface::VALUE] = dynamic_cast<const Value*>(this);
249 std::string Accessible::GetInterfaceName(AtspiInterface interface)
251 static const std::unordered_map<AtspiInterface, std::string_view> interfaceMap{
252 {AtspiInterface::ACCESSIBLE, "org.a11y.atspi.Accessible"},
253 {AtspiInterface::ACTION, "org.a11y.atspi.Action"},
254 {AtspiInterface::APPLICATION, "org.a11y.atspi.Application"},
255 {AtspiInterface::CACHE, "org.a11y.atspi.Cache"},
256 {AtspiInterface::COLLECTION, "org.a11y.atspi.Collection"},
257 {AtspiInterface::COMPONENT, "org.a11y.atspi.Component"},
258 {AtspiInterface::DEVICE_EVENT_CONTROLLER, "org.a11y.atspi.DeviceEventController"},
259 {AtspiInterface::DEVICE_EVENT_LISTENER, "org.a11y.atspi.DeviceEventListener"},
260 {AtspiInterface::DOCUMENT, "org.a11y.atspi.Document"},
261 {AtspiInterface::EDITABLE_TEXT, "org.a11y.atspi.EditableText"},
262 {AtspiInterface::EVENT_DOCUMENT, "org.a11y.atspi.Event.Document"},
263 {AtspiInterface::EVENT_FOCUS, "org.a11y.atspi.Event.Focus"},
264 {AtspiInterface::EVENT_KEYBOARD, "org.a11y.atspi.Event.Keyboard"},
265 {AtspiInterface::EVENT_MOUSE, "org.a11y.atspi.Event.Mouse"},
266 {AtspiInterface::EVENT_OBJECT, "org.a11y.atspi.Event.Object"},
267 {AtspiInterface::EVENT_TERMINAL, "org.a11y.atspi.Event.Terminal"},
268 {AtspiInterface::EVENT_WINDOW, "org.a11y.atspi.Event.Window"},
269 {AtspiInterface::HYPERLINK, "org.a11y.atspi.Hyperlink"},
270 {AtspiInterface::HYPERTEXT, "org.a11y.atspi.Hypertext"},
271 {AtspiInterface::IMAGE, "org.a11y.atspi.Image"},
272 {AtspiInterface::REGISTRY, "org.a11y.atspi.Registry"},
273 {AtspiInterface::SELECTION, "org.a11y.atspi.Selection"},
274 {AtspiInterface::SOCKET, "org.a11y.atspi.Socket"},
275 {AtspiInterface::TABLE, "org.a11y.atspi.Table"},
276 {AtspiInterface::TABLE_CELL, "org.a11y.atspi.TableCell"},
277 {AtspiInterface::TEXT, "org.a11y.atspi.Text"},
278 {AtspiInterface::VALUE, "org.a11y.atspi.Value"},
281 auto it = interfaceMap.find(interface);
283 if(it == interfaceMap.end())
288 return std::string{it->second};
291 Dali::Actor Accessible::GetCurrentlyHighlightedActor()
293 return IsUp() ? Bridge::GetCurrentBridge()->mData->mCurrentlyHighlightedActor : Dali::Actor{};
296 void Accessible::SetCurrentlyHighlightedActor(Dali::Actor actor)
300 Bridge::GetCurrentBridge()->mData->mCurrentlyHighlightedActor = actor;
304 Dali::Actor Accessible::GetHighlightActor()
306 return IsUp() ? Bridge::GetCurrentBridge()->mData->mHighlightActor : Dali::Actor{};
309 void Accessible::SetHighlightActor(Dali::Actor actor)
313 Bridge::GetCurrentBridge()->mData->mHighlightActor = actor;
317 void Bridge::ForceDown()
319 auto highlighted = Accessible::GetCurrentlyHighlightedActor();
322 auto component = dynamic_cast<Component*>(Accessible::Get(highlighted));
325 component->ClearHighlight();
331 void Bridge::SetIsOnRootLevel(Accessible* owner)
333 owner->mIsOnRootLevel = true;
338 class AdaptorAccessible : public ActorAccessible
344 AdaptorAccessible(Dali::Actor actor, bool isRoot)
345 : ActorAccessible(actor),
350 bool GrabFocus() override
355 bool GrabHighlight() override
360 bool ClearHighlight() override
365 Role GetRole() const override
367 return mRoot ? Role::WINDOW : Role::REDUNDANT_OBJECT;
370 States GetStates() override
375 auto window = Dali::DevelWindow::Get(Self());
376 auto visible = window.IsVisible();
377 state[State::ENABLED] = true;
378 state[State::SENSITIVE] = true;
379 state[State::SHOWING] = visible;
380 state[State::VISIBLE] = true;
381 state[State::ACTIVE] = visible;
385 auto parentState = GetParent()->GetStates();
386 state[State::SHOWING] = parentState[State::SHOWING];
387 state[State::VISIBLE] = parentState[State::VISIBLE];
392 Attributes GetAttributes() const override
395 Self().GetTypeInfo(type);
397 {"class", type.GetName()},
401 bool DoGesture(const GestureInfo& gestureInfo) override
406 std::vector<Relation> GetRelationSet() override
410 }; // AdaptorAccessible
412 using AdaptorAccessiblesType = std::unordered_map<const Dali::RefObject*, std::unique_ptr<AdaptorAccessible> >;
414 // Save RefObject from an Actor in Accessible::Get()
415 AdaptorAccessiblesType gAdaptorAccessibles;
417 std::function<Accessible*(Dali::Actor)> convertingFunctor = [](Dali::Actor) -> Accessible* {
421 ObjectRegistry objectRegistry;
424 void Accessible::SetObjectRegistry(ObjectRegistry registry)
426 objectRegistry = registry;
427 objectRegistry.ObjectDestroyedSignal().Connect([](const Dali::RefObject* obj) {
428 gAdaptorAccessibles.erase(obj);
432 void Accessible::RegisterExternalAccessibleGetter(std::function<Accessible*(Dali::Actor)> functor)
434 convertingFunctor = functor;
437 Accessible* Accessible::Get(Dali::Actor actor, bool isRoot)
444 auto accessible = convertingFunctor(actor);
447 auto pair = gAdaptorAccessibles.emplace(&actor.GetBaseObject(), nullptr);
450 pair.first->second.reset(new AdaptorAccessible(actor, isRoot));
452 accessible = pair.first->second.get();