Merge branch 'devel/master' into tizen
authorWoochan Lee <wc0917.lee@samsung.com>
Tue, 28 Mar 2023 05:37:34 +0000 (14:37 +0900)
committerWoochan Lee <wc0917.lee@samsung.com>
Tue, 28 Mar 2023 05:37:34 +0000 (14:37 +0900)
46 files changed:
automated-tests/src/dali-adaptor-internal/utc-Dali-FontClient.cpp
automated-tests/src/dali-graphics/CMakeLists.txt
automated-tests/src/dali-graphics/utc-Dali-GraphicsFramebuffer.cpp
automated-tests/src/dali-graphics/utc-Dali-GraphicsTexture.cpp [new file with mode: 0644]
dali/devel-api/adaptor-framework/accessibility-bridge.h
dali/devel-api/adaptor-framework/accessibility.cpp
dali/devel-api/adaptor-framework/style-monitor.cpp
dali/devel-api/adaptor-framework/style-monitor.h
dali/devel-api/file.list
dali/devel-api/text-abstraction/font-client.cpp
dali/devel-api/text-abstraction/font-client.h
dali/devel-api/text-abstraction/glyph-buffer-data.cpp [new file with mode: 0644]
dali/devel-api/text-abstraction/glyph-buffer-data.h [new file with mode: 0644]
dali/internal/accessibility/bridge/bridge-base.h
dali/internal/accessibility/bridge/bridge-object.cpp
dali/internal/accessibility/bridge/bridge-object.h
dali/internal/accessibility/bridge/dummy/dummy-atspi.h
dali/internal/adaptor/common/adaptor-impl.cpp
dali/internal/graphics/gles-impl/egl-graphics-controller.cpp
dali/internal/styling/common/style-monitor-impl.cpp
dali/internal/styling/common/style-monitor-impl.h
dali/internal/text/text-abstraction/cairo-renderer.cpp
dali/internal/text/text-abstraction/font-client-impl.cpp
dali/internal/text/text-abstraction/font-client-impl.h
dali/internal/text/text-abstraction/plugin/bitmap-font-cache-item.cpp
dali/internal/text/text-abstraction/plugin/bitmap-font-cache-item.h
dali/internal/text/text-abstraction/plugin/embedded-item.cpp
dali/internal/text/text-abstraction/plugin/embedded-item.h
dali/internal/text/text-abstraction/plugin/font-cache-item-interface.h
dali/internal/text/text-abstraction/plugin/font-client-plugin-impl.cpp
dali/internal/text/text-abstraction/plugin/font-client-plugin-impl.h
dali/internal/text/text-abstraction/plugin/font-client-utils.cpp
dali/internal/text/text-abstraction/plugin/font-client-utils.h
dali/internal/text/text-abstraction/plugin/font-face-cache-item.cpp
dali/internal/text/text-abstraction/plugin/font-face-cache-item.h
dali/internal/text/text-abstraction/plugin/font-face-glyph-cache-manager.cpp
dali/internal/text/text-abstraction/plugin/font-face-glyph-cache-manager.h
dali/internal/text/text-abstraction/plugin/harfbuzz-proxy-font.cpp
dali/internal/window-system/common/window-impl.cpp
dali/internal/window-system/common/window-render-surface.cpp
dali/internal/window-system/common/window-render-surface.h
dali/internal/window-system/common/window-system.cpp [new file with mode: 0644]
dali/internal/window-system/common/window-system.h
dali/internal/window-system/file.list
dali/public-api/dali-adaptor-version.cpp
packaging/dali-adaptor.spec

index 4868e3c..be22f59 100644 (file)
@@ -139,9 +139,9 @@ int UtcDaliFontClientAtlasLimitationEnabled(void)
 
   // Block's width or height are less than 512
   tet_infoline("UtcDaliFontClientAtlasLimitationEnabled PointSize=200");
-  uint32_t                                     pointSize200 = 200 * TextAbstraction::FontClient::NUMBER_OF_POINTS_PER_ONE_UNIT_OF_POINT_SIZE;
-  TextAbstraction::FontId                      fontId200    = fontClient.GetFontId(fontDescription, pointSize200);
-  TextAbstraction::FontClient::GlyphBufferData glyphBufferData200;
+  uint32_t                         pointSize200 = 200 * TextAbstraction::FontClient::NUMBER_OF_POINTS_PER_ONE_UNIT_OF_POINT_SIZE;
+  TextAbstraction::FontId          fontId200    = fontClient.GetFontId(fontDescription, pointSize200);
+  TextAbstraction::GlyphBufferData glyphBufferData200;
   glyphBufferData200.width  = 0;
   glyphBufferData200.height = 0;
   fontClient.CreateBitmap(fontId200, 68, false, false, glyphBufferData200, 0);
@@ -152,8 +152,8 @@ int UtcDaliFontClientAtlasLimitationEnabled(void)
   // Block's width or height are  greater than 512 and less than 1024
   uint32_t pointSize1000 = 1000 * TextAbstraction::FontClient::NUMBER_OF_POINTS_PER_ONE_UNIT_OF_POINT_SIZE;
   tet_infoline("UtcDaliFontClientAtlasLimitationEnabled PointSize=1000");
-  TextAbstraction::FontId                      fontId1000 = fontClient.GetFontId(fontDescription, pointSize1000);
-  TextAbstraction::FontClient::GlyphBufferData glyphBufferData1000;
+  TextAbstraction::FontId          fontId1000 = fontClient.GetFontId(fontDescription, pointSize1000);
+  TextAbstraction::GlyphBufferData glyphBufferData1000;
   glyphBufferData1000.width  = 0;
   glyphBufferData1000.height = 0;
   fontClient.CreateBitmap(fontId1000, 68, false, false, glyphBufferData1000, 0);
@@ -164,8 +164,8 @@ int UtcDaliFontClientAtlasLimitationEnabled(void)
   // Block's width or height are greater than 1024 and less than 2048
   uint32_t pointSize2000 = 2000 * TextAbstraction::FontClient::NUMBER_OF_POINTS_PER_ONE_UNIT_OF_POINT_SIZE;
   tet_infoline("UtcDaliFontClientAtlasLimitationEnabled PointSize=2000");
-  TextAbstraction::FontId                      fontId2000 = fontClient.GetFontId(fontDescription, pointSize2000);
-  TextAbstraction::FontClient::GlyphBufferData glyphBufferData2000;
+  TextAbstraction::FontId          fontId2000 = fontClient.GetFontId(fontDescription, pointSize2000);
+  TextAbstraction::GlyphBufferData glyphBufferData2000;
   glyphBufferData2000.width  = 0;
   glyphBufferData2000.height = 0;
   fontClient.CreateBitmap(fontId2000, 68, false, false, glyphBufferData2000, 0);
@@ -196,9 +196,9 @@ int UtcDaliFontClientAtlasLimitationDisabled(void)
 
   // Block's width or height are less than 512
   tet_infoline("UtcDaliFontClientAtlasLimitationDisabled PointSize=200");
-  uint32_t                                     pointSize200 = 200 * TextAbstraction::FontClient::NUMBER_OF_POINTS_PER_ONE_UNIT_OF_POINT_SIZE;
-  TextAbstraction::FontId                      fontId200    = fontClient.GetFontId(fontDescription, pointSize200);
-  TextAbstraction::FontClient::GlyphBufferData glyphBufferData200;
+  uint32_t                         pointSize200 = 200 * TextAbstraction::FontClient::NUMBER_OF_POINTS_PER_ONE_UNIT_OF_POINT_SIZE;
+  TextAbstraction::FontId          fontId200    = fontClient.GetFontId(fontDescription, pointSize200);
+  TextAbstraction::GlyphBufferData glyphBufferData200;
   glyphBufferData200.width  = 0;
   glyphBufferData200.height = 0;
   fontClient.CreateBitmap(fontId200, 68, false, false, glyphBufferData200, 0);
@@ -208,9 +208,9 @@ int UtcDaliFontClientAtlasLimitationDisabled(void)
 
   // Block's width or height are  greater than 512 and less than 1024
   tet_infoline("UtcDaliFontClientAtlasLimitationDisabled PointSize=1000");
-  uint32_t                                     pointSize1000 = 1000 * TextAbstraction::FontClient::NUMBER_OF_POINTS_PER_ONE_UNIT_OF_POINT_SIZE;
-  TextAbstraction::FontId                      fontId1000    = fontClient.GetFontId(fontDescription, pointSize1000);
-  TextAbstraction::FontClient::GlyphBufferData glyphBufferData1000;
+  uint32_t                         pointSize1000 = 1000 * TextAbstraction::FontClient::NUMBER_OF_POINTS_PER_ONE_UNIT_OF_POINT_SIZE;
+  TextAbstraction::FontId          fontId1000    = fontClient.GetFontId(fontDescription, pointSize1000);
+  TextAbstraction::GlyphBufferData glyphBufferData1000;
   glyphBufferData1000.width  = 0;
   glyphBufferData1000.height = 0;
   fontClient.CreateBitmap(fontId1000, 68, false, false, glyphBufferData1000, 0);
@@ -220,9 +220,9 @@ int UtcDaliFontClientAtlasLimitationDisabled(void)
 
   // Block's width or height are greater than 1024 and less than 2048
   tet_infoline("UtcDaliFontClientAtlasLimitationDisabled PointSize=2000");
-  uint32_t                                     pointSize2000 = 2000 * TextAbstraction::FontClient::NUMBER_OF_POINTS_PER_ONE_UNIT_OF_POINT_SIZE;
-  TextAbstraction::FontId                      fontId2000    = fontClient.GetFontId(fontDescription, pointSize2000);
-  TextAbstraction::FontClient::GlyphBufferData glyphBufferData2000;
+  uint32_t                         pointSize2000 = 2000 * TextAbstraction::FontClient::NUMBER_OF_POINTS_PER_ONE_UNIT_OF_POINT_SIZE;
+  TextAbstraction::FontId          fontId2000    = fontClient.GetFontId(fontDescription, pointSize2000);
+  TextAbstraction::GlyphBufferData glyphBufferData2000;
   glyphBufferData2000.width  = 0;
   glyphBufferData2000.height = 0;
   fontClient.CreateBitmap(fontId2000, 68, false, false, glyphBufferData2000, 0);
@@ -231,11 +231,11 @@ int UtcDaliFontClientAtlasLimitationDisabled(void)
   DALI_TEST_GREATER(glyphBufferData2000.height, 1024u, TEST_LOCATION); //1148u
 
   // Test GlyphBufferData move
