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>
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>
37 using namespace Dali::Accessibility;
40 const std::string& Dali::Accessibility::Address::GetBus() const
42 return mBus.empty() && Bridge::GetCurrentBridge() ? Bridge::GetCurrentBridge()->GetBusName() : mBus;
45 std::string EmptyAccessibleWithAddress::GetRoleName()
50 std::string Accessible::GetLocalizedRoleName()
55 std::string Accessible::GetRoleName()
63 case Role::ACCELERATOR_LABEL:
65 return "accelerator label";
91 case Role::CHECK_MENU_ITEM:
93 return "check menu item";
95 case Role::COLOR_CHOOSER:
97 return "color chooser";
99 case Role::COLUMN_HEADER:
101 return "column header";
103 case Role::COMBO_BOX:
107 case Role::DATE_EDITOR:
109 return "date editor";
111 case Role::DESKTOP_ICON:
113 return "desktop icon";
115 case Role::DESKTOP_FRAME:
117 return "desktop frame";
127 case Role::DIRECTORY_PANE:
129 return "directory pane";
131 case Role::DRAWING_AREA:
133 return "drawing area";
135 case Role::FILE_CHOOSER:
137 return "file chooser";
143 case Role::FOCUS_TRAVERSABLE:
145 return "focus traversable";
147 case Role::FONT_CHOOSER:
149 return "font chooser";
155 case Role::GLASS_PANE:
159 case Role::HTML_CONTAINER:
161 return "html container";
171 case Role::INTERNAL_FRAME:
173 return "internal frame";
179 case Role::LAYERED_PANE:
181 return "layered pane";
187 case Role::LIST_ITEM:
199 case Role::MENU_ITEM:
203 case Role::OPTION_PANE:
205 return "option pane";
211 case Role::PAGE_TAB_LIST:
213 return "page tab list";
219 case Role::PASSWORD_TEXT:
221 return "password text";
223 case Role::POPUP_MENU:
227 case Role::PROGRESS_BAR:
229 return "progress bar";
231 case Role::PUSH_BUTTON:
233 return "push button";
235 case Role::RADIO_BUTTON:
237 return "radio button";
239 case Role::RADIO_MENU_ITEM:
241 return "radio menu item";
243 case Role::ROOT_PANE:
247 case Role::ROW_HEADER:
251 case Role::SCROLL_BAR:
255 case Role::SCROLL_PANE:
257 return "scroll pane";
259 case Role::SEPARATOR:
267 case Role::SPIN_BUTTON:
269 return "spin button";
271 case Role::SPLIT_PANE:
275 case Role::STATUS_BAR:
283 case Role::TABLE_CELL:
287 case Role::TABLE_COLUMN_HEADER:
289 return "table column header";
291 case Role::TABLE_ROW_HEADER:
293 return "table row header";
295 case Role::TEAROFF_MENU_ITEM:
297 return "tearoff menu item";
307 case Role::TOGGLE_BUTTON:
309 return "toggle button";
323 case Role::TREE_TABLE:
351 case Role::PARAGRAPH:
359 case Role::APPLICATION:
361 return "application";
363 case Role::AUTOCOMPLETE:
365 return "autocomplete";
387 case Role::DOCUMENT_FRAME:
389 return "document frame";
403 case Role::REDUNDANT_OBJECT:
405 return "redundant object";
415 case Role::INPUT_METHOD_WINDOW:
417 return "input method window";
419 case Role::TABLE_ROW:
423 case Role::TREE_ITEM:
427 case Role::DOCUMENT_SPREADSHEET:
429 return "document spreadsheet";
431 case Role::DOCUMENT_PRESENTATION:
433 return "document presentation";
435 case Role::DOCUMENT_TEXT:
437 return "document text";
439 case Role::DOCUMENT_WEB:
441 return "document web";
443 case Role::DOCUMENT_EMAIL:
445 return "document email";
459 case Role::IMAGE_MAP:
463 case Role::NOTIFICATION:
465 return "notification";
471 case Role::LEVEL_BAR:
475 case Role::TITLE_BAR:
479 case Role::BLOCK_QUOTE:
481 return "block quote";
491 case Role::DEFINITION:
527 case Role::MATH_FRACTION:
529 return "math fraction";
531 case Role::MATH_ROOT:
535 case Role::SUBSCRIPT:
539 case Role::SUPERSCRIPT:
541 return "superscript";
543 case Role::MAX_COUNT:
551 Dali::Actor Accessible::GetCurrentlyHighlightedActor()
553 return IsUp() ? Bridge::GetCurrentBridge()->mData->mCurrentlyHighlightedActor : Dali::Actor{};
556 void Accessible::SetCurrentlyHighlightedActor(Dali::Actor actor)
560 Bridge::GetCurrentBridge()->mData->mCurrentlyHighlightedActor = actor;
564 Dali::Actor Accessible::GetHighlightActor()
566 return IsUp() ? Bridge::GetCurrentBridge()->mData->mHighlightActor : Dali::Actor{};
569 void Accessible::SetHighlightActor(Dali::Actor actor)
573 Bridge::GetCurrentBridge()->mData->mHighlightActor = actor;
577 void Bridge::ForceDown()
579 auto highlighted = Accessible::GetCurrentlyHighlightedActor();
582 auto component = dynamic_cast<Component*>(Accessible::Get(highlighted));
585 component->ClearHighlight();
591 void Bridge::SetIsOnRootLevel(Accessible* owner)
593 owner->mIsOnRootLevel = true;
598 class AdaptorAccessible : public virtual Accessible, public virtual Collection, public virtual Component
601 Dali::WeakHandle<Dali::Actor> mSelf;
606 auto handle = mSelf.GetHandle();
608 // AdaptorAccessible is deleted on ObjectDestroyedSignal
609 // for the respective actor (see `nonControlAccessibles`).
610 DALI_ASSERT_ALWAYS(handle);
616 AdaptorAccessible(Dali::Actor actor, bool isRoot)
622 Dali::Rect<> GetExtents(Dali::Accessibility::CoordinateType type) override
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);
631 if(type == Dali::Accessibility::CoordinateType::WINDOW)
633 return {position.x, position.y, size.x, size.y};
635 else // Dali::Accessibility::CoordinateType::SCREEN
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};
643 Dali::Accessibility::ComponentLayer GetLayer() override
645 return Dali::Accessibility::ComponentLayer::WINDOW;
648 int16_t GetMdiZOrder() override
653 double GetAlpha() override
658 bool GrabFocus() override
663 bool GrabHighlight() override
668 bool ClearHighlight() override
673 bool IsScrollable() override
678 std::string GetName() override
680 return Self().GetProperty<std::string>(Dali::Actor::Property::NAME);
683 std::string GetDescription() override
688 Accessible* GetParent() override
692 auto data = GetBridgeData();
693 return data->mBridge->GetApplication();
695 return Get(Self().GetParent());
698 size_t GetChildCount() override
700 return static_cast<size_t>(Self().GetChildCount());
703 Accessible* GetChildAtIndex(size_t index) override
705 auto numberOfChildren = static_cast<size_t>(Self().GetChildCount());
706 if(index >= numberOfChildren)
708 throw std::domain_error{"invalid index " + std::to_string(index) + " for object with " + std::to_string(numberOfChildren) + " children"};
710 return Get(Self().GetChildAt(static_cast<unsigned int>(index)));
713 size_t GetIndexInParent() override
715 auto parent = Self().GetParent();
720 auto size = static_cast<size_t>(parent.GetChildCount());
721 for(auto i = 0u; i < size; ++i)
723 if(parent.GetChildAt(i) == Self())
728 throw std::domain_error{"actor is not a child of it's parent"};
731 Role GetRole() override
733 return mRoot ? Role::WINDOW : Role::REDUNDANT_OBJECT;
736 States GetStates() override
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;
751 auto parentState = GetParent()->GetStates();
752 state[State::SHOWING] = parentState[State::SHOWING];
753 state[State::VISIBLE] = parentState[State::VISIBLE];
758 Attributes GetAttributes() override
761 Self().GetTypeInfo(type);
764 {"class", type.GetName()},
768 bool DoGesture(const GestureInfo& gestureInfo) override
773 std::vector<Relation> GetRelationSet() override
778 Dali::Actor GetInternalActor() override
780 return mSelf.GetHandle();
782 }; // AdaptorAccessible
784 using AdaptorAccessiblesType = std::unordered_map<const Dali::RefObject*, std::unique_ptr<AdaptorAccessible> >;
786 // Save RefObject from an Actor in Accessible::Get()
787 AdaptorAccessiblesType gAdaptorAccessibles;
789 std::function<Accessible*(Dali::Actor)> convertingFunctor = [](Dali::Actor) -> Accessible* {
793 ObjectRegistry objectRegistry;
796 void Accessible::SetObjectRegistry(ObjectRegistry registry)
798 objectRegistry = registry;
801 void Accessible::RegisterExternalAccessibleGetter(std::function<Accessible*(Dali::Actor)> functor)
803 convertingFunctor = functor;
806 Accessible* Accessible::Get(Dali::Actor actor, bool isRoot)
813 auto accessible = convertingFunctor(actor);
816 if(gAdaptorAccessibles.empty() && objectRegistry)
818 objectRegistry.ObjectDestroyedSignal().Connect([](const Dali::RefObject* obj) {
819 gAdaptorAccessibles.erase(obj);
822 auto pair = gAdaptorAccessibles.emplace(&actor.GetBaseObject(), nullptr);
825 pair.first->second.reset(new AdaptorAccessible(actor, isRoot));
827 accessible = pair.first->second.get();