Add ICU class to text abstaction 11/317511/7
authorBowon Ryu <bowon.ryu@samsung.com>
Fri, 3 Jan 2025 02:25:12 +0000 (11:25 +0900)
committerBowon Ryu <bowon.ryu@samsung.com>
Thu, 6 Mar 2025 06:08:27 +0000 (15:08 +0900)
Dali ICU class dynamically loads icu.so via ICUPLugin of dali-extension.
* ICUPlugin is an abstract interface, used by dali-adaptor to access icu plugin.

Change-Id: I1f2b9c702ee000a13e733cc5c232b7c66d256149
Signed-off-by: Bowon Ryu <bowon.ryu@samsung.com>
dali/devel-api/file.list
dali/devel-api/text-abstraction/icu-plugin.h [new file with mode: 0644]
dali/devel-api/text-abstraction/icu.cpp [new file with mode: 0644]
dali/devel-api/text-abstraction/icu.h [new file with mode: 0644]
dali/internal/text/file.list
dali/internal/text/text-abstraction/icu-impl.cpp [new file with mode: 0644]
dali/internal/text/text-abstraction/icu-impl.h [new file with mode: 0644]

index 63f0be2792aac44014cf561b271139dff2ab57f9..0549a09b647413f4d8249b2da2dd976cc42cb511 100755 (executable)
@@ -191,6 +191,7 @@ SET( devel_api_text_abstraction_src_files
    ${adaptor_devel_api_dir}/text-abstraction/text-renderer.cpp
    ${adaptor_devel_api_dir}/text-abstraction/text-renderer-layout-helper.cpp
    ${adaptor_devel_api_dir}/text-abstraction/hyphenation.cpp
+   ${adaptor_devel_api_dir}/text-abstraction/icu.cpp
    ${adaptor_devel_api_dir}/text-abstraction/emoji-character-properties.cpp
    ${adaptor_devel_api_dir}/text-abstraction/emoji-helper.cpp
 )