-  TextAbstraction::FontClient::GlyphBufferData movedGlyphBufferData2000 = std::move(glyphBufferData2000);
+  TextAbstraction::GlyphBufferData movedGlyphBufferData2000 = std::move(glyphBufferData2000);
 
   for(int i = 0; i < 50; ++i)
   {
-    TextAbstraction::FontClient::GlyphBufferData dummy = std::move(movedGlyphBufferData2000);
+    TextAbstraction::GlyphBufferData dummy = std::move(movedGlyphBufferData2000);
     movedGlyphBufferData2000                           = std::move(dummy);
 
     // Test moved GlyphBufferData destruct well
index 4f9d368..329f8d4 100644 (file)
@@ -12,6 +12,7 @@ SET(TC_SOURCES
     utc-Dali-GraphicsNativeImage.cpp
     utc-Dali-GraphicsProgram.cpp
     utc-Dali-GraphicsSampler.cpp
+    utc-Dali-GraphicsTexture.cpp
 )
 
 LIST(APPEND TC_SOURCES
@@ -21,18 +22,10 @@ LIST(APPEND TC_SOURCES
   ../dali-adaptor/dali-test-suite-utils/test-actor-utils.cpp
   ../dali-adaptor/dali-test-suite-utils/test-graphics-application.cpp
   ../dali-adaptor/dali-test-suite-utils/test-gl-abstraction.cpp
+
   ../dali-adaptor/dali-test-suite-utils/test-graphics-sync-impl.cpp
   ../dali-adaptor/dali-test-suite-utils/test-graphics-sync-object.cpp
-  ../dali-adaptor/dali-test-suite-utils/test-graphics-buffer.cpp
-  ../dali-adaptor/dali-test-suite-utils/test-graphics-command-buffer.cpp
-  ../dali-adaptor/dali-test-suite-utils/test-graphics-controller.cpp
-  ../dali-adaptor/dali-test-suite-utils/test-graphics-framebuffer.cpp
-  ../dali-adaptor/dali-test-suite-utils/test-graphics-texture.cpp
-  ../dali-adaptor/dali-test-suite-utils/test-graphics-sampler.cpp
-  ../dali-adaptor/dali-test-suite-utils/test-graphics-pipeline.cpp
-  ../dali-adaptor/dali-test-suite-utils/test-graphics-reflection.cpp
-  ../dali-adaptor/dali-test-suite-utils/test-graphics-shader.cpp
-  ../dali-adaptor/dali-test-suite-utils/test-graphics-program.cpp
+
   ../dali-adaptor/dali-test-suite-utils/test-native-image.cpp
   ../dali-adaptor/dali-test-suite-utils/test-platform-abstraction.cpp
   ../dali-adaptor/dali-test-suite-utils/test-render-controller.cpp
index 4ba7f19..733a8ec 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 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.
@@ -226,35 +226,44 @@ int UtcDaliGraphicsFramebufferAttachDepthStencilTexture(void)
 
   auto& gl = app.GetGlAbstraction();
 
-  uint32_t width  = 16u;
-  uint32_t height = 24u;
+  {
+    uint32_t width  = 16u;
+    uint32_t height = 24u;
 
-  FrameBuffer framebuffer = FrameBuffer::New(width, height, FrameBuffer::Attachment::STENCIL);
+    FrameBuffer framebuffer = FrameBuffer::New(width, height, FrameBuffer::Attachment::STENCIL);
 
-  DALI_TEST_CHECK(framebuffer);
+    DALI_TEST_CHECK(framebuffer);
 
-  Texture dummyColorTexture        = CreateTexture(TextureType::TEXTURE_2D, Pixel::RGBA8888, width, height);
-  Texture dummyDepthStencilTexture = CreateTexture(TextureType::TEXTURE_2D, Pixel::DEPTH_STENCIL, width, height);
-  Actor   dummyActor               = CreateRenderableActor(dummyColorTexture);
-  framebuffer.AttachColorTexture(dummyColorTexture);
-  DevelFrameBuffer::AttachDepthStencilTexture(framebuffer, dummyDepthStencilTexture);
+    Texture dummyColorTexture        = CreateTexture(TextureType::TEXTURE_2D, Pixel::RGBA8888, width, height);
+    Texture dummyDepthStencilTexture = CreateTexture(TextureType::TEXTURE_2D, Pixel::DEPTH_STENCIL, width, height);
+    Actor   dummyActor               = CreateRenderableActor(dummyColorTexture);
+    framebuffer.AttachColorTexture(dummyColorTexture);
+    DevelFrameBuffer::AttachDepthStencilTexture(framebuffer, dummyDepthStencilTexture);
 
-  app.GetScene().Add(dummyActor);
+    app.GetScene().Add(dummyActor);
 
-  auto renderTask = CreateRenderTask(app, framebuffer);
+    auto renderTask = CreateRenderTask(app, framebuffer);
 
-  DALI_TEST_CHECK(renderTask);
+    DALI_TEST_CHECK(renderTask);
 
-  app.SendNotification();
-  app.Render(16); // The above actor will get rendered and drawn once.
+    app.SendNotification();
+    app.Render(16); // The above actor will get rendered and drawn once.
 
-  DALI_TEST_EQUALS(gl.CheckFramebufferColorAttachmentCount(), 1u, TEST_LOCATION);
-  DALI_TEST_EQUALS(gl.CheckFramebufferDepthAttachmentCount(), 1u, TEST_LOCATION);
-  DALI_TEST_EQUALS(gl.CheckFramebufferStencilAttachmentCount(), 1u, TEST_LOCATION);
-  DALI_TEST_EQUALS(gl.CheckFramebufferDepthStencilAttachmentCount(), 1u, TEST_LOCATION);
-  DALI_TEST_EQUALS(gl.CheckFramebufferDepthAttachment(), (GLenum)GL_FALSE, TEST_LOCATION);
-  DALI_TEST_EQUALS(gl.CheckFramebufferStencilAttachment(), (GLenum)GL_FALSE, TEST_LOCATION);
-  DALI_TEST_EQUALS(gl.CheckFramebufferDepthStencilAttachment(), (GLenum)GL_FALSE, TEST_LOCATION); // Check whether renderbuffer attached by DEPTH_STENCIL.
+    DALI_TEST_EQUALS(gl.CheckFramebufferColorAttachmentCount(), 1u, TEST_LOCATION);
+    DALI_TEST_EQUALS(gl.CheckFramebufferDepthAttachmentCount(), 1u, TEST_LOCATION);
+    DALI_TEST_EQUALS(gl.CheckFramebufferStencilAttachmentCount(), 1u, TEST_LOCATION);
+    DALI_TEST_EQUALS(gl.CheckFramebufferDepthStencilAttachmentCount(), 1u, TEST_LOCATION);
+    DALI_TEST_EQUALS(gl.CheckFramebufferDepthAttachment(), (GLenum)GL_FALSE, TEST_LOCATION);
+    DALI_TEST_EQUALS(gl.CheckFramebufferStencilAttachment(), (GLenum)GL_FALSE, TEST_LOCATION);
+    DALI_TEST_EQUALS(gl.CheckFramebufferDepthStencilAttachment(), (GLenum)GL_FALSE, TEST_LOCATION); // Check whether renderbuffer attached by DEPTH_STENCIL.
+
+    UnparentAndReset(dummyActor);
+  }
+  // Ensure some cleanup happens!
+  app.SendNotification();
+  app.Render(16);
+  app.SendNotification();
+  app.Render(16);
 
   END_TEST;
 }
@@ -298,4 +307,4 @@ int UtcDaliGraphicsFramebufferAttachStencilAndDepthTexture(void)
   DALI_TEST_EQUALS(gl.CheckFramebufferDepthStencilAttachment(), (GLenum)GL_FALSE, TEST_LOCATION); // Check whether renderbuffer attached by DEPTH_STENCIL.
 
   END_TEST;
-}
\ No newline at end of file
+}
diff --git a/automated-tests/src/dali-graphics/utc-Dali-GraphicsTexture.cpp b/automated-tests/src/dali-graphics/utc-Dali-GraphicsTexture.cpp
new file mode 100644 (file)
index 0000000..62864ac
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2023 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/dali.h>
+
+#include <dali/internal/graphics/gles-impl/egl-graphics-controller.h>
+#include <test-actor-utils.h>
+#include <test-graphics-application.h>
+#include <test-graphics-framebuffer.h>
+
+using namespace Dali;
+
+namespace
+{
+} // namespace
+
+void utc_dali_texture_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+void utc_dali_texture_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliTextureConvertUpload(void)
+{
+  TestGraphicsApplication app;
+  tet_infoline("UtcDaliGraphicsConvertUpload - Test that an RGB image is converted to RGBA after upload");
+
+  auto& gl = app.GetGlAbstraction();
+  gl.EnableTextureCallTrace(true);
+  gl.EnableTexParameterCallTrace(true);
+
+  int     size    = 200;
+  Texture texture = Texture::New(TextureType::TEXTURE_2D, Pixel::RGBA8888, size, size);
+
+  int       bufferSize = size * size * 3;
+  uint8_t*  buffer     = reinterpret_cast<uint8_t*>(malloc(bufferSize));
+  PixelData pixelData  = PixelData::New(buffer, bufferSize, size, size, Pixel::RGB888, PixelData::FREE);
+  texture.Upload(pixelData, 0u, 0u, 0u, 0u, size, size);
+
+  Sampler sampler = Sampler::New();
+  sampler.SetFilterMode(FilterMode::LINEAR, FilterMode::LINEAR);
+
+  TextureSet textureSet = TextureSet::New();
+  textureSet.SetTexture(0u, texture);
+  textureSet.SetSampler(0u, sampler);
+
+  Actor dummyActor = CreateRenderableActor2(textureSet, "", "");
+  app.GetScene().Add(dummyActor);
+
+  app.SendNotification();
+  app.Render(16);
+
+  // Check that TexImage2D was called with right format
+  auto&                       textureTrace      = gl.GetTextureTrace();
+  auto&                       texParameterTrace = gl.GetTexParameterTrace();
+  TraceCallStack::NamedParams namedParams;
+  DALI_TEST_CHECK(textureTrace.FindMethodAndGetParameters("TexImage2D", namedParams));
+  std::stringstream s;
+  s << std::hex << GL_RGBA;
+
+  DALI_TEST_EQUALS(texParameterTrace.CountMethod("TexParameteri"), 4, TEST_LOCATION);
+  std::stringstream out;
+  out << std::hex << GL_TEXTURE_2D << ", " << GL_TEXTURE_MIN_FILTER << ", " << GL_LINEAR;
+  DALI_TEST_EQUALS(texParameterTrace.TestMethodAndParams(0, "TexParameteri", out.str()), true, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(namedParams["format"].str(), s.str(), TEST_LOCATION);
+  END_TEST;
+}
index 0737c69..22dbb5e 100644 (file)
@@ -339,6 +339,19 @@ struct DALI_ADAPTOR_API Bridge
   virtual void EmitBoundsChanged(Accessible* obj, Rect<> rect) = 0;
 
   /**
+   * @brief Emits org.a11y.atspi.Event.Window.PostRender on the AT-SPI bus.
+   *
+   * @param[in] obj The Accessible sender object
+   *
+   * The sender of this event is expected to be an Accessible object that
+   * represents a top-level window.
+   *
+   * The actual number of events emitted during a given time interval may be smaller
+   * than the number of calls to this method, but at least one is guaranteed.
+   */
+  virtual void EmitPostRender(Accessible *obj) = 0;
+
+  /**
    * @brief Emits key event on at-spi bus.
    *
    * Screen-reader might receive this event and reply, that given keycode is consumed. In that case
index b780b3f..4c83f43 100644 (file)
@@ -507,9 +507,8 @@ public:
 
   void OnPostRender()
   {
-    Accessibility::Bridge::GetCurrentBridge()->Emit(Accessibility::Accessible::Get(Self()), Accessibility::WindowEvent::POST_RENDER);
+    Accessibility::Bridge::GetCurrentBridge()->EmitPostRender(this);
   }
-
 }; // AdaptorAccessible
 
 using AdaptorAccessiblesType = std::unordered_map<const Dali::RefObject*, std::unique_ptr<AdaptorAccessible> >;
index 233505a..a65b61b 100644 (file)
@@ -49,6 +49,11 @@ StyleMonitor StyleMonitor::DownCast(BaseHandle handle)
   return StyleMonitor(dynamic_cast<Internal::Adaptor::StyleMonitor*>(handle.GetObjectPtr()));
 }
 
+bool StyleMonitor::EnsureFontClientCreated()
+{
+  return GetImplementation(*this).EnsureFontClientCreated();
+}
+
 std::string StyleMonitor::GetDefaultFontFamily() const
 {
   return GetImplementation(*this).GetDefaultFontFamily();
index 2708eec..fabf58f 100644 (file)
@@ -118,6 +118,15 @@ public: // Creation & Destruction
   static StyleMonitor DownCast(BaseHandle handle);
 
 public: // Style Information
+
+  /**
+   * @brief Ensure the font client has been created.
+   *
+   * If font client doesn't exist, create it and set default values.
+   * @return true if the font client has been created.
+   */
+  bool EnsureFontClientCreated();
+
   /**
    * @brief Retrieves the default font family.
    * @return The default font family.
index 9a6bd2f..9199da3 100755 (executable)
@@ -172,6 +172,7 @@ SET( devel_api_text_abstraction_src_files
    ${adaptor_devel_api_dir}/text-abstraction/font-client.cpp
    ${adaptor_devel_api_dir}/text-abstraction/font-list.cpp
    ${adaptor_devel_api_dir}/text-abstraction/font-metrics.cpp
+   ${adaptor_devel_api_dir}/text-abstraction/glyph-buffer-data.cpp
    ${adaptor_devel_api_dir}/text-abstraction/glyph-info.cpp
    ${adaptor_devel_api_dir}/text-abstraction/script.cpp
    ${adaptor_devel_api_dir}/text-abstraction/segmentation.cpp
@@ -190,6 +191,7 @@ SET( text_abstraction_header_files
    ${adaptor_devel_api_dir}/text-abstraction/font-client.h
    ${adaptor_devel_api_dir}/text-abstraction/font-list.h
    ${adaptor_devel_api_dir}/text-abstraction/font-metrics.h
+   ${adaptor_devel_api_dir}/text-abstraction/glyph-buffer-data.h
    ${adaptor_devel_api_dir}/text-abstraction/glyph-info.h
    ${adaptor_devel_api_dir}/text-abstraction/script.h
    ${adaptor_devel_api_dir}/text-abstraction/segmentation.h
index 27c9160..908acea 100644 (file)
 #include <dali/devel-api/text-abstraction/font-client.h>
 
 // INTERNAL INCLUDES
-#include <dali/internal/imaging/common/image-operations.h>
 #include <dali/internal/text/text-abstraction/font-client-impl.h>
 
 namespace Dali
 {
 namespace TextAbstraction
 {
+// FontClient static const value definition.
+
 const PointSize26Dot6 FontClient::DEFAULT_POINT_SIZE   = 768u;                           // 12*64
 const float           FontClient::DEFAULT_ITALIC_ANGLE = 12.f * Dali::Math::PI_OVER_180; // FreeType documentation states the software italic is done by doing a horizontal shear of 12 degrees (file ftsynth.h).
 
@@ -49,571 +50,6 @@ const Size FontClient::MAX_SIZE_FIT_IN_ATLAS(MAX_TEXT_ATLAS_WIDTH - PADDING_TEXT
 
 const uint32_t FontClient::NUMBER_OF_POINTS_PER_ONE_UNIT_OF_POINT_SIZE = 64u; //Found this value from toolkit
 
-// FontClient::GlyphBufferData
-
-FontClient::GlyphBufferData::GlyphBufferData()
-: buffer{nullptr},
-  width{0u},
-  height{0u},
-  outlineOffsetX{0},
-  outlineOffsetY{0},
-  format{Pixel::A8},
-  compressionType{CompressionType::NO_COMPRESSION},
-  isColorEmoji{false},
-  isColorBitmap{false},
-  isBufferOwned{false}
-{
-}
-
-FontClient::GlyphBufferData::~GlyphBufferData()
-{
-  if(isBufferOwned)
-  {
-    free(buffer);
-  }
-}
-
-FontClient::GlyphBufferData::GlyphBufferData(FontClient::GlyphBufferData&& rhs) noexcept
-: buffer{rhs.buffer},
-  width{rhs.width},
-  height{rhs.height},
-  outlineOffsetX{rhs.outlineOffsetX},
-  outlineOffsetY{rhs.outlineOffsetY},
-  format{rhs.format},
-  compressionType{rhs.compressionType},
-  isColorEmoji{rhs.isColorEmoji},
-  isColorBitmap{rhs.isColorBitmap},
-  isBufferOwned{rhs.isBufferOwned}
-{
-  // Remove moved data
-  rhs.buffer        = nullptr;
-  rhs.isBufferOwned = false;
-}
-
-FontClient::GlyphBufferData& FontClient::GlyphBufferData::operator=(FontClient::GlyphBufferData&& rhs) noexcept
-{
-  buffer          = rhs.buffer;
-  width           = rhs.width;
-  height          = rhs.height;
-  outlineOffsetX  = rhs.outlineOffsetX;
-  outlineOffsetY  = rhs.outlineOffsetY;
-  format          = rhs.format;
-  compressionType = rhs.compressionType;
-  isColorEmoji    = rhs.isColorEmoji;
-  isColorBitmap   = rhs.isColorBitmap;
-  isBufferOwned   = rhs.isBufferOwned;
-
-  // Remove moved data
-  rhs.buffer        = nullptr;
-  rhs.isBufferOwned = false;
-
-  return *this;
-}
-
-size_t FontClient::GlyphBufferData::Compress(const uint8_t* const __restrict__ inBuffer, GlyphBufferData& __restrict__ outBufferData)
-{
-  size_t bufferSize                       = 0u;
-  uint8_t*& __restrict__ compressedBuffer = outBufferData.buffer;
-  switch(outBufferData.compressionType)
-  {
-    case TextAbstraction::FontClient::GlyphBufferData::CompressionType::NO_COMPRESSION:
-    {
-      bufferSize = static_cast<size_t>(outBufferData.width) * static_cast<size_t>(outBufferData.height) * static_cast<size_t>(Pixel::GetBytesPerPixel(outBufferData.format));
-
-      compressedBuffer = (uint8_t*)malloc(bufferSize);
-      if(DALI_UNLIKELY(compressedBuffer == nullptr))
-      {
-        return 0u;
-      }
-      outBufferData.isBufferOwned = true;
-
-      // Copy buffer without compress
-      memcpy(compressedBuffer, inBuffer, bufferSize);
-      break;
-    }
-    case TextAbstraction::FontClient::GlyphBufferData::CompressionType::BPP_4:
-    {
-      const uint32_t widthByte       = outBufferData.width * Pixel::GetBytesPerPixel(outBufferData.format);
-      const uint32_t componentCount  = (widthByte >> 1);
-      const bool     considerPadding = (widthByte & 1) ? true : false;
-
-      // For BIT_PER_PIXEL_4 type, we can know final compressed buffer size immediatly.
-      bufferSize       = static_cast<size_t>(outBufferData.height) * static_cast<size_t>(componentCount + (considerPadding ? 1 : 0));
-      compressedBuffer = (uint8_t*)malloc(bufferSize);
-      if(DALI_UNLIKELY(compressedBuffer == nullptr))
-      {
-        return 0u;
-      }
-      outBufferData.isBufferOwned = true;
-
-      uint8_t* __restrict__ outBufferPtr      = compressedBuffer;
-      const uint8_t* __restrict__ inBufferPtr = inBuffer;
-
-      // Compress for each line
-      for(uint32_t y = 0; y < outBufferData.height; ++y)
-      {
-        for(uint32_t x = 0; x < componentCount; ++x)
-        {
-          const uint8_t v0 = Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++));
-          const uint8_t v1 = Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++));
-
-          *(outBufferPtr++) = (v0 << 4) | v1;
-        }
-        if(considerPadding)
-        {
-          *(outBufferPtr++) = Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++));
-        }
-      }
-      break;
-    }
-    case TextAbstraction::FontClient::GlyphBufferData::CompressionType::RLE_4:
-    {
-      const uint32_t widthByte = outBufferData.width * Pixel::GetBytesPerPixel(outBufferData.format);
-
-      // Allocate temperal buffer. Note that RLE4 can be bigger than original buffer.
-      uint8_t* __restrict__ tempBuffer = (uint8_t*)malloc(outBufferData.height * (widthByte + 1));
-      if(DALI_UNLIKELY(tempBuffer == nullptr))
-      {
-        return 0u;
-      }
-
-      uint8_t* __restrict__ outBufferPtr      = tempBuffer;
-      const uint8_t* __restrict__ inBufferPtr = inBuffer;
-
-      bufferSize = 0u;
-
-      // Compress for each line
-      for(uint32_t y = 0; y < outBufferData.height; ++y)
-      {
-        uint32_t encodedByte = 0;
-        while(encodedByte < widthByte)
-        {
-          // Case 1 : Remain only 1 byte
-          if(DALI_UNLIKELY(encodedByte + 1 == widthByte))
-          {
-            const uint8_t prev0 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
-            const uint8_t v0    = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++)) - prev0) & 0x0f; // Intented underflow
-            *(outBufferPtr++)   = v0;
-            ++encodedByte;
-            ++bufferSize;
-          }
-          // Case 2 : Remain only 2 byte
-          else if(DALI_UNLIKELY(encodedByte + 2 == widthByte))
-          {
-            const uint8_t prev0 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
-            const uint8_t v0    = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++)) - prev0) & 0x0f; // Intented underflow
-            const uint8_t prev1 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
-            const uint8_t v1    = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++)) - prev1) & 0x0f; // Intented underflow
-            encodedByte += 2;
-            if(v0 == v1)
-            {
-              *(outBufferPtr++) = 0x80 | v0;
-              ++bufferSize;
-            }
-            else
-            {
-              *(outBufferPtr++) = 0x10 | v0;
-              *(outBufferPtr++) = v1 << 4;
-              bufferSize += 2;
-            }
-          }
-          // Case 3 : Normal case. Remain byte bigger or equal than 3.
-          else
-          {
-            // Compress rule -
-            // Read 2 byte as v0 and v1.
-            // - If v0 == v1, We can compress. mark the first bit as 1. and remain 3 bit mark as the "runLength - 2".
-            //   runLength can be maximum 9.
-            // - If v0 != v1, We cannot compress. mark the first bit as 0. and remain 3 bit mark as the "(nonRunLength - 1) / 2"
-            //   Due to the BitPerPixel is 4, nonRunLength should be odd value.
-            //   nonRunLength cutted if v0 == v1.
-            //   nonRunLength can be maximum 15.
-
-            const uint8_t prev0 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
-            const uint8_t v0    = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++)) - prev0) & 0x0f; // Intented underflow
-            const uint8_t prev1 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
-            const uint8_t v1    = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++)) - prev1) & 0x0f; // Intented underflow
-            encodedByte += 2;
-            // We can compress by RLE
-            if(v0 == v1)
-            {
-              uint8_t runLength = 2;
-              while(encodedByte < widthByte && runLength < 9)
-              {
-                const uint8_t prev2 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
-                const uint8_t v2    = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr)) - prev2) & 0x0f; // Intented underflow
-                if(v2 == v0)
-                {
-                  ++inBufferPtr;
-                  ++encodedByte;
-                  ++runLength;
-                }
-                else
-                {
-                  break;
-                }
-              }
-
-              // Update (runLength - 2) result.
-              *(outBufferPtr++) = ((0x8 | (runLength - 2)) << 4) | v0;
-              ++bufferSize;
-            }
-            // We cannot compress by RLE.
-            else
-            {
-              // Read one more value.
-              const uint8_t prev2 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
-              const uint8_t v2    = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++)) - prev2) & 0x0f; // Intented underflow
-              ++encodedByte;
-
-              uint8_t  nonRunLength          = 3;
-              uint8_t* nonRunLengthHeaderPtr = outBufferPtr;
-              *(outBufferPtr++)              = v0;
-              *(outBufferPtr++)              = (v1 << 4) | v2;
-              bufferSize += 2;
-              while(encodedByte < widthByte && nonRunLength < 15)
-              {
-                if(DALI_LIKELY(encodedByte + 1 < widthByte))
-                {
-                  const uint8_t prew0 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
-                  const uint8_t w0    = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr)) - prew0) & 0x0f; // Intented underflow
-                  const uint8_t prew1 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr + 1 - widthByte));
-                  const uint8_t w1    = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr + 1)) - prew1) & 0x0f; // Intented underflow
-                  if(w0 == w1)
-                  {
-                    // Stop non-compress logic.
-                    break;
-                  }
-                  else
-                  {
-                    ++bufferSize;
-                    *(outBufferPtr++) = (w0 << 4) | w1;
-                    inBufferPtr += 2;
-                    encodedByte += 2;
-                    nonRunLength += 2;
-                  }
-                }
-                else
-                {
-                  // Edge case. There is only one pixel remained.
-                  const uint8_t prew0 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
-                  const uint8_t w0    = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr)) - prew0) & 0x0f; // Intented underflow
-                  {
-                    ++bufferSize;
-                    *(outBufferPtr++) = (w0 << 4);
-                    ++encodedByte;
-                    ++inBufferPtr;
-                    // Increase nonRunLength 2 even latest value is invalid.
-                    nonRunLength += 2;
-                  }
-                }
-              }
-
-              // Update (nonRunLength-1)/2 result into header.
-              *(nonRunLengthHeaderPtr) |= (nonRunLength >> 1) << 4;
-            }
-          }
-        }
-      }
-
-      // Allocate and copy data
-      compressedBuffer = (uint8_t*)malloc(bufferSize);
-      if(DALI_UNLIKELY(compressedBuffer == nullptr))
-      {
-        free(tempBuffer);
-        return 0u;
-      }
-      outBufferData.isBufferOwned = true;
-
-      memcpy(compressedBuffer, tempBuffer, bufferSize);
-      free(tempBuffer);
-
-      break;
-    }
-    default:
-    {
-      break;
-    }
-  }
-
-  return bufferSize;
-}
-
-void FontClient::GlyphBufferData::Decompress(const GlyphBufferData& __restrict__ inBufferData, uint8_t* __restrict__ outBuffer)
-{
-  if(DALI_UNLIKELY(outBuffer == nullptr))
-  {
-    return;
-  }
-
-  switch(inBufferData.compressionType)
-  {
-    case TextAbstraction::FontClient::GlyphBufferData::CompressionType::NO_COMPRESSION:
-    {
-      const auto bufferSize = inBufferData.width * inBufferData.height * Pixel::GetBytesPerPixel(inBufferData.format);
-
-      // Copy buffer without compress
-      memcpy(outBuffer, inBufferData.buffer, bufferSize);
-      break;
-    }
-    case TextAbstraction::FontClient::GlyphBufferData::CompressionType::BPP_4:
-    {
-      const uint32_t widthByte       = inBufferData.width * Pixel::GetBytesPerPixel(inBufferData.format);
-      const uint32_t componentCount  = (widthByte >> 1);
-      const bool     considerPadding = (widthByte & 1) ? true : false;
-
-      uint8_t* __restrict__ outBufferPtr      = outBuffer;
-      const uint8_t* __restrict__ inBufferPtr = inBufferData.buffer;
-
-      // Compress for each line
-      for(uint32_t y = 0; y < inBufferData.height; ++y)
-      {
-        for(uint32_t x = 0; x < componentCount; ++x)
-        {
-          const uint8_t v  = *(inBufferPtr++);
-          const uint8_t v0 = (v >> 4) & 0x0f;
-          const uint8_t v1 = v & 0x0f;
-
-          *(outBufferPtr++) = (v0 << 4) | v0;
-          *(outBufferPtr++) = (v1 << 4) | v1;
-        }
-        if(considerPadding)
-        {
-          const uint8_t v   = *(inBufferPtr++);
-          *(outBufferPtr++) = (v << 4) | v;
-        }
-      }
-      break;
-    }
-    case TextAbstraction::FontClient::GlyphBufferData::CompressionType::RLE_4:
-    {
-      const uint32_t widthByte = inBufferData.width * Pixel::GetBytesPerPixel(inBufferData.format);
-
-      uint8_t* __restrict__ outBufferPtr      = outBuffer;
-      const uint8_t* __restrict__ inBufferPtr = inBufferData.buffer;
-      // Compress for each line
-      for(uint32_t y = 0; y < inBufferData.height; ++y)
-      {
-        uint32_t x           = 0;
-        uint32_t decodedByte = 0;
-        while(decodedByte < widthByte)
-        {
-          const uint8_t v = *(inBufferPtr++);
-          ++x;
-          // Compress by RLE
-          if(v & 0x80)
-          {
-            const uint8_t runLength = ((v >> 4) & 0x07) + 2u;
-            decodedByte += runLength;
-            const uint8_t repeatValue = v & 0x0f;
-            for(uint8_t iter = 0; iter < runLength; ++iter)
-            {
-              const uint8_t prev0 = DALI_UNLIKELY(y == 0) ? 0 : (*(outBufferPtr - widthByte)) & 0x0f;
-              const uint8_t v0    = (prev0 + repeatValue) & 0x0f;
-              *(outBufferPtr++)   = (v0 << 4) | v0;
-            }
-          }
-          // Not compress by RLE
-          else
-          {
-            const uint8_t nonRunLength = (((v >> 4) & 0x07) << 1u) + 1u;
-            decodedByte += nonRunLength;
-            // First value.
-            const uint8_t prev0 = DALI_UNLIKELY(y == 0) ? 0 : (*(outBufferPtr - widthByte)) & 0x0f;
-            const uint8_t v0    = (prev0 + (v & 0x0f)) & 0x0f;
-            *(outBufferPtr++)   = (v0 << 4) | v0;
-
-            const bool ignoreLastValue = decodedByte > widthByte ? true : false;
-            if(DALI_UNLIKELY(ignoreLastValue))
-            {
-              --decodedByte;
-              for(uint8_t iter = 1; iter + 2 < nonRunLength; iter += 2)
-              {
-                const uint8_t w     = *(inBufferPtr++);
-                const uint8_t prew0 = DALI_UNLIKELY(y == 0) ? 0 : (*(outBufferPtr - widthByte)) & 0x0f;
-                const uint8_t w0    = (prew0 + ((w >> 4) & 0x0f)) & 0x0f;
-                const uint8_t prew1 = DALI_UNLIKELY(y == 0) ? 0 : (*(outBufferPtr - widthByte + 1)) & 0x0f;
-                const uint8_t w1    = (prew1 + (w & 0x0f)) & 0x0f;
-                ++x;
-
-                *(outBufferPtr++) = (w0 << 4) | w0;
-                *(outBufferPtr++) = (w1 << 4) | w1;
-              }
-              // Last value.
-              {
-                const uint8_t w     = ((*(inBufferPtr++)) >> 4) & 0x0f;
-                const uint8_t prew0 = DALI_UNLIKELY(y == 0) ? 0 : (*(outBufferPtr - widthByte)) & 0x0f;
-                const uint8_t w0    = (prew0 + w) & 0x0f;
-                ++x;
-
-                *(outBufferPtr++) = (w0 << 4) | w0;
-              }
-            }
-            else
-            {
-              for(uint8_t iter = 1; iter < nonRunLength; iter += 2)
-              {
-                const uint8_t w     = *(inBufferPtr++);
-                const uint8_t prew0 = DALI_UNLIKELY(y == 0) ? 0 : (*(outBufferPtr - widthByte)) & 0x0f;
-                const uint8_t w0    = (prew0 + ((w >> 4) & 0x0f)) & 0x0f;
-                const uint8_t prew1 = DALI_UNLIKELY(y == 0) ? 0 : (*(outBufferPtr - widthByte + 1)) & 0x0f;
-                const uint8_t w1    = (prew1 + (w & 0x0f)) & 0x0f;
-                ++x;
-
-                *(outBufferPtr++) = (w0 << 4) | w0;
-                *(outBufferPtr++) = (w1 << 4) | w1;
-              }
-            }
-          }
-        }
-      }
-      break;
-    }
-    default:
-    {
-      break;
-    }
-  }
-}
-
-void FontClient::GlyphBufferData::DecompressScanline(const GlyphBufferData& __restrict__ inBufferData, uint8_t* __restrict__ outBuffer, uint32_t& __restrict__ offset)
-{
-  switch(inBufferData.compressionType)
-  {
-    case TextAbstraction::FontClient::GlyphBufferData::CompressionType::NO_COMPRESSION:
-    {
-      const auto bufferSize = inBufferData.width * Pixel::GetBytesPerPixel(inBufferData.format);
-
-      // Copy buffer without compress
-      memcpy(outBuffer, inBufferData.buffer + offset, bufferSize);
-
-      // Update offset
-      offset += bufferSize;
-      break;
-    }
-    case TextAbstraction::FontClient::GlyphBufferData::CompressionType::BPP_4:
-    {
-      const uint32_t widthByte       = inBufferData.width * Pixel::GetBytesPerPixel(inBufferData.format);
-      const uint32_t componentCount  = (widthByte >> 1);
-      const bool     considerPadding = (widthByte & 1) ? true : false;
-
-      uint8_t* __restrict__ outBufferPtr      = outBuffer;
-      const uint8_t* __restrict__ inBufferPtr = inBufferData.buffer + offset;
-
-      // Decompress scanline
-      for(uint32_t x = 0; x < componentCount; ++x)
-      {
-        const uint8_t v  = *(inBufferPtr++);
-        const uint8_t v0 = (v >> 4) & 0x0f;
-        const uint8_t v1 = v & 0x0f;
-
-        *(outBufferPtr++) = (v0 << 4) | v0;
-        *(outBufferPtr++) = (v1 << 4) | v1;
-      }
-      if(considerPadding)
-      {
-        const uint8_t v   = *(inBufferPtr++);
-        *(outBufferPtr++) = (v << 4) | v;
-      }
-
-      // Update offset
-      offset += (widthByte + 1u) >> 1u;
-      break;
-    }
-    case TextAbstraction::FontClient::GlyphBufferData::CompressionType::RLE_4:
-    {
-      const uint32_t widthByte = inBufferData.width * Pixel::GetBytesPerPixel(inBufferData.format);
-
-      uint8_t* __restrict__ outBufferPtr      = outBuffer;
-      const uint8_t* __restrict__ inBufferPtr = inBufferData.buffer + offset;
-
-      // If offset is zero, fill outBuffer as 0 first.
-      if(DALI_UNLIKELY(offset == 0))
-      {
-        memset(outBufferPtr, 0, widthByte);
-      }
-
-      // Decompress scanline
-      uint32_t decodedByte = 0;
-      while(decodedByte < widthByte)
-      {
-        const uint8_t v = *(inBufferPtr++);
-        ++offset;
-        // Compress by RLE
-        if(v & 0x80)
-        {
-          const uint8_t runLength = ((v >> 4) & 0x07) + 2u;
-          decodedByte += runLength;
-          const uint8_t repeatValue = (v & 0x0f);
-          for(uint8_t iter = 0; iter < runLength; ++iter)
-          {
-            const uint8_t prev0 = (*(outBufferPtr)) & 0x0f;
-            const uint8_t v0    = (prev0 + repeatValue) & 0x0f;
-            *(outBufferPtr++)   = (v0 << 4) | v0;
-          }
-        }
-        // Not compress by RLE
-        else
-        {
-          const uint8_t nonRunLength = (((v >> 4) & 0x07) << 1u) + 1u;
-          decodedByte += nonRunLength;
-          // First value.
-          const uint8_t prev0 = (*(outBufferPtr)) & 0x0f;
-          const uint8_t v0    = (prev0 + (v & 0x0f)) & 0x0f;
-          *(outBufferPtr++)   = (v0 << 4) | v0;
-
-          const bool ignoreLastValue = decodedByte > widthByte ? true : false;
-          if(DALI_UNLIKELY(ignoreLastValue))
-          {
-            --decodedByte;
-            for(uint8_t iter = 1; iter + 2 < nonRunLength; iter += 2)
-            {
-              const uint8_t w     = *(inBufferPtr++);
-              const uint8_t prew0 = (*(outBufferPtr)) & 0x0f;
-              const uint8_t w0    = (prew0 + ((w >> 4) & 0x0f)) & 0x0f;
-              const uint8_t prew1 = (*(outBufferPtr + 1)) & 0x0f;
-              const uint8_t w1    = (prew1 + (w & 0x0f)) & 0x0f;
-              ++offset;
-
-              *(outBufferPtr++) = (w0 << 4) | w0;
-              *(outBufferPtr++) = (w1 << 4) | w1;
-            }
-            // Last value.
-            {
-              const uint8_t w     = ((*(inBufferPtr++)) >> 4) & 0x0f;
-              const uint8_t prew0 = (*(outBufferPtr)) & 0x0f;
-              const uint8_t w0    = (prew0 + w) & 0x0f;
-              ++offset;
-
-              *(outBufferPtr++) = (w0 << 4) | w0;
-            }
-          }
-          else
-          {
-            for(uint8_t iter = 1; iter < nonRunLength; iter += 2)
-            {
-              const uint8_t w     = *(inBufferPtr++);
-              const uint8_t prew0 = (*(outBufferPtr)) & 0x0f;
-              const uint8_t w0    = (prew0 + ((w >> 4) & 0x0f)) & 0x0f;
-              const uint8_t prew1 = (*(outBufferPtr + 1)) & 0x0f;
-              const uint8_t w1    = (prew1 + (w & 0x0f)) & 0x0f;
-              ++offset;
-
-              *(outBufferPtr++) = (w0 << 4) | w0;
-              *(outBufferPtr++) = (w1 << 4) | w1;
-            }
-          }
-        }
-      }
-      break;
-    }
-    default:
-    {
-      break;
-    }
-  }
-}
-
 // FontClient
 
 FontClient FontClient::Get()
index 2f75e8c..df11ebf 100644 (file)
@@ -20,6 +20,7 @@
 
 // INTERNAL INCLUDES
 #include <dali/devel-api/text-abstraction/font-list.h>
+#include <dali/devel-api/text-abstraction/glyph-buffer-data.h>
 #include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
 #include <dali/public-api/common/dali-vector.h>
 #include <dali/public-api/dali-adaptor-common.h>
@@ -79,99 +80,6 @@ public:
   static const uint32_t NUMBER_OF_POINTS_PER_ONE_UNIT_OF_POINT_SIZE; ///< Factor multiply point-size in toolkit.
 
   /**
-   * @brief Struct used to retrieve the glyph's bitmap.
-   */
-  struct DALI_ADAPTOR_API GlyphBufferData
-  {
-    /**
-     * @brief Constructor.
-     *
-     * Initializes struct members to their defaults.
-     */
-    GlyphBufferData();
-
-    /**
-     * @brief Destructor.
-     */
-    ~GlyphBufferData();
-
-    /**
-     * @brief Move constructor.
-     *
-     * @param[in] rhs moved data.
-     */
-    GlyphBufferData(GlyphBufferData&& rhs) noexcept;
-
-    /**
-     * @brief Move assign operator.
-     *
-     * @param[in] rhs moved data.
-     * @return A reference to this.
-     */
-    GlyphBufferData& operator=(GlyphBufferData&& rhs) noexcept;
-
-    // Compression method of buffer. Each buffer compressed line by line
-    enum class CompressionType
-    {
-      NO_COMPRESSION = 0, // No compression
-      BPP_4          = 1, // Compress as 4 bit. Color become value * 17 (0x00, 0x11, 0x22, ... 0xee, 0xff).
-                          // Only works for Pixel::L8 format
-      RLE_4 = 2,          // Compress as 4 bit, and Run-Length-Encode. For more high compress rate, we store difference between previous scanline.
-                          // Only works for Pixel::L8 format
-    };
-
-    /**
-     * @brief Helper static function to compress raw buffer from inBuffer to outBufferData.buffer.
-     * outBufferData will have it's own buffer.
-     *
-     * @pre outBufferData must not have it's own buffer.
-     * @param[in] inBuffer The input raw data.
-     * @param[in, out] outBufferData The output glyph buffer data.
-     * @return Size of compressed out buffer, Or 0 if compress failed.
-     */
-    static size_t Compress(const uint8_t* const inBuffer, GlyphBufferData& outBufferData);
-
-    /**
-     * @brief Helper static function to decompress raw buffer from inBuffer to outBufferPtr.
-     * If outBuffer is nullptr, Do nothing.
-     *
-     * @pre outBuffer memory should be allocated.
-     * @param[in] inBufferData The input glyph buffer data.
-     * @param[in, out] outBuffer The output pointer of raw buffer data.
-     */
-    static void Decompress(const GlyphBufferData& inBufferData, uint8_t* outBuffer);
-
-    /**
-     * @brief Special Helper static function to decompress raw buffer from inBuffer to outBuffer one scanline.
-     * After decompress one scanline successed, offset will be changed.
-     *
-     * @pre outBuffer memory should be allocated.
-     * @pre if inBufferData's compression type is RLE4, outBuffer memory should store the previous scanline data.
-     * @param[in] inBufferData The input glyph buffer data.
-     * @param[in, out] outBuffer The output pointer of raw buffer data.
-     * @param[in, out] offset The offset of input. It will be changed as next scanline's offset.
-     */
-    static void DecompressScanline(const GlyphBufferData& inBufferData, uint8_t* outBuffer, uint32_t& offset);
-
-  private:
-    // Delete copy operation.
-    GlyphBufferData(const GlyphBufferData& rhs) = delete;
-    GlyphBufferData& operator=(const GlyphBufferData& rhs) = delete;
-
-  public:
-    uint8_t*        buffer;            ///< The glyph's bitmap buffer data.
-    uint32_t        width;             ///< The width of the bitmap.
-    uint32_t        height;            ///< The height of the bitmap.
-    int             outlineOffsetX;    ///< The additional horizontal offset to be added for the glyph's position for outline.
-    int             outlineOffsetY;    ///< The additional vertical offset to be added for the glyph's position for outline.
-    Pixel::Format   format;            ///< The pixel's format of the bitmap.
-    CompressionType compressionType;   ///< The type of buffer compression.
-    bool            isColorEmoji : 1;  ///< Whether the glyph is an emoji.
-    bool            isColorBitmap : 1; ///< Whether the glyph is a color bitmap.
-    bool            isBufferOwned : 1; ///< Whether the glyph's bitmap buffer data owned by this class or not. Becareful when you use non-owned buffer data.
-  };
-
-  /**
    * @brief Used to load an embedded item into the font client.
    */
   struct EmbeddedItemDescription
diff --git a/dali/devel-api/text-abstraction/glyph-buffer-data.cpp b/dali/devel-api/text-abstraction/glyph-buffer-data.cpp
new file mode 100644 (file)
index 0000000..fec3884
--- /dev/null
@@ -0,0 +1,593 @@
+/*
+ * Copyright (c) 2023 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/glyph-buffer-data.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/imaging/common/image-operations.h>
+
+namespace Dali
+{
+namespace TextAbstraction
+{
+GlyphBufferData::GlyphBufferData()
+: buffer{nullptr},
+  width{0u},
+  height{0u},
+  outlineOffsetX{0},
+  outlineOffsetY{0},
+  format{Pixel::A8},
+  compressionType{CompressionType::NO_COMPRESSION},
+  isColorEmoji{false},
+  isColorBitmap{false},
+  isBufferOwned{false}
+{
+}
+
+GlyphBufferData::~GlyphBufferData()
+{
+  if(isBufferOwned)
+  {
+    free(buffer);
+  }
+}
+
+GlyphBufferData::GlyphBufferData(GlyphBufferData&& rhs) noexcept
+: buffer{rhs.buffer},
+  width{rhs.width},
+  height{rhs.height},
+  outlineOffsetX{rhs.outlineOffsetX},
+  outlineOffsetY{rhs.outlineOffsetY},
+  format{rhs.format},
+  compressionType{rhs.compressionType},
+  isColorEmoji{rhs.isColorEmoji},
+  isColorBitmap{rhs.isColorBitmap},
+  isBufferOwned{rhs.isBufferOwned}
+{
+  // Remove moved data
+  rhs.buffer        = nullptr;
+  rhs.isBufferOwned = false;
+}
+
+GlyphBufferData& GlyphBufferData::operator=(GlyphBufferData&& rhs) noexcept
+{
+  buffer          = rhs.buffer;
+  width           = rhs.width;
+  height          = rhs.height;
+  outlineOffsetX  = rhs.outlineOffsetX;
+  outlineOffsetY  = rhs.outlineOffsetY;
+  format          = rhs.format;
+  compressionType = rhs.compressionType;
+  isColorEmoji    = rhs.isColorEmoji;
+  isColorBitmap   = rhs.isColorBitmap;
+  isBufferOwned   = rhs.isBufferOwned;
+
+  // Remove moved data
+  rhs.buffer        = nullptr;
+  rhs.isBufferOwned = false;
+
+  return *this;
+}
+
+size_t GlyphBufferData::Compress(const uint8_t* const __restrict__ inBuffer, GlyphBufferData& __restrict__ outBufferData)
+{
+  size_t bufferSize                       = 0u;
+  uint8_t*& __restrict__ compressedBuffer = outBufferData.buffer;
+  switch(outBufferData.compressionType)
+  {
+    case TextAbstraction::GlyphBufferData::CompressionType::NO_COMPRESSION:
+    {
+      bufferSize = static_cast<size_t>(outBufferData.width) * static_cast<size_t>(outBufferData.height) * static_cast<size_t>(Pixel::GetBytesPerPixel(outBufferData.format));
+
+      compressedBuffer = (uint8_t*)malloc(bufferSize);
+      if(DALI_UNLIKELY(compressedBuffer == nullptr))
+      {
+        return 0u;
+      }
+      outBufferData.isBufferOwned = true;
+
+      // Copy buffer without compress
+      memcpy(compressedBuffer, inBuffer, bufferSize);
+      break;
+    }
+    case TextAbstraction::GlyphBufferData::CompressionType::BPP_4:
+    {
+      const uint32_t widthByte       = outBufferData.width * Pixel::GetBytesPerPixel(outBufferData.format);
+      const uint32_t componentCount  = (widthByte >> 1);
+      const bool     considerPadding = (widthByte & 1) ? true : false;
+
+      // For BIT_PER_PIXEL_4 type, we can know final compressed buffer size immediatly.
+      bufferSize       = static_cast<size_t>(outBufferData.height) * static_cast<size_t>(componentCount + (considerPadding ? 1 : 0));
+      compressedBuffer = (uint8_t*)malloc(bufferSize);
+      if(DALI_UNLIKELY(compressedBuffer == nullptr))
+      {
+        return 0u;
+      }
+      outBufferData.isBufferOwned = true;
+
+      uint8_t* __restrict__ outBufferPtr      = compressedBuffer;
+      const uint8_t* __restrict__ inBufferPtr = inBuffer;
+
+      // Compress for each line
+      for(uint32_t y = 0; y < outBufferData.height; ++y)
+      {
+        for(uint32_t x = 0; x < componentCount; ++x)
+        {
+          const uint8_t v0 = Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++));
+          const uint8_t v1 = Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++));
+
+          *(outBufferPtr++) = (v0 << 4) | v1;
+        }
+        if(considerPadding)
+        {
+          *(outBufferPtr++) = Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++));
+        }
+      }
+      break;
+    }
+    case TextAbstraction::GlyphBufferData::CompressionType::RLE_4:
+    {
+      const uint32_t widthByte = outBufferData.width * Pixel::GetBytesPerPixel(outBufferData.format);
+
+      // Allocate temperal buffer. Note that RLE4 can be bigger than original buffer.
+      uint8_t* __restrict__ tempBuffer = (uint8_t*)malloc(outBufferData.height * (widthByte + 1));
+      if(DALI_UNLIKELY(tempBuffer == nullptr))
+      {
+        return 0u;
+      }
+
+      uint8_t* __restrict__ outBufferPtr      = tempBuffer;
+      const uint8_t* __restrict__ inBufferPtr = inBuffer;
+
+      bufferSize = 0u;
+
+      // Compress for each line
+      for(uint32_t y = 0; y < outBufferData.height; ++y)
+      {
+        uint32_t encodedByte = 0;
+        while(encodedByte < widthByte)
+        {
+          // Case 1 : Remain only 1 byte
+          if(DALI_UNLIKELY(encodedByte + 1 == widthByte))
+          {
+            const uint8_t prev0 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
+            const uint8_t v0    = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++)) - prev0) & 0x0f; // Intented underflow
+            *(outBufferPtr++)   = v0;
+            ++encodedByte;
+            ++bufferSize;
+          }
+          // Case 2 : Remain only 2 byte
+          else if(DALI_UNLIKELY(encodedByte + 2 == widthByte))
+          {
+            const uint8_t prev0 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
+            const uint8_t v0    = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++)) - prev0) & 0x0f; // Intented underflow
+            const uint8_t prev1 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
+            const uint8_t v1    = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++)) - prev1) & 0x0f; // Intented underflow
+            encodedByte += 2;
+            if(v0 == v1)
+            {
+              *(outBufferPtr++) = 0x80 | v0;
+              ++bufferSize;
+            }
+            else
+            {
+              *(outBufferPtr++) = 0x10 | v0;
+              *(outBufferPtr++) = v1 << 4;
+              bufferSize += 2;
+            }
+          }
+          // Case 3 : Normal case. Remain byte bigger or equal than 3.
+          else
+          {
+            // Compress rule -
+            // Read 2 byte as v0 and v1.
+            // - If v0 == v1, We can compress. mark the first bit as 1. and remain 3 bit mark as the "runLength - 2".
+            //   runLength can be maximum 9.
+            // - If v0 != v1, We cannot compress. mark the first bit as 0. and remain 3 bit mark as the "(nonRunLength - 1) / 2"
+            //   Due to the BitPerPixel is 4, nonRunLength should be odd value.
+            //   nonRunLength cutted if v0 == v1.
+            //   nonRunLength can be maximum 15.
+
+            const uint8_t prev0 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
+            const uint8_t v0    = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++)) - prev0) & 0x0f; // Intented underflow
+            const uint8_t prev1 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
+            const uint8_t v1    = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++)) - prev1) & 0x0f; // Intented underflow
+            encodedByte += 2;
+            // We can compress by RLE
+            if(v0 == v1)
+            {
+              uint8_t runLength = 2;
+              while(encodedByte < widthByte && runLength < 9)
+              {
+                const uint8_t prev2 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
+                const uint8_t v2    = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr)) - prev2) & 0x0f; // Intented underflow
+                if(v2 == v0)
+                {
+                  ++inBufferPtr;
+                  ++encodedByte;
+                  ++runLength;
+                }
+                else
+                {
+                  break;
+                }
+              }
+
+              // Update (runLength - 2) result.
+              *(outBufferPtr++) = ((0x8 | (runLength - 2)) << 4) | v0;
+              ++bufferSize;
+            }
+            // We cannot compress by RLE.
+            else
+            {
+              // Read one more value.
+              const uint8_t prev2 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
+              const uint8_t v2    = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++)) - prev2) & 0x0f; // Intented underflow
+              ++encodedByte;
+
+              uint8_t  nonRunLength          = 3;
+              uint8_t* nonRunLengthHeaderPtr = outBufferPtr;
+              *(outBufferPtr++)              = v0;
+              *(outBufferPtr++)              = (v1 << 4) | v2;
+              bufferSize += 2;
+              while(encodedByte < widthByte && nonRunLength < 15)
+              {
+                if(DALI_LIKELY(encodedByte + 1 < widthByte))
+                {
+                  const uint8_t prew0 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
+                  const uint8_t w0    = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr)) - prew0) & 0x0f; // Intented underflow
+                  const uint8_t prew1 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr + 1 - widthByte));
+                  const uint8_t w1    = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr + 1)) - prew1) & 0x0f; // Intented underflow
+                  if(w0 == w1)
+                  {
+                    // Stop non-compress logic.
+                    break;
+                  }
+                  else
+                  {
+                    ++bufferSize;
+                    *(outBufferPtr++) = (w0 << 4) | w1;
+                    inBufferPtr += 2;
+                    encodedByte += 2;
+                    nonRunLength += 2;
+                  }
+                }
+                else
+                {
+                  // Edge case. There is only one pixel remained.
+                  const uint8_t prew0 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
+                  const uint8_t w0    = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr)) - prew0) & 0x0f; // Intented underflow
+                  {
+                    ++bufferSize;
+                    *(outBufferPtr++) = (w0 << 4);
+                    ++encodedByte;
+                    ++inBufferPtr;
+                    // Increase nonRunLength 2 even latest value is invalid.
+                    nonRunLength += 2;
+                  }
+                }
+              }
+
+              // Update (nonRunLength-1)/2 result into header.
+              *(nonRunLengthHeaderPtr) |= (nonRunLength >> 1) << 4;
+            }
+          }
+        }
+      }
+
+      // Allocate and copy data
+      compressedBuffer = (uint8_t*)malloc(bufferSize);
+      if(DALI_UNLIKELY(compressedBuffer == nullptr))
+      {
+        free(tempBuffer);
+        return 0u;
+      }
+      outBufferData.isBufferOwned = true;
+
+      memcpy(compressedBuffer, tempBuffer, bufferSize);
+      free(tempBuffer);
+
+      break;
+    }
+    default:
+    {
+      break;
+    }
+  }
+
+  return bufferSize;
+}
+
+void GlyphBufferData::Decompress(const GlyphBufferData& __restrict__ inBufferData, uint8_t* __restrict__ outBuffer)
+{
+  if(DALI_UNLIKELY(outBuffer == nullptr))
+  {
+    return;
+  }
+
+  switch(inBufferData.compressionType)
+  {
+    case TextAbstraction::GlyphBufferData::CompressionType::NO_COMPRESSION:
+    {
+      const auto bufferSize = inBufferData.width * inBufferData.height * Pixel::GetBytesPerPixel(inBufferData.format);
+
+      // Copy buffer without compress
+      memcpy(outBuffer, inBufferData.buffer, bufferSize);
+      break;
+    }
+    case TextAbstraction::GlyphBufferData::CompressionType::BPP_4:
+    {
+      const uint32_t widthByte       = inBufferData.width * Pixel::GetBytesPerPixel(inBufferData.format);
+      const uint32_t componentCount  = (widthByte >> 1);
+      const bool     considerPadding = (widthByte & 1) ? true : false;
+
+      uint8_t* __restrict__ outBufferPtr      = outBuffer;
+      const uint8_t* __restrict__ inBufferPtr = inBufferData.buffer;
+
+      // Compress for each line
+      for(uint32_t y = 0; y < inBufferData.height; ++y)
+      {
+        for(uint32_t x = 0; x < componentCount; ++x)
+        {
+          const uint8_t v  = *(inBufferPtr++);
+          const uint8_t v0 = (v >> 4) & 0x0f;
+          const uint8_t v1 = v & 0x0f;
+
+          *(outBufferPtr++) = (v0 << 4) | v0;
+          *(outBufferPtr++) = (v1 << 4) | v1;
+        }
+        if(considerPadding)
+        {
+          const uint8_t v   = *(inBufferPtr++);
+          *(outBufferPtr++) = (v << 4) | v;
+        }
+      }
+      break;
+    }
+    case TextAbstraction::GlyphBufferData::CompressionType::RLE_4:
+    {
+      const uint32_t widthByte = inBufferData.width * Pixel::GetBytesPerPixel(inBufferData.format);
+
+      uint8_t* __restrict__ outBufferPtr      = outBuffer;
+      const uint8_t* __restrict__ inBufferPtr = inBufferData.buffer;
+      // Compress for each line
+      for(uint32_t y = 0; y < inBufferData.height; ++y)
+      {
+        uint32_t x           = 0;
+        uint32_t decodedByte = 0;
+        while(decodedByte < widthByte)
+        {
+          const uint8_t v = *(inBufferPtr++);
+          ++x;
+          // Compress by RLE
+          if(v & 0x80)
+          {
+            const uint8_t runLength = ((v >> 4) & 0x07) + 2u;
+            decodedByte += runLength;
+            const uint8_t repeatValue = v & 0x0f;
+            for(uint8_t iter = 0; iter < runLength; ++iter)
+            {
+              const uint8_t prev0 = DALI_UNLIKELY(y == 0) ? 0 : (*(outBufferPtr - widthByte)) & 0x0f;
+              const uint8_t v0    = (prev0 + repeatValue) & 0x0f;
+              *(outBufferPtr++)   = (v0 << 4) | v0;
+            }
+          }
+          // Not compress by RLE
+          else
+          {
+            const uint8_t nonRunLength = (((v >> 4) & 0x07) << 1u) + 1u;
+            decodedByte += nonRunLength;
+            // First value.
+            const uint8_t prev0 = DALI_UNLIKELY(y == 0) ? 0 : (*(outBufferPtr - widthByte)) & 0x0f;
+            const uint8_t v0    = (prev0 + (v & 0x0f)) & 0x0f;
+            *(outBufferPtr++)   = (v0 << 4) | v0;
+
+            const bool ignoreLastValue = decodedByte > widthByte ? true : false;
+            if(DALI_UNLIKELY(ignoreLastValue))
+            {
+              --decodedByte;
+              for(uint8_t iter = 1; iter + 2 < nonRunLength; iter += 2)
+              {
+                const uint8_t w     = *(inBufferPtr++);
+                const uint8_t prew0 = DALI_UNLIKELY(y == 0) ? 0 : (*(outBufferPtr - widthByte)) & 0x0f;
+                const uint8_t w0    = (prew0 + ((w >> 4) & 0x0f)) & 0x0f;
+                const uint8_t prew1 = DALI_UNLIKELY(y == 0) ? 0 : (*(outBufferPtr - widthByte + 1)) & 0x0f;
+                const uint8_t w1    = (prew1 + (w & 0x0f)) & 0x0f;
+                ++x;
+
+                *(outBufferPtr++) = (w0 << 4) | w0;
+                *(outBufferPtr++) = (w1 << 4) | w1;
+              }
+              // Last value.
+              {
+                const uint8_t w     = ((*(inBufferPtr++)) >> 4) & 0x0f;
+                const uint8_t prew0 = DALI_UNLIKELY(y == 0) ? 0 : (*(outBufferPtr - widthByte)) & 0x0f;
+                const uint8_t w0    = (prew0 + w) & 0x0f;
+                ++x;
+
+                *(outBufferPtr++) = (w0 << 4) | w0;
+              }
+            }
+            else
+            {
+              for(uint8_t iter = 1; iter < nonRunLength; iter += 2)
+              {
+                const uint8_t w     = *(inBufferPtr++);
+                const uint8_t prew0 = DALI_UNLIKELY(y == 0) ? 0 : (*(outBufferPtr - widthByte)) & 0x0f;
+                const uint8_t w0    = (prew0 + ((w >> 4) & 0x0f)) & 0x0f;
+                const uint8_t prew1 = DALI_UNLIKELY(y == 0) ? 0 : (*(outBufferPtr - widthByte + 1)) & 0x0f;
+                const uint8_t w1    = (prew1 + (w & 0x0f)) & 0x0f;
+                ++x;
+
+                *(outBufferPtr++) = (w0 << 4) | w0;
+                *(outBufferPtr++) = (w1 << 4) | w1;
+              }
+            }
+          }
+        }
+      }
+      break;
+    }
+    default:
+    {
+      break;
+    }
+  }
+}
+
+void GlyphBufferData::DecompressScanline(const GlyphBufferData& __restrict__ inBufferData, uint8_t* __restrict__ outBuffer, uint32_t& __restrict__ offset)
+{
+  switch(inBufferData.compressionType)
+  {
+    case TextAbstraction::GlyphBufferData::CompressionType::NO_COMPRESSION:
+    {
+      const auto bufferSize = inBufferData.width * Pixel::GetBytesPerPixel(inBufferData.format);
+
+      // Copy buffer without compress
+      memcpy(outBuffer, inBufferData.buffer + offset, bufferSize);
+
+      // Update offset
+      offset += bufferSize;
+      break;
+    }
+    case TextAbstraction::GlyphBufferData::CompressionType::BPP_4:
+    {
+      const uint32_t widthByte       = inBufferData.width * Pixel::GetBytesPerPixel(inBufferData.format);
+      const uint32_t componentCount  = (widthByte >> 1);
+      const bool     considerPadding = (widthByte & 1) ? true : false;
+
+      uint8_t* __restrict__ outBufferPtr      = outBuffer;
+      const uint8_t* __restrict__ inBufferPtr = inBufferData.buffer + offset;
+
+      // Decompress scanline
+      for(uint32_t x = 0; x < componentCount; ++x)
+      {
+        const uint8_t v  = *(inBufferPtr++);
+        const uint8_t v0 = (v >> 4) & 0x0f;
+        const uint8_t v1 = v & 0x0f;
+
+        *(outBufferPtr++) = (v0 << 4) | v0;
+        *(outBufferPtr++) = (v1 << 4) | v1;
+      }
+      if(considerPadding)
+      {
+        const uint8_t v   = *(inBufferPtr++);
+        *(outBufferPtr++) = (v << 4) | v;
+      }
+
+      // Update offset
+      offset += (widthByte + 1u) >> 1u;
+      break;
+    }
+    case TextAbstraction::GlyphBufferData::CompressionType::RLE_4:
+    {
+      const uint32_t widthByte = inBufferData.width * Pixel::GetBytesPerPixel(inBufferData.format);
+
+      uint8_t* __restrict__ outBufferPtr      = outBuffer;
+      const uint8_t* __restrict__ inBufferPtr = inBufferData.buffer + offset;
+
+      // If offset is zero, fill outBuffer as 0 first.
+      if(DALI_UNLIKELY(offset == 0))
+      {
+        memset(outBufferPtr, 0, widthByte);
+      }
+
+      // Decompress scanline
+      uint32_t decodedByte = 0;
+      while(decodedByte < widthByte)
+      {
+        const uint8_t v = *(inBufferPtr++);
+        ++offset;
+        // Compress by RLE
+        if(v & 0x80)
+        {
+          const uint8_t runLength = ((v >> 4) & 0x07) + 2u;
+          decodedByte += runLength;
+          const uint8_t repeatValue = (v & 0x0f);
+          for(uint8_t iter = 0; iter < runLength; ++iter)
+          {
+            const uint8_t prev0 = (*(outBufferPtr)) & 0x0f;
+            const uint8_t v0    = (prev0 + repeatValue) & 0x0f;
+            *(outBufferPtr++)   = (v0 << 4) | v0;
+          }
+        }
+        // Not compress by RLE
+        else
+        {
+          const uint8_t nonRunLength = (((v >> 4) & 0x07) << 1u) + 1u;
+          decodedByte += nonRunLength;
+          // First value.
+          const uint8_t prev0 = (*(outBufferPtr)) & 0x0f;
+          const uint8_t v0    = (prev0 + (v & 0x0f)) & 0x0f;
+          *(outBufferPtr++)   = (v0 << 4) | v0;
+
+          const bool ignoreLastValue = decodedByte > widthByte ? true : false;
+          if(DALI_UNLIKELY(ignoreLastValue))
+          {
+            --decodedByte;
+            for(uint8_t iter = 1; iter + 2 < nonRunLength; iter += 2)
+            {
+              const uint8_t w     = *(inBufferPtr++);
+              const uint8_t prew0 = (*(outBufferPtr)) & 0x0f;
+              const uint8_t w0    = (prew0 + ((w >> 4) & 0x0f)) & 0x0f;
+              const uint8_t prew1 = (*(outBufferPtr + 1)) & 0x0f;
+              const uint8_t w1    = (prew1 + (w & 0x0f)) & 0x0f;
+              ++offset;
+
+              *(outBufferPtr++) = (w0 << 4) | w0;
+              *(outBufferPtr++) = (w1 << 4) | w1;
+            }
+            // Last value.
+            {
+              const uint8_t w     = ((*(inBufferPtr++)) >> 4) & 0x0f;
+              const uint8_t prew0 = (*(outBufferPtr)) & 0x0f;
+              const uint8_t w0    = (prew0 + w) & 0x0f;
+              ++offset;
+
+              *(outBufferPtr++) = (w0 << 4) | w0;
+            }
+          }
+          else
+          {
+            for(uint8_t iter = 1; iter < nonRunLength; iter += 2)
+            {
+              const uint8_t w     = *(inBufferPtr++);
+              const uint8_t prew0 = (*(outBufferPtr)) & 0x0f;
+              const uint8_t w0    = (prew0 + ((w >> 4) & 0x0f)) & 0x0f;
+              const uint8_t prew1 = (*(outBufferPtr + 1)) & 0x0f;
+              const uint8_t w1    = (prew1 + (w & 0x0f)) & 0x0f;
+              ++offset;
+
+              *(outBufferPtr++) = (w0 << 4) | w0;
+              *(outBufferPtr++) = (w1 << 4) | w1;
+            }
+          }
+        }
+      }
+      break;
+    }
+    default:
+    {
+      break;
+    }
+  }
+}
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/dali/devel-api/text-abstraction/glyph-buffer-data.h b/dali/devel-api/text-abstraction/glyph-buffer-data.h
new file mode 100644 (file)
index 0000000..89afaa8
--- /dev/null
@@ -0,0 +1,130 @@
+#ifndef DALI_TEXT_ABSTRACTION_GLYPH_BUFFER_DATA_H
+#define DALI_TEXT_ABSTRACTION_GLYPH_BUFFER_DATA_H
+
+/*
+ * Copyright (c) 2023 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/images/pixel.h>
+#include <cstddef> /// for size_t
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+namespace TextAbstraction
+{
+/**
+  * @brief Struct used to retrieve the glyph's bitmap.
+  */
+struct DALI_ADAPTOR_API GlyphBufferData
+{
+  /**
+    * @brief Constructor.
+    *
+    * Initializes struct members to their defaults.
+    */
+  GlyphBufferData();
+
+  /**
+    * @brief Destructor.
+    */
+  ~GlyphBufferData();
+
+  /**
+    * @brief Move constructor.
+    *
+    * @param[in] rhs moved data.
+    */
+  GlyphBufferData(GlyphBufferData&& rhs) noexcept;
+
+  /**
+    * @brief Move assign operator.
+    *
+    * @param[in] rhs moved data.
+    * @return A reference to this.
+    */
+  GlyphBufferData& operator=(GlyphBufferData&& rhs) noexcept;
+
+  // Compression method of buffer. Each buffer compressed line by line
+  enum class CompressionType
+  {
+    NO_COMPRESSION = 0, // No compression
+    BPP_4          = 1, // Compress as 4 bit. Color become value * 17 (0x00, 0x11, 0x22, ... 0xee, 0xff).
+                        // Only works for Pixel::L8 format
+    RLE_4 = 2,          // Compress as 4 bit, and Run-Length-Encode. For more high compress rate, we store difference between previous scanline.
+                        // Only works for Pixel::L8 format
+  };
+
+  /**
+    * @brief Helper static function to compress raw buffer from inBuffer to outBufferData.buffer.
+    * outBufferData will have it's own buffer.
+    *
+    * @pre outBufferData must not have it's own buffer.
+    * @param[in] inBuffer The input raw data.
+    * @param[in, out] outBufferData The output glyph buffer data.
+    * @return Size of compressed out buffer, Or 0 if compress failed.
+    */
+  static size_t Compress(const uint8_t* const inBuffer, GlyphBufferData& outBufferData);
+
+  /**
+    * @brief Helper static function to decompress raw buffer from inBuffer to outBufferPtr.
+    * If outBuffer is nullptr, Do nothing.
+    *
+    * @pre outBuffer memory should be allocated.
+    * @param[in] inBufferData The input glyph buffer data.
+    * @param[in, out] outBuffer The output pointer of raw buffer data.
+    */
+  static void Decompress(const GlyphBufferData& inBufferData, uint8_t* outBuffer);
+
+  /**
+    * @brief Special Helper static function to decompress raw buffer from inBuffer to outBuffer one scanline.
+    * After decompress one scanline successed, offset will be changed.
+    *
+    * @pre outBuffer memory should be allocated.
+    * @pre if inBufferData's compression type is RLE4, outBuffer memory should store the previous scanline data.
+    * @param[in] inBufferData The input glyph buffer data.
+    * @param[in, out] outBuffer The output pointer of raw buffer data.
+    * @param[in, out] offset The offset of input. It will be changed as next scanline's offset.
+    */
+  static void DecompressScanline(const GlyphBufferData& inBufferData, uint8_t* outBuffer, uint32_t& offset);
+
+private:
+  // Delete copy operation.
+  GlyphBufferData(const GlyphBufferData& rhs) = delete;
+  GlyphBufferData& operator=(const GlyphBufferData& rhs) = delete;
+
+public:
+  uint8_t*        buffer;            ///< The glyph's bitmap buffer data.
+  uint32_t        width;             ///< The width of the bitmap.
+  uint32_t        height;            ///< The height of the bitmap.
+  int             outlineOffsetX;    ///< The additional horizontal offset to be added for the glyph's position for outline.
+  int             outlineOffsetY;    ///< The additional vertical offset to be added for the glyph's position for outline.
+  Pixel::Format   format;            ///< The pixel's format of the bitmap.
+  CompressionType compressionType;   ///< The type of buffer compression.
+  bool            isColorEmoji : 1;  ///< Whether the glyph is an emoji.
+  bool            isColorBitmap : 1; ///< Whether the glyph is a color bitmap.
+  bool            isBufferOwned : 1; ///< Whether the glyph's bitmap buffer data owned by this class or not. Becareful when you use non-owned buffer data.
+};
+
+} // namespace TextAbstraction
+
+} // namespace Dali
+
+#endif //DALI_TEXT_ABSTRACTION_GLYPH_INFO_H
index 094d2c5..4b5d815 100644 (file)
@@ -281,6 +281,7 @@ enum class CoalescableMessages
 {
   BOUNDS_CHANGED, ///< Bounds changed
   SET_OFFSET, ///< Set offset
+  POST_RENDER, ///< Post render
 };
 
 // Custom specialization of std::hash
