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 <dali/public-api/object/weak-handle.h>
26 #include <string_view>
27 #include <unordered_map>
30 #include <dali/devel-api/adaptor-framework/accessibility-bridge.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/collection.h>
35 #include <dali/devel-api/atspi-interfaces/component.h>
36 #include <dali/internal/adaptor/common/adaptor-impl.h>
37 #include <dali/public-api/dali-adaptor-common.h>
39 using namespace Dali::Accessibility;
42 const std::string& Dali::Accessibility::Address::GetBus() const
44 return mBus.empty() && Bridge::GetCurrentBridge() ? Bridge::GetCurrentBridge()->GetBusName() : mBus;
47 std::string Accessible::GetLocalizedRoleName() const
52 std::string Accessible::GetRoleName() const
54 static const std::unordered_map<Role, std::string_view> roleMap{
55 {Role::INVALID, "invalid"},
56 {Role::ACCELERATOR_LABEL, "accelerator label"},
57 {Role::ALERT, "alert"},
58 {Role::ANIMATION, "animation"},
59 {Role::ARROW, "arrow"},
60 {Role::CALENDAR, "calendar"},
61 {Role::CANVAS, "canvas"},
62 {Role::CHECK_BOX, "check box"},
63 {Role::CHECK_MENU_ITEM, "check menu item"},
64 {Role::COLOR_CHOOSER, "color chooser"},
65 {Role::COLUMN_HEADER, "column header"},
66 {Role::COMBO_BOX, "combo box"},
67 {Role::DATE_EDITOR, "date editor"},
68 {Role::DESKTOP_ICON, "desktop icon"},
69 {Role::DESKTOP_FRAME, "desktop frame"},
71 {Role::DIALOG, "dialog"},
72 {Role::DIRECTORY_PANE, "directory pane"},
73 {Role::DRAWING_AREA, "drawing area"},
74 {Role::FILE_CHOOSER, "file chooser"},
75 {Role::FILLER, "filler"},
76 {Role::FOCUS_TRAVERSABLE, "focus traversable"},
77 {Role::FONT_CHOOSER, "font chooser"},
78 {Role::FRAME, "frame"},
79 {Role::GLASS_PANE, "glass pane"},
80 {Role::HTML_CONTAINER, "html container"},
82 {Role::IMAGE, "image"},
83 {Role::INTERNAL_FRAME, "internal frame"},
84 {Role::LABEL, "label"},
85 {Role::LAYERED_PANE, "layered pane"},
87 {Role::LIST_ITEM, "list item"},
89 {Role::MENU_BAR, "menu bar"},
90 {Role::MENU_ITEM, "menu item"},
91 {Role::OPTION_PANE, "option pane"},
92 {Role::PAGE_TAB, "page tab"},
93 {Role::PAGE_TAB_LIST, "page tab list"},
94 {Role::PANEL, "panel"},
95 {Role::PASSWORD_TEXT, "password text"},
96 {Role::POPUP_MENU, "popup menu"},
97 {Role::PROGRESS_BAR, "progress bar"},
98 {Role::PUSH_BUTTON, "push button"},
99 {Role::RADIO_BUTTON, "radio button"},
100 {Role::RADIO_MENU_ITEM, "radio menu item"},
101 {Role::ROOT_PANE, "root pane"},
102 {Role::ROW_HEADER, "row header"},
103 {Role::SCROLL_BAR, "scroll bar"},
104 {Role::SCROLL_PANE, "scroll pane"},
105 {Role::SEPARATOR, "separator"},
106 {Role::SLIDER, "slider"},
107 {Role::SPIN_BUTTON, "spin button"},
108 {Role::SPLIT_PANE, "split pane"},
109 {Role::STATUS_BAR, "status bar"},
110 {Role::TABLE, "table"},
111 {Role::TABLE_CELL, "table cell"},
112 {Role::TABLE_COLUMN_HEADER, "table column header"},
113 {Role::TABLE_ROW_HEADER, "table row header"},
114 {Role::TEAROFF_MENU_ITEM, "tearoff menu item"},
115 {Role::TERMINAL, "terminal"},
116 {Role::TEXT, "text"},
117 {Role::TOGGLE_BUTTON, "toggle button"},
118 {Role::TOOL_BAR, "tool bar"},
119 {Role::TOOL_TIP, "tool tip"},
120 {Role::TREE, "tree"},
121 {Role::TREE_TABLE, "tree table"},
122 {Role::UNKNOWN, "unknown"},
123 {Role::VIEWPORT, "viewport"},
124 {Role::WINDOW, "window"},
125 {Role::EXTENDED, "extended"},
126 {Role::HEADER, "header"},
127 {Role::FOOTER, "footer"},
128 {Role::PARAGRAPH, "paragraph"},
129 {Role::RULER, "ruler"},
130 {Role::APPLICATION, "application"},
131 {Role::AUTOCOMPLETE, "autocomplete"},
132 {Role::EDITBAR, "edit bar"},
133 {Role::EMBEDDED, "embedded"},
134 {Role::ENTRY, "entry"},
135 {Role::CHART, "chart"},
136 {Role::CAPTION, "caution"},
137 {Role::DOCUMENT_FRAME, "document frame"},
138 {Role::HEADING, "heading"},
139 {Role::PAGE, "page"},
140 {Role::SECTION, "section"},
141 {Role::REDUNDANT_OBJECT, "redundant object"},
142 {Role::FORM, "form"},
143 {Role::LINK, "link"},
144 {Role::INPUT_METHOD_WINDOW, "input method window"},
145 {Role::TABLE_ROW, "table row"},
146 {Role::TREE_ITEM, "tree item"},
147 {Role::DOCUMENT_SPREADSHEET, "document spreadsheet"},
148 {Role::DOCUMENT_PRESENTATION, "document presentation"},
149 {Role::DOCUMENT_TEXT, "document text"},
150 {Role::DOCUMENT_WEB, "document web"},
151 {Role::DOCUMENT_EMAIL, "document email"},
152 {Role::COMMENT, "comment"},
153 {Role::LIST_BOX, "list box"},
154 {Role::GROUPING, "grouping"},
155 {Role::IMAGE_MAP, "image map"},
156 {Role::NOTIFICATION, "notification"},
157 {Role::INFO_BAR, "info bar"},
158 {Role::LEVEL_BAR, "level bar"},
159 {Role::TITLE_BAR, "title bar"},
160 {Role::BLOCK_QUOTE, "block quote"},
161 {Role::AUDIO, "audio"},
162 {Role::VIDEO, "video"},
163 {Role::DEFINITION, "definition"},
164 {Role::ARTICLE, "article"},
165 {Role::LANDMARK, "landmark"},
167 {Role::MARQUEE, "marquee"},
168 {Role::MATH, "math"},
169 {Role::RATING, "rating"},
170 {Role::TIMER, "timer"},
171 {Role::STATIC, "static"},
172 {Role::MATH_FRACTION, "math fraction"},
173 {Role::MATH_ROOT, "math root"},
174 {Role::SUBSCRIPT, "subscript"},
175 {Role::SUPERSCRIPT, "superscript"},
178 auto it = roleMap.find(GetRole());
180 if(it == roleMap.end())
185 return std::string{it->second};
188 Dali::Actor Accessible::GetCurrentlyHighlightedActor()
190 return IsUp() ? Bridge::GetCurrentBridge()->mData->mCurrentlyHighlightedActor : Dali::Actor{};
193 void Accessible::SetCurrentlyHighlightedActor(Dali::Actor actor)
197 Bridge::GetCurrentBridge()->mData->mCurrentlyHighlightedActor = actor;
201 Dali::Actor Accessible::GetHighlightActor()
203 return IsUp() ? Bridge::GetCurrentBridge()->mData->mHighlightActor : Dali::Actor{};
206 void Accessible::SetHighlightActor(Dali::Actor actor)
210 Bridge::GetCurrentBridge()->mData->mHighlightActor = actor;
214 void Bridge::ForceDown()
216 auto highlighted = Accessible::GetCurrentlyHighlightedActor();
219 auto component = dynamic_cast<Component*>(Accessible::Get(highlighted));
222 component->ClearHighlight();
228 void Bridge::SetIsOnRootLevel(Accessible* owner)
230 owner->mIsOnRootLevel = true;
235 class AdaptorAccessible : public virtual Accessible, public virtual Collection, public virtual Component
238 Dali::WeakHandle<Dali::Actor> mSelf;
241 Dali::Actor Self() const
243 auto handle = mSelf.GetHandle();
245 // AdaptorAccessible is deleted on ObjectDestroyedSignal
246 // for the respective actor (see `nonControlAccessibles`).
247 DALI_ASSERT_ALWAYS(handle);
253 AdaptorAccessible(Dali::Actor actor, bool isRoot)
259 Dali::Rect<> GetExtents(Dali::Accessibility::CoordinateType type) const override
261 Dali::Actor actor = Self();
262 Vector2 screenPosition = actor.GetProperty(Actor::Property::SCREEN_POSITION).Get<Vector2>();
263 Vector3 size = actor.GetCurrentProperty<Vector3>(Actor::Property::SIZE) * actor.GetCurrentProperty<Vector3>(Actor::Property::WORLD_SCALE);
264 bool positionUsesAnchorPoint = actor.GetProperty(Actor::Property::POSITION_USES_ANCHOR_POINT).Get<bool>();
265 Vector3 anchorPointOffSet = size * (positionUsesAnchorPoint ? actor.GetCurrentProperty<Vector3>(Actor::Property::ANCHOR_POINT) : AnchorPoint::TOP_LEFT);
266 Vector2 position = Vector2(screenPosition.x - anchorPointOffSet.x, screenPosition.y - anchorPointOffSet.y);
268 if(type == Dali::Accessibility::CoordinateType::WINDOW)
270 return {position.x, position.y, size.x, size.y};
272 else // Dali::Accessibility::CoordinateType::SCREEN
274 auto window = Dali::DevelWindow::Get(actor);
275 auto windowPosition = window.GetPosition();
276 return {position.x + windowPosition.GetX(), position.y + windowPosition.GetY(), size.x, size.y};
280 Dali::Accessibility::ComponentLayer GetLayer() const override
282 return Dali::Accessibility::ComponentLayer::WINDOW;
285 int16_t GetMdiZOrder() const override
290 double GetAlpha() const override
295 bool GrabFocus() override
300 bool GrabHighlight() override
305 bool ClearHighlight() override
310 bool IsScrollable() const override
315 std::string GetName() const override
317 return Self().GetProperty<std::string>(Dali::Actor::Property::NAME);
320 std::string GetDescription() const override
325 Accessible* GetParent() override
329 auto data = GetBridgeData();
330 return data->mBridge->GetApplication();
332 return Get(Self().GetParent());
335 size_t GetChildCount() const override
337 return static_cast<size_t>(Self().GetChildCount());
340 Accessible* GetChildAtIndex(size_t index) override
342 auto numberOfChildren = static_cast<size_t>(Self().GetChildCount());
343 if(index >= numberOfChildren)
345 throw std::domain_error{"invalid index " + std::to_string(index) + " for object with " + std::to_string(numberOfChildren) + " children"};
347 return Get(Self().GetChildAt(static_cast<unsigned int>(index)));
350 size_t GetIndexInParent() override
352 auto parent = Self().GetParent();
357 auto size = static_cast<size_t>(parent.GetChildCount());
358 for(auto i = 0u; i < size; ++i)
360 if(parent.GetChildAt(i) == Self())
365 throw std::domain_error{"actor is not a child of it's parent"};
368 Role GetRole() const override
370 return mRoot ? Role::WINDOW : Role::REDUNDANT_OBJECT;
373 States GetStates() override
378 auto window = Dali::DevelWindow::Get(Self());
379 auto visible = window.IsVisible();
380 state[State::ENABLED] = true;
381 state[State::SENSITIVE] = true;
382 state[State::SHOWING] = visible;
383 state[State::VISIBLE] = true;
384 state[State::ACTIVE] = visible;
388 auto parentState = GetParent()->GetStates();
389 state[State::SHOWING] = parentState[State::SHOWING];
390 state[State::VISIBLE] = parentState[State::VISIBLE];
395 Attributes GetAttributes() const override
398 Self().GetTypeInfo(type);
400 {"class", type.GetName()},
404 bool DoGesture(const GestureInfo& gestureInfo) override
409 std::vector<Relation> GetRelationSet() override
414 Dali::Actor GetInternalActor() override
416 return mSelf.GetHandle();
418 }; // AdaptorAccessible
420 using AdaptorAccessiblesType = std::unordered_map<const Dali::RefObject*, std::unique_ptr<AdaptorAccessible> >;
422 // Save RefObject from an Actor in Accessible::Get()
423 AdaptorAccessiblesType gAdaptorAccessibles;
425 std::function<Accessible*(Dali::Actor)> convertingFunctor = [](Dali::Actor) -> Accessible* {
429 ObjectRegistry objectRegistry;
432 void Accessible::SetObjectRegistry(ObjectRegistry registry)
434 objectRegistry = registry;
437 void Accessible::RegisterExternalAccessibleGetter(std::function<Accessible*(Dali::Actor)> functor)
439 convertingFunctor = functor;
442 Accessible* Accessible::Get(Dali::Actor actor, bool isRoot)
449 auto accessible = convertingFunctor(actor);
452 if(gAdaptorAccessibles.empty() && objectRegistry)
454 objectRegistry.ObjectDestroyedSignal().Connect([](const Dali::RefObject* obj) {
455 gAdaptorAccessibles.erase(obj);
458 auto pair = gAdaptorAccessibles.emplace(&actor.GetBaseObject(), nullptr);
461 pair.first->second.reset(new AdaptorAccessible(actor, isRoot));
463 accessible = pair.first->second.get();