*.creator.user
/docs/generated/*
/build/tizen/doc
+/build/tizen-cmake/doc
/build/tizen/.cov
/build/desktop
/packaging/home*
../dali/dali-test-suite-utils/test-platform-abstraction.cpp
../dali/dali-test-suite-utils/test-render-controller.cpp
../dali/dali-test-suite-utils/test-trace-call-stack.cpp
+ ../dali/dali-test-suite-utils/test-addon-manager.cpp
)
PKG_CHECK_MODULES(${CAPI_LIB} REQUIRED
ADD_EXECUTABLE(${EXEC_NAME} ${EXEC_NAME}.cpp ${TC_SOURCES})
TARGET_LINK_LIBRARIES(${EXEC_NAME}
${${CAPI_LIB}_LIBRARIES}
- --coverage
+ --coverage -ldl
)
INSTALL(PROGRAMS ${EXEC_NAME}
SET(TC_SOURCES
utc-Dali-Actor.cpp
+ utc-Dali-AddOn.cpp
utc-Dali-AlphaFunction.cpp
utc-Dali-AngleAxis.cpp
utc-Dali-Animation.cpp
dali-test-suite-utils/test-platform-abstraction.cpp
dali-test-suite-utils/test-render-controller.cpp
dali-test-suite-utils/test-trace-call-stack.cpp
+ dali-test-suite-utils/test-addon-manager.cpp
)
PKG_CHECK_MODULES(${CAPI_LIB} REQUIRED
dali-test-suite-utils
)
+ADD_DEFINITIONS( -DADDON_LIBS_PATH=\"${CMAKE_CURRENT_BINARY_DIR}\" )
+
ADD_EXECUTABLE(${EXEC_NAME} ${EXEC_NAME}.cpp ${TC_SOURCES})
TARGET_LINK_LIBRARIES(${EXEC_NAME}
${${CAPI_LIB}_LIBRARIES}
- -lpthread --coverage
+ -lpthread -ldl --coverage
)
+# Path to installed precompiled addons
+
INSTALL(PROGRAMS ${EXEC_NAME}
DESTINATION ${BIN_DIR}/${EXEC_NAME}
)
+
+# build addons
+MESSAGE( STATUS "BINDIR: ${CMAKE_CURRENT_BINARY_DIR}")
+SET(ADDON_NAME SampleAddOn )
+SET(ADDON_SOURCES test-sample-addon.cpp )
+ADD_LIBRARY( ${ADDON_NAME} SHARED ${ADDON_SOURCES} )
+TARGET_LINK_LIBRARIES(${ADDON_NAME}
+ -lpthread -ldl --coverage
+ )
+
+INSTALL( TARGETS ${ADDON_NAME} DESTINATION ${BIN_DIR} )
+
+# store AddOn list
+FILE( WRITE ${CMAKE_CURRENT_BINARY_DIR}/addons.txt lib${ADDON_NAME}.so )
--- /dev/null
+/*
+ * Copyright (c) 2020 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test-addon-manager.h"
+#include <dali-test-suite-utils.h>
+#include <cstring>
+#include <dlfcn.h>
+
+#ifndef ADDON_LIBS_PATH
+#define ADDON_LIBS_PATH ""
+#endif
+
+namespace Dali
+{
+namespace Test
+{
+
+std::vector<std::string> AddOnManager::EnumerateAddOns()
+{
+ std::string listFileName(ADDON_LIBS_PATH);
+ listFileName += "/addons.txt";
+
+ // Read list of available test addons
+ tet_printf("Enumerating addons, file: %s\n", listFileName.c_str());
+ std::vector<std::string> addons{};
+ auto* fin = fopen( listFileName.c_str(), "r" );
+ char* lineBuf = new char[256];
+ size_t n = 256;
+ while( getline( &lineBuf, &n, fin ) > 0 )
+ {
+ tet_printf("Adding %s\n", lineBuf);
+ addons.emplace_back( lineBuf );
+ }
+ fclose(fin);
+ delete [] lineBuf;
+ std::vector<std::string> retval{};
+ // Open addons
+ for( auto& name : addons )
+ {
+ std::string path(ADDON_LIBS_PATH);
+ path += "/";
+ path += name;
+
+ mAddOnCache.emplace_back();
+ mAddOnCache.back().handle = dlopen( path.c_str(), RTLD_DEEPBIND|RTLD_LAZY );
+ if( !mAddOnCache.back().handle )
+ {
+ mAddOnCache.back().valid = false;
+ tet_printf( "Can't open addon lib: %s\n", path.c_str());
+ continue;
+ }
+ // Here addon must self register
+ if( !mAddOnCache.back().valid )
+ {
+ puts("Addon invalid!");
+ }
+ else
+ {
+ tet_printf( "Valid AddOn: %s\n", mAddOnCache.back().name.c_str() );
+ retval.emplace_back( mAddOnCache.back().name );
+ }
+ }
+
+ return retval;
+
+ /**
+ * Check for self-registering addons
+ */
+}
+
+void AddOnManager::RegisterAddOnDispatchTable( const AddOnDispatchTable* dispatchTable )
+{
+ // Register the dispatch table
+ auto& entry = mAddOnCache.back();
+ entry.name = dispatchTable->name;
+ tet_printf( "Registering AddOn: %s\n", entry.name.c_str());
+ entry.GetGlobalProc = dispatchTable->GetGlobalProc;
+ entry.GetInstanceProc = dispatchTable->GetInstanceProc;
+ entry.GetAddOnInfo = dispatchTable->GetAddOnInfo;
+ entry.OnStart = dispatchTable->OnStart;
+ entry.OnStop = dispatchTable->OnStop;
+ entry.OnPause = dispatchTable->OnPause;
+ entry.OnResume = dispatchTable->OnResume;
+ entry.valid = true;
+}
+
+bool AddOnManager::GetAddOnInfo(const std::string& name, AddOnInfo& info )
+{
+ auto retval = false;
+ std::find_if( mAddOnCache.begin(), mAddOnCache.end(),
+ [&retval, name, &info]( AddOnCacheEntry& entry )
+ {
+ if(entry.name == name)
+ {
+ entry.GetAddOnInfo( info );
+ retval = true;
+ return true;
+ }
+ return false;
+ });
+ return retval;
+}
+
+std::vector<AddOnLibrary> AddOnManager::LoadAddOns( const std::vector<std::string>& addonNames )
+{
+ if(mAddOnCache.empty())
+ {
+ EnumerateAddOns();
+ }
+
+ std::vector<AddOnLibrary> retval{};
+ for( auto& name : addonNames)
+ {
+ size_t index = 0;
+ auto iter = std::find_if( mAddOnCache.begin(), mAddOnCache.end(),
+ [&retval, name, &index]( AddOnCacheEntry& entry )
+ {
+ index++;
+ if(entry.name == name)
+ {
+ return true;
+ }
+ return false;
+ });
+ if( iter != mAddOnCache.end() )
+ {
+ retval.emplace_back( *reinterpret_cast<void**>( &index ) );
+ }
+ else
+ {
+ retval.emplace_back( nullptr );
+ }
+ }
+
+ return retval;
+}
+
+void* AddOnManager::GetGlobalProc( const Dali::AddOnLibrary& addOnLibrary, const char* procName )
+{
+ auto index = *reinterpret_cast<const size_t*>( &addOnLibrary );
+ return mAddOnCache[index-1].GetGlobalProc( procName );
+}
+
+void* AddOnManager::GetInstanceProc( const Dali::AddOnLibrary& addOnLibrary, const char* procName )
+{
+ auto index = *reinterpret_cast<const size_t*>( &addOnLibrary );
+ return mAddOnCache[index-1].GetInstanceProc( procName );
+}
+
+void AddOnManager::Start()
+{
+ for( auto& entry : mAddOnCache )
+ {
+ if(entry.OnStart)
+ {
+ entry.OnStart();
+ }
+ }
+}
+
+void AddOnManager::Resume()
+{
+ for( auto& entry : mAddOnCache )
+ {
+ if(entry.OnResume)
+ {
+ entry.OnResume();
+ }
+ }
+}
+
+void AddOnManager::Stop()
+{
+ for( auto& entry : mAddOnCache )
+ {
+ if(entry.OnStop)
+ {
+ entry.OnStop();
+ }
+ }
+}
+
+void AddOnManager::Pause()
+{
+ for( auto& entry : mAddOnCache )
+ {
+ if(entry.OnPause)
+ {
+ entry.OnPause();
+ }
+ }
+}
+
+}
+}
+
--- /dev/null
+#ifndef TEST_ADDON_MANAGER_H
+#define TEST_ADDON_MANAGER_H
+
+/*
+ * Copyright (c) 2020 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/integration-api/addon-manager.h>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <string>
+
+namespace Dali
+{
+namespace Test
+{
+class AddOnManager : public Dali::Integration::AddOnManager
+{
+public:
+
+ /**
+ * @brief Constructor, initialised by the Adaptor
+ */
+ AddOnManager() = default;
+
+ /**
+ * @brief Destructor
+ */
+ virtual ~AddOnManager() = default;
+
+ std::vector<std::string> EnumerateAddOns() override;
+
+ bool GetAddOnInfo(const std::string& name, AddOnInfo& info ) override;
+
+ std::vector<AddOnLibrary> LoadAddOns( const std::vector<std::string>& addonNames ) override;
+
+ void* GetGlobalProc( const Dali::AddOnLibrary& addOnLibrary, const char* procName ) override;
+
+ void* GetInstanceProc( const Dali::AddOnLibrary& addOnLibrary, const char* procName ) override;
+
+ void RegisterAddOnDispatchTable( const AddOnDispatchTable* dispatchTable ) override;
+
+ void Start() override;
+
+ void Resume() override;
+
+ void Stop() override;
+
+ void Pause() override;
+
+ struct AddOnCacheEntry
+ {
+ std::string name{};
+ AddOnInfo info{};
+
+ // library handle
+ void* handle {nullptr};
+
+ // main function pointers
+ void(*GetAddOnInfo)(AddOnInfo& ) = nullptr; ///< Returns AddOnInfo structure
+ void*(*GetInstanceProc)( const char* ) = nullptr; ///< Returns pointer of instance function (member funtion)
+ void*(*GetGlobalProc)( const char* ) = nullptr; ///< Returns pointer of global function (non-member function)
+
+ void(*OnStart)() = nullptr;
+ void(*OnResume)() = nullptr;
+ void(*OnPause)() = nullptr;
+ void(*OnStop)() = nullptr;
+
+ bool valid = false;
+ };
+
+ std::vector<AddOnCacheEntry> mAddOnCache;
+};
+} // Namespace Test
+} // namespace Dali
+
+#endif // TEST_ADDON_MANAGER_H
--- /dev/null
+/*
+ * Copyright (c) 2020 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <cstring>
+#include <dali/devel-api/addons/addon-base.h>
+#include <dali-test-suite-utils.h>
+
+static const std::string DUMMY_ADDON_NAME = "SampleAddOn";
+
+int StringLen( const char* str )
+{
+ return strlen( str );
+}
+
+int DoSum( int a, int b )
+{
+ return a+b;
+}
+
+class TestDummyAddOn : public Dali::AddOns::AddOnBase
+{
+public:
+
+ void GetAddOnInfo( Dali::AddOnInfo& info ) override
+ {
+ info.type = Dali::AddOnType::GENERIC;
+ info.name = "SampleAddOn";
+ info.version = Dali::DALI_ADDON_VERSION( 1, 0, 0 );
+ info.next = nullptr;
+ tet_printf( "SampleAddOn: GetAddOnInfo() : name = %s\n", info.name.c_str());
+ }
+
+ /**
+ * Dispatch table for global functions
+ * @return
+ */
+ Dali::AddOns::DispatchTable* GetGlobalDispatchTable() override
+ {
+ static Dali::AddOns::DispatchTable dispatchTable{};
+ if( dispatchTable.Empty() )
+ {
+ dispatchTable["DoSum"] = DoSum;
+ dispatchTable["StringLen"] = StringLen;
+ }
+ return &dispatchTable;
+ }
+
+ /**
+ * Lifecycle
+ */
+
+ void OnStart() override
+ {
+ }
+
+ void OnStop() override
+ {
+ }
+
+ void OnPause() override
+ {
+ }
+
+ void OnResume() override
+ {
+ }
+
+ /**
+ * Dispatch table for instance functions
+ * @return
+ */
+ Dali::AddOns::DispatchTable* GetInstanceDispatchTable() override
+ {
+ return nullptr;
+ }
+};
+
+REGISTER_ADDON_CLASS( TestDummyAddOn );
--- /dev/null
+/*
+ * Copyright (c) 2020 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali-test-suite-utils.h>
+#include <dali/devel-api/common/addon-binder.h>
+#include "dali-test-suite-utils/test-addon-manager.h"
+
+struct DummyAddOn : public Dali::AddOn::AddOnBinder
+{
+ DummyAddOn() : Dali::AddOn::AddOnBinder( "SampleAddOn" )
+ {}
+
+ ~DummyAddOn() = default;
+
+ ADDON_BIND_FUNCTION( DoSum, int(int, int) );
+
+ ADDON_BIND_FUNCTION( StringLen, int() );
+};
+
+int UtcDaliAddOnBinderP(void)
+{
+ TestApplication application;
+
+ auto* addOnManager = new Dali::Test::AddOnManager();
+
+ tet_infoline("Testing Dali::AddOn::AddOnBinder");
+
+ DummyAddOn addon;
+
+ // Test whether library handle is non-null
+ DALI_TEST_EQUALS( addon.GetHandle(), (void*)1, TEST_LOCATION );
+
+ // Test whether addon is valid
+ auto isValid = addon.IsValid();
+ DALI_TEST_EQUALS( isValid, true, TEST_LOCATION );
+
+ // Test AddOnInfo
+ const auto& info = addon.GetAddOnInfo();
+ DALI_TEST_EQUALS( info.name, "SampleAddOn", TEST_LOCATION );
+
+ delete addOnManager;
+
+ END_TEST;
+}
+
+int UtcDaliAddOnManagerNotSupportedP(void)
+{
+ TestApplication application;
+
+ tet_infoline("Testing Dali::AddOn::AddOnBinder when AddOnManager not supported");
+
+ // Not supported
+ using VoidPtr = void*;
+ DALI_TEST_EQUALS( VoidPtr(Dali::Integration::AddOnManager::Get()), VoidPtr(nullptr), TEST_LOCATION );
+
+ DummyAddOn addon{};
+
+ // Test whether library handle is non-null
+ DALI_TEST_EQUALS( addon.GetHandle(), (void*)0, TEST_LOCATION );
+
+ // Test whether addon is valid
+ auto isValid = addon.IsValid();
+ DALI_TEST_EQUALS( isValid, false, TEST_LOCATION );
+
+ END_TEST;
+}
--- /dev/null
+#ifndef DALI_ADDONS_ADDON_BASE_H
+#define DALI_ADDONS_ADDON_BASE_H
+
+/*
+ * Copyright (c) 2020 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/integration-api/addon-manager.h>
+#include <dali/devel-api/addons/addon-dispatch-table.h>
+#include <vector>
+
+namespace Dali
+{
+namespace AddOns
+{
+
+/**
+ * @class AddOnBase
+ *
+ * @brief AddOnBase is a base class for AddOns and should be used rather
+ * than writing exported functions of the AddOn directly.
+ *
+ */
+class AddOnBase
+{
+protected:
+
+ /**
+ * @brief Constructor
+ */
+ AddOnBase()
+ {
+ mSingleton = this;
+ }
+
+public:
+
+ /**
+ * @brief Destructor
+ */
+ virtual ~AddOnBase() = default;
+
+ /**
+ * @brief Retrieves AddOn info
+ * @param[out] addonInfo AddOnInfo structure to fill by the function
+ */
+ virtual void GetAddOnInfo( Dali::AddOnInfo& addonInfo ) = 0;
+
+ /**
+ * @brief Returns a dispatch table for global functions.
+ * @return Valid dispatch table object or nullptr
+ */
+ virtual DispatchTable* GetGlobalDispatchTable() = 0;
+
+ /**
+ * @brief Returns a dispatch table for instance functions
+ * @return Valid dispatch table object or nullptr
+ */
+ virtual DispatchTable* GetInstanceDispatchTable() = 0;
+
+ /**
+ * @brief OnStart event.
+ * It's optional and should be implemented by the AddOn when it's required to handle the event.
+ */
+ virtual void OnStart() {}
+
+ /**
+ * @brief OnResume event.
+ * It's optional and should be implemented by the AddOn when it's required to handle the event.
+ */
+ virtual void OnResume() {}
+
+ /**
+ * @brief OnPause event.
+ * It's optional and should be implemented by the AddOn when it's required to handle the event.
+ */
+ virtual void OnPause() {}
+
+ /**
+ * @brief OnStop event.
+ * It's optional and should be implemented by the AddOn when it's required to handle the event.
+ */
+ virtual void OnStop() {}
+
+ /**
+ * @brief Getter of static singleton
+ * @return Returns valid singleton pointer
+ */
+ static AddOnBase* Get()
+ {
+ return mSingleton;
+ }
+
+private:
+
+ static AddOnBase* mSingleton;
+};
+
+/**
+ * @brief The function is automatically added to the AddOn code
+ * with use of REGISTER_ADDON_CLASS() macro
+ * @return The valid pointer to the AddOnBase interface
+ */
+extern Dali::AddOns::AddOnBase* CreateAddOn();
+
+/**
+ * Fills AddOnInfo structure.
+ * @param[out] info Reference to AddOnInfo structure
+ */
+template<class T>
+void GetAddOnInfo( Dali::AddOnInfo& info )
+{
+ auto* addon = Dali::AddOns::AddOnBase::Get();
+ addon->GetAddOnInfo( info );
+}
+
+/**
+ * Returns pointer to AddOn's global function
+ * @param[in] funcname Name of function
+ * @return Valid pointer or nullptr if function not found.
+ */
+template<class T>
+void* GetGlobalProc( const char* funcname )
+{
+ if( !funcname )
+ {
+ return nullptr;
+ }
+ auto* addon = Dali::AddOns::AddOnBase::Get();
+
+ // AddOn must be initialised up to this point!
+ if( !addon )
+ {
+ return nullptr;
+ }
+
+ static Dali::AddOns::DispatchTable* globalDispatchTable = addon->GetGlobalDispatchTable();
+
+ if( globalDispatchTable )
+ {
+ return globalDispatchTable->Find( funcname );
+ }
+ return nullptr;
+}
+
+/**
+ * Returns pointer to AddOn's instance function
+ * @param[in] funcname Name of function
+ * @return Valid pointer or nullptr if function not found.
+ */
+template<class T>
+void* GetInstanceProc( const char* funcname )
+{
+ if( !funcname )
+ {
+ return nullptr;
+ }
+
+ auto* addon = Dali::AddOns::AddOnBase::Get();
+
+ // AddOn must be initialised up to this point!
+ if( !addon )
+ {
+ return nullptr;
+ }
+
+ static Dali::AddOns::DispatchTable* instanceDispatchTable = addon->GetInstanceDispatchTable();
+
+ if( instanceDispatchTable )
+ {
+ return instanceDispatchTable->Find( funcname );
+ }
+ return nullptr;
+}
+
+/**
+ * Lifecycle functions to export.
+ * They will be instantiated only if macro REGISTER_ADDON_CLASS is used
+ */
+template<class T>
+void OnStart()
+{
+ auto* addon = Dali::AddOns::AddOnBase::Get();
+ addon->OnStart();
+}
+
+template<class T>
+void OnPause()
+{
+ auto* addon = Dali::AddOns::AddOnBase::Get();
+ addon->OnPause();
+}
+
+template<class T>
+void OnResume()
+{
+ auto* addon = Dali::AddOns::AddOnBase::Get();
+ addon->OnResume();
+}
+
+template<class T>
+void OnStop()
+{
+ auto* addon = Dali::AddOns::AddOnBase::Get();
+ addon->OnStop();
+}
+
+/**
+ * @brief AddOn library internal constructor.
+ */
+inline void AddOnConstructorInternal()
+{
+ auto* addon = Dali::AddOns::CreateAddOn();
+
+ Dali::AddOnInfo info{};
+ addon->GetAddOnInfo( info );
+
+ // Generate dispatch tables
+ addon->GetGlobalDispatchTable();
+ addon->GetInstanceDispatchTable();
+
+ // Bind basic functions
+ Dali::AddOnDispatchTable table;
+ table.name = info.name;
+ table.GetAddOnInfo = GetAddOnInfo<void>;
+ table.GetGlobalProc = GetGlobalProc<void>;
+ table.GetInstanceProc = GetInstanceProc<void>;
+ table.OnStart = OnStart<void>;
+ table.OnStop = OnStop<void>;
+ table.OnResume = OnResume<void>;
+ table.OnPause = OnPause<void>;
+
+ // Register dispatch table
+ Dali::Integration::AddOnManager::Get()->RegisterAddOnDispatchTable( &table );
+}
+
+} // namespace AddOns
+} // namespace Dali
+
+/**
+ * Macro must be used in order to auto-register AddOn with the AddOnManager.
+ * Note: The macro requires GCC/Clang compiler and currently only Linux-based environment
+ * is supported.
+ */
+#define REGISTER_ADDON_CLASS( ADDON_CLASS_WITH_FULL_NAMESPACE ) \
+namespace Dali { namespace AddOns { \
+__attribute__((constructor)) void AddOnConstructor() { \
+ AddOnConstructorInternal();\
+}\
+AddOnBase* AddOnBase::mSingleton = nullptr; \
+AddOnBase* CreateAddOn() \
+{\
+ return new ADDON_CLASS_WITH_FULL_NAMESPACE();\
+}\
+}}
+
+#endif // DALI_ADDON_BASE_H
--- /dev/null
+#ifndef DALI_ADDON_DISPATCH_TABLE_H
+#define DALI_ADDON_DISPATCH_TABLE_H
+
+/*
+ * Copyright (c) 2020 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Dali
+{
+namespace AddOns
+{
+
+/**
+ * DispatchTable contains essential function pointers
+ * needed to register the AddOn with AddOnManager.
+ */
+struct DispatchTable
+{
+ typedef void* FunctionPointer;
+ /**
+ * Struct Entry
+ * The structure contains details of a single function binding
+ */
+ struct Entry
+ {
+ /**
+ * @brief Assignment operator. Converts function pointer into void*.
+ * @param[in] funcPtr Function pointer
+ * @return Reference to self
+ */
+ template<class T>
+ Entry &operator=(T funcPtr)
+ {
+ functionPtr = reinterpret_cast<void *>( funcPtr );
+ if (index < 0)
+ {
+ index = int32_t(table->entries.size());
+ table->entries.emplace_back(*this);
+ }
+ else
+ {
+ table->entries[index].functionPtr = reinterpret_cast<void *>( funcPtr );
+ }
+ return *this;
+ }
+
+ std::string functionName{}; ///< Name of function
+ void* functionPtr{nullptr}; ///< Function pointer
+ DispatchTable* table{nullptr}; ///< DispatchTable associated with entry
+ int32_t index = -1; ///< Index within the dispatch table
+ };
+
+ /**
+ * @brief Accessor of an indexed entry from the dispatch table
+ * @param[in] functionName name of function
+ * @return Returns Entry object
+ */
+ Entry operator[](const char *functionName)
+ {
+ auto iter = std::find_if(entries.begin(), entries.end(), [functionName](Entry &entry)
+ {
+ if (entry.functionName == functionName)
+ {
+ return true;
+ }
+ return false;
+ });
+ if (iter == entries.end())
+ {
+ Entry retval;
+ retval.table = this;
+ retval.functionName = functionName;
+ return retval;
+ }
+ return Entry(*iter);
+ }
+
+ /**
+ * @brief Tests whether cache is empty
+ * @return True if empty, False otherwise
+ */
+ bool Empty() const
+ {
+ return entries.empty();
+ }
+
+ /**
+ * @brief Returns size of cache
+ * @return Size of cache
+ */
+ uint32_t Size() const
+ {
+ return entries.size();
+ }
+
+ /**
+ * @brief Function pointer lookup
+ * @param[in] funcName Name of function
+ * @return valid pointer or nullptr if function not found
+ */
+ FunctionPointer Find(const char *funcName)
+ {
+ if (entries.empty())
+ {
+ return nullptr;
+ }
+
+ auto iter = std::find_if(entries.begin(), entries.end(), [funcName, entries = &this->entries](Entry &entry)
+ {
+ return (entry.functionName == funcName);
+ });
+ if (iter != entries.end())
+ {
+ return iter->functionPtr;
+ }
+ return nullptr;
+ }
+
+ std::vector <Entry> entries;
+};
+
+} // namespace AddOns
+
+} // namespace Dali
+
+#endif // DALI_ADDON_DISPATCH_TABLE_H
--- /dev/null
+/*
+ * Copyright (c) 2018 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "addon-binder.h"
+
+namespace Dali
+{
+
+namespace AddOn
+{
+
+Dali::Integration::AddOnManager* AddOnBinder::mAddOnManager = nullptr;
+
+} // namespace AddOn
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_ADDON_BINDER_H
+#define DALI_ADDON_BINDER_H
+
+/*
+ * Copyright (c) 2020 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dali/integration-api/addon-manager.h>
+
+namespace Dali
+{
+namespace AddOn
+{
+
+/**
+ * Class automates binding an AddOn interface.
+ *
+ * This interface is meant to be used as a base
+ * for classes that use function binding macros.
+ *
+ * Sample use:
+ * \code{.cpp}
+ * #include <dali/devel-api/common/addon-binder.h>
+ * struct AddOnImageLoader : public Dali::DevelAddOn::AddOnBinder
+ * {
+ * // Constructor requires the AddOn name and optional version (0 - any version accepted)
+ * AddOnImageLoader( const char* addonname ) : Dali::DevelAddOn::AddOnBinder( addonname, 0 ) {}
+ *
+ * ~AddOnImageLoader() = default;
+ *
+ * // Binding block
+ * // Using ADDON_BIND_FUNCTION() macro requires function name (resolved by the AddOn) and function
+ * // signature. It will generate member function with correct binding.
+ *
+ * // LoadBitmap
+ * ADDON_BIND_FUNCTION( LoadBitmap, bool(const Dali::ImageLoader::Input&, Dali::Devel::PixelBuffer&) );
+ *
+ * // LoadHeader
+ * ADDON_BIND_FUNCTION( LoadHeader, bool(const Dali::ImageLoader::Input&, unsigned int&, unsigned int&) );
+ *
+ * // GetFormatExtension
+ * ADDON_BIND_FUNCTION( GetFormatExtension, const char*() );
+ *
+ * // GetFormatMagicNumber
+ * ADDON_BIND_FUNCTION( GetFormatMagicNumber, uint16_t() );
+ *
+ * // GetBitmapProfile
+ * ADDON_BIND_FUNCTION( GetBitmapProfile, Bitmap::Profile() );
+ * };
+ * \endcode
+ */
+
+class AddOnBinder
+{
+public:
+
+ /**
+ * @brief Constructor. Opens an AddOn and creates interface
+ * @param[in] addonName Name of AddOn
+ * @param[in] version Version of AddOn
+ */
+ explicit AddOnBinder( const char* addonName, uint32_t version = 0u )
+ {
+ mAddOnManager = Dali::Integration::AddOnManager::Get();
+ if (mAddOnManager)
+ {
+ mAddOnHandle = mAddOnManager->GetAddOn(addonName);
+ if (mAddOnHandle)
+ {
+ mAddOnManager->GetAddOnInfo(addonName, mAddOnInfo);
+ }
+ }
+ }
+
+ /**
+ * @brief Destructor
+ */
+ virtual ~AddOnBinder() = default;
+
+ /**
+ * @brief Looks up and converts c-style void* function into pointer of type T
+ * @param[in] funcName name of the function
+ * @return Returns a new pointer
+ */
+ template<class T>
+ T* ConvertFunction( const std::string& funcName )
+ {
+ if(mAddOnHandle)
+ {
+ auto ptr = mAddOnManager->GetGlobalProc(mAddOnHandle, funcName.c_str());
+ return *reinterpret_cast<T**>(&ptr);
+ }
+ return nullptr;
+ }
+
+ /**
+ * @brief Returns a handle to the AddOn library
+ * @return Handle object
+ */
+ Dali::AddOnLibrary GetHandle()
+ {
+ return mAddOnHandle;
+ }
+
+ /**
+ * @brief Returns pointer to the global AddOn function.
+ * @param[in] name Name of the function
+ * @return Valid pointer or nullptr
+ */
+ void* GetGlobalProc( const char* name )
+ {
+ return mAddOnManager ? mAddOnManager->GetGlobalProc( mAddOnHandle, name ) : nullptr;
+ }
+
+ /**
+ * @brief Returns pointer to the instance AddOn function.
+ * @param[in] name Name of the function
+ * @return Valid pointer or nullptr
+ */
+ void* GetInstanceProc( const char* name )
+ {
+ return mAddOnManager ? mAddOnManager->GetInstanceProc( mAddOnHandle, name ) : nullptr;
+ }
+
+ /**
+ * @brief Tests whether the interface is valid
+ * @return True if valid, false otherwise
+ */
+ virtual bool IsValid()
+ {
+ return GetHandle() != nullptr;
+ }
+
+ /**
+ * @brief Returns AddOn info structure
+ * @return AddOn info structure.
+ */
+ const AddOnInfo& GetAddOnInfo() const
+ {
+ return mAddOnInfo;
+ }
+
+protected:
+
+ static DALI_CORE_API Dali::Integration::AddOnManager* mAddOnManager; ///< Pointer to the AddOn manager
+
+ Dali::AddOnLibrary mAddOnHandle { nullptr }; ///< Handle to the AddOn library
+ Dali::AddOnInfo mAddOnInfo {}; ///< Stored AddOnInfo structure
+};
+
+
+/**
+ * Macro binds function as a member function of the class, for example, the call:
+ *
+ * ADDON_BIND_FUNCTION( SomeAddOnFunction, void(int, char*) );
+ *
+ * will create a std::function object named SomeAddOnFunction and bound to the AddOn library.
+ */
+#define ADDON_BIND_FUNCTION( FUNCNAME, FUNCTYPE ) \
+std::function<FUNCTYPE> FUNCNAME{ConvertFunction<FUNCTYPE>( std::string(#FUNCNAME) )};
+
+} // namespace AddOn
+} // namespace Dali
+
+#endif // DALI_ADDON_BINDER_H
${devel_api_src_dir}/animation/animation-data.cpp
${devel_api_src_dir}/animation/animation-devel.cpp
${devel_api_src_dir}/animation/path-constrainer.cpp
+ ${devel_api_src_dir}/common/addon-binder.cpp
${devel_api_src_dir}/common/hash.cpp
${devel_api_src_dir}/common/singleton-service.cpp
${devel_api_src_dir}/common/stage-devel.cpp
${devel_api_src_dir}/actors/camera-actor-devel.h
)
+SET( devel_api_core_addons_header_files
+ ${devel_api_src_dir}/addons/addon-base.h
+ ${devel_api_src_dir}/addons/addon-dispatch-table.h
+)
SET( devel_api_core_animation_header_files
${devel_api_src_dir}/animation/animation-data.h
SET( devel_api_core_common_header_files
+ ${devel_api_src_dir}/common/addon-binder.h
${devel_api_src_dir}/common/bitwise-enum.h
${devel_api_src_dir}/common/circular-queue.h
${devel_api_src_dir}/common/hash.h
SET( DEVEL_API_HEADERS ${DEVEL_API_HEADERS}
${devel_api_core_actors_header_files}
+ ${devel_api_core_addons_header_files}
${devel_api_core_animation_header_files}
${devel_api_core_common_header_files}
${devel_api_core_events_header_files}
--- /dev/null
+/*
+ * Copyright (c) 2020 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "addon-manager.h"
+
+namespace Dali
+{
+namespace Integration
+{
+AddOnManager* AddOnManager::mSingleton = nullptr;
+
+AddOnManager::AddOnManager()
+{
+ mSingleton = this;
+}
+
+AddOnManager::~AddOnManager() = default;
+
+AddOnManager* AddOnManager::Get()
+{
+ return mSingleton;
+}
+}
+}
--- /dev/null
+#ifndef DALI_INTEGRATION_ADDON_MANAGER_H
+#define DALI_INTEGRATION_ADDON_MANAGER_H
+
+/*
+ * Copyright (c) 2020 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/public-api/object/base-handle.h>
+
+// EXTERNAL EXCLUDES
+#include <string>
+#include <memory>
+#include <vector>
+#include <functional>
+#include <cstdio>
+
+namespace Dali
+{
+// Type of extensions (may be used internally)
+enum class AddOnType
+{
+ GENERIC,
+ IMAGE_LOADER
+};
+
+/**
+ * @brief Helper function building the version number as 32-bit integer.
+ * The return value should be used to encode AddOnInfo::version field.
+ *
+ * @param[in] maj Major version number
+ * @param[in] min Minor version number
+ * @param[in] rev Revision version number
+ * @return returns 32-bit version number
+ */
+constexpr uint32_t DALI_ADDON_VERSION( uint32_t maj, uint32_t min, uint32_t rev )
+{
+ return ((maj&0xff) << 24) | ((min & 0xfff) << 16);
+}
+
+/**
+ * Structure describes AddOn details
+ */
+struct AddOnInfo
+{
+ AddOnType type; /// may be use in order to classify extension
+ void* next; /// holds pointer to additional data-structures
+
+ std::string name; /// Name of the extension
+ uint32_t version;
+
+ /**
+ * Structure contains details of build
+ */
+ struct BuildInfo
+ {
+ uint32_t libCoreVersion;
+ uint32_t libAdaptorVersion;
+ uint32_t libToolkitVersion;
+ } buildInfo;
+};
+
+/**
+ * The structure contains essential function pointers which AddOnManager
+ * requires in order to use AddOns.
+ */
+struct AddOnDispatchTable
+{
+ std::string name;
+ void (*GetAddOnInfo)( Dali::AddOnInfo&) = nullptr;
+ void*(*GetGlobalProc)(const char*) = nullptr;
+ void*(*GetInstanceProc)(const char*) = nullptr;
+
+ // Lifecycle callbacks
+ void(*OnStart)() = nullptr;
+ void(*OnResume)() = nullptr;
+ void(*OnPause)() = nullptr;
+ void(*OnStop)() = nullptr;
+};
+
+/**
+ * The AddOnLibrary type represents fully opaque object which hides
+ * the actual handle to the library and other related data.
+ */
+typedef void* AddOnLibrary;
+
+namespace Integration
+{
+/**
+ * AddOnManager class
+ *
+ * Handles DALi AddOn support. The object of AddOnManager exists as a singleton and
+ * is created by the Adaptor. The AddOnManager is used by:
+ *
+ * 1) Application - query the AddOns and obtain AddOn interfaces
+ * 2) DALi - handling lifecycle events
+ * 3) AddOn - self-registering the AddOn dispatch table
+ *
+ * It is up to the implementation how the AddOn libraries are enumerated and opened. Any
+ * caching (functions, open libraries) must be handled by the implementation.
+ */
+class DALI_CORE_API AddOnManager
+{
+protected:
+ /**
+ * @brief Constructor, initialised by the Adaptor
+ */
+ AddOnManager();
+
+public:
+
+ /**
+ * @brief Destructor
+ */
+ virtual ~AddOnManager();
+
+ // Functions called by the application
+public:
+ /**
+ * @brief Retrieves list of the available AddOns
+ * @return List of AddOn names
+ */
+ virtual std::vector<std::string> EnumerateAddOns() = 0;
+
+ /**
+ * @brief Returns AddOnInfo structure for specified AddOn name
+ * @param[in] name Name of AddOn
+ * @param[out]] info Output reference
+ * @return True on success, False if extension info cannot be retrieved
+ */
+ virtual bool GetAddOnInfo(const std::string& name, AddOnInfo& info ) = 0;
+
+ /**
+ * @brief Loads and initialises specified extensions
+ * @param[in] extensionNames Array of extension names
+ * @return vector of initialised extension handles
+ */
+ virtual std::vector<AddOnLibrary> LoadAddOns( const std::vector<std::string>& addonNames ) = 0;
+
+ /**
+ * @brief Loads AddOn with specified name
+ * @param[in] addOnName Name of AddOn to be acquired
+ * @return Returns a valid handle or nullptr
+ */
+ inline AddOnLibrary GetAddOn( const std::string& addonName )
+ {
+ return LoadAddOns( { addonName } )[0];
+ }
+
+ /**
+ * @brief Returns AddOn global function pointer
+ * @param[in] addOnLibrary valid AddOn library object
+ * @param[in] procName Name of the function to retrieve
+ * @return Pointer to the function or null if function doesn't exist
+ */
+ virtual void* GetGlobalProc( const Dali::AddOnLibrary& addOnLibrary, const char* procName ) = 0;
+
+ /**
+ * @brief Returns addon instance function pointer
+ * @param[in] addOnLibrary valid AddOn library object
+ * @param[in] procName Name of the function to retrieve
+ * @return Pointer to the function or null if function doesn't exist
+ */
+ virtual void* GetInstanceProc( const Dali::AddOnLibrary& addOnLibrary, const char* procName ) = 0;
+
+ /**
+ * @brief Returns addon global function of specified type
+ * @param[in] addOnLibrary valid AddOn library object
+ * @param[in] procName Name of the function to retrieve
+ * @return std::function object or null if function doesn't exist
+ */
+ template<class T>
+ DALI_INTERNAL std::function<T> GetGlobalProc( const Dali::AddOnLibrary& addonlibrary, const char* procName )
+ {
+ auto ptr = GetGlobalProc( addonlibrary, procName );
+ if( ptr )
+ {
+ return std::function<T>( *reinterpret_cast<T**>(&ptr) );
+ }
+ return {};
+ };
+
+ /**
+ * @brief Returns AddOn instance function of specified type
+ * @param[in] addOnLibrary valid AddOn library object
+ * @param[in] procName Name of the function to retrieve
+ * @return std::function object or null if function doesn't exist
+ */
+ template<class T>
+ DALI_INTERNAL std::function<T> GetInstanceProc( const Dali::AddOnLibrary& addOnLibrary, const char* procName )
+ {
+ auto ptr = GetInstanceProc( addOnLibrary, procName );
+ if( ptr )
+ {
+ return std::function<T>( *reinterpret_cast<T**>(&ptr) );
+ }
+ return {};
+ };
+
+ /**
+ * @brief Invokes global function by name
+ * @param[in] addOnLibrary valid AddOn library object
+ * @param[in] functionName Name of function to be called
+ * @param args[in] Arguments
+ * @return Result of called function
+ */
+ template<class R, class... Args>
+ DALI_INTERNAL R InvokeGlobalProc( AddOnLibrary addOnLibrary, const char* functionName, Args&&... args)
+ {
+ return std::move(GetGlobalProc<R(Args...)>( addOnLibrary, functionName )( args... ));
+ }
+
+ // Lifecycle events, functions are called by the Adaptor
+public:
+
+ /**
+ * @brief Lifecycle pause function
+ */
+ virtual void Pause() = 0;
+
+ /**
+ * @brief Lifecycle resume function
+ */
+ virtual void Resume() = 0;
+
+ /**
+ * @brief Lifecycle start function
+ */
+ virtual void Start() = 0;
+
+ /**
+ * @brief Lifecycle stop function
+ */
+ virtual void Stop() = 0;
+
+ // Functions called by the AddOn
+public:
+
+ /**
+ * @brief Registers the dispatch table with AddOnManager.
+ *
+ * The function must be called by the AddOn in order to self-register and add
+ * the dispatch table. The platform-dependent implementation must override it
+ * in order to store the dispatch table. The way the dispatch table is stored
+ * depends on the implementation.
+ *
+ * @param[in] dispatchTable Pointer to the valid dispatch table
+ */
+ virtual void RegisterAddOnDispatchTable( const AddOnDispatchTable* dispatchTable ) = 0;
+
+ /**
+ * @brief Retrieves AddOnManager singleton
+ * @return pointer to the AddOnManager
+ */
+ static AddOnManager* Get();
+
+protected:
+
+ static AddOnManager* mSingleton; ///< Singleton storing an instance of AddOnManager
+};
+} // namespace Integration
+} // namespace Dali
+
+#endif // DALI_INTEGRATION_ADDON_MANAGER
# Add platform abstraction source files here
SET( platform_abstraction_src_files
+ ${platform_abstraction_src_dir}/addon-manager.cpp
${platform_abstraction_src_dir}/bitmap.cpp
${platform_abstraction_src_dir}/core.cpp
${platform_abstraction_src_dir}/debug.cpp
SET( platform_abstraction_header_files
+ ${platform_abstraction_src_dir}/addon-manager.h
${platform_abstraction_src_dir}/core.h
${platform_abstraction_src_dir}/core-enumerations.h
${platform_abstraction_src_dir}/context-notifier.h