index bacbd6e..ee57751 100644 (file)
@@ -238,6 +238,13 @@ void BridgeObject::EmitBoundsChanged(Accessible* obj, Dali::Rect<> rect)
   });
 }
 
+void BridgeObject::EmitPostRender(Accessible *obj)
+{
+  AddCoalescableMessage(CoalescableMessages::POST_RENDER, obj, 0.5f, [=]() {
+    Emit(obj, WindowEvent::POST_RENDER);
+  });
+}
+
 void BridgeObject::EmitCursorMoved(Accessible* obj, unsigned int cursorPosition)
 {
   if(!IsUp() || obj->IsHidden() || obj->GetSuppressedEvents()[AtspiEvent::TEXT_CARET_MOVED])
@@ -343,4 +350,4 @@ void BridgeObject::EmitScrollFinished(Accessible* obj)
     Accessible::GetInterfaceName(AtspiInterface::EVENT_OBJECT),
     "ScrollFinished",
     {"", "root"});
-}
\ No newline at end of file
+}
index 1b6637d..8ca6924 100644 (file)
@@ -81,6 +81,11 @@ protected:
   void EmitBoundsChanged(Dali::Accessibility::Accessible* obj, Dali::Rect<> rect) override;
 
   /**
+   * @copydoc Dali::Accessibility::Bridge::EmitPostRender()
+   */
+  void EmitPostRender(Dali::Accessibility::Accessible* obj) override;
+
+  /**
    * @copydoc Dali::Accessibility::Bridge::EmitMovedOutOfScreen()
    */
   void EmitMovedOutOfScreen(Dali::Accessibility::Accessible* obj, Dali::Accessibility::ScreenRelativeMoveType type) override;