@@ -212,6 +213,8 @@ SET( text_abstraction_header_files
    ${adaptor_devel_api_dir}/text-abstraction/text-renderer.h
    ${adaptor_devel_api_dir}/text-abstraction/text-renderer-layout-helper.h
    ${adaptor_devel_api_dir}/text-abstraction/hyphenation.h
+   ${adaptor_devel_api_dir}/text-abstraction/icu.h
+   ${adaptor_devel_api_dir}/text-abstraction/icu-plugin.h
    ${adaptor_devel_api_dir}/text-abstraction/emoji-character-properties.h
    ${adaptor_devel_api_dir}/text-abstraction/emoji-helper.h
    ${adaptor_devel_api_dir}/text-abstraction/defined-characters.h
diff --git a/dali/devel-api/text-abstraction/icu-plugin.h b/dali/devel-api/text-abstraction/icu-plugin.h
new file mode 100644 (file)
index 0000000..84c31ea
--- /dev/null
@@ -0,0 +1,71 @@
+#ifndef DALI_PLATFORM_TEXT_ABSTRACTION_ICU_PLUGIN_H
+#define DALI_PLATFORM_TEXT_ABSTRACTION_ICU_PLUGIN_H
+
+/*
+ * Copyright (c) 2025 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/devel-api/text-abstraction/text-abstraction-definitions.h>
+
+// EXTERNAL INCLUDES
+#include <string>
+
+namespace Dali
+{
+namespace TextAbstraction
+{
+
+/**
+ * @brief ICUPlugin is an abstract interface, used by dali-adaptor to access icu plugin.
+ * A concrete implementation must be created for each platform and provided as dynamic library.
+ */
+class ICUPlugin
+{
+public:
+  /**
+   * @brief Constructor.
+   */
+  ICUPlugin()
+  {
+  }
+
+  /**
+   * @brief Destructor.
+   */
+  virtual ~ICUPlugin()
+  {
+  }
+
+  /**
+   * @brief Update line break information by ICU.
+   * @remark Updates given line break information with ICU dictionary-based word wrap information that unibreak does not support.
+   * @param[in] text A string of UTF-8 characters.
+   * @param[in] numberOfCharacters The number of characters.
+   * @param[in] locale The locale code. (en, ko, en_US, ko_KR.utf8, etc. ICU accepts most formats of locale code), The usual expected form is language_locale (ko_KR).
+   * @param[out] breakInfo The unibreak line break information buffer.
+   */
+  virtual void UpdateLineBreakInfoByLocale(const std::string& text,
+                                           Length             numberOfCharacters,
+                                           const char*        locale,
+                                           LineBreakInfo*     breakInfo) = 0;
+};
+
+} // namespace TextAbstraction
+
+} // namespace Dali
+
+#endif // DALI_PLATFORM_TEXT_ABSTRACTION_ICU_PLUGIN_H
diff --git a/dali/devel-api/text-abstraction/icu.cpp b/dali/devel-api/text-abstraction/icu.cpp
new file mode 100644 (file)
index 0000000..e8c4bdd
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2025 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/devel-api/text-abstraction/icu.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/text/text-abstraction/icu-impl.h>
+
+namespace Dali
+{
+namespace TextAbstraction
+{
+ICU::ICU()
+{
+}
+
+ICU::~ICU()
+{
+}
+
+ICU::ICU(Internal::ICU* impl)
+: BaseHandle(impl)
+{
+}
+
+ICU ICU::New()
+{
+  auto icuImpl = new Internal::ICU();
+
+  return ICU(icuImpl);
+}
+
+void ICU::UpdateLineBreakInfoByLocale(const std::string& text,
+                                      Length             numberOfCharacters,
+                                      const char*        locale,
+                                      LineBreakInfo*     breakInfo)
+{
+  GetImplementation(*this).UpdateLineBreakInfoByLocale(text, numberOfCharacters, locale, breakInfo);
+}
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/dali/devel-api/text-abstraction/icu.h b/dali/devel-api/text-abstraction/icu.h
new file mode 100644 (file)
index 0000000..8d5e4e9
--- /dev/null
@@ -0,0 +1,89 @@
+#ifndef DALI_PLATFORM_TEXT_ABSTRACTION_ICU_H
+#define DALI_PLATFORM_TEXT_ABSTRACTION_ICU_H
+
+/*
+ * Copyright (c) 2025 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/devel-api/text-abstraction/text-abstraction-definitions.h>
+#include <dali/public-api/dali-adaptor-common.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-handle.h>
+
+namespace Dali
+{
+namespace TextAbstraction
+{
+namespace Internal DALI_INTERNAL
+{
+class ICU;
+
+} // namespace DALI_INTERNAL
+
+/**
+ * @brief To support ICU in dali. ICU, International Components for Unicode.
+ */
+class DALI_ADAPTOR_API ICU : public BaseHandle
+{
+public:
+  /**
+   * @brief Create an uninitialized ICU handle.
+   *
+   */
+  ICU();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~ICU();
+
+  /**
+   * @brief This constructor is used by ICU::New().
+   *
+   * @param[in] implementation A pointer to the internal icu object.
+   */
+  explicit DALI_INTERNAL ICU(Internal::ICU* implementation);
+
+  /**
+   * @brief Create a handle to the new ICU instance.
+   *
+   * @return A handle to the ICU.
+   */
+  static ICU New();
+
+  /**
+   * @brief Update line break information by ICU.
+   * @remark Updates given line break information with ICU dictionary-based word wrap information that unibreak does not support.
+   * @param[in] text A string of UTF-8 characters.
+   * @param[in] numberOfCharacters The number of characters.
+   * @param[in] locale The locale code. (en, ko, en_US, ko_KR.utf8, etc. ICU accepts most formats of locale code), The usual expected form is language_locale (ko_KR).
+   * @param[out] breakInfo The unibreak line break information buffer.
+   */
+  void UpdateLineBreakInfoByLocale(const std::string& text,
+                                   Length             numberOfCharacters,
+                                   const char*        locale,
+                                   LineBreakInfo*     breakInfo);
+};
+
+} // namespace TextAbstraction
+
+} // namespace Dali
+
+#endif // DALI_PLATFORM_TEXT_ABSTRACTION_ICU_H
index b734d8efc118e9d02b49260d64937ec4dc0da4e1..96f01d20bf70eb1973ab693c4e64898e59c678b1 100644 (file)
@@ -7,6 +7,7 @@ SET( adaptor_text_common_src_files
     ${adaptor_text_dir}/text-abstraction/shaping-impl.cpp
     ${adaptor_text_dir}/text-abstraction/text-renderer-impl.cpp
     ${adaptor_text_dir}/text-abstraction/hyphenation-impl.cpp
+    ${adaptor_text_dir}/text-abstraction/icu-impl.cpp
     ${adaptor_text_dir}/text-abstraction/plugin/bitmap-font-cache-item.cpp
     ${adaptor_text_dir}/text-abstraction/plugin/embedded-item.cpp
     ${adaptor_text_dir}/text-abstraction/plugin/font-client-utils.cpp
diff --git a/dali/internal/text/text-abstraction/icu-impl.cpp b/dali/internal/text/text-abstraction/icu-impl.cpp
new file mode 100644 (file)
index 0000000..532d1d6
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2025 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.
+ *
+ */
+
+// CLASS  HEADER
+#include <dali/internal/text/text-abstraction/icu-impl.h>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+// EXTERNAL INCLUDES
+#include <dlfcn.h>
+
+namespace
+{
+const char* ICU_PLUGIN_SO("libdali2-icu-plugin.so");
+} // namespace
+
+namespace Dali
+{
+namespace TextAbstraction
+{
+namespace Internal
+{
+
+ICU::ICU()
+: mPlugin(nullptr),
+  mHandle(nullptr),
+  mCreateICUPluginPtr(nullptr),
+  mDestroyICUPluginPtr(nullptr),
+  mInitialized(false)
+{
+}
+
+ICU::~ICU()
+{
+  if(mHandle != nullptr)
+  {
+    if(mDestroyICUPluginPtr != nullptr)
+    {
+      mDestroyICUPluginPtr(mPlugin);
+    }
+    dlclose(mHandle);
+  }
+}
+
+void ICU::Initialize()
+{
+  // Try once.
+  mInitialized = true;
+
+  char* error = nullptr;
+
+  mHandle = dlopen(ICU_PLUGIN_SO, RTLD_LAZY);
+  if(mHandle == nullptr)
+  {
+    error = dlerror();
+    DALI_LOG_ERROR("ICU, dlopen error: %s\n", error ? error : "null");
+    return;
+  }
+
+  mCreateICUPluginPtr = reinterpret_cast<CreateICUPluginFunction>(dlsym(mHandle, "CreateICUPlugin"));
+  if(mCreateICUPluginPtr == nullptr)
+  {
+    error = dlerror();
+    DALI_LOG_ERROR("Can't load symbol CreateICUPlugin(), error: %s\n", error ? error : "null");
+    dlclose(mHandle);
+    mHandle = nullptr;
+    return;
+  }
+
+  mDestroyICUPluginPtr = reinterpret_cast<DestroyICUPluginFunction>(dlsym(mHandle, "DestroyICUPlugin"));
+  if(mDestroyICUPluginPtr == nullptr)
+  {
+    error = dlerror();
+    DALI_LOG_ERROR("Can't load symbol DestroyICUPlugin(), error: %s\n", error ? error : "null");
+    dlclose(mHandle);
+    mHandle             = nullptr;
+    mCreateICUPluginPtr = nullptr;
+    return;
+  }
+
+  mPlugin = mCreateICUPluginPtr();
+  if(mPlugin == nullptr)
+  {
+    DALI_LOG_ERROR("Can't create the ICUPlugin object\n");
+    dlclose(mHandle);
+    mHandle              = nullptr;
+    mCreateICUPluginPtr  = nullptr;
+    mDestroyICUPluginPtr = nullptr;
+    return;
+  }
+}
+
+void ICU::UpdateLineBreakInfoByLocale(const std::string& text,
+                                      Length             numberOfCharacters,
+                                      const char*        locale,
+                                      LineBreakInfo*     breakInfo)
+{
+  if(!mInitialized)
+  {
+    Initialize();
+  }
+  if(mPlugin != nullptr)
+  {
+    mPlugin->UpdateLineBreakInfoByLocale(text, numberOfCharacters, locale, breakInfo);
+  }
+}
+
+} // namespace Internal
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/dali/internal/text/text-abstraction/icu-impl.h b/dali/internal/text/text-abstraction/icu-impl.h
new file mode 100644 (file)
index 0000000..b37ef8c
--- /dev/null
@@ -0,0 +1,102 @@
+#ifndef DALI_INTERNAL_TEXT_ABSTRACTION_ICU_IMPL_H
+#define DALI_INTERNAL_TEXT_ABSTRACTION_ICU_IMPL_H
+
+/*
+ * Copyright (c) 2025 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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/icu-plugin.h>
+#include <dali/devel-api/text-abstraction/icu.h>
+
+namespace Dali
+{
+namespace TextAbstraction
+{
+namespace Internal
+{
+/**
+ * Implementation of the ICU
+ */
+class ICU : public BaseObject
+{
+public:
+  /**
+   * Constructor
+   */
+  ICU();
+
+  /**
+   * Destructor
+   */
+  ~ICU();
+
+  /**
+   * @brief Dali::TextAbstraction::ICU::UpdateLineBreakInfoByLocale()
+   */
+  void UpdateLineBreakInfoByLocale(const std::string& text,
+                                   Length             numberOfCharacters,
+                                   const char*        locale,
+                                   LineBreakInfo*     breakInfo);
+
+private:
+  /**
+   * @brief Initializes member data and dynamically load icu-plugin.so of dali-extension.
+   */
+  void Initialize();
+
+private:
+  ICUPlugin* mPlugin; ///< icu plugin handle
+  void*      mHandle; ///< Handle for the loaded library
+
+  using CreateICUPluginFunction  = ICUPlugin* (*)();
+  using DestroyICUPluginFunction = void (*)(ICUPlugin* plugin);
+
+  CreateICUPluginFunction  mCreateICUPluginPtr;
+  DestroyICUPluginFunction mDestroyICUPluginPtr;
+
+  bool mInitialized : 1; ///< Whether Initialize() has been called, prevents dlopen from being attempted again.
+
+private:
+  ICU(const ICU&);
+  ICU& operator=(const ICU&);
+
+}; // class ICU
+
+} // namespace Internal
+
+} // namespace TextAbstraction
+
+inline static TextAbstraction::Internal::ICU& GetImplementation(TextAbstraction::ICU& icu)
+{
+  DALI_ASSERT_ALWAYS(icu && "icu handle is empty");
+  BaseObject& handle = icu.GetBaseObject();
+  return static_cast<TextAbstraction::Internal::ICU&>(handle);
+}
+
+inline static const TextAbstraction::Internal::ICU& GetImplementation(const TextAbstraction::ICU& icu)
+{
+  DALI_ASSERT_ALWAYS(icu && "icu handle is empty");
+  const BaseObject& handle = icu.GetBaseObject();
+  return static_cast<const TextAbstraction::Internal::ICU&>(handle);
+}
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_TEXT_ABSTRACTION_ICU_IMPL_H