AddOn support 25/238025/11
authoradam.b <adam.b@samsung.com>
Fri, 24 Jul 2020 11:42:51 +0000 (12:42 +0100)
committeradam.b <adam.b@samsung.com>
Fri, 24 Jul 2020 11:43:10 +0000 (12:43 +0100)
Added devel-api to make use of addons easier

Change-Id: I98fa1da7cdfae7e101d53f5f3b9b3ca1806cba00

15 files changed:
.gitignore
automated-tests/src/dali-internal/CMakeLists.txt
automated-tests/src/dali/CMakeLists.txt
automated-tests/src/dali/dali-test-suite-utils/test-addon-manager.cpp [new file with mode: 0644]
automated-tests/src/dali/dali-test-suite-utils/test-addon-manager.h [new file with mode: 0644]
automated-tests/src/dali/test-sample-addon.cpp [new file with mode: 0644]
automated-tests/src/dali/utc-Dali-AddOn.cpp [new file with mode: 0644]
dali/devel-api/addons/addon-base.h [new file with mode: 0644]
dali/devel-api/addons/addon-dispatch-table.h [new file with mode: 0644]
dali/devel-api/common/addon-binder.cpp [new file with mode: 0644]
dali/devel-api/common/addon-binder.h [new file with mode: 0644]
dali/devel-api/file.list
dali/integration-api/addon-manager.cpp [new file with mode: 0644]
dali/integration-api/addon-manager.h [new file with mode: 0644]
dali/integration-api/file.list

index 559051e..2912c11 100644 (file)
@@ -40,6 +40,7 @@ libdali2-core.so*
 *.creator.user
 /docs/generated/*
 /build/tizen/doc
+/build/tizen-cmake/doc
 /build/tizen/.cov
 /build/desktop
 /packaging/home*
index f39572a..22a472d 100644 (file)
@@ -27,6 +27,7 @@ LIST(APPEND TC_SOURCES
         ../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
@@ -51,7 +52,7 @@ INCLUDE_DIRECTORIES(
 ADD_EXECUTABLE(${EXEC_NAME} ${EXEC_NAME}.cpp ${TC_SOURCES})
 TARGET_LINK_LIBRARIES(${EXEC_NAME}
     ${${CAPI_LIB}_LIBRARIES}
-    --coverage
+    --coverage -ldl
 )
 
 INSTALL(PROGRAMS ${EXEC_NAME}
index cd300d0..632363b 100644 (file)
@@ -7,6 +7,7 @@ SET(CAPI_LIB "dali")
 
 SET(TC_SOURCES
         utc-Dali-Actor.cpp
+        utc-Dali-AddOn.cpp
         utc-Dali-AlphaFunction.cpp
         utc-Dali-AngleAxis.cpp
         utc-Dali-Animation.cpp
@@ -119,6 +120,7 @@ LIST(APPEND TC_SOURCES
         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
@@ -138,12 +140,30 @@ INCLUDE_DIRECTORIES(
     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 )
diff --git a/automated-tests/src/dali/dali-test-suite-utils/test-addon-manager.cpp b/automated-tests/src/dali/dali-test-suite-utils/test-addon-manager.cpp
new file mode 100644 (file)
index 0000000..307e0a0
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * 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();
+    }
+  }
+}
+
+}
+}
+
diff --git a/automated-tests/src/dali/dali-test-suite-utils/test-addon-manager.h b/automated-tests/src/dali/dali-test-suite-utils/test-addon-manager.h
new file mode 100644 (file)
index 0000000..e924876
--- /dev/null
@@ -0,0 +1,89 @@
+#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
diff --git a/automated-tests/src/dali/test-sample-addon.cpp b/automated-tests/src/dali/test-sample-addon.cpp
new file mode 100644 (file)
index 0000000..8a3931e
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * 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 );
diff --git a/automated-tests/src/dali/utc-Dali-AddOn.cpp b/automated-tests/src/dali/utc-Dali-AddOn.cpp
new file mode 100644 (file)
index 0000000..f221d51
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * 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;
+}
diff --git a/dali/devel-api/addons/addon-base.h b/dali/devel-api/addons/addon-base.h
new file mode 100644 (file)
index 0000000..f3c3279
--- /dev/null
@@ -0,0 +1,270 @@
+#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
diff --git a/dali/devel-api/addons/addon-dispatch-table.h b/dali/devel-api/addons/addon-dispatch-table.h
new file mode 100644 (file)
index 0000000..1699a5c
--- /dev/null
@@ -0,0 +1,139 @@
+#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
diff --git a/dali/devel-api/common/addon-binder.cpp b/dali/devel-api/common/addon-binder.cpp
new file mode 100644 (file)
index 0000000..3f56e79
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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
diff --git a/dali/devel-api/common/addon-binder.h b/dali/devel-api/common/addon-binder.h
new file mode 100644 (file)
index 0000000..b43a90e
--- /dev/null
@@ -0,0 +1,177 @@
+#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
index afe91fc..b450186 100644 (file)
@@ -8,6 +8,7 @@ SET( devel_api_src_files
   ${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
@@ -41,6 +42,10 @@ SET( devel_api_core_actors_header_files
   ${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
@@ -50,6 +55,7 @@ SET( devel_api_core_animation_header_files
 
 
 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
@@ -126,6 +132,7 @@ SET( SOURCES ${SOURCES}
 
 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}
diff --git a/dali/integration-api/addon-manager.cpp b/dali/integration-api/addon-manager.cpp
new file mode 100644 (file)
index 0000000..1376386
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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;
+}
+}
+}
diff --git a/dali/integration-api/addon-manager.h b/dali/integration-api/addon-manager.h
new file mode 100644 (file)
index 0000000..f957f62
--- /dev/null
@@ -0,0 +1,277 @@
+#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
index 940771c..f5ffa3c 100644 (file)
@@ -3,6 +3,7 @@ SET( platform_abstraction_src_dir ${ROOT_SRC_DIR}/dali/integration-api )
 
 # 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
@@ -24,6 +25,7 @@ SET( platform_abstraction_src_files
 
 
 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