index 0bbaccd..447ba4d 100644 (file)
@@ -166,6 +166,10 @@ struct DummyBridge : Dali::Accessibility::Bridge
   {
   }
 
+  void EmitPostRender(Accessibility::Accessible *obj) override
+  {
+  }
+
   Accessibility::Consumed Emit(Accessibility::KeyEventType type, unsigned int keyCode, const std::string& keyName, unsigned int timeStamp, bool isText) override
   {
     return Accessibility::Consumed::YES;
index 42b9309..8522cf9 100644 (file)
@@ -67,6 +67,7 @@
 #include <dali/internal/window-system/common/event-handler.h>
 #include <dali/internal/window-system/common/window-impl.h>
 #include <dali/internal/window-system/common/window-render-surface.h>
+#include <dali/internal/window-system/common/window-system.h>
 
 #include <dali/devel-api/adaptor-framework/accessibility-bridge.h>
 #include <dali/internal/system/common/logging.h>
@@ -404,10 +405,7 @@ void Adaptor::Start()
   dpiHor = dpiVer = 0;
 
   defaultWindow->GetSurface()->GetDpi(dpiHor, dpiVer);
-
-  // set the DPI value for font rendering
-  FontClient fontClient = FontClient::Get();
-  fontClient.SetDpi(dpiHor, dpiVer);
+  Dali::Internal::Adaptor::WindowSystem::SetDpi(dpiHor, dpiVer);
 
   // Initialize the thread controller
   mThreadController->Initialize();
index b093c7f..fa90dba 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 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.
 // CLASS HEADER
 #include <dali/internal/graphics/gles-impl/egl-graphics-controller.h>
 
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+
 // INTERNAL INCLUDES
 #include <dali/integration-api/adaptor-framework/render-surface-interface.h>
 #include <dali/integration-api/debug.h>
 #include <dali/integration-api/gl-abstraction.h>
 #include <dali/integration-api/gl-defines.h>
 #include <dali/integration-api/graphics-sync-abstraction.h>
+#include <dali/integration-api/pixel-data-integ.h>
 #include <dali/internal/graphics/gles-impl/egl-sync-object.h>
 #include <dali/internal/graphics/gles-impl/gles-graphics-command-buffer.h>
 #include <dali/internal/graphics/gles-impl/gles-graphics-pipeline.h>
@@ -35,7 +39,6 @@
 #include <dali/internal/graphics/gles-impl/gles-sync-object.h>
 #include <dali/internal/graphics/gles-impl/gles3-graphics-memory.h>
 #include <dali/internal/graphics/gles/egl-sync-implementation.h>
-#include <dali/public-api/common/dali-common.h>
 
 #include <dali/internal/graphics/gles/egl-graphics.h>
 
@@ -338,8 +341,7 @@ void EglGraphicsController::CreateSurfaceContext(Dali::RenderSurfaceInterface* s
 void EglGraphicsController::DeleteSurfaceContext(Dali::RenderSurfaceInterface* surface)
 {
   mSurfaceContexts.erase(std::remove_if(
-                           mSurfaceContexts.begin(), mSurfaceContexts.end(), [surface](SurfaceContextPair& iter)
-                           { return surface == iter.first; }),
+                           mSurfaceContexts.begin(), mSurfaceContexts.end(), [surface](SurfaceContextPair& iter) { return surface == iter.first; }),
                          mSurfaceContexts.end());
 }
 
@@ -361,8 +363,7 @@ void EglGraphicsController::ActivateSurfaceContext(Dali::RenderSurfaceInterface*
 {
   if(surface && mGraphics->IsResourceContextSupported())
   {
-    auto iter = std::find_if(mSurfaceContexts.begin(), mSurfaceContexts.end(), [surface](SurfaceContextPair& iter)
-                             { return (iter.first == surface); });
+    auto iter = std::find_if(mSurfaceContexts.begin(), mSurfaceContexts.end(), [surface](SurfaceContextPair& iter) { return (iter.first == surface); });
 
     if(iter != mSurfaceContexts.end())
     {
@@ -677,115 +678,137 @@ void EglGraphicsController::ProcessTextureUpdateQueue()
     auto& info   = request.first;
     auto& source = request.second;
 
-    if(source.sourceType == Graphics::TextureUpdateSourceInfo::Type::MEMORY)
+    switch(source.sourceType)
     {
-      // GPU memory must be already allocated.
-
-      // Check if it needs conversion
-      auto*       texture            = static_cast<GLES::Texture*>(info.dstTexture);
-      const auto& createInfo         = texture->GetCreateInfo();
-      auto        srcFormat          = GLES::GLTextureFormatType(info.srcFormat).format;
-      auto        srcType            = GLES::GLTextureFormatType(info.srcFormat).type;
-      auto        destInternalFormat = GLES::GLTextureFormatType(createInfo.format).internalFormat;
-      auto        destFormat         = GLES::GLTextureFormatType(createInfo.format).format;
+      case Graphics::TextureUpdateSourceInfo::Type::MEMORY:
+      case Graphics::TextureUpdateSourceInfo::Type::PIXEL_DATA:
+      {
+        // GPU memory must be already allocated.
 
-      // From render-texture.cpp
-      const bool isSubImage(info.dstOffset2D.x != 0 || info.dstOffset2D.y != 0 ||
-                            info.srcExtent2D.width != (createInfo.size.width / (1 << info.level)) ||
-                            info.srcExtent2D.height != (createInfo.size.height / (1 << info.level)));
+        // Check if it needs conversion
+        auto*       texture            = static_cast<GLES::Texture*>(info.dstTexture);
+        const auto& createInfo         = texture->GetCreateInfo();
+        auto        srcFormat          = GLES::GLTextureFormatType(info.srcFormat).format;
+        auto        srcType            = GLES::GLTextureFormatType(info.srcFormat).type;
+        auto        destInternalFormat = GLES::GLTextureFormatType(createInfo.format).internalFormat;
+        auto        destFormat         = GLES::GLTextureFormatType(createInfo.format).format;
 
-      auto*                sourceBuffer = reinterpret_cast<uint8_t*>(source.memorySource.memory);
-      auto                 sourceStride = info.srcStride;
-      std::vector<uint8_t> tempBuffer;
+        // From render-texture.cpp
+        const bool isSubImage(info.dstOffset2D.x != 0 || info.dstOffset2D.y != 0 ||
+                              info.srcExtent2D.width != (createInfo.size.width / (1 << info.level)) ||
+                              info.srcExtent2D.height != (createInfo.size.height / (1 << info.level)));
 
-      if(mGlAbstraction->TextureRequiresConverting(srcFormat, destFormat, isSubImage))
-      {
-        // Convert RGB to RGBA if necessary.
-        if(texture->TryConvertPixelData(source.memorySource.memory, info.srcFormat, createInfo.format, info.srcSize, info.srcStride, info.srcExtent2D.width, info.srcExtent2D.height, tempBuffer))
+        uint8_t* sourceBuffer;
+        if(source.sourceType == Graphics::TextureUpdateSourceInfo::Type::MEMORY)
         {
-          sourceBuffer = &tempBuffer[0];
-          sourceStride = 0u; // Converted buffer compacted. make stride as 0.
-          srcFormat    = destFormat;
-          srcType      = GLES::GLTextureFormatType(createInfo.format).type;
+          sourceBuffer = reinterpret_cast<uint8_t*>(source.memorySource.memory);
         }
-      }
+        else
+        {
+          // Get buffer of PixelData
+          Dali::Integration::PixelDataBuffer pixelBufferData = Dali::Integration::GetPixelDataBuffer(source.pixelDataSource.pixelData);
 
-      // Calculate the maximum mipmap level for the texture
-      texture->SetMaxMipMapLevel(std::max(texture->GetMaxMipMapLevel(), info.level));
+          sourceBuffer = pixelBufferData.buffer + info.srcOffset;
+        }
 
-      GLenum bindTarget{GL_TEXTURE_2D};
-      GLenum target{GL_TEXTURE_2D};
+        auto                 sourceStride = info.srcStride;
+        std::vector<uint8_t> tempBuffer;
 
-      if(createInfo.textureType == Graphics::TextureType::TEXTURE_CUBEMAP)
-      {
-        bindTarget = GL_TEXTURE_CUBE_MAP;
-        target     = GL_TEXTURE_CUBE_MAP_POSITIVE_X + info.layer;
-      }
+        if(mGlAbstraction->TextureRequiresConverting(srcFormat, destFormat, isSubImage))
+        {
+          // Convert RGB to RGBA if necessary.
+          if(texture->TryConvertPixelData(sourceBuffer, info.srcFormat, createInfo.format, info.srcSize, info.srcStride, info.srcExtent2D.width, info.srcExtent2D.height, tempBuffer))
+          {
+            sourceBuffer = &tempBuffer[0];
+            sourceStride = 0u; // Converted buffer compacted. make stride as 0.
+            srcFormat    = destFormat;
+            srcType      = GLES::GLTextureFormatType(createInfo.format).type;
+          }
+        }
 
-      mGlAbstraction->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
-      mGlAbstraction->PixelStorei(GL_UNPACK_ROW_LENGTH, sourceStride);
+        // Calculate the maximum mipmap level for the texture
+        texture->SetMaxMipMapLevel(std::max(texture->GetMaxMipMapLevel(), info.level));
 
-      mCurrentContext->BindTexture(bindTarget, texture->GetTextureTypeId(), texture->GetGLTexture());
+        GLenum bindTarget{GL_TEXTURE_2D};
+        GLenum target{GL_TEXTURE_2D};
 
-      if(!isSubImage)
-      {
-        if(!texture->IsCompressed())
+        if(createInfo.textureType == Graphics::TextureType::TEXTURE_CUBEMAP)
         {
-          mGlAbstraction->TexImage2D(target,
-                                     info.level,
-                                     destInternalFormat,
-                                     info.srcExtent2D.width,
-                                     info.srcExtent2D.height,
-                                     0,
-                                     srcFormat,
-                                     srcType,
-                                     sourceBuffer);
+          bindTarget = GL_TEXTURE_CUBE_MAP;
+          target     = GL_TEXTURE_CUBE_MAP_POSITIVE_X + info.layer;
         }
-        else
+
+        mGlAbstraction->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
+        mGlAbstraction->PixelStorei(GL_UNPACK_ROW_LENGTH, sourceStride);
+
+        mCurrentContext->BindTexture(bindTarget, texture->GetTextureTypeId(), texture->GetGLTexture());
+
+        if(!isSubImage)
         {
-          mGlAbstraction->CompressedTexImage2D(target,
-                                               info.level,
-                                               destInternalFormat,
-                                               info.srcExtent2D.width,
-                                               info.srcExtent2D.height,
-                                               0,
-                                               info.srcSize,
-                                               sourceBuffer);
+          if(!texture->IsCompressed())
+          {
+            mGlAbstraction->TexImage2D(target,
+                                       info.level,
+                                       destInternalFormat,
+                                       info.srcExtent2D.width,
+                                       info.srcExtent2D.height,
+                                       0,
+                                       srcFormat,
+                                       srcType,
+                                       sourceBuffer);
+          }
+          else
+          {
+            mGlAbstraction->CompressedTexImage2D(target,
+                                                 info.level,
+                                                 destInternalFormat,
+                                                 info.srcExtent2D.width,
+                                                 info.srcExtent2D.height,
+                                                 0,
+                                                 info.srcSize,
+                                                 sourceBuffer);
+          }
         }
-      }
-      else
-      {
-        if(!texture->IsCompressed())
+        else
         {
-          mGlAbstraction->TexSubImage2D(target,
-                                        info.level,
-                                        info.dstOffset2D.x,
-                                        info.dstOffset2D.y,
-                                        info.srcExtent2D.width,
-                                        info.srcExtent2D.height,
-                                        srcFormat,
-                                        srcType,
-                                        sourceBuffer);
+          if(!texture->IsCompressed())
+          {
+            mGlAbstraction->TexSubImage2D(target,
+                                          info.level,
+                                          info.dstOffset2D.x,
+                                          info.dstOffset2D.y,
+                                          info.srcExtent2D.width,
+                                          info.srcExtent2D.height,
+                                          srcFormat,
+                                          srcType,
+                                          sourceBuffer);
+          }
+          else
+          {
+            mGlAbstraction->CompressedTexSubImage2D(target,
+                                                    info.level,
+                                                    info.dstOffset2D.x,
+                                                    info.dstOffset2D.y,
+                                                    info.srcExtent2D.width,
+                                                    info.srcExtent2D.height,
+                                                    srcFormat,
+                                                    info.srcSize,
+                                                    sourceBuffer);
+          }
         }
-        else
+
+        if(source.sourceType == Graphics::TextureUpdateSourceInfo::Type::MEMORY)
         {
-          mGlAbstraction->CompressedTexSubImage2D(target,
-                                                  info.level,
-                                                  info.dstOffset2D.x,
-                                                  info.dstOffset2D.y,
-                                                  info.srcExtent2D.width,
-                                                  info.srcExtent2D.height,
-                                                  srcFormat,
-                                                  info.srcSize,
-                                                  sourceBuffer);
+          // free staging memory
+          free(source.memorySource.memory);
         }
+        break;
+      }
+      default:
+      {
+        // TODO: other sources
+        break;
       }
-      // free staging memory
-      free(source.memorySource.memory);
-    }
-    else
-    {
-      // TODO: other sources
     }
 
     mTextureUpdateRequests.pop();
@@ -823,6 +846,12 @@ void EglGraphicsController::UpdateTextures(const std::vector<TextureUpdateInfo>&
         source.memorySource.memory = stagingBuffer;
         break;
       }
+      case Graphics::TextureUpdateSourceInfo::Type::PIXEL_DATA:
+      {
+        // Increase CPU memory usage since ownership of PixelData is now on mTextureUpdateRequests.
+        mTextureUploadTotalCPUMemoryUsed += info.srcSize;
+        break;
+      }
       case Graphics::TextureUpdateSourceInfo::Type::BUFFER:
       {
         // TODO, with PBO support
index 3e9000d..01adfbd 100644 (file)
@@ -83,23 +83,32 @@ Dali::StyleMonitor StyleMonitor::Get()
 StyleMonitor::StyleMonitor()
 : mDefaultFontSize(-1)
 {
-  mFontClient = TextAbstraction::FontClient::Get();
-  GetSystemDefaultFontFamily(mFontClient, mDefaultFontFamily);
-  DALI_LOG_INFO(gLogFilter, Debug::Verbose, "StyleMonitor::StyleMonitor::DefaultFontFamily(%s)\n", mDefaultFontFamily.c_str());
-  mDefaultFontSize = mFontClient.GetDefaultFontSize();
 }
 
 StyleMonitor::~StyleMonitor()
 {
 }
 
+bool StyleMonitor::EnsureFontClientCreated()
+{
+  if(!mFontClient)
+  {
+    mFontClient = TextAbstraction::FontClient::Get();
+    GetSystemDefaultFontFamily(mFontClient, mDefaultFontFamily);
+    DALI_LOG_INFO(gLogFilter, Debug::Verbose, "StyleMonitor::StyleMonitor::DefaultFontFamily(%s)\n", mDefaultFontFamily.c_str());
+    mDefaultFontSize = mFontClient.GetDefaultFontSize();
+  }
+
+  return mFontClient != nullptr ? true : false;
+}
+
 void StyleMonitor::StyleChanged(StyleChange::Type styleChange)
 {
   switch(styleChange)
   {
     case StyleChange::DEFAULT_FONT_CHANGE:
     {
-      if(mFontClient)
+      if(EnsureFontClientCreated())
       {
         mFontClient.ResetSystemDefaults();
         GetSystemDefaultFontFamily(mFontClient, mDefaultFontFamily);
@@ -110,7 +119,10 @@ void StyleMonitor::StyleChanged(StyleChange::Type styleChange)
 
     case StyleChange::DEFAULT_FONT_SIZE_CHANGE:
     {
-      mDefaultFontSize = mFontClient.GetDefaultFontSize();
+      if(EnsureFontClientCreated())
+      {
+        mDefaultFontSize = mFontClient.GetDefaultFontSize();
+      }
       break;
     }
 
index 14f8fb5..a8bc511 100644 (file)
@@ -63,6 +63,11 @@ public:
   // Style Information
 
   /**
+   * @copydoc Dali::StyleMonitor::EnsureFontClientCreated()
+   */
+  bool EnsureFontClientCreated();
+
+  /**
    * @copydoc Dali::StyleMonitor::GetDefaultFontFamily() const
    */
   std::string GetDefaultFontFamily() const;
index d58c3f1..4d7af0d 100644 (file)
@@ -92,7 +92,7 @@ struct GlyphBuffer
     DELETE
   };
 
-  GlyphBuffer(Dali::TextAbstraction::FontClient::GlyphBufferData& data, DestructorType type)
+  GlyphBuffer(Dali::TextAbstraction::GlyphBufferData& data, DestructorType type)
   : data(data),
     type(type)
   {
@@ -114,8 +114,8 @@ struct GlyphBuffer
     }
   }
 
-  Dali::TextAbstraction::FontClient::GlyphBufferData& data;
-  DestructorType                                      type;
+  Dali::TextAbstraction::GlyphBufferData& data;
+  DestructorType                          type;
 };
 
 /**
@@ -364,7 +364,7 @@ bool ConvertSizeForCairo(
 void CopyImageToSurface(
   const TextAbstraction::TextRenderer::Parameters& parameters,
   const Pixel::Format                              pixelFormat,
-  TextAbstraction::FontClient::GlyphBufferData&    data,
+  TextAbstraction::GlyphBufferData&                data,
   unsigned char*                                   buffer,
   const int                                        rgbaCase,
   const double                                     glyphX,
@@ -853,7 +853,7 @@ Devel::PixelBuffer RenderTextCairo(const TextAbstraction::TextRenderer::Paramete
           const cairo_glyph_t& glyph = *(cairoGlyphsBuffer + index);
 
           // Retrieve the image
-          TextAbstraction::FontClient::GlyphBufferData data;
+          TextAbstraction::GlyphBufferData data;
           if(isEmoji)
           {
             data.width  = parameters.glyphs[run.glyphIndex].width;
@@ -893,12 +893,12 @@ Devel::PixelBuffer RenderTextCairo(const TextAbstraction::TextRenderer::Paramete
             const unsigned int pixelSize = Pixel::GetBytesPerPixel(data.format);
 
             // If we need to decompress, create new memory and replace ownership.
-            if(data.compressionType != TextAbstraction::FontClient::GlyphBufferData::CompressionType::NO_COMPRESSION)
+            if(data.compressionType != TextAbstraction::GlyphBufferData::CompressionType::NO_COMPRESSION)
             {
               uint8_t* newBuffer = (uint8_t*)malloc(widthOut * heightOut * pixelSize);
               if(DALI_LIKELY(newBuffer != nullptr))
               {
-                TextAbstraction::FontClient::GlyphBufferData::Decompress(data, newBuffer);
+                TextAbstraction::GlyphBufferData::Decompress(data, newBuffer);
                 if(data.isBufferOwned)
                 {
                   // Release previous buffer
@@ -906,7 +906,7 @@ Devel::PixelBuffer RenderTextCairo(const TextAbstraction::TextRenderer::Paramete
                 }
                 data.isBufferOwned   = true;
                 data.buffer          = newBuffer;
-                data.compressionType = TextAbstraction::FontClient::GlyphBufferData::CompressionType::NO_COMPRESSION;
+                data.compressionType = TextAbstraction::GlyphBufferData::CompressionType::NO_COMPRESSION;
               }
             }
 
@@ -926,7 +926,7 @@ Devel::PixelBuffer RenderTextCairo(const TextAbstraction::TextRenderer::Paramete
                 free(data.buffer);
               }
               data.isBufferOwned   = true;
-              data.compressionType = Dali::TextAbstraction::FontClient::GlyphBufferData::CompressionType::NO_COMPRESSION;
+              data.compressionType = Dali::TextAbstraction::GlyphBufferData::CompressionType::NO_COMPRESSION;
               data.buffer          = pixelsOut;
               data.width           = widthOut;
               data.height          = heightOut;
index f6e5c9c..4b4c239 100644 (file)
@@ -26,6 +26,7 @@
 // INTERNAL INCLUDES
 #include <dali/devel-api/common/singleton-service.h>
 #include <dali/internal/text/text-abstraction/plugin/font-client-plugin-impl.h>
+#include <dali/internal/window-system/common/window-system.h>
 
 #include <dali/devel-api/text-abstraction/glyph-info.h>
 
@@ -76,6 +77,15 @@ Dali::TextAbstraction::FontClient FontClient::Get()
         fontClientHandle = Dali::TextAbstraction::FontClient(new FontClient);
       }
 
+      uint32_t horizontalDpi, verticalDpi;
+      fontClientHandle.GetDpi(horizontalDpi, verticalDpi);
+      if(horizontalDpi == 0u || verticalDpi == 0u)
+      {
+        horizontalDpi = verticalDpi = 0u;
+        Dali::Internal::Adaptor::WindowSystem::GetDpi(horizontalDpi, verticalDpi);
+        fontClientHandle.SetDpi(horizontalDpi, verticalDpi);
+      }
+
       service.Register(typeid(fontClientHandle), fontClientHandle);
     }
   }
@@ -298,7 +308,7 @@ bool FontClient::GetGlyphMetrics(GlyphInfo* array, uint32_t size, GlyphType type
   return mPlugin->GetGlyphMetrics(array, size, type, horizontal);
 }
 
-void FontClient::CreateBitmap(FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth)
+void FontClient::CreateBitmap(FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::GlyphBufferData& data, int outlineWidth)
 {
   CreatePlugin();
 
index d93a053..288b8aa 100644 (file)
@@ -197,9 +197,9 @@ public: // API for Dali::TextAbstraction::FontClient used.
   bool GetGlyphMetrics(GlyphInfo* array, uint32_t size, GlyphType type, bool horizontal);
 
   /**
-   * @copydoc Dali::TextAbstraction::FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth )
+   * @copydoc Dali::TextAbstraction::FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::GlyphBufferData& data, int outlineWidth )
    */
-  void CreateBitmap(FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth);
+  void CreateBitmap(FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::GlyphBufferData& data, int outlineWidth);
 
   /**
    * @copydoc Dali::TextAbstraction::FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, int outlineWidth )
index 248bf82..addd860 100644 (file)
@@ -98,7 +98,7 @@ bool BitmapFontCacheItem::GetGlyphMetrics(GlyphInfo& glyphInfo, unsigned int dpi
 }
 
 void BitmapFontCacheItem::CreateBitmap(
-  GlyphIndex glyphIndex, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth, bool isItalicRequired, bool isBoldRequired) const
+  GlyphIndex glyphIndex, Dali::TextAbstraction::GlyphBufferData& data, int outlineWidth, bool isItalicRequired, bool isBoldRequired) const
 {
   unsigned int index = 0u;
   for(auto& item : font.glyphs)
index c763c84..889b5b8 100644 (file)
@@ -59,7 +59,7 @@ struct BitmapFontCacheItem : public FontCacheItemInterface
   /**
    * @copydoc FontCacheItemInterface::CreateBitmap()
    */
-  void CreateBitmap(GlyphIndex glyphIndex, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth, bool isItalicRequired, bool isBoldRequired) const override;
+  void CreateBitmap(GlyphIndex glyphIndex, Dali::TextAbstraction::GlyphBufferData& data, int outlineWidth, bool isItalicRequired, bool isBoldRequired) const override;
 
   /**
    * @copydoc FontCacheItemInterface::IsColorGlyph()
index c2486c1..a0c8335 100644 (file)
@@ -30,8 +30,8 @@ void EmbeddedItem::GetGlyphMetrics(GlyphInfo& glyph)
   glyph.scaleFactor = 1.f;
 }
 
-void EmbeddedItem::CreateBitmap(const std::vector<PixelBufferCacheItem>&            pixelBufferCache,
-                                Dali::TextAbstraction::FontClient::GlyphBufferData& data)
+void EmbeddedItem::CreateBitmap(const std::vector<PixelBufferCacheItem>& pixelBufferCache,
+                                Dali::TextAbstraction::GlyphBufferData&  data)
 {
   data.width  = width;
   data.height = height;
@@ -46,7 +46,7 @@ void EmbeddedItem::CreateBitmap(const std::vector<PixelBufferCacheItem>&
   else
   {
     data.isBufferOwned   = true;
-    data.compressionType = Dali::TextAbstraction::FontClient::GlyphBufferData::CompressionType::NO_COMPRESSION;
+    data.compressionType = Dali::TextAbstraction::GlyphBufferData::CompressionType::NO_COMPRESSION;
 
     // Creates the output buffer
     const uint32_t bufferSize = data.width * data.height * 4u;
index 4f58b8b..863a75e 100644 (file)
@@ -48,8 +48,8 @@ struct EmbeddedItem
    * @param[in]  pixelBufferCache The pixel buffer cache
    * @param[out] data The bitmap data.
    */
-  void CreateBitmap(const std::vector<PixelBufferCacheItem>&            pixelBufferCache,
-                    Dali::TextAbstraction::FontClient::GlyphBufferData& data);
+  void CreateBitmap(const std::vector<PixelBufferCacheItem>& pixelBufferCache,
+                    Dali::TextAbstraction::GlyphBufferData&  data);
 
   PixelBufferId pixelBufferId{0u}; ///< Index to the vector of pixel buffers
   uint32_t      width{0u};         ///< The desired width.
index c5cce86..01a5d1c 100644 (file)
@@ -54,7 +54,7 @@ struct FontCacheItemInterface
    * @param[in] isItalicRequired
    * @param[in] isBoldRequired
    */
-  virtual void CreateBitmap(GlyphIndex glyphIndex, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth, bool isItalicRequired, bool isBoldRequired) const = 0;
+  virtual void CreateBitmap(GlyphIndex glyphIndex, Dali::TextAbstraction::GlyphBufferData& data, int outlineWidth, bool isItalicRequired, bool isBoldRequired) const = 0;
 
   /**
    * Return true if the glyph is colored
index e319b46..8814847 100644 (file)
@@ -778,7 +778,7 @@ bool FontClient::Plugin::GetVectorMetrics(GlyphInfo* array,
 #endif
 }
 
-void FontClient::Plugin::CreateBitmap(FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth) const
+void FontClient::Plugin::CreateBitmap(FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::GlyphBufferData& data, int outlineWidth) const
 {
   data.isColorBitmap                          = false;
   data.isColorEmoji                           = false;
@@ -796,15 +796,15 @@ void FontClient::Plugin::CreateBitmap(FontId fontId, GlyphIndex glyphIndex, bool
 
 PixelData FontClient::Plugin::CreateBitmap(FontId fontId, GlyphIndex glyphIndex, int outlineWidth) const
 {
-  TextAbstraction::FontClient::GlyphBufferData data;
+  TextAbstraction::GlyphBufferData data;
 
   CreateBitmap(fontId, glyphIndex, false, false, data, outlineWidth);
 
   // If data is compressed or not owned buffer, copy this.
-  if(!data.isBufferOwned || data.compressionType != TextAbstraction::FontClient::GlyphBufferData::CompressionType::NO_COMPRESSION)
+  if(!data.isBufferOwned || data.compressionType != TextAbstraction::GlyphBufferData::CompressionType::NO_COMPRESSION)
   {
     uint8_t* newBuffer = (uint8_t*)malloc(data.width * data.height * Pixel::GetBytesPerPixel(data.format));
-    TextAbstraction::FontClient::GlyphBufferData::Decompress(data, newBuffer);
+    TextAbstraction::GlyphBufferData::Decompress(data, newBuffer);
     if(data.isBufferOwned)
     {
       free(data.buffer);
@@ -812,7 +812,7 @@ PixelData FontClient::Plugin::CreateBitmap(FontId fontId, GlyphIndex glyphIndex,
 
     data.buffer          = newBuffer;
     data.isBufferOwned   = true;
-    data.compressionType = TextAbstraction::FontClient::GlyphBufferData::CompressionType::NO_COMPRESSION;
+    data.compressionType = TextAbstraction::GlyphBufferData::CompressionType::NO_COMPRESSION;
   }
 
   return PixelData::New(data.buffer,
index 8961200..2eeb281 100644 (file)
@@ -228,9 +228,9 @@ public: // Dali::TextAbstraction::FontClient
   bool GetVectorMetrics(GlyphInfo* array, uint32_t size, bool horizontal) const;
 
   /**
-   * @copydoc Dali::TextAbstraction::FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth )
+   * @copydoc Dali::TextAbstraction::FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::GlyphBufferData& data, int outlineWidth )
    */
-  void CreateBitmap(FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth) const;
+  void CreateBitmap(FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::GlyphBufferData& data, int outlineWidth) const;
 
   /**
    * @copydoc Dali::TextAbstraction::FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, int outlineWidth )
index 2ca3b1c..5bfedb1 100644 (file)
@@ -161,7 +161,7 @@ const FontSlant::Type DefaultFontSlant()
  * @param[in] srcHeight The height of the bitmap.
  * @param[in] srcBuffer The buffer of the bitmap.
  */
-void ConvertBitmap(TextAbstraction::FontClient::GlyphBufferData& data, unsigned int srcWidth, unsigned int srcHeight, const unsigned char* const srcBuffer, const Pixel::Format srcFormat)
+void ConvertBitmap(TextAbstraction::GlyphBufferData& data, unsigned int srcWidth, unsigned int srcHeight, const unsigned char* const srcBuffer, const Pixel::Format srcFormat)
 {
   // Set the input dimensions.
   const ImageDimensions inputDimensions(srcWidth, srcHeight);
@@ -176,7 +176,7 @@ void ConvertBitmap(TextAbstraction::FontClient::GlyphBufferData& data, unsigned
   data.format = srcFormat;
 
   // Note we don't compress here
-  data.compressionType = TextAbstraction::FontClient::GlyphBufferData::CompressionType::NO_COMPRESSION;
+  data.compressionType = TextAbstraction::GlyphBufferData::CompressionType::NO_COMPRESSION;
 
   const uint32_t bytePerPixel = Dali::Pixel::GetBytesPerPixel(srcFormat);
 
@@ -211,7 +211,7 @@ void ConvertBitmap(TextAbstraction::FontClient::GlyphBufferData& data, unsigned
  * @param[in] moveBuffer Whether the bitmap buffer move. True if just copy buffer pointer. False if we use memcpy. (Default is false.)
  * @note If you set moveBuffer=true, the bitmap's buffer moved frome srcBitmap to data. So srcBitmap buffer changed as nullptr.
  */
-void ConvertBitmap(TextAbstraction::FontClient::GlyphBufferData& data, FT_Bitmap& srcBitmap, bool isShearRequired, bool moveBuffer)
+void ConvertBitmap(TextAbstraction::GlyphBufferData& data, FT_Bitmap& srcBitmap, bool isShearRequired, bool moveBuffer)
 {
   data.buffer = nullptr;
   if(srcBitmap.width * srcBitmap.rows > 0)
@@ -305,7 +305,7 @@ void ConvertBitmap(TextAbstraction::FontClient::GlyphBufferData& data, FT_Bitmap
           data.format = Pixel::L8; // Sets the pixel format.
 
           // Note we don't compress here
-          data.compressionType = TextAbstraction::FontClient::GlyphBufferData::CompressionType::NO_COMPRESSION;
+          data.compressionType = TextAbstraction::GlyphBufferData::CompressionType::NO_COMPRESSION;
 
           if(moveBuffer)
           {
index 17ff1d7..e6b5f5f 100644 (file)
 
 namespace Dali::TextAbstraction::Internal
 {
-void ConvertBitmap(TextAbstraction::FontClient::GlyphBufferData& data,
-                   unsigned int                                  srcWidth,
-                   unsigned int                                  srcHeight,
-                   const unsigned char* const                    srcBuffer,
-                   const Pixel::Format                           srcFormat);
-
-void ConvertBitmap(TextAbstraction::FontClient::GlyphBufferData& data,
-                   FT_Bitmap&                                    srcBitmap,
-                   bool                                          isShearRequired,
-                   bool                                          moveBuffer = false);
+void ConvertBitmap(TextAbstraction::GlyphBufferData& data,
+                   unsigned int                      srcWidth,
+                   unsigned int                      srcHeight,
+                   const unsigned char* const        srcBuffer,
+                   const Pixel::Format               srcFormat);
+
+void ConvertBitmap(TextAbstraction::GlyphBufferData& data,
+                   FT_Bitmap&                        srcBitmap,
+                   bool                              isShearRequired,
+                   bool                              moveBuffer = false);
 
 /**
  * @brief Creates a font family pattern used to match fonts.
index 90fbb02..7c70411 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 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.
@@ -83,9 +83,9 @@ inline GlyphCacheManager::CompressionPolicyType GetRenderedGlyphCompressPolicy()
   using Dali::EnvironmentVariable::GetEnvironmentVariable;
   static auto policyString = GetEnvironmentVariable(RENDERED_GLYPH_COMPRESS_POLICY_ENV);
 
-  static auto policy = policyString ? policyString[0] == 's' || policyString[0] == 'S' ? GlyphCacheManager::CompressionPolicyType::SPEED
-                                                                                       : policyString[0] == 'm' || policyString[0] == 'M' ? GlyphCacheManager::CompressionPolicyType::MEMORY
-                                                                                                                                          : DEFAULT_RENDERED_GLYPH_COMPRESS_POLICY
+  static auto policy = policyString ? policyString[0] == 's' || policyString[0] == 'S'   ? GlyphCacheManager::CompressionPolicyType::SPEED
+                                      : policyString[0] == 'm' || policyString[0] == 'M' ? GlyphCacheManager::CompressionPolicyType::MEMORY
+                                                                                         : DEFAULT_RENDERED_GLYPH_COMPRESS_POLICY
                                     : DEFAULT_RENDERED_GLYPH_COMPRESS_POLICY;
   return policy;
 }
@@ -219,18 +219,20 @@ bool FontFaceCacheItem::GetGlyphMetrics(GlyphInfo& glyphInfo, unsigned int dpiVe
 {
   bool success(true);
 
-  GlyphCacheManager::GlyphCacheData glyphData;
-  FT_Error                          error;
+  GlyphCacheManager::GlyphCacheDataPtr glyphDataPtr;
+  FT_Error                             error;
 
 #ifdef FREETYPE_BITMAP_SUPPORT
   // Check to see if we should be loading a Fixed Size bitmap?
   if(mIsFixedSizeBitmap)
   {
     FT_Select_Size(mFreeTypeFace, mFixedSizeIndex); ///< @todo: needs to be investigated why it's needed to select the size again.
-    mGlyphCacheManager->GetGlyphCacheDataFromIndex(mFreeTypeFace, glyphInfo.index, FT_LOAD_COLOR, glyphInfo.isBoldRequired, glyphData, error);
+    mGlyphCacheManager->GetGlyphCacheDataFromIndex(mFreeTypeFace, glyphInfo.index, FT_LOAD_COLOR, glyphInfo.isBoldRequired, glyphDataPtr, error);
 
     if(FT_Err_Ok == error)
     {
+      GlyphCacheManager::GlyphCacheData& glyphData = *glyphDataPtr.get();
+
       glyphInfo.width    = mFixedWidthPixels;
       glyphInfo.height   = mFixedHeightPixels;
       glyphInfo.advance  = mFixedWidthPixels;
@@ -285,7 +287,7 @@ bool FontFaceCacheItem::GetGlyphMetrics(GlyphInfo& glyphInfo, unsigned int dpiVe
     // FT_LOAD_DEFAULT causes some issues in the alignment of the glyph inside the bitmap.
     // i.e. with the SNum-3R font.
     // @todo: add an option to use the FT_LOAD_DEFAULT if required?
-    mGlyphCacheManager->GetGlyphCacheDataFromIndex(mFreeTypeFace, glyphInfo.index, FT_LOAD_NO_AUTOHINT, glyphInfo.isBoldRequired, glyphData, error);
+    mGlyphCacheManager->GetGlyphCacheDataFromIndex(mFreeTypeFace, glyphInfo.index, FT_LOAD_NO_AUTOHINT, glyphInfo.isBoldRequired, glyphDataPtr, error);
 
     // Keep the width of the glyph before doing the software emboldening.
     // It will be used to calculate a scale factor to be applied to the
@@ -294,6 +296,8 @@ bool FontFaceCacheItem::GetGlyphMetrics(GlyphInfo& glyphInfo, unsigned int dpiVe
 
     if(FT_Err_Ok == error)
     {
+      GlyphCacheManager::GlyphCacheData& glyphData = *glyphDataPtr.get();
+
       const auto& metrics = glyphData.mGlyphMetrics;
 
       glyphInfo.width  = static_cast<float>(metrics.width) * FROM_266;
@@ -313,12 +317,12 @@ bool FontFaceCacheItem::GetGlyphMetrics(GlyphInfo& glyphInfo, unsigned int dpiVe
       if(isEmboldeningRequired)
       {
         // Get dummy glyph data without embolden.
-        GlyphCacheManager::GlyphCacheData dummyData;
-        if(mGlyphCacheManager->GetGlyphCacheDataFromIndex(mFreeTypeFace, glyphInfo.index, FT_LOAD_NO_AUTOHINT, false, dummyData, error))
+        GlyphCacheManager::GlyphCacheDataPtr dummyDataPtr;
+        if(mGlyphCacheManager->GetGlyphCacheDataFromIndex(mFreeTypeFace, glyphInfo.index, FT_LOAD_NO_AUTOHINT, false, dummyDataPtr, error))
         {
           // If the glyph is emboldened by software, the advance is multiplied by a
           // scale factor to make it slightly bigger.
-          const float width = static_cast<float>(dummyData.mGlyphMetrics.width) * FROM_266;
+          const float width = static_cast<float>(dummyDataPtr->mGlyphMetrics.width) * FROM_266;
           if(!EqualsZero(width))
           {
             glyphInfo.advance *= (glyphInfo.width / width);
@@ -357,11 +361,11 @@ bool FontFaceCacheItem::GetGlyphMetrics(GlyphInfo& glyphInfo, unsigned int dpiVe
  * @param[in]  isBoldRequired    Whether the glyph requires bold style.
  */
 void FontFaceCacheItem::CreateBitmap(
-  GlyphIndex glyphIndex, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth, bool isItalicRequired, bool isBoldRequired) const
+  GlyphIndex glyphIndex, Dali::TextAbstraction::GlyphBufferData& data, int outlineWidth, bool isItalicRequired, bool isBoldRequired) const
 {
-  GlyphCacheManager::GlyphCacheData glyphData;
-  FT_Error                          error;
-  FT_Int32                          loadFlag;
+  GlyphCacheManager::GlyphCacheDataPtr glyphDataPtr;
+  FT_Error                             error;
+  FT_Int32                             loadFlag;
   // For the software italics.
   bool isShearRequired = false;
 
@@ -379,10 +383,12 @@ void FontFaceCacheItem::CreateBitmap(
     // @todo: add an option to use the FT_LOAD_DEFAULT if required?
     loadFlag = FT_LOAD_NO_AUTOHINT;
   }
-  mGlyphCacheManager->GetGlyphCacheDataFromIndex(mFreeTypeFace, glyphIndex, loadFlag, isBoldRequired, glyphData, error);
+  mGlyphCacheManager->GetGlyphCacheDataFromIndex(mFreeTypeFace, glyphIndex, loadFlag, isBoldRequired, glyphDataPtr, error);
 
   if(FT_Err_Ok == error)
   {
+    GlyphCacheManager::GlyphCacheData& glyphData = *glyphDataPtr.get();
+
     if(isItalicRequired && !(glyphData.mStyleFlags & FT_STYLE_FLAG_ITALIC))
     {
       // Will do the software italic.
@@ -486,16 +492,16 @@ void FontFaceCacheItem::CreateBitmap(
           {
             mGlyphCacheManager->CacheRenderedGlyphBuffer(mFreeTypeFace, glyphIndex, loadFlag, isBoldRequired, bitmapGlyph->bitmap, GetRenderedGlyphCompressPolicy());
 
-            GlyphCacheManager::GlyphCacheData dummyData;
-            mGlyphCacheManager->GetGlyphCacheDataFromIndex(mFreeTypeFace, glyphIndex, loadFlag, isBoldRequired, dummyData, error);
+            GlyphCacheManager::GlyphCacheDataPtr dummyDataPtr;
+            mGlyphCacheManager->GetGlyphCacheDataFromIndex(mFreeTypeFace, glyphIndex, loadFlag, isBoldRequired, dummyDataPtr, error);
 
-            if(DALI_LIKELY(FT_Err_Ok == error && dummyData.mRenderedBuffer))
+            if(DALI_LIKELY(FT_Err_Ok == error && dummyDataPtr->mRenderedBuffer))
             {
-              data.buffer          = dummyData.mRenderedBuffer->buffer;
-              data.width           = dummyData.mRenderedBuffer->width;
-              data.height          = dummyData.mRenderedBuffer->height;
-              data.format          = dummyData.mRenderedBuffer->format;
-              data.compressionType = dummyData.mRenderedBuffer->compressionType;
+              data.buffer          = dummyDataPtr->mRenderedBuffer->buffer;
+              data.width           = dummyDataPtr->mRenderedBuffer->width;
+              data.height          = dummyDataPtr->mRenderedBuffer->height;
+              data.format          = dummyDataPtr->mRenderedBuffer->format;
+              data.compressionType = dummyDataPtr->mRenderedBuffer->compressionType;
               data.isBufferOwned   = false;
             }
             else
@@ -541,8 +547,8 @@ bool FontFaceCacheItem::IsColorGlyph(GlyphIndex glyphIndex) const
   // Check to see if this is fixed size bitmap
   if(mHasColorTables)
   {
-    GlyphCacheManager::GlyphCacheData dummyData;
-    mGlyphCacheManager->GetGlyphCacheDataFromIndex(mFreeTypeFace, glyphIndex, FT_LOAD_COLOR, false, dummyData, error);
+    GlyphCacheManager::GlyphCacheDataPtr dummyDataPtr;
+    mGlyphCacheManager->GetGlyphCacheDataFromIndex(mFreeTypeFace, glyphIndex, FT_LOAD_COLOR, false, dummyDataPtr, error);
   }
 #endif
   return FT_Err_Ok == error;
index 10608d7..f7ca2eb 100644 (file)
@@ -79,7 +79,7 @@ struct FontFaceCacheItem : public FontCacheItemInterface
   /**
    * @copydoc FontCacheItemInterface::CreateBitmap()
    */
-  void CreateBitmap(GlyphIndex glyphIndex, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth, bool isItalicRequired, bool isBoldRequired) const override;
+  void CreateBitmap(GlyphIndex glyphIndex, Dali::TextAbstraction::GlyphBufferData& data, int outlineWidth, bool isItalicRequired, bool isBoldRequired) const override;
 
   /**
    * @copydoc FontCacheItemInterface::IsColorGlyph()
index a241635..96817db 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 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.
@@ -49,12 +49,12 @@ GlyphCacheManager::~GlyphCacheManager()
 }
 
 bool GlyphCacheManager::GetGlyphCacheDataFromIndex(
-  const FT_Face    freeTypeFace,
-  const GlyphIndex index,
-  const FT_Int32   flag,
-  const bool       isBoldRequired,
-  GlyphCacheData&  glyphData,
-  FT_Error&        error)
+  const FT_Face      freeTypeFace,
+  const GlyphIndex   index,
+  const FT_Int32     flag,
+  const bool         isBoldRequired,
+  GlyphCacheDataPtr& glyphDataPtr,
+  FT_Error&          error)
 {
   // Append some error value here instead of FT_Err_Ok.
   error = static_cast<FT_Error>(-1);
@@ -69,17 +69,19 @@ bool GlyphCacheManager::GetGlyphCacheDataFromIndex(
     {
       auto removedData = mLRUGlyphCache.Pop();
 
-      DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, "FontClient::Plugin::GlyphCacheManager::GetGlyphCacheDataFromIndex. Remove oldest cache for glyph : %p\n", removedData.mGlyph);
-
-      // Release Glyph data resource
-      removedData.ReleaseGlyphData();
+      DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, "FontClient::Plugin::GlyphCacheManager::GetGlyphCacheDataFromIndex. Remove oldest cache for glyph : %p\n", removedData->mGlyph);
     }
 
+    // Create new GlyphCacheData.
+    glyphDataPtr = std::make_shared<GlyphCacheData>();
+
+    GlyphCacheData& glyphData = *glyphDataPtr.get();
+
     const bool loadSuccess = LoadGlyphDataFromIndex(freeTypeFace, index, flag, isBoldRequired, glyphData, error);
     if(loadSuccess)
     {
       // Copy and cached data.
-      mLRUGlyphCache.Push(key, glyphData);
+      mLRUGlyphCache.Push(key, glyphDataPtr);
 
       DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, "FontClient::Plugin::GlyphCacheManager::GetGlyphCacheDataFromIndex. Create cache for face : %p, index : %u flag : %d isBold : %d isBitmap : %d, glyph : %p\n", freeTypeFace, index, static_cast<int>(flag), isBoldRequired, glyphData.mIsBitmap, glyphData.mGlyph);
     }
@@ -91,9 +93,9 @@ bool GlyphCacheManager::GetGlyphCacheDataFromIndex(
     error = FT_Err_Ok;
 
     // We already notify that we use this glyph. And now, copy cached data.
-    glyphData = mLRUGlyphCache.GetElement(iter);
+    glyphDataPtr = mLRUGlyphCache.GetElement(iter);
 
-    DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, "FontClient::Plugin::GlyphCacheManager::GetGlyphCacheDataFromIndex. Find cache for face : %p, index : %u flag : %d isBold : %d isBitmap : %d, glyph : %p\n", freeTypeFace, index, static_cast<int>(flag), isBoldRequired, glyphData.mIsBitmap, glyphData.mGlyph);
+    DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, "FontClient::Plugin::GlyphCacheManager::GetGlyphCacheDataFromIndex. Find cache for face : %p, index : %u flag : %d isBold : %d isBitmap : %d, glyph : %p\n", freeTypeFace, index, static_cast<int>(flag), isBoldRequired, glyphDataPtr->mIsBitmap, glyphDataPtr->mGlyph);
     return true;
   }
 }
@@ -201,37 +203,32 @@ void GlyphCacheManager::ResizeBitmapGlyph(
     // Skip this API if desired size is zero
     return;
   }
-  FT_Error       error;
-  GlyphCacheData originGlyphData;
-  if(GetGlyphCacheDataFromIndex(freeTypeFace, index, flag, isBoldRequired, originGlyphData, error))
+  FT_Error          error;
+  GlyphCacheDataPtr glyphDataPtr;
+  if(GetGlyphCacheDataFromIndex(freeTypeFace, index, flag, isBoldRequired, glyphDataPtr, error))
   {
-    if(DALI_LIKELY(originGlyphData.mIsBitmap && originGlyphData.mBitmap))
+    GlyphCacheData& glyphData = *glyphDataPtr.get();
+    if(DALI_LIKELY(glyphData.mIsBitmap && glyphData.mBitmap))
     {
-      const bool requiredResize = (originGlyphData.mBitmap->rows != desiredHeight) || (originGlyphData.mBitmap->width != desiredWidth);
+      const bool requiredResize = (glyphData.mBitmap->rows != desiredHeight) || (glyphData.mBitmap->width != desiredWidth);
       if(requiredResize)
       {
-        // originalGlyphData is copy data. For change cached information, we should access as iterator.
-        const GlyphCacheKey key  = GlyphCacheKey(freeTypeFace, index, flag, isBoldRequired);
-        auto                iter = mLRUGlyphCache.Find(key);
-
-        GlyphCacheData& destinationGlpyhData = mLRUGlyphCache.GetElement(iter);
-
-        const ImageDimensions inputDimensions(destinationGlpyhData.mBitmap->width, destinationGlpyhData.mBitmap->rows);
+        const ImageDimensions inputDimensions(glyphData.mBitmap->width, glyphData.mBitmap->rows);
         const ImageDimensions desiredDimensions(desiredWidth, desiredHeight);
 
         uint8_t* desiredBuffer = nullptr;
 
-        switch(destinationGlpyhData.mBitmap->pixel_mode)
+        switch(glyphData.mBitmap->pixel_mode)
         {
           case FT_PIXEL_MODE_GRAY:
           {
-            if(destinationGlpyhData.mBitmap->pitch == static_cast<int>(destinationGlpyhData.mBitmap->width))
+            if(glyphData.mBitmap->pitch == static_cast<int>(glyphData.mBitmap->width))
             {
               desiredBuffer = (uint8_t*)malloc(desiredWidth * desiredHeight * sizeof(uint8_t)); // @note The caller is responsible for deallocating the bitmap data using free.
               // Resize bitmap here.
-              Dali::Internal::Platform::LanczosSample1BPP(destinationGlpyhData.mBitmap->buffer,
+              Dali::Internal::Platform::LanczosSample1BPP(glyphData.mBitmap->buffer,
                                                           inputDimensions,
-                                                          destinationGlpyhData.mBitmap->width,
+                                                          glyphData.mBitmap->width,
                                                           desiredBuffer,
                                                           desiredDimensions);
             }
@@ -240,13 +237,13 @@ void GlyphCacheManager::ResizeBitmapGlyph(
 #ifdef FREETYPE_BITMAP_SUPPORT
           case FT_PIXEL_MODE_BGRA:
           {
-            if(destinationGlpyhData.mBitmap->pitch == static_cast<int>(destinationGlpyhData.mBitmap->width << 2u))
+            if(glyphData.mBitmap->pitch == static_cast<int>(glyphData.mBitmap->width << 2u))
             {
               desiredBuffer = (uint8_t*)malloc((desiredWidth * desiredHeight * sizeof(uint8_t)) << 2u); // @note The caller is responsible for deallocating the bitmap data using free.
               // Resize bitmap here.
-              Dali::Internal::Platform::LanczosSample4BPP(destinationGlpyhData.mBitmap->buffer,
+              Dali::Internal::Platform::LanczosSample4BPP(glyphData.mBitmap->buffer,
                                                           inputDimensions,
-                                                          destinationGlpyhData.mBitmap->width,
+                                                          glyphData.mBitmap->width,
                                                           desiredBuffer,
                                                           desiredDimensions);
             }
@@ -264,23 +261,23 @@ void GlyphCacheManager::ResizeBitmapGlyph(
         {
           // Success to resize bitmap glyph.
           // Release origin bitmap buffer.
-          free(destinationGlpyhData.mBitmap->buffer);
+          free(glyphData.mBitmap->buffer);
 
           // Replace as desired buffer and size.
-          destinationGlpyhData.mBitmap->buffer = desiredBuffer;
-          destinationGlpyhData.mBitmap->width  = desiredWidth;
-          destinationGlpyhData.mBitmap->rows   = desiredHeight;
-          switch(destinationGlpyhData.mBitmap->pixel_mode)
+          glyphData.mBitmap->buffer = desiredBuffer;
+          glyphData.mBitmap->width  = desiredWidth;
+          glyphData.mBitmap->rows   = desiredHeight;
+          switch(glyphData.mBitmap->pixel_mode)
           {
             case FT_PIXEL_MODE_GRAY:
             {
-              destinationGlpyhData.mBitmap->pitch = desiredWidth;
+              glyphData.mBitmap->pitch = desiredWidth;
               break;
             }
 #ifdef FREETYPE_BITMAP_SUPPORT
             case FT_PIXEL_MODE_BGRA:
             {
-              destinationGlpyhData.mBitmap->pitch = desiredWidth << 2u;
+              glyphData.mBitmap->pitch = desiredWidth << 2u;
               break;
             }
 #endif
@@ -304,26 +301,21 @@ void GlyphCacheManager::CacheRenderedGlyphBuffer(
     // Skip this API if rendered bitmap size is zero
     return;
   }
-  FT_Error       error;
-  GlyphCacheData originGlyphData;
-  if(GetGlyphCacheDataFromIndex(freeTypeFace, index, flag, isBoldRequired, originGlyphData, error))
+  FT_Error          error;
+  GlyphCacheDataPtr glyphDataPtr;
+  if(GetGlyphCacheDataFromIndex(freeTypeFace, index, flag, isBoldRequired, glyphDataPtr, error))
   {
-    if(DALI_LIKELY(!originGlyphData.mIsBitmap && originGlyphData.mRenderedBuffer == nullptr))
+    GlyphCacheData& glyphData = *glyphDataPtr.get();
+    if(DALI_LIKELY(!glyphData.mIsBitmap && glyphData.mRenderedBuffer == nullptr))
     {
-      // originalGlyphData is copy data. For change cached information, we should access as iterator.
-      const GlyphCacheKey key  = GlyphCacheKey(freeTypeFace, index, flag, isBoldRequired);
-      auto                iter = mLRUGlyphCache.Find(key);
-
-      GlyphCacheData& destinationGlpyhData = mLRUGlyphCache.GetElement(iter);
-
-      destinationGlpyhData.mRenderedBuffer = new TextAbstraction::FontClient::GlyphBufferData();
-      if(DALI_UNLIKELY(!destinationGlpyhData.mRenderedBuffer))
+      glyphData.mRenderedBuffer = new TextAbstraction::GlyphBufferData();
+      if(DALI_UNLIKELY(!glyphData.mRenderedBuffer))
       {
         DALI_LOG_ERROR("Allocate GlyphBufferData failed\n");
         return;
       }
 
-      TextAbstraction::FontClient::GlyphBufferData& renderBuffer = *destinationGlpyhData.mRenderedBuffer;
+      TextAbstraction::GlyphBufferData& renderBuffer = *glyphData.mRenderedBuffer;
 
       // Set basic informations.
       renderBuffer.width  = srcBitmap.width;
@@ -338,28 +330,28 @@ void GlyphCacheManager::CacheRenderedGlyphBuffer(
           if(policy == CompressionPolicyType::SPEED)
           {
             // If policy is SPEED, we will not compress bitmap.
-            renderBuffer.compressionType = TextAbstraction::FontClient::GlyphBufferData::CompressionType::NO_COMPRESSION;
+            renderBuffer.compressionType = TextAbstraction::GlyphBufferData::CompressionType::NO_COMPRESSION;
           }
           else
           {
             // If small enough glyph, compress as BPP4 method.
             if(srcBitmap.width < THRESHOLD_WIDTH_FOR_RLE4_COMPRESSION)
             {
-              renderBuffer.compressionType = TextAbstraction::FontClient::GlyphBufferData::CompressionType::BPP_4;
+              renderBuffer.compressionType = TextAbstraction::GlyphBufferData::CompressionType::BPP_4;
             }
             else
             {
-              renderBuffer.compressionType = TextAbstraction::FontClient::GlyphBufferData::CompressionType::RLE_4;
+              renderBuffer.compressionType = TextAbstraction::GlyphBufferData::CompressionType::RLE_4;
             }
           }
 
-          const auto compressedBufferSize = TextAbstraction::FontClient::GlyphBufferData::Compress(srcBitmap.buffer, renderBuffer);
+          const auto compressedBufferSize = TextAbstraction::GlyphBufferData::Compress(srcBitmap.buffer, renderBuffer);
           if(DALI_UNLIKELY(compressedBufferSize == 0u))
           {
             DALI_ASSERT_DEBUG(0 == "Compress failed at FT_PIXEL_MODE_GRAY");
             DALI_LOG_ERROR("Compress failed. Ignore cache\n");
-            delete destinationGlpyhData.mRenderedBuffer;
-            destinationGlpyhData.mRenderedBuffer = nullptr;
+            delete glyphData.mRenderedBuffer;
+            glyphData.mRenderedBuffer = nullptr;
             return;
           }
           break;
@@ -368,16 +360,16 @@ void GlyphCacheManager::CacheRenderedGlyphBuffer(
         case FT_PIXEL_MODE_BGRA:
         {
           // Copy buffer without compress
-          renderBuffer.compressionType = TextAbstraction::FontClient::GlyphBufferData::CompressionType::NO_COMPRESSION;
+          renderBuffer.compressionType = TextAbstraction::GlyphBufferData::CompressionType::NO_COMPRESSION;
           renderBuffer.format          = Pixel::BGRA8888;
 
-          const auto compressedBufferSize = TextAbstraction::FontClient::GlyphBufferData::Compress(srcBitmap.buffer, renderBuffer);
+          const auto compressedBufferSize = TextAbstraction::GlyphBufferData::Compress(srcBitmap.buffer, renderBuffer);
           if(DALI_UNLIKELY(compressedBufferSize == 0u))
           {
             DALI_ASSERT_DEBUG(0 == "Compress failed at FT_PIXEL_MODE_BGRA");
             DALI_LOG_ERROR("Compress failed. Ignore cache\n");
-            delete destinationGlpyhData.mRenderedBuffer;
-            destinationGlpyhData.mRenderedBuffer = nullptr;
+            delete glyphData.mRenderedBuffer;
+            glyphData.mRenderedBuffer = nullptr;
             return;
           }
           break;
@@ -386,8 +378,8 @@ void GlyphCacheManager::CacheRenderedGlyphBuffer(
         default:
         {
           DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "FontClient::Plugin::GlyphCacheManager::CacheRenderedGlyphBuffer. FontClient Unable to create Bitmap of this PixelType\n");
-          delete destinationGlpyhData.mRenderedBuffer;
-          destinationGlpyhData.mRenderedBuffer = nullptr;
+          delete glyphData.mRenderedBuffer;
+          glyphData.mRenderedBuffer = nullptr;
           break;
         }
       }
@@ -422,15 +414,6 @@ void GlyphCacheManager::ClearCache(const std::size_t remainCount)
 {
   if(remainCount == 0u)
   {
-    // Release all data memory first.
-    auto endIter = mLRUGlyphCache.End();
-    for(auto iter = mLRUGlyphCache.Begin(); iter != endIter; ++iter)
-    {
-      // Get the reference of data. and release it.
-      auto& removedData = mLRUGlyphCache.GetElement(iter);
-      removedData.ReleaseGlyphData();
-    }
-
     // Clear all cache.
     mLRUGlyphCache.Clear();
   }
@@ -441,19 +424,19 @@ void GlyphCacheManager::ClearCache(const std::size_t remainCount)
     {
       auto removedData = mLRUGlyphCache.Pop();
 
-      DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, "FontClient::Plugin::GlyphCacheManager::ClearCache[%zu / %zu]. Remove oldest cache for glyph : %p\n", mLRUGlyphCache.Count(), remainCount, removedData.mGlyph);
-
-      // Release Glyph data resource
-      removedData.ReleaseGlyphData();
+      DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, "FontClient::Plugin::GlyphCacheManager::ClearCache[%zu / %zu]. Remove oldest cache for glyph : %p\n", mLRUGlyphCache.Count(), remainCount, removedData->mGlyph);
     }
   }
 }
 
+// GlyphCacheManager::GlyphCacheData
+
 void GlyphCacheManager::GlyphCacheData::ReleaseGlyphData()
 {
   if(mIsBitmap && mBitmap)
   {
     // Created FT_Bitmap object must be released with FT_Bitmap_Done
+    // But, this class's mBitmap it not an actual FT_Bitmap object. So free buffer is enough.
     free(mBitmap->buffer); // This buffer created by malloc
 
     delete mBitmap;
@@ -475,4 +458,73 @@ void GlyphCacheManager::GlyphCacheData::ReleaseGlyphData()
   mStyleFlags = 0;
 }
 
+GlyphCacheManager::GlyphCacheData::GlyphCacheData()
+: mGlyph{nullptr},
+  mGlyphMetrics{},
+  mStyleFlags{0},
+  mIsBitmap{false},
+  mRenderedBuffer{nullptr}
+{
+}
+
+GlyphCacheManager::GlyphCacheData::~GlyphCacheData()
+{
+  ReleaseGlyphData();
+}
+
+GlyphCacheManager::GlyphCacheData::GlyphCacheData(GlyphCacheData&& rhs) noexcept
+: mGlyph{nullptr},
+  mGlyphMetrics{},
+  mStyleFlags{0},
+  mIsBitmap{false},
+  mRenderedBuffer{nullptr}
+{
+  *this = std::move(rhs);
+}
+
+GlyphCacheManager::GlyphCacheData& GlyphCacheManager::GlyphCacheData::operator=(GlyphCacheData&& rhs) noexcept
+{
+  // Self-assignment detection
+  if(this == &rhs)
+  {
+    return *this;
+  }
+
+  // Delete self data first.
+  ReleaseGlyphData();
+
+  mIsBitmap = false;
+
+  if(rhs.mIsBitmap && rhs.mBitmap)
+  {
+    mIsBitmap = true;
+    mBitmap   = rhs.mBitmap;
+
+    rhs.mBitmap = nullptr;
+  }
+  else if(rhs.mGlyph)
+  {
+    mGlyph = rhs.mGlyph;
+
+    rhs.mGlyph = nullptr;
+  }
+  else
+  {
+    mGlyph = nullptr;
+  }
+
+  if(rhs.mRenderedBuffer)
+  {
+    mRenderedBuffer     = rhs.mRenderedBuffer;
+    rhs.mRenderedBuffer = nullptr;
+  }
+  else
+  {
+    mRenderedBuffer = nullptr;
+  }
+
+  mStyleFlags = rhs.mStyleFlags;
+  return *this;
+}
+
 } // namespace Dali::TextAbstraction::Internal
index 15f5e45..521c373 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TEST_ABSTRACTION_INTERNAL_FONT_FACE_GLYPH_CACHE_MANAGER_H
 
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 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.
  */
 
 // INTERNAL INCLUDES
-#include <dali/devel-api/text-abstraction/font-client.h> // For GlyphBufferData
+#include <dali/devel-api/text-abstraction/glyph-buffer-data.h>
 #include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
 #include <dali/internal/text/text-abstraction/plugin/lru-cache-container.h>
 
 // EXTERNAL INCLUDES
+#include <memory> // for std::shared_ptr
+
 #include <ft2build.h>
 #include FT_FREETYPE_H
 #include FT_GLYPH_H
@@ -53,10 +55,12 @@ public:
    */
   struct GlyphCacheData
   {
-    GlyphCacheData()
-    : mGlyph{nullptr}
-    {
-    }
+    GlyphCacheData();
+    ~GlyphCacheData();
+
+    // Move operations
+    GlyphCacheData(GlyphCacheData&& rhs) noexcept;
+    GlyphCacheData& operator=(GlyphCacheData&& rhs) noexcept;
 
     union
     {
@@ -67,14 +71,21 @@ public:
     FT_Int32          mStyleFlags{0};  // Get from FT_Face
     bool              mIsBitmap{false};
 
-    TextAbstraction::FontClient::GlyphBufferData* mRenderedBuffer{nullptr}; // Rendered glyph buffer. Cached only if system allow to cache and we rendered it before. Otherwise, just nullptr
+    TextAbstraction::GlyphBufferData* mRenderedBuffer{nullptr}; // Rendered glyph buffer. Cached only if system allow to cache and we rendered it before. Otherwise, just nullptr
+
+  private:
+    // Delete copy operations
+    GlyphCacheData(const GlyphCacheData&) = delete;
+    GlyphCacheData& operator=(const GlyphCacheData&) = delete;
 
     /**
-     * @brief Release the memory of loaded mGlyph / mBitmap.
+     * @brief Release the memory of loaded mGlyph / mBitmap and mRenderedBuffer.
      */
     void ReleaseGlyphData();
   };
 
+  using GlyphCacheDataPtr = std::shared_ptr<GlyphCacheData>;
+
   // Compression priority of rendered glyph buffer.
   enum class CompressionPolicyType
   {
@@ -87,32 +98,32 @@ public:
 
   /**
    * @brief Load GlyphCacheData from face. The result will be cached.
+   * @note Inputed glyph data pointer will be overwrited.
    *
    * @param[in] freeTypeFace The freetype face handle.
    * @param[in] index Index of glyph in this face.
    * @param[in] flag Flag when we load the glyph.
    * @param[in] isBoldRequired True if we require some software bold.
-   * @param[out] data Result of glyph load.
+   * @param[out] glyphDataPtr Result of pointer of glyph load.
    * @param[out] error Error code during load glyph.
    * @return True if load successfully. False if something error occured.
    */
   bool GetGlyphCacheDataFromIndex(
-    const FT_Face    freeTypeFace,
-    const GlyphIndex index,
-    const FT_Int32   flag,
-    const bool       isBoldRequired,
-    GlyphCacheData&  data,
-    FT_Error&        error);
+    const FT_Face      freeTypeFace,
+    const GlyphIndex   index,
+    const FT_Int32     flag,
+    const bool         isBoldRequired,
+    GlyphCacheDataPtr& glyphDataPtr,
+    FT_Error&          error);
 
   /**
    * @brief Load GlyphCacheData from face. The result will not be cached.
-   * @note If we call this API, We should release GlyphCacheData manually.
    *
    * @param[in] freeTypeFace The freetype face handle.
    * @param[in] index Index of glyph in this face.
    * @param[in] flag Flag when we load the glyph.
    * @param[in] isBoldRequired True if we require some software bold.
-   * @param[out] data Result of glyph load.
+   * @param[in, out] glyphData Result of glyph load.
    * @param[out] error Error code during load glyph.
    * @return True if load successfully. False if something error occured.
    */
@@ -121,7 +132,7 @@ public:
     const GlyphIndex index,
     const FT_Int32   flag,
     const bool       isBoldRequired,
-    GlyphCacheData&  data,
+    GlyphCacheData&  glyphData,
     FT_Error&        error);
 
   /**
@@ -229,7 +240,7 @@ private:
   // Private member value area.
   std::size_t mGlyphCacheMaxSize; ///< The maximum capacity of glyph cache.
 
-  using CacheContainer = LRUCacheContainer<GlyphCacheKey, GlyphCacheData, GlyphCacheKeyHash>;
+  using CacheContainer = LRUCacheContainer<GlyphCacheKey, GlyphCacheDataPtr, GlyphCacheKeyHash>;
 
   CacheContainer mLRUGlyphCache; ///< LRU Cache container of glyph
 };
index 53d3d0f..1b20663 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 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.
@@ -115,10 +115,10 @@ namespace
  *
  * @param[in] font_data HarfBuzzProxyFont::Impl pointer that register this callback as void* type.
  * @param[in] glyphIndex Index of glyph.
- * @param[out] glyphData The result of cached glyph data.
+ * @param[out] glyphDataPtr The result of cached glyph data pointer.
  * @return True if we success to get some glyph data. False otherwise.
  */
-static bool GetGlyphCacheData(void* font_data, const GlyphIndex& glyphIndex, GlyphCacheManager::GlyphCacheData& glyphData)
+static bool GetGlyphCacheData(void* font_data, const GlyphIndex& glyphIndex, GlyphCacheManager::GlyphCacheDataPtr& glyphDataPtr)
 {
   HarfBuzzProxyFont::Impl* impl = reinterpret_cast<HarfBuzzProxyFont::Impl*>(font_data);
 
@@ -126,7 +126,7 @@ static bool GetGlyphCacheData(void* font_data, const GlyphIndex& glyphIndex, Gly
   if(DALI_LIKELY(impl && impl->mGlyphCacheManager))
   {
     FT_Error error;
-    return impl->mGlyphCacheManager->GetGlyphCacheDataFromIndex(impl->mFreeTypeFace, glyphIndex, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING, false, glyphData, error);
+    return impl->mGlyphCacheManager->GetGlyphCacheDataFromIndex(impl->mFreeTypeFace, glyphIndex, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING, false, glyphDataPtr, error);
   }
   return false;
 }
@@ -214,9 +214,11 @@ static hb_bool_t GlyphVariantIndexConvertFunc(hb_font_t* font, void* font_data,
 static hb_position_t GlyphHorizontalAdvanceFunc(hb_font_t* font, void* font_data, hb_codepoint_t glyphIndex, void* user_data)
 {
   // Output data stored here.
-  GlyphCacheManager::GlyphCacheData glyphData;
-  if(GetGlyphCacheData(font_data, static_cast<GlyphIndex>(glyphIndex), glyphData))
+  GlyphCacheManager::GlyphCacheDataPtr glyphDataPtr;
+  if(GetGlyphCacheData(font_data, static_cast<GlyphIndex>(glyphIndex), glyphDataPtr))
   {
+    GlyphCacheManager::GlyphCacheData& glyphData = *glyphDataPtr.get();
+
     // Note : It may return invalid value for fixed size bitmap glyph.
     // But, Harfbuzz library also return Undefined advanced value if it is fixed size font.
     // So we'll also ignore that case.
@@ -236,9 +238,11 @@ static hb_position_t GlyphHorizontalAdvanceFunc(hb_font_t* font, void* font_data
 static hb_position_t GlyphVerticalAdvanceFunc(hb_font_t* font, void* font_data, hb_codepoint_t glyphIndex, void* user_data)
 {
   // Output data stored here.
-  GlyphCacheManager::GlyphCacheData glyphData;
-  if(GetGlyphCacheData(font_data, static_cast<GlyphIndex>(glyphIndex), glyphData))
+  GlyphCacheManager::GlyphCacheDataPtr glyphDataPtr;
+  if(GetGlyphCacheData(font_data, static_cast<GlyphIndex>(glyphIndex), glyphDataPtr))
   {
+    GlyphCacheManager::GlyphCacheData& glyphData = *glyphDataPtr.get();
+
     // Note : It may return invalid value for fixed size bitmap glyph.
     // But, Harfbuzz library also return Undefined advanced value if it is fixed size font.
     // So we'll also ignore that case.
@@ -277,9 +281,11 @@ static hb_bool_t GlyphHorizontalOriginFunc(hb_font_t* font, void* font_data, hb_
 static hb_bool_t GlyphVerticalOriginFunc(hb_font_t* font, void* font_data, hb_codepoint_t glyphIndex, hb_position_t* x, hb_position_t* y, void* user_data)
 {
   // Output data stored here.
-  GlyphCacheManager::GlyphCacheData glyphData;
-  if(GetGlyphCacheData(font_data, static_cast<GlyphIndex>(glyphIndex), glyphData))
+  GlyphCacheManager::GlyphCacheDataPtr glyphDataPtr;
+  if(GetGlyphCacheData(font_data, static_cast<GlyphIndex>(glyphIndex), glyphDataPtr))
   {
+    GlyphCacheManager::GlyphCacheData& glyphData = *glyphDataPtr.get();
+
     *x = glyphData.mGlyphMetrics.horiBearingX - glyphData.mGlyphMetrics.vertBearingX;
     *y = glyphData.mGlyphMetrics.horiBearingY + glyphData.mGlyphMetrics.vertBearingY;
     return true;
@@ -343,9 +349,11 @@ static hb_position_t GlyphVerticalKerningFunc(hb_font_t* font, void* font_data,
 static hb_bool_t GlyphExtentsFunc(hb_font_t* font, void* font_data, hb_codepoint_t glyphIndex, hb_glyph_extents_t* extents, void* user_data)
 {
   // Output data stored here.
-  GlyphCacheManager::GlyphCacheData glyphData;
-  if(!GetGlyphCacheData(font_data, static_cast<GlyphIndex>(glyphIndex), glyphData))
+  GlyphCacheManager::GlyphCacheDataPtr glyphDataPtr;
+  if(GetGlyphCacheData(font_data, static_cast<GlyphIndex>(glyphIndex), glyphDataPtr))
   {
+    GlyphCacheManager::GlyphCacheData& glyphData = *glyphDataPtr.get();
+
     extents->x_bearing = glyphData.mGlyphMetrics.horiBearingX;
     extents->y_bearing = glyphData.mGlyphMetrics.horiBearingY;
     extents->width     = glyphData.mGlyphMetrics.width;
index a7a5e6c..98f3dbd 100644 (file)
@@ -731,7 +731,7 @@ void Window::SetPosition(Dali::Window::WindowPosition position)
   int32_t      newX    = position.GetX();
   int32_t      newY    = position.GetY();
 
-  mWindowSurface->MoveResize(PositionSize(newX, newY, oldRect.width, oldRect.height));
+  mWindowSurface->Move(PositionSize(newX, newY, oldRect.width, oldRect.height));
 
   if((oldRect.x != newX) || (oldRect.y != newY))
   {
index bfc4462..1337ff8 100644 (file)
@@ -420,6 +420,16 @@ void WindowRenderSurface::UpdatePositionSize(Dali::PositionSize positionSize)
   }
 }
 
+void WindowRenderSurface::Move(Dali::PositionSize positionSize)
+{
+  mPositionSize.x = positionSize.x;
+  mPositionSize.y = positionSize.y;
+
+  DALI_LOG_RELEASE_INFO("Update Position by client (%d, %d)\n", positionSize.x, positionSize.y);
+
+  mWindowBase->Move(positionSize);
+}
+
 void WindowRenderSurface::MoveResize(Dali::PositionSize positionSize)
 {
   mPositionSize.x = positionSize.x;
index a6643e6..6d9ed1b 100644 (file)
@@ -140,6 +140,13 @@ public: // API
   void UpdatePositionSize(Dali::PositionSize positionSize);
 
   /**
+   * @brief Moves the window to the specified position.
+   *
+   * @param positionSize The new position of the window.
+   */
+  void Move(Dali::PositionSize positionSize);
+
+  /**
    * @brief This signal is emitted when the output is transformed.
    */
   OutputSignalType& OutputTransformedSignal();
diff --git a/dali/internal/window-system/common/window-system.cpp b/dali/internal/window-system/common/window-system.cpp
new file mode 100644 (file)
index 0000000..a5f27d3
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2023 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 HEADERS
+#include <dali/internal/window-system/common/window-system.h>
+
+// EXTERNAL_HEADERS
+#include <cstdio>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+namespace WindowSystem
+{
+namespace
+{
+static uint32_t gDpiHorizontal = 0u;
+static uint32_t gDpiVertical   = 0u;
+} // unnamed namespaces
+
+void SetDpi(uint32_t dpiHorizontal, uint32_t dpiVertical)
+{
+  gDpiHorizontal = dpiHorizontal;
+  gDpiVertical = dpiVertical;
+}
+
+void GetDpi(uint32_t& dpiHorizontal, uint32_t& dpiVertical)
+{
+  dpiHorizontal = gDpiHorizontal;
+  dpiVertical = gDpiVertical;
+}
+
+} // namespace WindowSystem
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#pragma GCC diagnostic pop
index 9fa8b5f..6a1ffce 100644 (file)
@@ -41,6 +41,24 @@ void Initialize();
 void Shutdown();
 
 /**
+ * @brief Set the DPI of the target screen.
+ *
+ * @note Multiple screens are not currently supported.
+ * @param[in] horizontalDpi The horizontal resolution in DPI.
+ * @param[in] verticalDpi The vertical resolution in DPI.
+ */
+void SetDpi(uint32_t dpiHorizontal, uint32_t dpiVertical);
+
+/**
+ * @brief Retrieves the DPI previously set to the target screen.
+ *
+ * @note Multiple screens are not currently supported.
+ * @param[out] horizontalDpi The horizontal resolution in DPI.
+ * @param[out] verticalDpi The vertical resolution in DPI.
+ */
+void GetDpi(uint32_t& dpiHorizontal, uint32_t& dpiVertical);
+
+/**
  * @brief Get the screen size
  */
 void GetScreenSize(int32_t& width, int32_t& height);
index ac9be4f..c142f37 100644 (file)
@@ -3,13 +3,14 @@
 SET( adaptor_window_system_common_src_files
     ${adaptor_window_system_dir}/common/display-connection.cpp
     ${adaptor_window_system_dir}/common/event-handler.cpp
+    ${adaptor_window_system_dir}/common/gl-window-impl.cpp
+    ${adaptor_window_system_dir}/common/gl-window-render-thread.cpp
     ${adaptor_window_system_dir}/common/native-render-surface-factory.cpp
     ${adaptor_window_system_dir}/common/orientation-impl.cpp
     ${adaptor_window_system_dir}/common/window-base.cpp
     ${adaptor_window_system_dir}/common/window-impl.cpp
     ${adaptor_window_system_dir}/common/window-render-surface.cpp
-    ${adaptor_window_system_dir}/common/gl-window-impl.cpp
-    ${adaptor_window_system_dir}/common/gl-window-render-thread.cpp
+    ${adaptor_window_system_dir}/common/window-system.cpp
 )
 
 # module: window-system, backend: tizen-wayland
index b3c2b4c..319a8cf 100644 (file)
@@ -27,7 +27,7 @@ namespace Dali
 {
 const unsigned int ADAPTOR_MAJOR_VERSION = 2;
 const unsigned int ADAPTOR_MINOR_VERSION = 2;
-const unsigned int ADAPTOR_MICRO_VERSION = 18;
+const unsigned int ADAPTOR_MICRO_VERSION = 19;
 const char* const  ADAPTOR_BUILD_DATE    = __DATE__ " " __TIME__;
 
 #ifdef DEBUG_ENABLED
index 648ece4..513a1ad 100644 (file)
@@ -17,7 +17,7 @@
 
 Name:       dali2-adaptor
 Summary:    The DALi Tizen Adaptor
-Version:    2.2.18
+Version:    2.2.19
 Release:    1
 Group:      System/Libraries
 License:    Apache-2.0 and BSD-3-Clause and MIT