/*
- * 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.
#include <dali/public-api/actors/actor.h>
#include <dali/public-api/actors/layer.h>
#include <dali/public-api/object/base-object.h>
-#include <dali/public-api/object/object-registry.h>
#include <dali/public-api/object/type-info.h>
#include <dali/public-api/object/type-registry-helper.h>
#include <string_view>
#include <dali/devel-api/atspi-interfaces/hyperlink.h>
#include <dali/devel-api/atspi-interfaces/hypertext.h>
#include <dali/devel-api/atspi-interfaces/selection.h>
+#include <dali/devel-api/atspi-interfaces/socket.h>
+#include <dali/devel-api/atspi-interfaces/table-cell.h>
+#include <dali/devel-api/atspi-interfaces/table.h>
#include <dali/devel-api/atspi-interfaces/text.h>
#include <dali/devel-api/atspi-interfaces/value.h>
#include <dali/internal/adaptor/common/adaptor-impl.h>
+#include <dali/internal/window-system/common/window-impl.h>
#include <dali/public-api/dali-adaptor-common.h>
using namespace Dali::Accessibility;
interfaces[AtspiInterface::HYPERLINK] = dynamic_cast<const Hyperlink*>(this);
interfaces[AtspiInterface::HYPERTEXT] = dynamic_cast<const Hypertext*>(this);
interfaces[AtspiInterface::SELECTION] = dynamic_cast<const Selection*>(this);
+ interfaces[AtspiInterface::SOCKET] = dynamic_cast<const Socket*>(this);
+ interfaces[AtspiInterface::TABLE] = dynamic_cast<const Table*>(this);
+ interfaces[AtspiInterface::TABLE_CELL] = dynamic_cast<const TableCell*>(this);
interfaces[AtspiInterface::TEXT] = dynamic_cast<const Text*>(this);
interfaces[AtspiInterface::VALUE] = dynamic_cast<const Value*>(this);
}
}
+bool Accessible::IsHighlighted() const
+{
+ Dali::Actor self = GetInternalActor();
+
+ return self && self == GetCurrentlyHighlightedActor();
+}
+
Dali::Actor Accessible::GetHighlightActor()
{
return IsUp() ? Bridge::GetCurrentBridge()->mData->mHighlightActor : Dali::Actor{};
{
class AdaptorAccessible : public ActorAccessible
{
-protected:
- bool mRoot = false;
+private:
+ std::unique_ptr<TriggerEventInterface> mRenderNotification{nullptr};
+ bool mRoot{false};
public:
AdaptorAccessible(Dali::Actor actor, bool isRoot)
bool GrabHighlight() override
{
- return false;
+ if(!IsUp())
+ {
+ return false;
+ }
+
+ // Only window accessible is able to grab and clear highlight
+ if(!mRoot)
+ {
+ return false;
+ }
+
+ auto self = Self();
+ auto oldHighlightedActor = GetCurrentlyHighlightedActor();
+ if(self == oldHighlightedActor)
+ {
+ return true;
+ }
+
+ // Clear the old highlight.
+ if(oldHighlightedActor)
+ {
+ auto oldHighlightedObject = Dali::Accessibility::Component::DownCast(Accessible::Get(oldHighlightedActor));
+ if(oldHighlightedObject)
+ {
+ oldHighlightedObject->ClearHighlight();
+ }
+ }
+
+ SetCurrentlyHighlightedActor(self);
+
+ auto window = Dali::DevelWindow::Get(self);
+ Dali::Internal::Adaptor::Window& windowImpl = Dali::GetImplementation(window);
+ windowImpl.EmitAccessibilityHighlightSignal(true);
+
+ return true;
}
bool ClearHighlight() override
{
- return false;
+ if(!IsUp())
+ {
+ return false;
+ }
+
+ // Only window accessible is able to grab and clear highlight
+ if(!mRoot)
+ {
+ return false;
+ }
+
+ if(!IsHighlighted())
+ {
+ return false;
+ }
+
+ SetCurrentlyHighlightedActor({});
+
+ auto window = Dali::DevelWindow::Get(Self());
+ Dali::Internal::Adaptor::Window& windowImpl = Dali::GetImplementation(window);
+ windowImpl.EmitAccessibilityHighlightSignal(false);
+
+ return true;
}
Role GetRole() const override
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
{
return {};
}
-}; // AdaptorAccessible
-using AdaptorAccessiblesType = std::unordered_map<const Dali::RefObject*, std::unique_ptr<AdaptorAccessible> >;
+ void SetListenPostRender(bool enabled) override
+ {
+ if(!mRoot)
+ {
+ return;
+ }
-// Save RefObject from an Actor in Accessible::Get()
-AdaptorAccessiblesType gAdaptorAccessibles;
+ auto window = Dali::DevelWindow::Get(Self());
+ Dali::Internal::Adaptor::Window& windowImpl = Dali::GetImplementation(window);
-std::function<Accessible*(Dali::Actor)> convertingFunctor = [](Dali::Actor) -> Accessible* {
- return nullptr;
+ if(!mRenderNotification)
+ {
+ mRenderNotification = std::unique_ptr<TriggerEventInterface>(
+ 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 ConvertingResult = std::pair<std::shared_ptr<Accessible>, bool>;
+
+std::function<ConvertingResult(Dali::Actor)> convertingFunctor = [](Dali::Actor) -> ConvertingResult {
+ return {nullptr, true};
};
-ObjectRegistry objectRegistry;
} // namespace
-void Accessible::SetObjectRegistry(ObjectRegistry registry)
-{
- objectRegistry = registry;
- objectRegistry.ObjectDestroyedSignal().Connect([](const Dali::RefObject* obj) {
- gAdaptorAccessibles.erase(obj);
- });
-}
-
-void Accessible::RegisterExternalAccessibleGetter(std::function<Accessible*(Dali::Actor)> functor)
+void Accessible::RegisterExternalAccessibleGetter(std::function<ConvertingResult(Dali::Actor)> functor)
{
convertingFunctor = functor;
}
-Accessible* Accessible::Get(Dali::Actor actor, bool isRoot)
+std::shared_ptr<Accessible> Accessible::GetOwningPtr(Dali::Actor actor)
{
if(!actor)
{
return nullptr;
}
- auto accessible = convertingFunctor(actor);
- if(!accessible)
+ auto bridge = Bridge::GetCurrentBridge();
+
+ // Try finding exsiting accessible object.
+ auto accessible = bridge->GetAccessible(actor);
+ if(accessible)
+ {
+ return accessible;
+ }
+
+ // No acessible object created, let's create one.
+ auto result = convertingFunctor(actor);
+ accessible = result.first;
+ const bool creationEnabled = result.second;
+ if(!accessible && creationEnabled)
{
- auto pair = gAdaptorAccessibles.emplace(&actor.GetBaseObject(), nullptr);
- if(pair.second)
+ bool isRoot = false;
+ Dali::Integration::Scene scene = Dali::Integration::Scene::Get(actor);
+ if(scene)
{
- pair.first->second.reset(new AdaptorAccessible(actor, isRoot));
+ isRoot = (actor == scene.GetRootLayer());
+ }
+ accessible = std::make_shared<AdaptorAccessible>(actor, isRoot);
+ }
+
+ if(accessible)
+ {
+ uint32_t actorId = actor.GetProperty<int>(Dali::Actor::Property::ID);
+ bridge->AddAccessible(actorId, accessible);
+ if(auto actorAccesible = std::dynamic_pointer_cast<ActorAccessible>(accessible))
+ {
+ actorAccesible->StartObservingDestruction();
}
- accessible = pair.first->second.get();
}
return accessible;
}
+
+Accessible* Accessible::Get(Dali::Actor actor)
+{
+ auto accessible = Accessible::GetOwningPtr(actor);
+ return accessible ? accessible.get() : nullptr;
+}
\ No newline at end of file