X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali%2Fdevel-api%2Fadaptor-framework%2Faccessibility.cpp;h=f69c96cdc768806952b25f6658ba5a8ad6cb10ac;hb=HEAD;hp=7caed8e450ed3375a8c3e161c7e48f895d7e894f;hpb=bca8807cab8f86a80f680a394e81d03cdff5f5f4;p=platform%2Fcore%2Fuifw%2Fdali-adaptor.git diff --git a/dali/devel-api/adaptor-framework/accessibility.cpp b/dali/devel-api/adaptor-framework/accessibility.cpp index 7caed8e..6caf3d8 100644 --- a/dali/devel-api/adaptor-framework/accessibility.cpp +++ b/dali/devel-api/adaptor-framework/accessibility.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2020 Samsung Electronics Co., Ltd + * Copyright 2022 Samsung Electronics Co., Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,18 +22,30 @@ #include #include #include -#include #include #include // INTERNAL INCLUDES #include +#include #include #include #include +#include +#include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include #include using namespace Dali::Accessibility; @@ -185,6 +197,102 @@ std::string Accessible::GetRoleName() const return std::string{it->second}; } +AtspiInterfaces Accessible::GetInterfaces() const +{ + if(!mInterfaces) + { + mInterfaces = DoGetInterfaces(); + DALI_ASSERT_DEBUG(mInterfaces); // There has to be at least AtspiInterface::ACCESSIBLE + } + + return mInterfaces; +} + +std::vector Accessible::GetInterfacesAsStrings() const +{ + std::vector ret; + AtspiInterfaces interfaces = GetInterfaces(); + + for(std::size_t i = 0u; i < static_cast(AtspiInterface::MAX_COUNT); ++i) + { + auto interface = static_cast(i); + + if(interfaces[interface]) + { + auto name = GetInterfaceName(interface); + + DALI_ASSERT_DEBUG(!name.empty()); + ret.emplace_back(std::move(name)); + } + } + + return ret; +} + +AtspiInterfaces Accessible::DoGetInterfaces() const +{ + AtspiInterfaces interfaces; + + interfaces[AtspiInterface::ACCESSIBLE] = true; + interfaces[AtspiInterface::ACTION] = dynamic_cast(this); + interfaces[AtspiInterface::APPLICATION] = dynamic_cast(this); + interfaces[AtspiInterface::COLLECTION] = dynamic_cast(this); + interfaces[AtspiInterface::COMPONENT] = dynamic_cast(this); + interfaces[AtspiInterface::EDITABLE_TEXT] = dynamic_cast(this); + interfaces[AtspiInterface::HYPERLINK] = dynamic_cast(this); + interfaces[AtspiInterface::HYPERTEXT] = dynamic_cast(this); + interfaces[AtspiInterface::SELECTION] = dynamic_cast(this); + interfaces[AtspiInterface::SOCKET] = dynamic_cast(this); + interfaces[AtspiInterface::TABLE] = dynamic_cast(this); + interfaces[AtspiInterface::TABLE_CELL] = dynamic_cast(this); + interfaces[AtspiInterface::TEXT] = dynamic_cast(this); + interfaces[AtspiInterface::VALUE] = dynamic_cast(this); + + return interfaces; +} + +std::string Accessible::GetInterfaceName(AtspiInterface interface) +{ + static const std::unordered_map interfaceMap{ + {AtspiInterface::ACCESSIBLE, "org.a11y.atspi.Accessible"}, + {AtspiInterface::ACTION, "org.a11y.atspi.Action"}, + {AtspiInterface::APPLICATION, "org.a11y.atspi.Application"}, + {AtspiInterface::CACHE, "org.a11y.atspi.Cache"}, + {AtspiInterface::COLLECTION, "org.a11y.atspi.Collection"}, + {AtspiInterface::COMPONENT, "org.a11y.atspi.Component"}, + {AtspiInterface::DEVICE_EVENT_CONTROLLER, "org.a11y.atspi.DeviceEventController"}, + {AtspiInterface::DEVICE_EVENT_LISTENER, "org.a11y.atspi.DeviceEventListener"}, + {AtspiInterface::DOCUMENT, "org.a11y.atspi.Document"}, + {AtspiInterface::EDITABLE_TEXT, "org.a11y.atspi.EditableText"}, + {AtspiInterface::EVENT_DOCUMENT, "org.a11y.atspi.Event.Document"}, + {AtspiInterface::EVENT_FOCUS, "org.a11y.atspi.Event.Focus"}, + {AtspiInterface::EVENT_KEYBOARD, "org.a11y.atspi.Event.Keyboard"}, + {AtspiInterface::EVENT_MOUSE, "org.a11y.atspi.Event.Mouse"}, + {AtspiInterface::EVENT_OBJECT, "org.a11y.atspi.Event.Object"}, + {AtspiInterface::EVENT_TERMINAL, "org.a11y.atspi.Event.Terminal"}, + {AtspiInterface::EVENT_WINDOW, "org.a11y.atspi.Event.Window"}, + {AtspiInterface::HYPERLINK, "org.a11y.atspi.Hyperlink"}, + {AtspiInterface::HYPERTEXT, "org.a11y.atspi.Hypertext"}, + {AtspiInterface::IMAGE, "org.a11y.atspi.Image"}, + {AtspiInterface::REGISTRY, "org.a11y.atspi.Registry"}, + {AtspiInterface::SELECTION, "org.a11y.atspi.Selection"}, + {AtspiInterface::SOCKET, "org.a11y.atspi.Socket"}, + {AtspiInterface::TABLE, "org.a11y.atspi.Table"}, + {AtspiInterface::TABLE_CELL, "org.a11y.atspi.TableCell"}, + {AtspiInterface::TEXT, "org.a11y.atspi.Text"}, + {AtspiInterface::VALUE, "org.a11y.atspi.Value"}, + }; + + auto it = interfaceMap.find(interface); + + if(it == interfaceMap.end()) + { + return {}; + } + + return std::string{it->second}; +} + Dali::Actor Accessible::GetCurrentlyHighlightedActor() { return IsUp() ? Bridge::GetCurrentBridge()->mData->mCurrentlyHighlightedActor : Dali::Actor{}; @@ -198,6 +306,13 @@ void Accessible::SetCurrentlyHighlightedActor(Dali::Actor actor) } } +bool Accessible::IsHighlighted() const +{ + Dali::Actor self = GetInternalActor(); + + return self && self == GetCurrentlyHighlightedActor(); +} + Dali::Actor Accessible::GetHighlightActor() { return IsUp() ? Bridge::GetCurrentBridge()->mData->mHighlightActor : Dali::Actor{}; @@ -232,66 +347,21 @@ void Bridge::SetIsOnRootLevel(Accessible* owner) namespace { -class AdaptorAccessible : public virtual Accessible, public virtual Collection, public virtual Component +class AdaptorAccessible : public ActorAccessible { -protected: - Dali::WeakHandle mSelf; - bool mRoot = false; +private: + std::unique_ptr mRenderNotification = nullptr; - Dali::Actor Self() const - { - auto handle = mSelf.GetHandle(); - - // AdaptorAccessible is deleted on ObjectDestroyedSignal - // for the respective actor (see `nonControlAccessibles`). - DALI_ASSERT_ALWAYS(handle); - - return handle; - } +protected: + bool mRoot = false; public: AdaptorAccessible(Dali::Actor actor, bool isRoot) - : mSelf(actor), + : ActorAccessible(actor), mRoot(isRoot) { } - Dali::Rect<> GetExtents(Dali::Accessibility::CoordinateType type) const override - { - Dali::Actor actor = Self(); - Vector2 screenPosition = actor.GetProperty(Actor::Property::SCREEN_POSITION).Get(); - Vector3 size = actor.GetCurrentProperty(Actor::Property::SIZE) * actor.GetCurrentProperty(Actor::Property::WORLD_SCALE); - bool positionUsesAnchorPoint = actor.GetProperty(Actor::Property::POSITION_USES_ANCHOR_POINT).Get(); - Vector3 anchorPointOffSet = size * (positionUsesAnchorPoint ? actor.GetCurrentProperty(Actor::Property::ANCHOR_POINT) : AnchorPoint::TOP_LEFT); - Vector2 position = Vector2(screenPosition.x - anchorPointOffSet.x, screenPosition.y - anchorPointOffSet.y); - - if(type == Dali::Accessibility::CoordinateType::WINDOW) - { - return {position.x, position.y, size.x, size.y}; - } - else // Dali::Accessibility::CoordinateType::SCREEN - { - auto window = Dali::DevelWindow::Get(actor); - auto windowPosition = window.GetPosition(); - return {position.x + windowPosition.GetX(), position.y + windowPosition.GetY(), size.x, size.y}; - } - } - - Dali::Accessibility::ComponentLayer GetLayer() const override - { - return Dali::Accessibility::ComponentLayer::WINDOW; - } - - int16_t GetMdiZOrder() const override - { - return 0; - } - - double GetAlpha() const override - { - return 0; - } - bool GrabFocus() override { return false; @@ -299,70 +369,68 @@ public: bool GrabHighlight() override { - return false; - } - - bool ClearHighlight() override - { - return false; - } - - bool IsScrollable() const override - { - return false; - } + if(!IsUp()) + { + return false; + } - std::string GetName() const override - { - return Self().GetProperty(Dali::Actor::Property::NAME); - } + // Only window accessible is able to grab and clear highlight + if(!mRoot) + { + return false; + } - std::string GetDescription() const override - { - return ""; - } + auto self = Self(); + auto oldHighlightedActor = GetCurrentlyHighlightedActor(); + if(self == oldHighlightedActor) + { + return true; + } - Accessible* GetParent() override - { - if(IsOnRootLevel()) + // Clear the old highlight. + if(oldHighlightedActor) { - auto data = GetBridgeData(); - return data->mBridge->GetApplication(); + auto oldHighlightedObject = Dali::Accessibility::Component::DownCast(Accessible::Get(oldHighlightedActor)); + if(oldHighlightedObject) + { + oldHighlightedObject->ClearHighlight(); + } } - return Get(Self().GetParent()); - } - size_t GetChildCount() const override - { - return static_cast(Self().GetChildCount()); + SetCurrentlyHighlightedActor(self); + + auto window = Dali::DevelWindow::Get(self); + Dali::Internal::Adaptor::Window& windowImpl = Dali::GetImplementation(window); + windowImpl.EmitAccessibilityHighlightSignal(true); + + return true; } - Accessible* GetChildAtIndex(size_t index) override + bool ClearHighlight() override { - auto numberOfChildren = static_cast(Self().GetChildCount()); - if(index >= numberOfChildren) + if(!IsUp()) { - throw std::domain_error{"invalid index " + std::to_string(index) + " for object with " + std::to_string(numberOfChildren) + " children"}; + return false; } - return Get(Self().GetChildAt(static_cast(index))); - } - size_t GetIndexInParent() override - { - auto parent = Self().GetParent(); - if(!parent) + // Only window accessible is able to grab and clear highlight + if(!mRoot) { - return 0; + return false; } - auto size = static_cast(parent.GetChildCount()); - for(auto i = 0u; i < size; ++i) + + if(!IsHighlighted()) { - if(parent.GetChildAt(i) == Self()) - { - return i; - } + return false; } - throw std::domain_error{"actor is not a child of it's parent"}; + + SetCurrentlyHighlightedActor({}); + + auto window = Dali::DevelWindow::Get(Self()); + Dali::Internal::Adaptor::Window& windowImpl = Dali::GetImplementation(window); + windowImpl.EmitAccessibilityHighlightSignal(false); + + return true; } Role GetRole() const override @@ -383,22 +451,36 @@ public: state[State::VISIBLE] = true; state[State::ACTIVE] = visible; } - else + else if(GetParent()) { auto parentState = GetParent()->GetStates(); state[State::SHOWING] = parentState[State::SHOWING]; state[State::VISIBLE] = parentState[State::VISIBLE]; } + else + { + state[State::SHOWING] = false; + state[State::VISIBLE] = false; + } return state; } Attributes GetAttributes() const override { + Attributes attributes; + + if(mRoot) + { + Dali::Window window = Dali::DevelWindow::Get(Self()); + Dali::Internal::Adaptor::Window& windowImpl = Dali::GetImplementation(window); + attributes["resID"] = windowImpl.GetNativeResourceId(); + } + Dali::TypeInfo type; Self().GetTypeInfo(type); - return { - {"class", type.GetName()}, - }; + attributes["class"] = type.GetName(); + + return attributes; } bool DoGesture(const GestureInfo& gestureInfo) override @@ -411,18 +493,49 @@ public: return {}; } - Dali::Actor GetInternalActor() override + void SetListenPostRender(bool enabled) override { - return mSelf.GetHandle(); + if(!mRoot) + { + return; + } + + auto window = Dali::DevelWindow::Get(Self()); + Dali::Internal::Adaptor::Window& windowImpl = Dali::GetImplementation(window); + + if(!mRenderNotification) + { + mRenderNotification = std::unique_ptr( + TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &AdaptorAccessible::OnPostRender), + TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER)); + } + + if(enabled) + { + windowImpl.SetRenderNotification(mRenderNotification.get()); + } + else + { + windowImpl.SetRenderNotification(nullptr); + } + } + + void OnPostRender() + { + Accessibility::Bridge::GetCurrentBridge()->EmitPostRender(shared_from_this()); } }; // AdaptorAccessible -using AdaptorAccessiblesType = std::unordered_map >; +using AdaptorAccessiblesType = std::unordered_map>; // Save RefObject from an Actor in Accessible::Get() -AdaptorAccessiblesType gAdaptorAccessibles; +AdaptorAccessiblesType& GetAdaptorAccessibles() +{ + static AdaptorAccessiblesType gAdaptorAccessibles; + return gAdaptorAccessibles; +} -std::function convertingFunctor = [](Dali::Actor) -> Accessible* { +std::function(Dali::Actor)> convertingFunctor = [](Dali::Actor) -> std::shared_ptr { return nullptr; }; @@ -432,14 +545,17 @@ ObjectRegistry objectRegistry; void Accessible::SetObjectRegistry(ObjectRegistry registry) { objectRegistry = registry; + objectRegistry.ObjectDestroyedSignal().Connect([](const Dali::RefObject* obj) { + GetAdaptorAccessibles().erase(obj); + }); } -void Accessible::RegisterExternalAccessibleGetter(std::function functor) +void Accessible::RegisterExternalAccessibleGetter(std::function(Dali::Actor)> functor) { convertingFunctor = functor; } -Accessible* Accessible::Get(Dali::Actor actor, bool isRoot) +std::shared_ptr Accessible::GetOwningPtr(Dali::Actor actor) { if(!actor) { @@ -449,19 +565,25 @@ Accessible* Accessible::Get(Dali::Actor actor, bool isRoot) auto accessible = convertingFunctor(actor); if(!accessible) { - if(gAdaptorAccessibles.empty() && objectRegistry) - { - objectRegistry.ObjectDestroyedSignal().Connect([](const Dali::RefObject* obj) { - gAdaptorAccessibles.erase(obj); - }); - } - auto pair = gAdaptorAccessibles.emplace(&actor.GetBaseObject(), nullptr); + auto pair = GetAdaptorAccessibles().emplace(&actor.GetBaseObject(), nullptr); if(pair.second) { + bool isRoot = false; + Dali::Integration::Scene scene = Dali::Integration::Scene::Get(actor); + if(scene) + { + isRoot = (actor == scene.GetRootLayer()); + } pair.first->second.reset(new AdaptorAccessible(actor, isRoot)); } - accessible = pair.first->second.get(); + accessible = pair.first->second; } return accessible; } + +Accessible* Accessible::Get(Dali::Actor actor) +{ + auto accessible = Accessible::GetOwningPtr(actor); + return accessible ? accessible.get() : nullptr; +} \ No newline at end of file