Merge branch 'devel/master' of ssh://review.tizen.org:29418/platform/core/uifw/dali...
authorjoogab.yun <joogab.yun@samsung.com>
Mon, 4 Jul 2022 04:59:25 +0000 (13:59 +0900)
committerjoogab.yun <joogab.yun@samsung.com>
Mon, 4 Jul 2022 04:59:25 +0000 (13:59 +0900)
Change-Id: Ib72cf0219230a43c92d7990df9d72184fbe22e7d

234 files changed:
automated-tests/images/flag-24bpp.bmp.buffer [moved from automated-tests/images/flag-24bpp.buffer with 100% similarity]
automated-tests/images/test-image.wbmp.buffer [new file with mode: 0644]
automated-tests/images/w3c_home_256.bmp [new file with mode: 0755]
automated-tests/images/w3c_home_256.bmp.buffer [new file with mode: 0644]
automated-tests/resources/lake_front.jpg [new file with mode: 0644]
automated-tests/src/dali-adaptor-internal/CMakeLists.txt
automated-tests/src/dali-adaptor-internal/image-loaders.cpp
automated-tests/src/dali-adaptor-internal/utc-Dali-BmpLoader.cpp
automated-tests/src/dali-adaptor-internal/utc-Dali-ImageOperations.cpp
automated-tests/src/dali-adaptor-internal/utc-Dali-LRUCacheContainer.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor-internal/utc-Dali-WbmpLoader.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-application.cpp
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-application.h
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-abstraction.cpp
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-abstraction.h
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-application.cpp
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-buffer.cpp
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-command-buffer.h
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-controller.cpp
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-program.cpp
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-reflection.cpp
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-reflection.h
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-trace-call-stack.cpp
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-trace-call-stack.h
automated-tests/src/dali-adaptor/utc-Dali-EncodedImageBuffer.cpp
automated-tests/src/dali-adaptor/utc-Dali-GifLoading.cpp
automated-tests/src/dali-adaptor/utc-Dali-ImageLoading.cpp
automated-tests/src/dali-adaptor/utc-Dali-PixelBuffer.cpp
automated-tests/src/dali-adaptor/utc-Dali-Window.cpp
build/tizen/CMakeLists.txt
build/tizen/deps-check.cmake
dali/devel-api/adaptor-framework/accessibility-bitset.h
dali/devel-api/adaptor-framework/accessibility-bridge.h
dali/devel-api/adaptor-framework/accessibility.cpp
dali/devel-api/adaptor-framework/accessibility.h
dali/devel-api/adaptor-framework/animated-image-loading.cpp
dali/devel-api/adaptor-framework/animated-image-loading.h
dali/devel-api/adaptor-framework/application-devel.cpp
dali/devel-api/adaptor-framework/application-devel.h
dali/devel-api/adaptor-framework/atspi-accessibility.cpp
dali/devel-api/adaptor-framework/atspi-accessibility.h
dali/devel-api/adaptor-framework/drag-and-drop.cpp
dali/devel-api/adaptor-framework/drag-and-drop.h
dali/devel-api/adaptor-framework/image-loader-input.h
dali/devel-api/adaptor-framework/image-loading.cpp
dali/devel-api/adaptor-framework/image-loading.h
dali/devel-api/adaptor-framework/input-method-context.h
dali/devel-api/adaptor-framework/native-image-source-queue.cpp
dali/devel-api/adaptor-framework/native-image-source-queue.h
dali/devel-api/adaptor-framework/pixel-buffer.cpp
dali/devel-api/adaptor-framework/pixel-buffer.h
dali/devel-api/adaptor-framework/proxy-accessible.h
dali/devel-api/adaptor-framework/vector-image-renderer-plugin.h [deleted file]
dali/devel-api/adaptor-framework/vector-image-renderer.cpp
dali/devel-api/adaptor-framework/vector-image-renderer.h
dali/devel-api/adaptor-framework/web-engine-plugin.h
dali/devel-api/adaptor-framework/web-engine.cpp
dali/devel-api/adaptor-framework/web-engine.h
dali/devel-api/adaptor-framework/window-devel.cpp
dali/devel-api/adaptor-framework/window-devel.h
dali/devel-api/atspi-interfaces/accessible.h
dali/devel-api/atspi-interfaces/action.h
dali/devel-api/atspi-interfaces/application.h
dali/devel-api/atspi-interfaces/collection.h
dali/devel-api/atspi-interfaces/component.h
dali/devel-api/atspi-interfaces/editable-text.h
dali/devel-api/atspi-interfaces/hyperlink.h
dali/devel-api/atspi-interfaces/hypertext.h
dali/devel-api/atspi-interfaces/selection.h
dali/devel-api/atspi-interfaces/socket.h [new file with mode: 0644]
dali/devel-api/atspi-interfaces/text.h
dali/devel-api/atspi-interfaces/value.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/font-list.h
dali/integration-api/adaptor-framework/scene-holder-impl.h
dali/integration-api/adaptor-framework/scene-holder.cpp
dali/integration-api/adaptor-framework/scene-holder.h
dali/internal/accessibility/bridge/accessibility-common.h
dali/internal/accessibility/bridge/accessible.cpp
dali/internal/accessibility/bridge/bridge-accessible.cpp
dali/internal/accessibility/bridge/bridge-accessible.h
dali/internal/accessibility/bridge/bridge-action.cpp
dali/internal/accessibility/bridge/bridge-application.cpp
dali/internal/accessibility/bridge/bridge-base.cpp
dali/internal/accessibility/bridge/bridge-base.h
dali/internal/accessibility/bridge/bridge-collection.cpp
dali/internal/accessibility/bridge/bridge-component.cpp
dali/internal/accessibility/bridge/bridge-editable-text.cpp
dali/internal/accessibility/bridge/bridge-hyperlink.cpp
dali/internal/accessibility/bridge/bridge-hypertext.cpp
dali/internal/accessibility/bridge/bridge-impl.cpp
dali/internal/accessibility/bridge/bridge-object.cpp
dali/internal/accessibility/bridge/bridge-object.h
dali/internal/accessibility/bridge/bridge-selection.cpp
dali/internal/accessibility/bridge/bridge-socket.cpp [new file with mode: 0644]
dali/internal/accessibility/bridge/bridge-socket.h [new file with mode: 0644]
dali/internal/accessibility/bridge/bridge-text.cpp
dali/internal/accessibility/bridge/bridge-text.h
dali/internal/accessibility/bridge/bridge-value.cpp
dali/internal/accessibility/bridge/dummy-atspi.cpp
dali/internal/accessibility/bridge/dummy-atspi.h
dali/internal/accessibility/file.list
dali/internal/adaptor/common/application-impl.cpp
dali/internal/adaptor/common/combined-update-render-controller-debug.h
dali/internal/adaptor/common/combined-update-render-controller.cpp
dali/internal/adaptor/tizen-wayland/framework-tizen.cpp
dali/internal/drag-and-drop/common/drag-and-drop-impl.h
dali/internal/drag-and-drop/generic/drag-and-drop-impl-generic.cpp
dali/internal/drag-and-drop/generic/drag-and-drop-impl-generic.h
dali/internal/drag-and-drop/tizen-wayland/drag-and-drop-impl-ecore-wl2.cpp
dali/internal/drag-and-drop/tizen-wayland/drag-and-drop-impl-ecore-wl2.h
dali/internal/graphics/common/egl-image-extensions.h
dali/internal/graphics/gles-impl/egl-graphics-controller-debug.cpp
dali/internal/graphics/gles-impl/egl-graphics-controller.cpp
dali/internal/graphics/gles-impl/gles-context.cpp
dali/internal/graphics/gles-impl/gles-context.h
dali/internal/graphics/gles-impl/gles-graphics-command-buffer.cpp
dali/internal/graphics/gles-impl/gles-graphics-command-buffer.h
dali/internal/graphics/gles-impl/gles-graphics-reflection.cpp
dali/internal/graphics/gles-impl/gles-graphics-types.h
dali/internal/graphics/gles/egl-implementation.cpp
dali/internal/graphics/gles/gl-implementation.h
dali/internal/graphics/tizen/egl-image-extensions-tizen.cpp
dali/internal/imaging/common/alpha-mask.cpp
dali/internal/imaging/common/alpha-mask.h
dali/internal/imaging/common/animated-image-loading-impl.h
dali/internal/imaging/common/encoded-image-buffer-impl.cpp
dali/internal/imaging/common/encoded-image-buffer-impl.h
dali/internal/imaging/common/file-download.cpp
dali/internal/imaging/common/gaussian-blur.cpp
dali/internal/imaging/common/gif-loading.cpp
dali/internal/imaging/common/gif-loading.h
dali/internal/imaging/common/image-loader.cpp
dali/internal/imaging/common/image-loader.h
dali/internal/imaging/common/image-operations.cpp
dali/internal/imaging/common/image-operations.h
dali/internal/imaging/common/loader-astc.cpp
dali/internal/imaging/common/loader-bmp.cpp
dali/internal/imaging/common/loader-gif.cpp
dali/internal/imaging/common/loader-ico.cpp
dali/internal/imaging/common/loader-jpeg-turbo.cpp
dali/internal/imaging/common/loader-jpeg.h
dali/internal/imaging/common/loader-ktx.cpp
dali/internal/imaging/common/loader-png.cpp
dali/internal/imaging/common/loader-wbmp.cpp
dali/internal/imaging/common/loader-webp.cpp
dali/internal/imaging/common/pixel-buffer-impl.cpp
dali/internal/imaging/common/pixel-buffer-impl.h
dali/internal/imaging/common/pixel-manipulation.cpp
dali/internal/imaging/common/webp-loading.cpp
dali/internal/imaging/common/webp-loading.h
dali/internal/imaging/tizen/native-image-source-queue-impl-tizen.cpp
dali/internal/input/common/input-method-context-impl.h
dali/internal/input/generic/input-method-context-impl-generic.cpp
dali/internal/input/generic/input-method-context-impl-generic.h
dali/internal/input/macos/input-method-context-impl-mac.h
dali/internal/input/tizen-wayland/input-method-context-impl-ecore-wl.cpp
dali/internal/input/tizen-wayland/input-method-context-impl-ecore-wl.h
dali/internal/input/ubuntu-x11/input-method-context-impl-x.h
dali/internal/input/windows/input-method-context-impl-win.h
dali/internal/network/common/automation.cpp
dali/internal/network/common/automation.h
dali/internal/network/common/network-performance-client.cpp
dali/internal/network/common/network-performance-protocol.cpp
dali/internal/network/common/network-performance-protocol.h
dali/internal/network/common/network-service-impl.cpp [new file with mode: 0644]
dali/internal/network/common/network-service-impl.h [new file with mode: 0644]
dali/internal/network/file.list
dali/internal/system/common/trigger-event.cpp
dali/internal/system/common/widget-controller.h
dali/internal/system/tizen-wayland/widget-application-impl-tizen.cpp
dali/internal/system/tizen-wayland/widget-application-impl-tizen.h
dali/internal/system/tizen-wayland/widget-controller-tizen.cpp
dali/internal/system/tizen-wayland/widget-controller-tizen.h
dali/internal/system/ubuntu-x11/widget-controller-x.cpp
dali/internal/system/ubuntu-x11/widget-controller-x.h
dali/internal/system/windows/widget-controller-win.cpp
dali/internal/system/windows/widget-controller-win.h
dali/internal/text/file.list
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/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 [new file with mode: 0644]
dali/internal/text/text-abstraction/plugin/font-face-glyph-cache-manager.h [new file with mode: 0644]
dali/internal/text/text-abstraction/plugin/harfbuzz-proxy-font.cpp [new file with mode: 0644]
dali/internal/text/text-abstraction/plugin/harfbuzz-proxy-font.h [new file with mode: 0644]
dali/internal/text/text-abstraction/plugin/lru-cache-container.h [new file with mode: 0644]
dali/internal/text/text-abstraction/shaping-impl.cpp
dali/internal/trace/android/trace-manager-impl-android.cpp
dali/internal/trace/generic/trace-manager-impl-generic.cpp
dali/internal/vector-image/common/vector-image-renderer-impl.cpp
dali/internal/vector-image/common/vector-image-renderer-impl.h
dali/internal/web-engine/common/web-engine-impl.cpp
dali/internal/web-engine/common/web-engine-impl.h
dali/internal/window-system/android/window-base-android.cpp
dali/internal/window-system/android/window-base-android.h
dali/internal/window-system/common/rotation-event.h
dali/internal/window-system/common/window-base.cpp
dali/internal/window-system/common/window-base.h
dali/internal/window-system/common/window-impl.cpp
dali/internal/window-system/common/window-impl.h
dali/internal/window-system/common/window-render-surface.cpp
dali/internal/window-system/common/window-render-surface.h
dali/internal/window-system/macos/window-base-mac.h
dali/internal/window-system/macos/window-base-mac.mm
dali/internal/window-system/tizen-wayland/display-connection-impl-ecore-wl.cpp
dali/internal/window-system/tizen-wayland/display-connection-impl-ecore-wl.h
dali/internal/window-system/tizen-wayland/ecore-wl/window-base-ecore-wl.cpp
dali/internal/window-system/tizen-wayland/ecore-wl/window-base-ecore-wl.h
dali/internal/window-system/tizen-wayland/ecore-wl2/window-base-ecore-wl2.cpp
dali/internal/window-system/tizen-wayland/ecore-wl2/window-base-ecore-wl2.h
dali/internal/window-system/ubuntu-x11/window-base-ecore-x.cpp
dali/internal/window-system/ubuntu-x11/window-base-ecore-x.h
dali/internal/window-system/windows/window-base-win.cpp
dali/internal/window-system/windows/window-base-win.h
dali/public-api/adaptor-framework/encoded-image-buffer.cpp
dali/public-api/adaptor-framework/encoded-image-buffer.h
dali/public-api/adaptor-framework/widget-application.cpp
dali/public-api/adaptor-framework/widget-impl.cpp
dali/public-api/adaptor-framework/widget-impl.h
dali/public-api/dali-adaptor-version.cpp
packaging/dali-adaptor.spec

diff --git a/automated-tests/images/test-image.wbmp.buffer b/automated-tests/images/test-image.wbmp.buffer
new file mode 100644 (file)
index 0000000..b40d0bc
Binary files /dev/null and b/automated-tests/images/test-image.wbmp.buffer differ
diff --git a/automated-tests/images/w3c_home_256.bmp b/automated-tests/images/w3c_home_256.bmp
new file mode 100755 (executable)
index 0000000..4b714ff
Binary files /dev/null and b/automated-tests/images/w3c_home_256.bmp differ
diff --git a/automated-tests/images/w3c_home_256.bmp.buffer b/automated-tests/images/w3c_home_256.bmp.buffer
new file mode 100644 (file)
index 0000000..ecee152
--- /dev/null
@@ -0,0 +1 @@
+\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4üþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþü\8c\8a\8c\8c\8a\8c\8c\8a\8ctvt¼º¼üþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþü\8c\8a\8cÌÎÌ\8c\8a\8c\8c\8a\8cÌÎÌ\8c\8a\8cÌÎÌüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþü\8c\8a\8cüþüDFDìîìDFDüþü\8c\8a\8cüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþü\8c\8a\8cüþü$"$DFD¼º¼üþü\8c\8a\8cüþüüþüìòüÄÎäÄÎäÄÎäÄÎäìòüüþüüþüüþüüþüüþüüþüÜæôÄÎäÄÎäÄÎäÄÎäüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþü¼Æä\94ªÔ\94ªÔ\94ªÔ¤¶ÜÄÎäÄÎäÄÎäÄÎäÄÎäÄÎäÄÎäÄÎäÄÎäÄÎäÄÎäìòüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüÌÎÌüþüüþütvtüþüDFDÌÎÌDFDÜÞÜ\8c\8a\8cüþüüþüÜæô\fF\9c\fF\9c\fF\9c\fF\9c¤¶ÜüþüüþüüþüüþüüþüüþüÔÚì\fF\9c\fF\9c\fF\9c\fF\9cÄÎäüþüüþüüþüüþüüþüüþüüþüüþüüþüüþü\14N¤\fF\9c\fF\9c\14N¤\fF\9c\fF\9c\fF\9c\fF\9c\14N¤\fF\9c\fF\9c\fF\9c\14N¤\fF\9c\fF\9c\fF\9cÄÎäüþüüþüüþüüþüüþüÌÎÌLNL\ 4\ 2\ 4\f\ e\f\^\ÜÞÜüþüüþüüþüìîì,.,üþüüþü¼º¼\8c\8a\8cüþüüþüìîìtvtìîìüþüüþüüþü$Z¬\fF\9c\fF\9c\fF\9cd\8aÄüþüüþüüþüüþüüþüüþüüþü\14N¤\fF\9c\fF\9c\14N¤t\96ÄüþüüþüüþüüþüüþüüþüüþüüþüüþüÄÎä\fB\9c\fF\9c\fF\9c\fF\9c\fF\9c\fF\9c\14N¤\fF\9c\fF\9c\fF\9c\fF\9c\fF\9c\fF\9c\fF\9c\fF\9c\fF\9cÄÎäüþüüþüüþüüþü\9c\9e\9c\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\9c\9e\9cüþüüþü|~|\ 4\ 2\ 4üþüüþüüþüÌÎÌ\8c\8a\8c\8c\8a\8c\8c\8a\8cìîìüþüüþüüþüüþüt\96Ä\14N¤\fF\9c\fF\9c\14N¤üþüüþüüþüüþüüþüüþüüþüd\8aÄ\fF\9c\fF\9c\fF\9c$Z¬üþüüþüüþüüþüüþüüþüüþüüþüüþüt\96Ä\fB\9c\fF\9c\fF\9c\fF\9c\fF\9c\fF\9c\fF\9c\fF\9c\fF\9c\fF\9c\fF\9c\14N¤\fF\9c\fF\9c\14N¤Dr´üþüüþüüþüüþüÌÎÌ\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4¼º¼ìîì\f\ e\f\ 4\ 2\ 4¼¾¼üþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüÄÎä\fF\9c\fF\9c\fF\9c\14N¤ÔÚìüþüüþüüþüüþüüþüüþü¤¶Ü\fF\9c\fF\9c\fF\9c\fF\9cÜæôüþüüþüüþüüþüüþüüþüüþüüþü4f¬\fB\9c\14N¤\fF\9c\fF\9c\14N¤\fF\9c\fF\9c\14N¤\fF\9c\fF\9c\fF\9c\fF\9c\fF\9c\fF\9c\fF\9cÄÎäüþüüþüüþüüþü\1c\1e\1c\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\1c\1e\1clnl\ 4\ 2\ 4\ 4\ 2\ 4\9c\9e\9cüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþü\14N¤\fF\9c\fF\9c\fF\9ct\96Äüþüüþüüþüüþüüþüüþüìòü\fF\9c\fF\9c\fF\9c\fF\9c\94ªÔüþüüþüüþüüþüüþüüþüüþüÜæô\fF\9c\fF\9c\fF\9c\fF\9cl\8aÄüþüüþüüþüüþüüþü´Âä\fF\9c\fF\9c\fF\9c\fF\9cd\8aÄüþüüþüüþüüþü\9c\9e\9c\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4,.,|~|lnl$"$\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\f\ e\fìîìüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüT~¼\fF\9c\fF\9c\fF\9c4f¬üþüüþüüþüüþüüþüüþüüþüDr´\fF\9c\14N¤\fF\9cT~¼üþüüþüüþüüþüüþüüþüüþü\94ªÔ\fF\9c\fF\9c\fF\9c\fF\9cìòüüþüüþüüþüüþüüþü$Z¬\fF\9c\fF\9c\fF\9c\14N¤ìòüüþüüþüüþüüþü<><\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\9c\9e\9cüþüüþüüþüìîì\^\\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4|~|üþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþü¤¶Ü\fF\9c\fF\9c\14N¤\fF\9cÜæôüþüüþüüþüüþüüþüüþüd\8aÄ\fF\9c\fF\9c\fF\9c\fF\9cìòüüþüüþüüþüüþüüþüüþüT~¼\fF\9c\fB\9c\fF\9c<j´üþüüþüüþüüþüüþü\84\9eÌ\fF\9c\14N¤\fF\9c\fF\9c\84\9eÌüþüüþüüþüüþüìîì\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\9c\9e\9cüþüüþüüþüüþüüþüüþü\^\\ 4\ 2\ 4\f\ e\fìîìüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüìòü\fF\9c\fF\9c\fF\9c\fF\9c¤¶Üüþüüþüüþüüþüüþüüþü\14N¤\fF\9c\fF\9c\fF\9c\fF\9c¼Æäüþüüþüüþüüþüüþüüþü\fF\9c\fF\9c\14N¤\fF\9c\94ªÔüþüüþüüþüüþüìòü\14N¤\fF\9c\fF\9c\fF\9c$Z¬üþüüþüüþüüþüüþü¬®¬\ 4\ 2\ 4\ 4\ 2\ 4\^\üþüüþüüþüüþüüþüüþüüþüüþü,.,|~|üþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþü<j´\fF\9c\fF\9c\fF\9cT~¼üþüüþüüþüüþüüþüÔÚì\14N¤\fF\9c\fF\9c\fF\9c\fF\9cd\8aÄüþüüþüüþüüþüüþü¼Æä\fF\9c\fF\9c\fF\9c\fF\9cÔÚìüþüüþüüþüüþüd\8aÄ\fF\9c\fF\9c\fF\9c\fF\9c¼Æäüþüüþüüþüüþüüþü|~|\ 4\ 2\ 4\ 4\ 2\ 4ÜÞÜüþüüþüüþüüþüüþüüþüüþüüþüÌÎÌìîìüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþü\94ªÔ\fF\9c\fF\9c\fF\9c\fF\9cüþüüþüüþüüþüüþü\84\9eÌ\fF\9c\fF\9c\14N¤\fF\9c\fF\9c$Z¬üþüüþüüþüüþüüþüd\8aÄ\fF\9c\fF\9c\fF\9c$Z¬üþüüþüüþüüþüÄÎä\fF\9c\fF\9c\14N¤\fF\9cDr´üþüüþüüþüüþüüþüüþüLNL\ 4\ 2\ 4LNLüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüÔÚì\fF\9c\fF\9c\14N¤\fF\9c´Âäüþüüþüüþüüþü4f¬\fF\9c\fF\9c\fF\9c\fF\9c\fF\9c\fF\9cÔÚìüþüüþüüþüüþü$Z¬\fF\9c\fF\9c\fF\9ct\96ÄüþüüþüüþüüþüDr´\fF\9c\fF\9c\fF\9c\fF\9cÜæôüþüüþüüþüüþüüþüüþü<><\ 4\ 2\ 4\9c\9e\9cüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþü$Z¬\fF\9c\fF\9c\fF\9ct\96ÄüþüüþüüþüÜæô\fF\9c\14N¤\fF\9c\fF\9c\fF\9c\fF\9c\14N¤\84\9eÌüþüüþüüþüÔÚì\fF\9c\fF\9c\fF\9c\fF\9c´Âäüþüüþüüþü¤¶Ü\fF\9c\fF\9c\fF\9c\fF\9cd\8aÄüþüüþüüþüüþüüþüüþüüþü<><\ 4\ 2\ 4ìîìüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüd\8aÄ\fF\9c\fF\9c\fF\9c$Z¬üþüüþüüþü¤¶Ü\fF\9c\fF\9c\fF\9c\14N¤\fF\9c\fF\9c\fF\9c4f¬üþüüþüüþü\94ªÔ\fF\9c\fF\9c\14N¤\14N¤üþüüþüüþüìòü$Z¬\fF\9c\14N¤\fF\9c\fF\9c\fF\9c<j´ÔÚìüþüüþüüþüüþüüþü<><\1c\1e\1cüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþü¼Æä\fF\9c\fF\9c\14N¤\fF\9cÔÚìüþüüþüT~¼\fF\9c\fF\9c\14N¤\84\9eÌ\fF\9c\fF\9c\fF\9c\fF\9cìòüüþüüþü<j´\fF\9c\fF\9c\fF\9cT~¼üþüüþüüþü\94ªÔ\fF\9c\fF\9c\fF\9c\fF\9c\fF\9c\14N¤\fF\9c\fF\9c¤¶Üüþüüþüüþüüþü<><<><üþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþü\fF\9c\fF\9c\fF\9c\fF\9c\94ªÔüþüüþü\14N¤\fF\9c\fF\9c\fF\9cÜæôT~¼\fF\9c\14N¤\fF\9c¤¶Üüþüìòü\fF\9c\fF\9c\fF\9c\fF\9c¤¶Üüþüüþüüþü\84\9eÌ\14N¤\fF\9c\fF\9c\fF\9c\fF\9c\fF\9c\fF\9c\fF\9c\fF\9c¤¶Üüþüüþüüþü|~|<><üþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüT~¼\fF\9c\fF\9c\fF\9cDr´üþü´Âä\fF\9c\fF\9c\fF\9c4f¬üþü\94ªÔ\fF\9c\fF\9c\fF\9cT~¼üþü¤¶Ü\fF\9c\fF\9c\fF\9c\fF\9cÜæôüþüüþüüþüÄÎä\84\9eÌ\84\9eÌ\84\9eÌ4f¬\14N¤\fF\9c\fF\9c\14N¤\fF\9c\14N¤ìòüüþüüþü\9c\9e\9c<><üþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþü¤¶Ü\fF\9c\14N¤\fF\9c\fF\9cìòüt\96Ä\fF\9c\fF\9c\14N¤t\96ÄüþüÜæô\fF\9c\fF\9c\fF\9c\14N¤üþüd\8aÄ\fF\9c\14N¤\fF\9c<j´üþüüþüüþüüþüüþüüþüüþüüþüüþüÄÎä\14N¤\fF\9c\fF\9c\fF\9c\fF\9c\84\9eÌüþüüþüÜÞÜ<><üþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüÜæô\fF\9c\fF\9c\fF\9c\fF\9c¤¶Ü$Z¬\fF\9c\fF\9c\fF\9cÔÚìüþüüþü$Z¬\fF\9c\fF\9c\fF\9cÄÎä\14N¤\fF\9c\fF\9c\fF\9c\84\9eÌüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüÔÚì\fF\9c\fF\9c\fF\9c\fF\9c\14N¤üþüüþüüþü|~|üþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþü4f¬\fF\9c\fF\9c\fF\9c<j´\fF\9c\fF\9c\fF\9c\14N¤üþüüþüüþüt\96Ä\14N¤\fF\9c\fF\9c<j´\fF\9c\fF\9c\fF\9c\fF\9cÔÚìüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüd\8aÄ\fF\9c\14N¤\fF\9c\fF\9cÔÚìüþüüþü¼¾¼üþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüt\96Ä\14N¤\fF\9c\fF\9c\fF\9c\fF\9c\fF\9c\fF\9cd\8aÄüþüüþüüþüÄÎä\fF\9c\fF\9c\fF\9c\fF\9c\fF\9c\fF\9c\fF\9c$Z¬üþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþü´Âä\fF\9c\fF\9c\fF\9c\14N¤\94ªÔüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüÔÚì\fF\9c\fF\9c\14N¤\fF\9c\fF\9c\14N¤\fF\9c¼Æäüþüüþüüþüüþü\14N¤\fF\9c\fF\9c\fF\9c\14N¤\fF\9c\fF\9cd\8aÄüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüÔÚì\fF\9c\fF\9c\fF\9c\fF\9c\84\9eÌüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþü\14N¤\fF\9c\fF\9c\fF\9c\fF\9c\fF\9c\fF\9cìòüüþüüþüüþüüþüd\8aÄ\fF\9c\fF\9c\fF\9c\fF\9c\fF\9c\fF\9c¼Æäüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþü\14N¤\fF\9c\fF\9c\fF\9c\84\9eÌüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüd\8aÄ\fF\9c\fF\9c\fF\9c\fF\9c\fF\9cT~¼üþüüþüüþüüþüüþü¤¶Ü\fF\9c\14N¤\fF\9c\fF\9c\fF\9c\fF\9cìòüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüÜæô\fF\9c\fF\9c\14N¤\fF\9cl\8aļ¾¼üþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüìîìüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþü¼Æä\fF\9c\fF\9c\fF\9c\fF\9c\fF\9c\94ªÔüþüüþüüþüüþüüþüìòü\fF\9c\fF\9c\fF\9c\14N¤\fF\9cT~¼üþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüÄÎä\fF\9c\fF\9c\fF\9c\fF\9c\84\9eÌLNLüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþü<><ÜÞÜüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüìòü\fF\9c\fF\9c\14N¤\fF\9c\fF\9cÜæôüþüüþüüþüüþüüþüüþüDr´\fF\9c\fF\9c\fF\9c\fF\9c\94ªÔüþüüþüüþü¼ÆäT~¼4f¬üþüüþüüþüüþüüþüüþüüþüt\96Ä\fF\9c\14N¤\fF\9c\fF\9cÄÎä\8c\8e\8c|~|üþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþü\8c\8a\8c\ 4\ 2\ 4¬®¬üþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüDr´\fF\9c\fF\9c\fF\9c<j´üþüüþüüþüüþüüþüüþüüþü\94ªÔ\fF\9c\fF\9c\fF\9c\fF\9cÜæôüþüüþü4f¬\fF\9c\fF\9c\fF\9c¼Æäüþüüþüüþüüþüüþüìòü$Z¬\fF\9c\fF\9c\fF\9c\fF\9cìòüÜÞÜ\ 4\ 2\ 4\9c\9e\9cüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüÌÎÌ\f\ e\f\ 4\ 2\ 4|~|üþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþü\94ªÔ\fF\9c\fF\9c\fF\9ct\96ÄüþüüþüüþüüþüüþüüþüüþüÜæô\fF\9c\fF\9c\fF\9c<j´üþüüþüüþüd\8aÄ\fF\9c\fF\9c\fF\9c\14N¤ÔÚìüþüüþüüþüüþüt\96Ä\fF\9c\fF\9c\fF\9c\fF\9cT~¼üþüüþülnl\ 4\ 2\ 4\9c\9e\9cüþüüþüüþüüþüüþüüþüüþüüþüÌÎÌ\f\ e\f\ 4\ 2\ 4\ 4\ 2\ 4\9c\9e\9cüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüÜæô\fF\9c\fF\9c\14N¤ÄÎäüþüüþüüþüüþüüþüüþüüþüüþü$Z¬\14N¤\fF\9ct\96ÄüþüüþüüþüÜæô\14N¤\fF\9c\fF\9c\fF\9c\14N¤\84\9eÌÄÎäÔÚìd\8aÄ\fF\9c\14N¤\fF\9c\fF\9c\14N¤ÄÎäüþüüþüìîì\f\ e\f\ 4\ 2\ 4\8c\8a\8cüþüüþüüþüüþüüþüüþü\8c\8a\8c\f\ e\f\ 4\ 2\ 4\ 4\ 2\ 4,.,üþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþü$Z¬\fF\9c\14N¤üþüüþüüþüüþüüþüüþüüþüüþüüþüt\96Ä\fF\9c\fF\9cÄÎäüþüüþüüþüüþü\84\9eÌ\fF\9c\fF\9c\14N¤\fF\9c\fF\9c\fF\9c\fF\9c\fF\9c\fF\9c\fF\9c\fF\9c\fF\9cT~¼üþüüþüüþüüþü¬®¬\ 4\ 2\ 4\ 4\ 2\ 4\1c\1e\1clnl¬®¬¬®¬lnl\1c\1e\1c\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\f\ e\fÜÞÜüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüt\96Ä\fF\9cd\8aÄüþüüþüüþüüþüüþüüþüüþüüþüüþüÄÎä\fF\9c\14N¤üþüüþüüþüüþüüþüüþüDr´\fF\9c\fF\9c\fF\9c\fF\9c\fF\9c\14N¤\fF\9c\fF\9c\fF\9c\fF\9c4f¬ìòüüþüüþüüþüüþüüþü\9c\9e\9c\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\f\ e\fÌÎÌüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüÄÎä\fF\9c¤¶Üüþüüþüüþüüþüüþüüþüüþüüþüüþüüþü\14N¤d\8aÄüþüüþüüþüüþüüþüüþüìòül\8aÄ\fF\9c\fF\9c\fF\9c\fF\9c\fF\9c\fF\9c\fF\9c\fF\9c<j´ìòüüþüüþüüþüüþüüþüüþüüþü\9c\9e\9c\f\ e\f\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\1c\1e\1cÌÎÌüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþü\14N¤ìòüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüd\8aĤ¶ÜüþüüþüüþüüþüüþüüþüüþüüþüÄÎäT~¼\fF\9c\14N¤\fF\9c\fF\9c<j´¤¶ÜüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüÜÞÜlnl,.,\ 4\ 2\ 4\ 4\ 2\ 4<><\8c\8e\8cìîìüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþü\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4\ 4\ 2\ 4
\ No newline at end of file
diff --git a/automated-tests/resources/lake_front.jpg b/automated-tests/resources/lake_front.jpg
new file mode 100644 (file)
index 0000000..470a679
Binary files /dev/null and b/automated-tests/resources/lake_front.jpg differ
index b6c2ec9..a99d4d3 100644 (file)
@@ -7,16 +7,18 @@ SET(CAPI_LIB "dali-adaptor-internal")
 
 SET(TC_SOURCES
     utc-Dali-AddOns.cpp
+    utc-Dali-BmpLoader.cpp
     utc-Dali-CommandLineOptions.cpp
     utc-Dali-CompressedTextures.cpp
     utc-Dali-FontClient.cpp
     utc-Dali-GifLoader.cpp
     utc-Dali-IcoLoader.cpp
-    utc-Dali-BmpLoader.cpp
     utc-Dali-ImageOperations.cpp
     utc-Dali-Internal-PixelBuffer.cpp
     utc-Dali-Lifecycle-Controller.cpp
+    utc-Dali-LRUCacheContainer.cpp
     utc-Dali-TiltSensor.cpp
+    utc-Dali-WbmpLoader.cpp
 )
 
 
index 843cb92..28449f0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -120,7 +120,7 @@ void TestImageLoading(const ImageDetails& image, const LoadFunctions& functions,
     if(*bufferPtr != *refBufferPtr)
     {
       tet_result(TET_FAIL);
-      tet_printf("%s Failed in %s at line %d\n", __PRETTY_FUNCTION__, __FILE__, __LINE__);
+      tet_printf("%s Failed in %s at line %d, %u'th buffer (input : %u != expect : %u)\n", __PRETTY_FUNCTION__, __FILE__, __LINE__, i, static_cast<unsigned int>(*bufferPtr), static_cast<unsigned int>(*refBufferPtr));
       break;
     }
   }
index 8200c65..7babde8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -38,3 +38,11 @@ int UtcDaliBmp24bpp(void)
 
   END_TEST;
 }
+int UtcDaliBmpRGB8(void)
+{
+  ImageDetails image(TEST_IMAGE_DIR "/w3c_home_256.bmp", 72u, 48u);
+
+  TestImageLoading(image, BmpLoaders);
+
+  END_TEST;
+}
\ No newline at end of file
index 17b7c06..6c54a62 100644 (file)
@@ -402,7 +402,7 @@ int UtcDaliImageOperationsDownscaleBitmap(void)
  */
 int UtcDaliImageOperationsDownscaleInPlacePow2RGB888(void)
 {
-  unsigned outWidth = -1, outHeight = -1;
+  unsigned outWidth = -1, outHeight = -1, outStride = -1;
 
   // Do downscaling to 1 x 1 so we can easily assert the value of the single pixel produced:
 
@@ -410,26 +410,29 @@ int UtcDaliImageOperationsDownscaleInPlacePow2RGB888(void)
   unsigned char check_4x4[16 * 3] = {
     0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff};
 
-  Dali::Internal::Platform::DownscaleInPlacePow2RGB888(check_4x4, 4, 4, 1, 1, BoxDimensionTestBoth, outWidth, outHeight);
+  Dali::Internal::Platform::DownscaleInPlacePow2RGB888(check_4x4, 4, 4, 4, 1, 1, BoxDimensionTestBoth, outWidth, outHeight, outStride);
   DALI_TEST_EQUALS(outWidth, 1u, TEST_LOCATION);
   DALI_TEST_EQUALS(outHeight, 1u, TEST_LOCATION);
+  DALI_TEST_EQUALS(outStride, 1u, TEST_LOCATION);
   DALI_TEST_EQUALS(check_4x4[0], (unsigned char)0x7f, TEST_LOCATION);
 
   // Scale down a 16 pixel black image with a single white pixel to a 1/16th grey single pixel:
   unsigned char single_4x4[16 * 3] = {
     0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-  Dali::Internal::Platform::DownscaleInPlacePow2RGB888(single_4x4, 4, 4, 1, 1, BoxDimensionTestBoth, outWidth, outHeight);
+  Dali::Internal::Platform::DownscaleInPlacePow2RGB888(single_4x4, 4, 4, 4, 1, 1, BoxDimensionTestBoth, outWidth, outHeight, outStride);
   DALI_TEST_EQUALS(outWidth, 1u, TEST_LOCATION);
   DALI_TEST_EQUALS(outHeight, 1u, TEST_LOCATION);
+  DALI_TEST_EQUALS(outStride, 1u, TEST_LOCATION);
   DALI_TEST_EQUALS(single_4x4[0], (unsigned char)0xf, TEST_LOCATION);
 
   // Scale down a 16 pixel black image with a single white pixel to a 1/16th grey single pixel:
   // (white pixel at bottom-right of image)
   unsigned char single_4x4_2[16 * 3] = {
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff};
-  Dali::Internal::Platform::DownscaleInPlacePow2RGB888(single_4x4_2, 4, 4, 1, 1, BoxDimensionTestBoth, outWidth, outHeight);
+  Dali::Internal::Platform::DownscaleInPlacePow2RGB888(single_4x4_2, 4, 4, 4, 1, 1, BoxDimensionTestBoth, outWidth, outHeight, outStride);
   DALI_TEST_EQUALS(outWidth, 1u, TEST_LOCATION);
   DALI_TEST_EQUALS(outHeight, 1u, TEST_LOCATION);
+  DALI_TEST_EQUALS(outStride, 1u, TEST_LOCATION);
   DALI_TEST_EQUALS(single_4x4_2[0], (unsigned char)0xf, TEST_LOCATION);
 
   // Build a larger ~600 x ~600 uniform magenta image for tests which only test output dimensions:
@@ -443,41 +446,50 @@ int UtcDaliImageOperationsDownscaleInPlacePow2RGB888(void)
   }
 
   // Scaling to 0 x 0 should stop at 1 x 1:
-  Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 352, 352, 0, 0, BoxDimensionTestBoth, outWidth, outHeight);
+  Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 352, 352, 352, 0, 0, BoxDimensionTestBoth, outWidth, outHeight, outStride);
   DALI_TEST_EQUALS(outWidth, 1u, TEST_LOCATION);
   DALI_TEST_EQUALS(outHeight, 1u, TEST_LOCATION);
+  DALI_TEST_CHECK(outStride == outWidth);
 
   // Scaling to 1 x 1 should hit 1 x 1:
-  Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 608, 608, 1, 1, BoxDimensionTestBoth, outWidth, outHeight);
+  Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 608, 608, 608, 1, 1, BoxDimensionTestBoth, outWidth, outHeight, outStride);
   DALI_TEST_EQUALS(outWidth, 1u, TEST_LOCATION);
   DALI_TEST_EQUALS(outHeight, 1u, TEST_LOCATION);
+  DALI_TEST_CHECK(outStride == outWidth);
 
   // Scaling to original dimensions should NOP:
-  Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 384, 384, 384, 384, BoxDimensionTestBoth, outWidth, outHeight);
+  Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 384, 384, 384, 384, 384, BoxDimensionTestBoth, outWidth, outHeight, outStride);
   DALI_TEST_EQUALS(outWidth, 384u, TEST_LOCATION);
   DALI_TEST_EQUALS(outHeight, 384u, TEST_LOCATION);
+  DALI_TEST_CHECK(outStride == outWidth);
 
   // More dimension tests:
 
-  Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 352, 352, 44, 11, BoxDimensionTestBoth, outWidth, outHeight);
+  Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 352, 352, 352, 44, 11, BoxDimensionTestBoth, outWidth, outHeight, outStride);
   DALI_TEST_EQUALS(outWidth, 44u, TEST_LOCATION);
   DALI_TEST_EQUALS(outHeight, 44u, TEST_LOCATION);
+  DALI_TEST_CHECK(outStride == outWidth);
 
-  Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 384, 384, 3, 48, BoxDimensionTestBoth, outWidth, outHeight);
+  Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 384, 384, 384, 3, 48, BoxDimensionTestBoth, outWidth, outHeight, outStride);
   DALI_TEST_EQUALS(outWidth, 48u, TEST_LOCATION);
   DALI_TEST_EQUALS(outHeight, 48u, TEST_LOCATION);
+  DALI_TEST_CHECK(outStride == outWidth);
 
-  Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 384, 384, 3, 3, BoxDimensionTestBoth, outWidth, outHeight);
+  Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 384, 384, 384, 3, 3, BoxDimensionTestBoth, outWidth, outHeight, outStride);
   DALI_TEST_CHECK(outWidth == 3u && outHeight == 3u);
+  DALI_TEST_CHECK(outStride == outWidth);
 
-  Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 320, 320, 5, 5, BoxDimensionTestBoth, outWidth, outHeight);
+  Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 320, 320, 320, 5, 5, BoxDimensionTestBoth, outWidth, outHeight, outStride);
   DALI_TEST_CHECK(outWidth == 5u && outHeight == 5u);
+  DALI_TEST_CHECK(outStride == outWidth);
 
-  Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 448, 448, 7, 7, BoxDimensionTestBoth, outWidth, outHeight);
+  Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 448, 448, 448, 7, 7, BoxDimensionTestBoth, outWidth, outHeight, outStride);
   DALI_TEST_CHECK(outWidth == 7u && outHeight == 7u);
+  DALI_TEST_CHECK(outStride == outWidth);
 
-  Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 352, 352, 11, 11, BoxDimensionTestBoth, outWidth, outHeight);
+  Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 352, 352, 352, 11, 11, BoxDimensionTestBoth, outWidth, outHeight, outStride);
   DALI_TEST_CHECK(outWidth == 11u && outHeight == 11u);
+  DALI_TEST_CHECK(outStride == outWidth);
 
   // Check that no pixel values were modified by the repeated averaging of identical pixels in tests above:
   unsigned int numNonMagenta = 0u;
@@ -495,19 +507,22 @@ int UtcDaliImageOperationsDownscaleInPlacePow2RGB888(void)
  */
 void TestDownscaleOutputsExpectedDimensionsRGBA8888(uint32_t pixels[], unsigned inputWidth, unsigned inputHeight, unsigned int desiredWidth, unsigned int desiredHeight, unsigned int expectedWidth, unsigned int expectedHeight, const char* const location)
 {
-  unsigned int resultingWidth = -1, resultingHeight = -1;
+  unsigned int resultingWidth = -1, resultingHeight = -1, resultingStride = -1;
   Dali::Internal::Platform::DownscaleInPlacePow2RGBA8888(
     reinterpret_cast<unsigned char*>(pixels),
     inputWidth,
     inputHeight,
+    inputWidth,
     desiredWidth,
     desiredHeight,
     BoxDimensionTestBoth,
     resultingWidth,
-    resultingHeight);
+    resultingHeight,
+    resultingStride);
 
   DALI_TEST_EQUALS(resultingWidth, expectedWidth, location);
   DALI_TEST_EQUALS(resultingHeight, expectedHeight, location);
+  DALI_TEST_EQUALS(resultingStride, expectedWidth, location);
 }
 
 /**
@@ -515,19 +530,22 @@ void TestDownscaleOutputsExpectedDimensionsRGBA8888(uint32_t pixels[], unsigned
  */
 void TestDownscaleOutputsExpectedDimensionsRGB565(uint16_t pixels[], unsigned inputWidth, unsigned inputHeight, unsigned int desiredWidth, unsigned int desiredHeight, unsigned int expectedWidth, unsigned int expectedHeight, const char* const location)
 {
-  unsigned int resultingWidth = -1, resultingHeight = -1;
+  unsigned int resultingWidth = -1, resultingHeight = -1, resultingStride = -1;
   Dali::Internal::Platform::DownscaleInPlacePow2RGB565(
     reinterpret_cast<unsigned char*>(pixels),
     inputWidth,
     inputHeight,
+    inputWidth,
     desiredWidth,
     desiredHeight,
     BoxDimensionTestBoth,
     resultingWidth,
-    resultingHeight);
+    resultingHeight,
+    resultingStride);
 
   DALI_TEST_EQUALS(resultingWidth, expectedWidth, location);
   DALI_TEST_EQUALS(resultingHeight, expectedHeight, location);
+  DALI_TEST_EQUALS(resultingStride, expectedWidth, location);
 }
 
 /**
@@ -535,19 +553,22 @@ void TestDownscaleOutputsExpectedDimensionsRGB565(uint16_t pixels[], unsigned in
  */
 void TestDownscaleOutputsExpectedDimensions2ComponentPair(uint8_t pixels[], unsigned inputWidth, unsigned inputHeight, unsigned int desiredWidth, unsigned int desiredHeight, unsigned int expectedWidth, unsigned int expectedHeight, const char* const location)
 {
-  unsigned int resultingWidth = -1, resultingHeight = -1;
+  unsigned int resultingWidth = -1, resultingHeight = -1, resultingStride = -1;
   Dali::Internal::Platform::DownscaleInPlacePow2ComponentPair(
     pixels,
     inputWidth,
     inputHeight,
+    inputWidth,
     desiredWidth,
     desiredHeight,
     BoxDimensionTestBoth,
     resultingWidth,
-    resultingHeight);
+    resultingHeight,
+    resultingStride);
 
   DALI_TEST_EQUALS(resultingWidth, expectedWidth, location);
   DALI_TEST_EQUALS(resultingHeight, expectedHeight, location);
+  DALI_TEST_EQUALS(resultingStride, expectedWidth, location);
 }
 
 /**
@@ -555,19 +576,22 @@ void TestDownscaleOutputsExpectedDimensions2ComponentPair(uint8_t pixels[], unsi
  */
 void TestDownscaleOutputsExpectedDimensionsSingleComponent(uint8_t pixels[], unsigned inputWidth, unsigned inputHeight, unsigned int desiredWidth, unsigned int desiredHeight, unsigned int expectedWidth, unsigned int expectedHeight, const char* const location)
 {
-  unsigned int resultingWidth = -1, resultingHeight = -1;
+  unsigned int resultingWidth = -1, resultingHeight = -1, resultingStride = -1;
   Dali::Internal::Platform::DownscaleInPlacePow2SingleBytePerPixel(
     pixels,
     inputWidth,
     inputHeight,
+    inputWidth,
     desiredWidth,
     desiredHeight,
     BoxDimensionTestBoth,
     resultingWidth,
-    resultingHeight);
+    resultingHeight,
+    resultingStride);
 
   DALI_TEST_EQUALS(resultingWidth, expectedWidth, location);
   DALI_TEST_EQUALS(resultingHeight, expectedHeight, location);
+  DALI_TEST_EQUALS(resultingStride, expectedWidth, location);
 }
 
 /**
@@ -581,58 +605,68 @@ int UtcDaliImageOperationsDownscaleInPlacePow2RGBA8888(void)
     image[i] = 0xffffffff;
   }
   unsigned char* const pixels         = reinterpret_cast<unsigned char*>(image);
-  unsigned int         resultingWidth = -1, resultingHeight = -1;
+  unsigned int         resultingWidth = -1, resultingHeight = -1, resultingStride = -1;
 
   // Test downscaling where the input size is an exact multiple of the desired size:
   // (We expect a perfect result here)
 
-  DownscaleInPlacePow2RGBA8888(pixels, 600, 600, 75, 75, BoxDimensionTestBoth, resultingWidth, resultingHeight);
+  DownscaleInPlacePow2RGBA8888(pixels, 600, 600, 600, 75, 75, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
   DALI_TEST_EQUALS(resultingWidth, 75u, TEST_LOCATION);
   DALI_TEST_EQUALS(resultingHeight, 75u, TEST_LOCATION);
+  DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
 
-  DownscaleInPlacePow2RGBA8888(pixels, 512, 512, 16, 16, BoxDimensionTestBoth, resultingWidth, resultingHeight);
+  DownscaleInPlacePow2RGBA8888(pixels, 512, 512, 512, 16, 16, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
   DALI_TEST_EQUALS(resultingWidth, 16u, TEST_LOCATION);
   DALI_TEST_EQUALS(resultingHeight, 16u, TEST_LOCATION);
+  DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
 
-  DownscaleInPlacePow2RGBA8888(pixels, 512, 64, 16, 2, BoxDimensionTestBoth, resultingWidth, resultingHeight);
+  DownscaleInPlacePow2RGBA8888(pixels, 512, 64, 512, 16, 2, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
   DALI_TEST_EQUALS(resultingWidth, 16u, TEST_LOCATION);
   DALI_TEST_EQUALS(resultingHeight, 2u, TEST_LOCATION);
+  DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
 
-  DownscaleInPlacePow2RGBA8888(pixels, 64, 1024, 4, 64, BoxDimensionTestBoth, resultingWidth, resultingHeight);
+  DownscaleInPlacePow2RGBA8888(pixels, 64, 1024, 64, 4, 64, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
   DALI_TEST_EQUALS(resultingWidth, 4u, TEST_LOCATION);
   DALI_TEST_EQUALS(resultingHeight, 64u, TEST_LOCATION);
+  DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
 
   // Test downscaling where the input size is slightly off being an exact multiple of the desired size:
   // (We expect a perfect match at the end because of rounding-down to an even width and height at each step)
 
-  DownscaleInPlacePow2RGBA8888(pixels, 601, 603, 75, 75, BoxDimensionTestBoth, resultingWidth, resultingHeight);
+  DownscaleInPlacePow2RGBA8888(pixels, 601, 603, 601, 75, 75, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
   DALI_TEST_EQUALS(resultingWidth, 75u, TEST_LOCATION);
   DALI_TEST_EQUALS(resultingHeight, 75u, TEST_LOCATION);
+  DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
 
-  DownscaleInPlacePow2RGBA8888(pixels, 736 + 1, 352 + 3, 23, 11, BoxDimensionTestBoth, resultingWidth, resultingHeight);
+  DownscaleInPlacePow2RGBA8888(pixels, 736 + 1, 352 + 3, 736 + 1, 23, 11, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
   DALI_TEST_EQUALS(resultingWidth, 23u, TEST_LOCATION);
   DALI_TEST_EQUALS(resultingHeight, 11u, TEST_LOCATION);
+  DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
 
-  DownscaleInPlacePow2RGBA8888(pixels, 384 + 3, 896 + 1, 3, 7, BoxDimensionTestBoth, resultingWidth, resultingHeight);
+  DownscaleInPlacePow2RGBA8888(pixels, 384 + 3, 896 + 1, 384 + 3, 3, 7, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
   DALI_TEST_EQUALS(resultingWidth, 3u, TEST_LOCATION);
   DALI_TEST_EQUALS(resultingHeight, 7u, TEST_LOCATION);
+  DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
 
   // Test downscales with source dimensions which are under a nice power of two by one:
 
   // The target is hit exactly due to losing spare columns or rows at each iteration:
-  DownscaleInPlacePow2RGBA8888(pixels, 63, 31, 7, 3, BoxDimensionTestBoth, resultingWidth, resultingHeight);
+  DownscaleInPlacePow2RGBA8888(pixels, 63, 31, 63, 7, 3, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
   DALI_TEST_EQUALS(resultingWidth, 7u, TEST_LOCATION);
   DALI_TEST_EQUALS(resultingHeight, 3u, TEST_LOCATION);
+  DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
 
   // Asking to downscale a bit smaller should stop at the dimensions of the last test as one more halving would go down to 3 x 1, which is too small.
-  DownscaleInPlacePow2RGBA8888(pixels, 63, 31, 4, 2, BoxDimensionTestBoth, resultingWidth, resultingHeight);
+  DownscaleInPlacePow2RGBA8888(pixels, 63, 31, 63, 4, 2, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
   DALI_TEST_EQUALS(resultingWidth, 7u, TEST_LOCATION);
   DALI_TEST_EQUALS(resultingHeight, 3u, TEST_LOCATION);
+  DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
 
   // Should stop at almost twice the requested dimensions:
-  DownscaleInPlacePow2RGBA8888(pixels, 15, 127, 4, 32, BoxDimensionTestBoth, resultingWidth, resultingHeight);
+  DownscaleInPlacePow2RGBA8888(pixels, 15, 127, 15, 4, 32, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
   DALI_TEST_EQUALS(resultingWidth, 7u, TEST_LOCATION);
   DALI_TEST_EQUALS(resultingHeight, 63u, TEST_LOCATION);
+  DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
 
   // Test downscales to 1 in one or both dimensions:
   // Parameters:                                         input-x  input-y, desired-x, desired-y, expected-x, expected-y
@@ -678,22 +712,25 @@ int UtcDaliImageOperationsDownscaleInPlacePow2RGBA8888Nops(void)
   }
   const uint32_t       imageHash      = HashPixels(image, numPixels);
   unsigned char* const pixels         = reinterpret_cast<unsigned char*>(image);
-  unsigned int         resultingWidth = -1, resultingHeight = -1;
+  unsigned int         resultingWidth = -1, resultingHeight = -1, resultingStride = -1;
 
   // Test downscales to the same size:
   // The point is just to be sure the downscale is a NOP in this case:
 
-  DownscaleInPlacePow2RGBA8888(pixels, 600, 600, 600, 600, BoxDimensionTestBoth, resultingWidth, resultingHeight);
+  DownscaleInPlacePow2RGBA8888(pixels, 600, 600, 600, 600, 600, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
   DALI_TEST_EQUALS(resultingWidth, 600u, TEST_LOCATION);
   DALI_TEST_EQUALS(resultingHeight, 600u, TEST_LOCATION);
+  DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
 
-  DownscaleInPlacePow2RGBA8888(pixels, 512, 128, 512, 128, BoxDimensionTestBoth, resultingWidth, resultingHeight);
+  DownscaleInPlacePow2RGBA8888(pixels, 512, 128, 512, 512, 128, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
   DALI_TEST_EQUALS(resultingWidth, 512u, TEST_LOCATION);
   DALI_TEST_EQUALS(resultingHeight, 128u, TEST_LOCATION);
+  DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
 
-  DownscaleInPlacePow2RGBA8888(pixels, 17, 1001, 17, 1001, BoxDimensionTestBoth, resultingWidth, resultingHeight);
+  DownscaleInPlacePow2RGBA8888(pixels, 17, 1001, 17, 17, 1001, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
   DALI_TEST_EQUALS(resultingWidth, 17u, TEST_LOCATION);
   DALI_TEST_EQUALS(resultingHeight, 1001u, TEST_LOCATION);
+  DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
 
   // Test downscales that request a larger size (we never upscale so these are NOPs too):
   // Parameters:                                         input-x  input-y, desired-x, desired-y, expected-x, expected-y
@@ -714,8 +751,8 @@ int UtcDaliImageOperationsDownscaleInPlacePow2RGBA8888Nops(void)
 int UtcDaliImageOperationsDownscaleInPlacePow2RGB565(void)
 {
   // Test that calling with null and zero parameters doesn't blow up:
-  unsigned int outWidth, outHeight;
-  DownscaleInPlacePow2RGB565(0, 0, 0, 0, 0, BoxDimensionTestBoth, outWidth, outHeight);
+  unsigned int outWidth, outHeight, outStride;
+  DownscaleInPlacePow2RGB565(0, 0, 0, 0, 0, 0, BoxDimensionTestBoth, outWidth, outHeight, outStride);
 
   uint16_t image[608 * 608];
   for(unsigned i = 0; i < sizeof(image) / sizeof(image[0]); ++i)
@@ -754,8 +791,8 @@ int UtcDaliImageOperationsDownscaleInPlacePow2RGB565(void)
 int UtcDaliImageOperationsDownscaleInPlacePow2ComponentPair(void)
 {
   // Simple test that a null pointer does not get dereferenced in the function:
-  unsigned int outWidth, outHeight;
-  DownscaleInPlacePow2ComponentPair(0, 0, 0, 0, 0, BoxDimensionTestBoth, outWidth, outHeight);
+  unsigned int outWidth, outHeight, outStride;
+  DownscaleInPlacePow2ComponentPair(0, 0, 0, 0, 0, 0, BoxDimensionTestBoth, outWidth, outHeight, outStride);
 
   // Simple tests of dimensions output:
 
@@ -793,8 +830,8 @@ int UtcDaliImageOperationsDownscaleInPlacePow2ComponentPair(void)
 int UtcDaliImageOperationsDownscaleInPlacePow2SingleBytePerPixel(void)
 {
   // Simple test that a null pointer does not get dereferenced in the function:
-  unsigned int outWidth, outHeight;
-  DownscaleInPlacePow2SingleBytePerPixel(0, 0, 0, 0, 0, BoxDimensionTestBoth, outWidth, outHeight);
+  unsigned int outWidth, outHeight, outStride;
+  DownscaleInPlacePow2SingleBytePerPixel(0, 0, 0, 0, 0, 0, BoxDimensionTestBoth, outWidth, outHeight, outStride);
 
   // Tests of output dimensions from downscaling:
   uint8_t image[608 * 608];
@@ -950,6 +987,26 @@ int UtcDaliImageOperationsHalveScanlineInPlace1Byte(void)
 /**
  * @brief Test the function for averaging vertically-adjacent pairs of single-byte-per-pixel pixels on a scanline.
  */
+int UtcDaliImageOperationsAverageScanlines1ExceptTest(void)
+{
+  // Edge cases for averagescanlines1:
+  unsigned char shortEven1[]   = {0x00, 0x00, 0xff, 0xff, 0xff, 0xfe, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x02, 0x03, 0x00, 0x01};
+  unsigned char shortEven2[]   = {0x00, 0xff, 0x00, 0xff, 0x01, 0x01, 0xff, 0xfe, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x03, 0x02};
+  unsigned char expectBuffer[] = {0x00, 0x7f, 0x7f, 0xff, 0x80, 0x7f, 0x80, 0x7f, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01};
+  unsigned char outputBuffer[sizeof(shortEven1)];
+
+  AverageScanlines1(shortEven1, shortEven2, outputBuffer, sizeof(shortEven1));
+  for(unsigned i = 0; i < sizeof(shortEven1); ++i)
+  {
+    DALI_TEST_EQUALS(unsigned(outputBuffer[i]), unsigned(expectBuffer[i]), TEST_LOCATION);
+  }
+
+  END_TEST;
+}
+
+/**
+ * @brief Test the function for averaging vertically-adjacent pairs of single-byte-per-pixel pixels on a scanline.
+ */
 int UtcDaliImageOperationsAverageScanlines1(void)
 {
   // Red and cyan, averaging to grey:
@@ -964,19 +1021,55 @@ int UtcDaliImageOperationsAverageScanlines1(void)
   }
 
   // Longer test reusing RGBA setup/test logic:
-  const size_t           scanlineLength = 4096u;
-  Dali::Vector<uint32_t> scanline1;
-  Dali::Vector<uint32_t> scanline2;
-  Dali::Vector<uint32_t> reference;
-  Dali::Vector<uint32_t> output;
-  SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
+  {
+    const size_t           scanlineLength = 4096u;
+    Dali::Vector<uint32_t> scanline1;
+    Dali::Vector<uint32_t> scanline2;
+    Dali::Vector<uint32_t> reference;
+    Dali::Vector<uint32_t> output;
+    SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
+
+    AverageScanlines1((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 4);
+
+    // Check the output matches the independently generated reference:
+    size_t numMatches = 0;
+    MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
+    DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
+  }
 
-  AverageScanlines1((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 4);
+  // Longer test reusing RGBA setup/test logic with none-8-divisable length
+  {
+    const size_t           scanlineLength = 1003u;
+    Dali::Vector<uint32_t> scanline1;
+    Dali::Vector<uint32_t> scanline2;
+    Dali::Vector<uint32_t> reference;
+    Dali::Vector<uint32_t> output;
+    SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
+
+    AverageScanlines1((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 4);
+
+    // Check the output matches the independently generated reference:
+    size_t numMatches = 0;
+    MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
+    DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
+  }
 
-  // Check the output matches the independently generated reference:
-  size_t numMatches = 0;
-  MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
-  DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
+  // Very short test reusing RGBA setup/test logic with less-than-8 length
+  {
+    const size_t           scanlineLength = 1003u;
+    Dali::Vector<uint32_t> scanline1;
+    Dali::Vector<uint32_t> scanline2;
+    Dali::Vector<uint32_t> reference;
+    Dali::Vector<uint32_t> output;
+    SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
+
+    AverageScanlines1((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 4);
+
+    // Check the output matches the independently generated reference:
+    size_t numMatches = 0;
+    MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
+    DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
+  }
 
   END_TEST;
 }
@@ -999,19 +1092,55 @@ int UtcDaliImageOperationsAverageScanlines2(void)
   }
 
   // Longer test reusing RGBA setup/test logic:
-  const size_t           scanlineLength = 4096u;
-  Dali::Vector<uint32_t> scanline1;
-  Dali::Vector<uint32_t> scanline2;
-  Dali::Vector<uint32_t> reference;
-  Dali::Vector<uint32_t> output;
-  SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
+  {
+    const size_t           scanlineLength = 4096u;
+    Dali::Vector<uint32_t> scanline1;
+    Dali::Vector<uint32_t> scanline2;
+    Dali::Vector<uint32_t> reference;
+    Dali::Vector<uint32_t> output;
+    SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
+
+    AverageScanlines2((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 2);
+
+    // Check the output matches the independently generated reference:
+    size_t numMatches = 0;
+    MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
+    DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
+  }
 
-  AverageScanlines2((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 2);
+  // Longer test reusing RGBA setup/test logic with none-8-divisable length
+  {
+    const size_t           scanlineLength = 501u;
+    Dali::Vector<uint32_t> scanline1;
+    Dali::Vector<uint32_t> scanline2;
+    Dali::Vector<uint32_t> reference;
+    Dali::Vector<uint32_t> output;
+    SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
+
+    AverageScanlines2((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 2);
+
+    // Check the output matches the independently generated reference:
+    size_t numMatches = 0;
+    MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
+    DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
+  }
 
-  // Check the output matches the independently generated reference:
-  size_t numMatches = 0;
-  MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
-  DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
+  // Very short test reusing RGBA setup/test logic with less-than-8 length
+  {
+    const size_t           scanlineLength = 3u;
+    Dali::Vector<uint32_t> scanline1;
+    Dali::Vector<uint32_t> scanline2;
+    Dali::Vector<uint32_t> reference;
+    Dali::Vector<uint32_t> output;
+    SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
+
+    AverageScanlines2((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 2);
+
+    // Check the output matches the independently generated reference:
+    size_t numMatches = 0;
+    MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
+    DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
+  }
 
   END_TEST;
 }
@@ -1033,19 +1162,55 @@ int UtcDaliImageOperationsAverageScanlines3(void)
   }
 
   // Longer test reusing RGBA setup/test logic:
-  const size_t           scanlineLength = 3 * 4 * 90u;
-  Dali::Vector<uint32_t> scanline1;
-  Dali::Vector<uint32_t> scanline2;
-  Dali::Vector<uint32_t> reference;
-  Dali::Vector<uint32_t> output;
-  SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
+  {
+    const size_t           scanlineLength = 3 * 4 * 90u;
+    Dali::Vector<uint32_t> scanline1;
+    Dali::Vector<uint32_t> scanline2;
+    Dali::Vector<uint32_t> reference;
+    Dali::Vector<uint32_t> output;
+    SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
+
+    AverageScanlines3((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 4 / 3);
+
+    // Check the output matches the independently generated reference:
+    size_t numMatches = 0;
+    MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
+    DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
+  }
 
-  AverageScanlines3((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 4 / 3);
+  // Longer test reusing RGBA setup/test logic with none-8-divisable length
+  {
+    const size_t           scanlineLength = 3 * 501u;
+    Dali::Vector<uint32_t> scanline1;
+    Dali::Vector<uint32_t> scanline2;
+    Dali::Vector<uint32_t> reference;
+    Dali::Vector<uint32_t> output;
+    SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
+
+    AverageScanlines3((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 4 / 3);
+
+    // Check the output matches the independently generated reference:
+    size_t numMatches = 0;
+    MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
+    DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
+  }
 
-  // Check the output matches the independently generated reference:
-  size_t numMatches = 0;
-  MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
-  DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
+  // Very short test reusing RGBA setup/test logic with less-than-8 length
+  {
+    const size_t           scanlineLength = 3u;
+    Dali::Vector<uint32_t> scanline1;
+    Dali::Vector<uint32_t> scanline2;
+    Dali::Vector<uint32_t> reference;
+    Dali::Vector<uint32_t> output;
+    SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
+
+    AverageScanlines3((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 4 / 3);
+
+    // Check the output matches the independently generated reference:
+    size_t numMatches = 0;
+    MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
+    DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
+  }
 
   END_TEST;
 }
@@ -1170,7 +1335,7 @@ int UtcDaliImageOperationsPointSampleCheckerboardRGBA888(void)
 
   uint32_t outputImage[desiredWidth * desiredHeight];
 
-  Dali::Internal::Platform::PointSample4BPP((const unsigned char*)&image->GetVector()[0], 256, 256, (unsigned char*)outputImage, desiredWidth, desiredHeight);
+  Dali::Internal::Platform::PointSample4BPP((const unsigned char*)&image->GetVector()[0], 256, 256, 256, (unsigned char*)outputImage, desiredWidth, desiredHeight);
 
   DALI_TEST_EQUALS(outputImage[0], (uint32_t)0xff0000ff, TEST_LOCATION);         // < Red corner pixel
   DALI_TEST_EQUALS(outputImage[7], (uint32_t)0xff00ff00, TEST_LOCATION);         // < Green corner pixel
@@ -1239,7 +1404,7 @@ int UtcDaliImageOperationsPointSampleRGBA888PixelsCorrectColor(void)
   buffer.resize(outputBufferSize);
   uint32_t* outputImage = &buffer[0];
 
-  Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, inputWidth, inputHeight, (unsigned char*)outputImage, desiredWidth, desiredHeight);
+  Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, inputWidth, inputHeight, inputWidth, (unsigned char*)outputImage, desiredWidth, desiredHeight);
 
   // Check that all the output pixels are the right color:
   const uint32_t reference           = inputImage[inputWidth * inputHeight / 2];
@@ -1272,38 +1437,38 @@ int UtcDaliImageOperationsPointSampleRGBA888ScaleToSinglePixel(void)
   // Try several different starting image sizes:
 
   // 1x1 -> 1x1:
-  Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1, 1, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
+  Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1, 1, 1, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
   DALI_TEST_EQUALS(outputImage, inputImage[0], TEST_LOCATION);
   outputImage = 0;
 
   // Single-pixel wide tall stripe:
-  Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1, 1024, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
+  Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1, 1024, 1, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
   DALI_TEST_EQUALS(outputImage, inputImage[0], TEST_LOCATION);
   outputImage = 0;
 
   // Single-pixel tall, wide strip:
-  Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1024, 1, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
+  Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1024, 1, 1024, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
   DALI_TEST_EQUALS(outputImage, inputImage[0], TEST_LOCATION);
   outputImage = 0;
 
   // Square mid-size image:
-  Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 103, 103, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
+  Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 103, 103, 103, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
   DALI_TEST_EQUALS(outputImage, inputImage[0], TEST_LOCATION);
   outputImage = 0;
 
   // Wide mid-size image:
-  Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 313, 79, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
+  Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 313, 79, 313, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
   DALI_TEST_EQUALS(outputImage, inputImage[0], TEST_LOCATION);
   outputImage = 0;
 
   // Tall mid-size image:
-  Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 53, 467, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
+  Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 53, 467, 53, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
   DALI_TEST_EQUALS(outputImage, inputImage[0], TEST_LOCATION);
   outputImage = 0;
 
   // 0 x 0 input image (make sure output not written to):
   outputImage = 0xDEADBEEF;
-  Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 0, 0, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
+  Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 0, 0, 0, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
   DALI_TEST_EQUALS(outputImage, (uint32_t)0xDEADBEEF, TEST_LOCATION);
   outputImage = 0;
 
@@ -1324,31 +1489,31 @@ int UtcDaliImageOperationsPointSampleRGBA888N(void)
   // Try several different starting image sizes:
 
   // 1x1 -> 1x1:
-  Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1, 1, (unsigned char*)outputImage, 0, 0);
+  Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1, 1, 1, (unsigned char*)outputImage, 0, 0);
   DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION);
 
   // Single-pixel wide tall stripe:
-  Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1, 102, (unsigned char*)outputImage, 0, 33);
+  Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1, 102, 1, (unsigned char*)outputImage, 0, 33);
   DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION);
 
   // Single-pixel tall, wide strip:
-  Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 102, 1, (unsigned char*)outputImage, 0, 67);
+  Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 102, 1, 102, (unsigned char*)outputImage, 0, 67);
   DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION);
 
   // Square mid-size image:
-  Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 103, 103, (unsigned char*)outputImage, 21, 0);
+  Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 103, 103, 103, (unsigned char*)outputImage, 21, 0);
   DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION);
 
   // Wide mid-size image to 0 height
-  Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 313, 79, (unsigned char*)outputImage, 99, 0);
+  Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 313, 79, 313, (unsigned char*)outputImage, 99, 0);
   DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION);
 
   // Tall mid-size image to 0 height, over width
-  Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 53, 46, (unsigned char*)outputImage, 9999, 0);
+  Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 53, 46, 53, (unsigned char*)outputImage, 9999, 0);
   DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION);
 
   // 0 x 0 input image:
-  Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 0, 0, (unsigned char*)outputImage, 200, 99);
+  Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 0, 0, 0, (unsigned char*)outputImage, 200, 99);
   DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION);
 
   END_TEST;
diff --git a/automated-tests/src/dali-adaptor-internal/utc-Dali-LRUCacheContainer.cpp b/automated-tests/src/dali-adaptor-internal/utc-Dali-LRUCacheContainer.cpp
new file mode 100644 (file)
index 0000000..08476ea
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2014 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 <iostream>
+#include <string>
+
+#include <dali-test-suite-utils.h>
+#include <dali/internal/text/text-abstraction/plugin/lru-cache-container.h>
+
+using namespace Dali::TextAbstraction::Internal;
+using TestLRUCacheIntInt    = LRUCacheContainer<int, int>;
+using TestLRUCacheIntString = LRUCacheContainer<int, std::string>;
+
+namespace
+{
+template<typename K, typename E>
+void TestLRUCacheExist(LRUCacheContainer<K, E>& cache, const K& key, bool expectExist, const char* location)
+{
+  auto iter = cache.Find(key);
+  DALI_TEST_EQUALS((iter != cache.End()), expectExist, location);
+}
+
+template<typename K, typename E>
+void TestLRUCachePop(LRUCacheContainer<K, E>& cache, const E& expectElement, const char* location)
+{
+  auto popElement = cache.Pop();
+  DALI_TEST_EQUALS(popElement, expectElement, location);
+}
+} // namespace
+
+void utc_dali_internal_lru_cache_container_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_internal_lru_cache_container_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliLRUCacheContainerPushPopTest(void)
+{
+  TestLRUCacheIntInt cache(3);
+
+  tet_infoline("Test LRUCache Push and Pop");
+
+  DALI_TEST_EQUALS(cache.IsEmpty(), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(cache.IsFull(), false, TEST_LOCATION);
+
+  cache.Push(1111, 111);
+  DALI_TEST_EQUALS(cache.IsEmpty(), false, TEST_LOCATION);
+
+  cache.Push(2222, 222);
+  cache.Push(3333, 333);
+  DALI_TEST_EQUALS(cache.IsFull(), true, TEST_LOCATION);
+
+  cache.Push(4444, 444);
+  DALI_TEST_EQUALS(cache.IsFull(), true, TEST_LOCATION);
+
+  TestLRUCacheExist(cache, 1111, false, TEST_LOCATION);
+  TestLRUCacheExist(cache, 2222, true, TEST_LOCATION);
+  TestLRUCacheExist(cache, 3333, true, TEST_LOCATION);
+  TestLRUCacheExist(cache, 4444, true, TEST_LOCATION);
+
+  TestLRUCachePop(cache, 222, TEST_LOCATION);
+  DALI_TEST_EQUALS(cache.IsFull(), false, TEST_LOCATION);
+
+  TestLRUCachePop(cache, 333, TEST_LOCATION);
+  DALI_TEST_EQUALS(cache.IsEmpty(), false, TEST_LOCATION);
+  DALI_TEST_EQUALS(cache.IsFull(), false, TEST_LOCATION);
+
+  cache.Push(5555, 555);
+  cache.Push(6666, 666);
+
+  // Replace exist key
+  cache.Push(5555, 777);
+  DALI_TEST_EQUALS(cache.IsFull(), true, TEST_LOCATION);
+
+  // Change element
+  DALI_TEST_EQUALS(cache.Get(5555), 777, TEST_LOCATION);
+  cache.Get(5555) = 888;
+  DALI_TEST_EQUALS(cache.Get(5555), 888, TEST_LOCATION);
+
+  TestLRUCachePop(cache, 444, TEST_LOCATION);
+
+  TestLRUCacheExist(cache, 2222, false, TEST_LOCATION);
+  TestLRUCacheExist(cache, 3333, false, TEST_LOCATION);
+  TestLRUCacheExist(cache, 4444, false, TEST_LOCATION);
+
+  TestLRUCachePop(cache, 666, TEST_LOCATION);
+  TestLRUCachePop(cache, 888, TEST_LOCATION);
+  DALI_TEST_EQUALS(cache.IsEmpty(), true, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliLRUCacheContainerPushPopTest2(void)
+{
+  TestLRUCacheIntString cache(3);
+
+  tet_infoline("Test LRUCache Push and Pop 2");
+
+  DALI_TEST_EQUALS(cache.IsEmpty(), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(cache.IsFull(), false, TEST_LOCATION);
+
+  cache.Push(1111, "111");
+  DALI_TEST_EQUALS(cache.IsEmpty(), false, TEST_LOCATION);
+
+  cache.Push(2222, "222");
+  cache.Push(3333, "333");
+  DALI_TEST_EQUALS(cache.IsFull(), true, TEST_LOCATION);
+
+  cache.Push(4444, "444");
+  DALI_TEST_EQUALS(cache.IsFull(), true, TEST_LOCATION);
+
+  TestLRUCacheExist(cache, 1111, false, TEST_LOCATION);
+  TestLRUCacheExist(cache, 2222, true, TEST_LOCATION);
+  TestLRUCacheExist(cache, 3333, true, TEST_LOCATION);
+  TestLRUCacheExist(cache, 4444, true, TEST_LOCATION);
+
+  TestLRUCachePop(cache, std::string("222"), TEST_LOCATION);
+  DALI_TEST_EQUALS(cache.IsFull(), false, TEST_LOCATION);
+
+  TestLRUCachePop(cache, std::string("333"), TEST_LOCATION);
+  DALI_TEST_EQUALS(cache.IsEmpty(), false, TEST_LOCATION);
+  DALI_TEST_EQUALS(cache.IsFull(), false, TEST_LOCATION);
+
+  cache.Push(5555, "555");
+  cache.Push(6666, "666");
+
+  // Replace exist key
+  cache.Push(5555, "777");
+  DALI_TEST_EQUALS(cache.IsFull(), true, TEST_LOCATION);
+
+  // Change element
+  DALI_TEST_EQUALS(cache.Get(5555), "777", TEST_LOCATION);
+  cache.Get(5555) = "888";
+  DALI_TEST_EQUALS(cache.Get(5555), "888", TEST_LOCATION);
+
+  TestLRUCachePop(cache, std::string("444"), TEST_LOCATION);
+
+  TestLRUCacheExist(cache, 2222, false, TEST_LOCATION);
+  TestLRUCacheExist(cache, 3333, false, TEST_LOCATION);
+  TestLRUCacheExist(cache, 4444, false, TEST_LOCATION);
+
+  TestLRUCachePop(cache, std::string("666"), TEST_LOCATION);
+  TestLRUCachePop(cache, std::string("888"), TEST_LOCATION);
+  DALI_TEST_EQUALS(cache.IsEmpty(), true, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliLRUCacheContainerPopEmptyNegative(void)
+{
+  TestLRUCacheIntInt cache(3);
+
+  tet_infoline("Test LRUCache Pop empty");
+
+  try
+  {
+    cache.Pop();
+    DALI_TEST_CHECK(false); // Should not get here
+  }
+  catch(...)
+  {
+    DALI_TEST_CHECK(true); // Asserted
+  }
+
+  END_TEST;
+}
+
+int UtcDaliLRUCacheContainerGetInvalidNegative(void)
+{
+  TestLRUCacheIntInt cache(3);
+
+  tet_infoline("Test LRUCache Get with invalid key");
+
+  cache.Push(111, 1);
+  cache.Push(222, 2);
+  cache.Push(333, 3);
+  cache.Push(444, 4);
+
+  try
+  {
+    cache.Get(111);
+    DALI_TEST_CHECK(false); // Should not get here
+  }
+  catch(...)
+  {
+    DALI_TEST_CHECK(true); // Asserted
+  }
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-adaptor-internal/utc-Dali-WbmpLoader.cpp b/automated-tests/src/dali-adaptor-internal/utc-Dali-WbmpLoader.cpp
new file mode 100644 (file)
index 0000000..8b2b6d7
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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 <stdlib.h>
+#include <iostream>
+
+#include <dali/internal/imaging/common/loader-wbmp.h>
+#include "image-loaders.h"
+
+using namespace Dali;
+
+namespace
+{
+static const LoadFunctions WbmpLoaders(TizenPlatform::LoadWbmpHeader, TizenPlatform::LoadBitmapFromWbmp);
+
+} // Unnamed namespace.
+
+int UtcDaliWbmpLoader(void)
+{
+  ImageDetails image(TEST_IMAGE_DIR "/test-image.wbmp", 32u, 64u);
+
+  TestImageLoading(image, WbmpLoaders);
+
+  END_TEST;
+}
\ No newline at end of file
index 2862284..873b7b3 100644 (file)
@@ -179,7 +179,7 @@ void TestApplication::SendNotification()
   mCore->ProcessEvents();
 }
 
-void TestApplication::DoUpdate(uint32_t intervalMilliseconds, const char* location)
+void TestApplication::DoUpdate(uint32_t intervalMilliseconds, const char* location, bool uploadOnly)
 {
   if(GetUpdateStatus() == 0 &&
      mRenderStatus.NeedsUpdate() == false &&
@@ -191,25 +191,28 @@ void TestApplication::DoUpdate(uint32_t intervalMilliseconds, const char* locati
   uint32_t nextVSyncTime  = mLastVSyncTime + intervalMilliseconds;
   float    elapsedSeconds = static_cast<float>(intervalMilliseconds) * 0.001f;
 
-  mCore->Update(elapsedSeconds, mLastVSyncTime, nextVSyncTime, mStatus, false, false);
+  mCore->Update(elapsedSeconds, mLastVSyncTime, nextVSyncTime, mStatus, false, false, uploadOnly);
 
   GetRenderController().Initialize();
 
   mLastVSyncTime = nextVSyncTime;
 }
 
-bool TestApplication::Render(uint32_t intervalMilliseconds, const char* location)
+bool TestApplication::Render(uint32_t intervalMilliseconds, const char* location, bool uploadOnly)
 {
-  DoUpdate(intervalMilliseconds, location);
+  DoUpdate(intervalMilliseconds, location, uploadOnly);
 
   // Reset the status
   mRenderStatus.SetNeedsUpdate(false);
   mRenderStatus.SetNeedsPostRender(false);
 
-  mCore->PreRender(mRenderStatus, false /*do not force clear*/, false /*do not skip rendering*/);
-  mCore->RenderScene(mRenderStatus, mScene, true /*render the off-screen buffers*/);
-  mCore->RenderScene(mRenderStatus, mScene, false /*render the surface*/);
-  mCore->PostRender(false /*do not skip rendering*/);
+  mCore->PreRender(mRenderStatus, false /*do not force clear*/);
+  if(!uploadOnly)
+  {
+    mCore->RenderScene(mRenderStatus, mScene, true /*render the off-screen buffers*/);
+    mCore->RenderScene(mRenderStatus, mScene, false /*render the surface*/);
+  }
+  mCore->PostRender();
 
   mFrame++;
 
@@ -220,7 +223,7 @@ bool TestApplication::PreRenderWithPartialUpdate(uint32_t intervalMilliseconds,
 {
   DoUpdate(intervalMilliseconds, location);
 
-  mCore->PreRender(mRenderStatus, false /*do not force clear*/, false /*do not skip rendering*/);
+  mCore->PreRender(mRenderStatus, false /*do not force clear*/);
   mCore->PreRender(mScene, damagedRects);
 
   return mStatus.KeepUpdating() || mRenderStatus.NeedsUpdate();
@@ -230,7 +233,7 @@ bool TestApplication::RenderWithPartialUpdate(std::vector<Rect<int>>& damagedRec
 {
   mCore->RenderScene(mRenderStatus, mScene, true /*render the off-screen buffers*/);
   mCore->RenderScene(mRenderStatus, mScene, false /*render the surface*/, clippingRect);
-  mCore->PostRender(false /*do not skip rendering*/);
+  mCore->PostRender();
 
   mFrame++;
 
@@ -261,10 +264,10 @@ bool TestApplication::GetRenderNeedsPostRender()
 bool TestApplication::RenderOnly()
 {
   // Update Time values
-  mCore->PreRender(mRenderStatus, false /*do not force clear*/, false /*do not skip rendering*/);
+  mCore->PreRender(mRenderStatus, false /*do not force clear*/);
   mCore->RenderScene(mRenderStatus, mScene, true /*render the off-screen buffers*/);
   mCore->RenderScene(mRenderStatus, mScene, false /*render the surface*/);
-  mCore->PostRender(false /*do not skip rendering*/);
+  mCore->PostRender();
 
   mFrame++;
 
index 02143a7..1b101c5 100644 (file)
@@ -72,7 +72,7 @@ public:
 
   void        ProcessEvent(const Integration::Event& event);
   void        SendNotification();
-  bool        Render(uint32_t intervalMilliseconds = DEFAULT_RENDER_INTERVAL, const char* location = NULL);
+  bool        Render(uint32_t intervalMilliseconds = DEFAULT_RENDER_INTERVAL, const char* location = NULL, bool uploadOnly = false);
   bool        PreRenderWithPartialUpdate(uint32_t intervalMilliseconds, const char* location, std::vector<Rect<int>>& damagedRects);
   bool        RenderWithPartialUpdate(std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect);
   uint32_t    GetUpdateStatus();
@@ -93,7 +93,7 @@ public:
   }
 
 private:
-  void DoUpdate(uint32_t intervalMilliseconds, const char* location = NULL);
+  void DoUpdate(uint32_t intervalMilliseconds, const char* location = NULL, bool uploadOnly = false);
 
 protected:
   TestPlatformAbstraction mPlatformAbstraction;
index e99de5c..e6416e3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -140,6 +140,8 @@ void TestGlAbstraction::Initialize()
     {"uViewMatrix", GL_FLOAT_MAT4, 1},
     {"uLightCameraProjectionMatrix", GL_FLOAT_MAT4, 1},
     {"uLightCameraViewMatrix", GL_FLOAT_MAT4, 1}};
+
+  // WARNING: IF YOU CHANGE THIS LIST, ALSO CHANGE UNIFORMS IN test-graphics-reflection.cpp
 }
 
 void TestGlAbstraction::PreRender()
index aec9f5d..a1f8405 100644 (file)
@@ -2,7 +2,7 @@
 #define TEST_GL_ABSTRACTION_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -913,8 +913,8 @@ public:
     if(it2 == uniformIDs.end())
     {
       // Uniform not found, so add it...
-      uniformIDs[name] = mLastUniformIdUsed++;
-      return mLastUniformIdUsed;
+      uniformIDs[name] = ++mLastUniformIdUsed;
+      return uniformIDs[name];
     }
 
     return it2->second;
@@ -991,7 +991,30 @@ public:
 
     for(const auto& uniform : mCustomUniformData)
     {
-      GetUniformLocation(program, uniform.name.c_str());
+      auto iter = uniform.name.find("[");
+      auto name = uniform.name;
+      if(iter != std::string::npos)
+      {
+        name            = uniform.name.substr(0, iter);
+        auto arrayCount = std::stoi(uniform.name.substr(iter + 1));
+        iter            = uniform.name.find("]");
+        std::string suffix;
+        if(iter != std::string::npos && iter + 1 != uniform.name.length())
+        {
+          suffix = uniform.name.substr(iter + 1); // If there is a suffix, it means its an element of an array of struct
+        }
+
+        for(int i = 0; i < arrayCount; ++i)
+        {
+          std::stringstream nss;
+          nss << name << "[" << i << "]" << suffix;
+          GetUniformLocation(program, nss.str().c_str()); // Generate a GL loc per element
+        }
+      }
+      else
+      {
+        GetUniformLocation(program, name.c_str());
+      }
     }
   }
 
index 66fae8f..0c6996e 100644 (file)
@@ -189,7 +189,7 @@ void TestGraphicsApplication::DoUpdate(uint32_t intervalMilliseconds, const char
   uint32_t nextVSyncTime  = mLastVSyncTime + intervalMilliseconds;
   float    elapsedSeconds = static_cast<float>(intervalMilliseconds) * 0.001f;
 
-  mCore->Update(elapsedSeconds, mLastVSyncTime, nextVSyncTime, mStatus, false, false);
+  mCore->Update(elapsedSeconds, mLastVSyncTime, nextVSyncTime, mStatus, false, false, false);
 
   GetRenderController().Initialize();
 
@@ -204,10 +204,10 @@ bool TestGraphicsApplication::Render(uint32_t intervalMilliseconds, const char*
   mRenderStatus.SetNeedsUpdate(false);
   mRenderStatus.SetNeedsPostRender(false);
 
-  mCore->PreRender(mRenderStatus, false /*do not force clear*/, false /*do not skip rendering*/);
+  mCore->PreRender(mRenderStatus, false /*do not force clear*/);
   mCore->RenderScene(mRenderStatus, mScene, true /*render the off-screen buffers*/);
   mCore->RenderScene(mRenderStatus, mScene, false /*render the surface*/);
-  mCore->PostRender(false /*do not skip rendering*/);
+  mCore->PostRender();
 
   mFrame++;
 
@@ -218,7 +218,7 @@ bool TestGraphicsApplication::PreRenderWithPartialUpdate(uint32_t intervalMillis
 {
   DoUpdate(intervalMilliseconds, location);
 
-  mCore->PreRender(mRenderStatus, false /*do not force clear*/, false /*do not skip rendering*/);
+  mCore->PreRender(mRenderStatus, false /*do not force clear*/);
   mCore->PreRender(mScene, damagedRects);
 
   return mStatus.KeepUpdating() || mRenderStatus.NeedsUpdate();
@@ -228,7 +228,7 @@ bool TestGraphicsApplication::RenderWithPartialUpdate(std::vector<Rect<int>>& da
 {
   mCore->RenderScene(mRenderStatus, mScene, true /*render the off-screen buffers*/, clippingRect);
   mCore->RenderScene(mRenderStatus, mScene, false /*render the surface*/, clippingRect);
-  mCore->PostRender(false /*do not skip rendering*/);
+  mCore->PostRender();
 
   mFrame++;
 
@@ -259,10 +259,10 @@ bool TestGraphicsApplication::GetRenderNeedsPostRender()
 bool TestGraphicsApplication::RenderOnly()
 {
   // Update Time values
-  mCore->PreRender(mRenderStatus, false /*do not force clear*/, false /*do not skip rendering*/);
+  mCore->PreRender(mRenderStatus, false /*do not force clear*/);
   mCore->RenderScene(mRenderStatus, mScene, true /*render the off-screen buffers*/);
   mCore->RenderScene(mRenderStatus, mScene, false /*render the surface*/);
-  mCore->PostRender(false /*do not skip rendering*/);
+  mCore->PostRender();
 
   mFrame++;
 
index 83b7899..27f0dce 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -28,7 +28,7 @@ TestGraphicsBuffer::TestGraphicsBuffer(TraceCallStack& callStack, TestGlAbstract
   mUsage(usage)
 {
   memory.resize(size);
-  mGl.GetBufferTrace().EnableLogging(true);
+  mGl.GetBufferTrace().EnableLogging(false);
 }
 
 void TestGraphicsBuffer::Bind()
@@ -82,65 +82,67 @@ GLenum TestGraphicsBuffer::GetTarget()
 
 void TestGraphicsBuffer::BindAsUniformBuffer(const TestGraphicsProgram* program, const Dali::UniformBufferBindingDescriptor& uboBinding) const
 {
-  auto* reflection = static_cast<const TestGraphicsReflection*>(&program->GetReflection());
-
-  Graphics::UniformBlockInfo uboInfo{};
-  reflection->GetUniformBlock(0, uboInfo);
+  auto*       reflection = static_cast<const TestGraphicsReflection*>(&program->GetReflection());
+  const auto& uboInfo    = reflection->GetTestUniformBlock(0u);
 
   auto  offset = uboBinding.offset;
   auto* data   = memory.data() + offset;
 
   for(const auto& member : uboInfo.members)
   {
-    auto type = reflection->GetMemberType(0, member.location);
-    switch(type)
+    uint32_t numElements = member.numElements > 0 ? member.numElements : 1;
+
+    for(uint32_t i = 0; i < numElements; ++i)
     {
-      case Property::VECTOR4:
-      {
-        auto value = *reinterpret_cast<const Dali::Vector4*>(data + member.offset);
-        mGl.Uniform4f(member.location, value.x, value.y, value.z, value.w);
-        break;
-      }
-      case Property::VECTOR3:
-      {
-        auto value = *reinterpret_cast<const Dali::Vector3*>(data + member.offset);
-        mGl.Uniform3f(member.location, value.x, value.y, value.z);
-        break;
-      }
-      case Property::VECTOR2:
-      {
-        auto value = *reinterpret_cast<const Dali::Vector2*>(data + member.offset);
-        mGl.Uniform2f(member.location, value.x, value.y);
-        break;
-      }
-      case Property::FLOAT:
-      {
-        auto value = *reinterpret_cast<const float*>(data + member.offset);
-        mGl.Uniform1f(member.location, value);
-        break;
-      }
-      case Property::INTEGER:
-      {
-        auto ptr   = reinterpret_cast<const GLint*>(data + member.offset);
-        auto value = *ptr;
-        mGl.Uniform1i(member.location, value);
-        break;
-      }
-      case Property::MATRIX:
-      {
-        auto value = reinterpret_cast<const float*>(data + member.offset);
-        mGl.UniformMatrix4fv(member.location, 1, GL_FALSE, value);
-        break;
-      }
-      case Property::MATRIX3:
-      {
-        auto value = reinterpret_cast<const float*>(data + member.offset);
-        mGl.UniformMatrix3fv(member.location, 1, GL_FALSE, value);
-        break;
-      }
-      default:
+      switch(member.type)
       {
-        fprintf(stderr, "\n%s type not found\n", member.name.c_str());
+        case Property::VECTOR4:
+        {
+          auto value = *reinterpret_cast<const Dali::Vector4*>(data + member.offsets[i]);
+          mGl.Uniform4f(member.locations[i], value.x, value.y, value.z, value.w);
+          break;
+        }
+        case Property::VECTOR3:
+        {
+          auto value = *reinterpret_cast<const Dali::Vector3*>(data + member.offsets[i]);
+          mGl.Uniform3f(member.locations[i], value.x, value.y, value.z);
+          break;
+        }
+        case Property::VECTOR2:
+        {
+          auto value = *reinterpret_cast<const Dali::Vector2*>(data + member.offsets[i]);
+          mGl.Uniform2f(member.locations[i], value.x, value.y);
+          break;
+        }
+        case Property::FLOAT:
+        {
+          auto value = *reinterpret_cast<const float*>(data + member.offsets[i]);
+          mGl.Uniform1f(member.locations[i], value);
+          break;
+        }
+        case Property::INTEGER:
+        {
+          auto ptr   = reinterpret_cast<const GLint*>(data + member.offsets[i]);
+          auto value = *ptr;
+          mGl.Uniform1i(member.locations[i], value);
+          break;
+        }
+        case Property::MATRIX:
+        {
+          auto value = reinterpret_cast<const float*>(data + member.offsets[i]);
+          mGl.UniformMatrix4fv(member.locations[i], 1, GL_FALSE, value);
+          break;
+        }
+        case Property::MATRIX3:
+        {
+          auto value = reinterpret_cast<const float*>(data + member.offsets[i]);
+          mGl.UniformMatrix3fv(member.locations[i], 1, GL_FALSE, value);
+          break;
+        }
+        default:
+        {
+          fprintf(stderr, "\n%s type not found\n", member.name.c_str());
+        }
       }
     }
   }
index 3df3219..407dade 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TEST_GRAPHICS_COMMAND_BUFFER_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -65,6 +65,7 @@ enum class CommandType
   SET_DEPTH_COMPARE_OP    = 1 << 24,
   SET_DEPTH_TEST_ENABLE   = 1 << 25,
   SET_DEPTH_WRITE_ENABLE  = 1 << 26,
+  DRAW_NATIVE             = 1 << 27,
 };
 
 std::ostream& operator<<(std::ostream& os, Graphics::StencilOp op);
@@ -123,7 +124,8 @@ struct DrawCallDescriptor
   {
     DRAW,
     DRAW_INDEXED,
-    DRAW_INDEXED_INDIRECT
+    DRAW_INDEXED_INDIRECT,
+    DRAW_NATIVE
   };
 
   Type type{}; ///< Type of the draw call
@@ -166,6 +168,11 @@ struct DrawCallDescriptor
       uint32_t                  drawCount;
       uint32_t                  stride;
     } drawIndexedIndirect;
+
+    struct
+    {
+      Graphics::DrawNativeInfo drawNativeInfo;
+    } drawNative;
   };
 };
 
@@ -265,6 +272,12 @@ struct Command
         data.bindUniformBuffers = rhs.data.bindUniformBuffers;
         break;
       }
+      case CommandType::DRAW_NATIVE:
+      {
+        data.draw.type       = rhs.data.draw.type;
+        data.draw.drawNative = rhs.data.draw.drawNative;
+        break;
+      }
       case CommandType::DRAW:
       {
         data.draw.type = rhs.data.draw.type;
@@ -418,6 +431,12 @@ struct Command
         data.bindPipeline = rhs.data.bindPipeline;
         break;
       }
+      case CommandType::DRAW_NATIVE:
+      {
+        data.draw.type       = rhs.data.draw.type;
+        data.draw.drawNative = rhs.data.draw.drawNative;
+        break;
+      }
       case CommandType::DRAW:
       {
         data.draw.type = rhs.data.draw.type;
@@ -647,9 +666,9 @@ public:
   {
   }
 
-  void BindVertexBuffers(uint32_t                             firstBinding,
-                         std::vector<const Graphics::Buffer*> buffers,
-                         std::vector<uint32_t>                offsets) override
+  void BindVertexBuffers(uint32_t                                    firstBinding,
+                         const std::vector<const Graphics::Buffer*>& buffers,
+                         const std::vector<uint32_t>&                offsets) override
   {
     mCommands.emplace_back();
     mCommands.back().type = CommandType::BIND_VERTEX_BUFFERS;
@@ -712,7 +731,7 @@ public:
     mCallStack.PushCall("BindPipeline", "");
   }
 
-  void BindTextures(std::vector<Graphics::TextureBinding>& textureBindings) override
+  void BindTextures(const std::vector<Graphics::TextureBinding>& textureBindings) override
   {
     mCommands.emplace_back();
     mCommands.back().type                              = CommandType::BIND_TEXTURES;
@@ -720,7 +739,7 @@ public:
     mCallStack.PushCall("BindTextures", "");
   }
 
-  void BindSamplers(std::vector<Graphics::SamplerBinding>& samplerBindings) override
+  void BindSamplers(const std::vector<Graphics::SamplerBinding>& samplerBindings) override
   {
     mCommands.emplace_back();
     mCommands.back().data.bindSamplers.samplerBindings = std::move(samplerBindings);
@@ -747,10 +766,10 @@ public:
   }
 
   void BeginRenderPass(
-    Graphics::RenderPass*             renderPass,
-    Graphics::RenderTarget*           renderTarget,
-    Graphics::Rect2D                  renderArea,
-    std::vector<Graphics::ClearValue> clearValues) override
+    Graphics::RenderPass*                    renderPass,
+    Graphics::RenderTarget*                  renderTarget,
+    Graphics::Rect2D                         renderArea,
+    const std::vector<Graphics::ClearValue>& clearValues) override
   {
     mCommands.emplace_back(CommandType::BEGIN_RENDER_PASS);
     auto& cmd                             = mCommands.back();
@@ -800,6 +819,16 @@ public:
     mCallStack.PushCall("ExecuteCommandBuffers", "");
   }
 
+  void DrawNative(const Graphics::DrawNativeInfo* drawInfo)
+  {
+    mCommands.emplace_back();
+    mCommands.back().type         = CommandType::DRAW_NATIVE;
+    auto& cmd                     = mCommands.back().data.draw;
+    cmd.type                      = DrawCallDescriptor::Type::DRAW_NATIVE;
+    cmd.drawNative.drawNativeInfo = *drawInfo;
+    mCallStack.PushCall("DrawNative", "");
+  }
+
   void Draw(
     uint32_t vertexCount,
     uint32_t instanceCount,
index 3ed6b56..6a8eab4 100644 (file)
@@ -584,15 +584,15 @@ public:
 };
 
 TestGraphicsController::TestGraphicsController()
-: mCallStack(true, "TestGraphicsController."),
-  mCommandBufferCallStack(true, "TestCommandBuffer."),
-  mFrameBufferCallStack(true, "TestFrameBuffer.")
+: mCallStack(false, "TestGraphicsController."),
+  mCommandBufferCallStack(false, "TestCommandBuffer."),
+  mFrameBufferCallStack(false, "TestFrameBuffer.")
 {
   mCallStack.Enable(true);
   mCommandBufferCallStack.Enable(true);
   auto& trace = mGl.GetTextureTrace();
   trace.Enable(true);
-  trace.EnableLogging(true);
+  trace.EnableLogging(false);
 }
 
 void TestGraphicsController::SubmitCommandBuffers(const Graphics::SubmitInfo& submitInfo)
@@ -693,6 +693,12 @@ void TestGraphicsController::ProcessCommandBuffer(TestGraphicsCommandBuffer& com
         BindPipeline(currentPipeline);
         break;
       }
+      case CommandType::DRAW_NATIVE:
+      {
+        auto info = &cmd.data.draw.drawNative.drawNativeInfo;
+        CallbackBase::ExecuteReturn<bool>(*info->callback, info->userData);
+        break;
+      }
       case CommandType::DRAW:
       {
         if(currentPipeline)
index a994157..8f2e0c7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,14 +20,15 @@ namespace Dali
 {
 TestGraphicsProgramImpl::TestGraphicsProgramImpl(TestGlAbstraction& gl, const Graphics::ProgramCreateInfo& createInfo, Property::Array& vertexFormats, std::vector<UniformData>& customUniforms)
 : mGl(gl),
+  mId(gl.CreateProgram()),
   mCreateInfo(createInfo),
-  mReflection(gl, vertexFormats, createInfo, customUniforms)
+  mReflection(gl, mId, vertexFormats, createInfo, customUniforms)
 {
-  mId = mGl.CreateProgram();
-
   // Ensure active sampler uniforms are set
   mGl.SetCustomUniforms(customUniforms);
-  mGl.LinkProgram(mId);
+
+  // Don't need to re-register uniforms in GL side - now done in creation of mReflection.
+  // Was previously done in mGl.LinkProgram(mId);
 }
 
 bool TestGraphicsProgramImpl::GetParameter(uint32_t parameterId, void* outData)
index 25c09b5..6cb90ba 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -50,10 +50,60 @@ static const std::vector<UniformData> UNIFORMS =
     UniformData("uViewMatrix", Property::Type::MATRIX),
     UniformData("uLightCameraProjectionMatrix", Property::Type::MATRIX),
     UniformData("uLightCameraViewMatrix", Property::Type::MATRIX),
+
+    // WARNING: IF YOU CHANGE THIS LIST, ALSO CHANGE mActiveUniforms IN test-gl-abstraction, Initialize
 };
+
+/**
+ * Helper function that returns size of uniform datatypes based
+ * on property type.
+ */
+constexpr int GetSizeForType(Property::Type type)
+{
+  switch(type)
+  {
+    case Property::Type::BOOLEAN:
+    {
+      return sizeof(bool);
+    }
+    case Property::Type::FLOAT:
+    {
+      return sizeof(float);
+    }
+    case Property::Type::INTEGER:
+    {
+      return sizeof(int);
+    }
+    case Property::Type::VECTOR2:
+    {
+      return sizeof(Vector2);
+    }
+    case Property::Type::VECTOR3:
+    {
+      return sizeof(Vector3);
+    }
+    case Property::Type::VECTOR4:
+    {
+      return sizeof(Vector4);
+    }
+    case Property::Type::MATRIX3:
+    {
+      return sizeof(Matrix3);
+    }
+    case Property::Type::MATRIX:
+    {
+      return sizeof(Matrix);
+    }
+    default:
+    {
+      return 0;
+    }
+  };
 }
 
-TestGraphicsReflection::TestGraphicsReflection(TestGlAbstraction& gl, Property::Array& vfs, const Graphics::ProgramCreateInfo& createInfo, std::vector<UniformData>& customUniforms)
+} // namespace
+
+TestGraphicsReflection::TestGraphicsReflection(TestGlAbstraction& gl, uint32_t programId, Property::Array& vfs, const Graphics::ProgramCreateInfo& createInfo, std::vector<UniformData>& customUniforms)
 : mGl(gl),
   mCustomUniforms(customUniforms)
 {
@@ -76,34 +126,104 @@ TestGraphicsReflection::TestGraphicsReflection(TestGlAbstraction& gl, Property::
   mDefaultUniformBlock.name          = "";
   mDefaultUniformBlock.members       = {};
   mDefaultUniformBlock.binding       = 0;
-  mDefaultUniformBlock.size          = 64 * (UNIFORMS.size() + mCustomUniforms.size());
   mDefaultUniformBlock.descriptorSet = 0;
   mDefaultUniformBlock.members.clear();
-  int loc = 0;
+
+  int offset = 0;
   for(const auto& data : UNIFORMS)
   {
     mDefaultUniformBlock.members.emplace_back();
-    auto& item        = mDefaultUniformBlock.members.back();
-    item.name         = data.name;
-    item.binding      = 0;
-    item.offset       = loc * 64;
-    item.location     = loc++;
+    auto& item   = mDefaultUniformBlock.members.back();
+    item.name    = data.name;
+    item.binding = 0;
+    item.offsets.push_back(offset);
+    item.locations.push_back(gl.GetUniformLocation(programId, data.name.c_str()));
     item.bufferIndex  = 0;
     item.uniformClass = Graphics::UniformClass::UNIFORM;
+    item.type         = data.type;
+    offset += GetSizeForType(data.type);
   }
 
   for(const auto& data : mCustomUniforms)
   {
     fprintf(stderr, "\ncustom uniforms: %s\n", data.name.c_str());
-    mDefaultUniformBlock.members.emplace_back();
-    auto& item        = mDefaultUniformBlock.members.back();
-    item.name         = data.name;
-    item.binding      = 0;
-    item.offset       = loc * 64;
-    item.location     = loc++;
-    item.bufferIndex  = 0;
-    item.uniformClass = Graphics::UniformClass::UNIFORM;
+
+    auto iter        = data.name.find("[", 0);
+    int  numElements = 1;
+    if(iter != std::string::npos)
+    {
+      auto baseName = data.name.substr(0, iter);
+      iter++;
+      numElements = std::stoi(data.name.substr(iter));
+      if(numElements == 0)
+      {
+        numElements = 1;
+      }
+      iter = data.name.find("]");
+      std::string suffix;
+      if(iter != std::string::npos && iter + 1 != data.name.length())
+      {
+        suffix = data.name.substr(iter + 1); // If there is a suffix, it means it is an element of an array of struct
+      }
+
+      if(!suffix.empty())
+      {
+        // Write multiple items
+        for(int i = 0; i < numElements; ++i)
+        {
+          std::stringstream elementNameStream;
+          elementNameStream << baseName << "[" << i << "]" << suffix;
+          mDefaultUniformBlock.members.emplace_back();
+          auto& item   = mDefaultUniformBlock.members.back();
+          item.name    = elementNameStream.str();
+          item.binding = 0;
+          item.offsets.push_back(offset);
+          item.locations.push_back(gl.GetUniformLocation(programId, elementNameStream.str().c_str()));
+          item.bufferIndex  = 0;
+          item.uniformClass = Graphics::UniformClass::UNIFORM;
+          item.type         = data.type;
+          offset += GetSizeForType(data.type);
+        }
+      }
+      else
+      {
+        // Write 1 item with multiple elements
+        mDefaultUniformBlock.members.emplace_back();
+        auto& item = mDefaultUniformBlock.members.back();
+
+        item.name         = baseName;
+        item.binding      = 0;
+        item.bufferIndex  = 0;
+        item.uniformClass = Graphics::UniformClass::UNIFORM;
+        item.type         = data.type;
+        item.numElements  = numElements;
+
+        for(int i = 0; i < numElements; ++i)
+        {
+          std::stringstream elementNameStream;
+          elementNameStream << baseName << "[" << i << "]";
+          item.locations.push_back(gl.GetUniformLocation(programId, elementNameStream.str().c_str()));
+          item.offsets.push_back(offset);
+          offset += GetSizeForType(data.type);
+        }
+      }
+    }
+    else
+    {
+      // Write 1 item with 1 element
+      mDefaultUniformBlock.members.emplace_back();
+      auto& item   = mDefaultUniformBlock.members.back();
+      item.name    = data.name;
+      item.binding = 0;
+      item.offsets.push_back(offset);
+      item.locations.push_back(gl.GetUniformLocation(programId, item.name.c_str()));
+      item.bufferIndex  = 0;
+      item.uniformClass = Graphics::UniformClass::UNIFORM;
+      item.type         = data.type;
+      offset += GetSizeForType(data.type);
+    }
   }
+  mDefaultUniformBlock.size = offset;
 
   mUniformBlocks.push_back(mDefaultUniformBlock);
 }
@@ -157,9 +277,13 @@ uint32_t TestGraphicsReflection::GetUniformBlockBinding(uint32_t index) const
 
 uint32_t TestGraphicsReflection::GetUniformBlockSize(uint32_t index) const
 {
-  // 64 bytes per uniform (64 = 4x4 matrix)
-  // TODO: fix if array will be used
-  return 64 * (UNIFORMS.size() + mCustomUniforms.size());
+  if(index >= mUniformBlocks.size())
+  {
+    return 0;
+  }
+
+  const auto& block = mUniformBlocks[index];
+  return block.size;
 }
 
 bool TestGraphicsReflection::GetUniformBlock(uint32_t index, Dali::Graphics::UniformBlockInfo& out) const
@@ -183,8 +307,8 @@ bool TestGraphicsReflection::GetUniformBlock(uint32_t index, Dali::Graphics::Uni
     out.members[i].name         = memberUniform.name;
     out.members[i].binding      = block.binding;
     out.members[i].uniformClass = Graphics::UniformClass::UNIFORM;
-    out.members[i].offset       = memberUniform.offset;
-    out.members[i].location     = memberUniform.location;
+    out.members[i].offset       = memberUniform.offsets[0];
+    out.members[i].location     = memberUniform.locations[0];
   }
 
   return true;
@@ -228,7 +352,7 @@ uint32_t TestGraphicsReflection::GetUniformBlockMemberOffset(uint32_t blockIndex
 {
   if(blockIndex < mUniformBlocks.size() && memberLocation < mUniformBlocks[blockIndex].members.size())
   {
-    return mUniformBlocks[blockIndex].members[memberLocation].offset;
+    return mUniformBlocks[blockIndex].members[memberLocation].offsets[0];
   }
   else
   {
@@ -252,9 +376,4 @@ Graphics::ShaderLanguage TestGraphicsReflection::GetLanguage() const
   return Graphics::ShaderLanguage::GLSL_3_1;
 }
 
-Dali::Property::Type TestGraphicsReflection::GetMemberType(int blockIndex, int location) const
-{
-  return location < static_cast<int>(UNIFORMS.size()) ? UNIFORMS[location].type : mCustomUniforms[location - UNIFORMS.size()].type;
-}
-
 } // namespace Dali
index 2147cae..e968bd5 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TEST_GRAPHICS_REFLECTION_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -26,7 +26,7 @@ namespace Dali
 class TestGraphicsReflection : public Graphics::Reflection
 {
 public:
-  TestGraphicsReflection(TestGlAbstraction& gl, Property::Array& vertexFormats, const Graphics::ProgramCreateInfo& createInfo, std::vector<UniformData>& customUniforms);
+  TestGraphicsReflection(TestGlAbstraction& gl, uint32_t program_id, Property::Array& vertexFormats, const Graphics::ProgramCreateInfo& createInfo, std::vector<UniformData>& customUniforms);
 
   uint32_t                                        GetVertexAttributeLocation(const std::string& name) const override;
   Dali::Graphics::VertexInputAttributeFormat      GetVertexAttributeFormat(uint32_t location) const override;
@@ -46,6 +46,27 @@ public:
   Graphics::ShaderLanguage                        GetLanguage() const override;
 
 public: // Test methods
+  struct TestUniformInfo
+  {
+    std::string            name{""}; // baseName in the case of arrays
+    Graphics::UniformClass uniformClass{Graphics::UniformClass::UNDEFINED};
+    uint32_t               binding{0u};
+    uint32_t               bufferIndex{0u};
+    std::vector<uint32_t>  offsets{};
+    std::vector<uint32_t>  locations{};
+    uint32_t               numElements{0u}; // 0 elements means this isn't an array; 1 element means this is an array of size 1
+    Property::Type         type;
+  };
+
+  struct TestUniformBlockInfo
+  {
+    std::string                  name{""};
+    uint32_t                     descriptorSet{0u};
+    uint32_t                     binding{0u};
+    uint32_t                     size{0u};
+    std::vector<TestUniformInfo> members{};
+  };
+
   void SetAttributes(std::vector<std::string> locations)
   {
     mAttributes.clear();
@@ -56,14 +77,17 @@ public: // Test methods
     }
   }
 
-  Dali::Property::Type GetMemberType(int blockIndex, int location) const;
+  const TestUniformBlockInfo& GetTestUniformBlock(uint32_t index) const
+  {
+    return mUniformBlocks[index];
+  }
 
   TestGlAbstraction&               mGl;
   mutable std::vector<std::string> mAttributes;
   std::vector<UniformData>         mCustomUniforms;
 
-  Graphics::UniformBlockInfo              mDefaultUniformBlock{}; ///< The emulated UBO containing all the standalone uniforms
-  std::vector<Graphics::UniformBlockInfo> mUniformBlocks{};       ///< List of uniform blocks
+  TestUniformBlockInfo              mDefaultUniformBlock{}; ///< The emulated UBO containing all the standalone uniforms
+  std::vector<TestUniformBlockInfo> mUniformBlocks{};       ///< List of uniform blocks
 };
 
 } // namespace Dali
index 7f2de63..2316036 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -146,7 +146,26 @@ bool TraceCallStack::FindMethodAndGetParameters(std::string method, std::string&
   }
   if(!found)
   {
-    fprintf(stderr, "Search for %s(%s) failed\n", method.c_str(), params.c_str());
+    fprintf(stderr, "Search for %s() failed\n", method.c_str());
+  }
+  return found;
+}
+
+bool TraceCallStack::FindMethodAndGetParameters(std::string method, NamedParams& params) const
+{
+  bool found = false;
+  for(size_t i = 0; i < mCallStack.size(); i++)
+  {
+    if(0 == mCallStack[i].method.compare(method))
+    {
+      found  = true;
+      params = mCallStack[i].namedParams;
+      break;
+    }
+  }
+  if(!found)
+  {
+    fprintf(stderr, "Search for %s() failed\n", method.c_str());
   }
   return found;
 }
index 6f720c5..c2d0a49 100644 (file)
@@ -207,6 +207,14 @@ public:
   bool FindMethodAndGetParameters(std::string method, std::string& params) const;
 
   /**
+   * Search for a method in the stack and return its parameters if found
+   * @param[in] method The name of the method
+   * @param[out] params of the method
+   * @return true if the method was in the stack
+   */
+  bool FindMethodAndGetParameters(std::string method, NamedParams& params) const;
+
+  /**
    * Count how many times a method was called
    * @param[in] method The name of the method
    * @return The number of times it was called
index 8bb9086..36b3f4f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  *
  */
 
-#include <stdlib.h>
-#include <unistd.h>
-#include <dali/dali.h>
 #include <dali-test-suite-utils.h>
+#include <dali/dali.h>
 #include <dali/public-api/adaptor-framework/encoded-image-buffer.h>
+#include <stdlib.h>
+#include <unistd.h>
 
 using namespace Dali;
 
@@ -65,7 +65,7 @@ int UtcDaliEncodedImageBufferCopyConstructor(void)
   EncodedImageBuffer buffer = EncodedImageBuffer::New(tinybuffer());
   EncodedImageBuffer bufferCopy(buffer);
 
-  DALI_TEST_EQUALS( (bool)bufferCopy, true, TEST_LOCATION );
+  DALI_TEST_EQUALS((bool)bufferCopy, true, TEST_LOCATION);
   END_TEST;
 }
 
@@ -74,10 +74,10 @@ int UtcDaliEncodedImageBufferAssignmentOperator(void)
   EncodedImageBuffer buffer = EncodedImageBuffer::New(tinybuffer());
 
   EncodedImageBuffer buffer2;
-  DALI_TEST_EQUALS( (bool)buffer2, false, TEST_LOCATION );
+  DALI_TEST_EQUALS((bool)buffer2, false, TEST_LOCATION);
 
   buffer2 = buffer;
-  DALI_TEST_EQUALS( (bool)buffer2, true, TEST_LOCATION );
+  DALI_TEST_EQUALS((bool)buffer2, true, TEST_LOCATION);
 
   END_TEST;
 }
@@ -97,8 +97,25 @@ int UtcDaliEncodedImageBufferGetRawBuffer(void)
   EncodedImageBuffer::RawBufferType::Iterator jter = getBuffer.Begin();
   for(; iter != originBuffer.End(); ++iter, ++jter)
   {
-    DALI_TEST_EQUALS(*iter, *jter, TEST_LOCATION );
+    DALI_TEST_EQUALS(*iter, *jter, TEST_LOCATION);
   }
 
   END_TEST;
 }
+
+int UtcDaliEncodedImageBufferGetHash(void)
+{
+  EncodedImageBuffer buffer1 = EncodedImageBuffer::New(tinybuffer());
+  EncodedImageBuffer buffer2 = EncodedImageBuffer::New(tinybuffer());
+  EncodedImageBuffer buffer3 = EncodedImageBuffer::New(EncodedImageBuffer::RawBufferType()); //< EmptyBuffer
+
+  tet_infoline("Test different encoded buffer with same data has same hash value.");
+  DALI_TEST_CHECK(buffer1 != buffer2);
+  DALI_TEST_CHECK(buffer1.GetHash() == buffer2.GetHash());
+
+  tet_infoline("Test hash with empty buffer.");
+  DALI_TEST_CHECK(buffer1.GetHash() != buffer3.GetHash());
+  DALI_TEST_CHECK(buffer2.GetHash() != buffer3.GetHash());
+
+  END_TEST;
+}
\ No newline at end of file
index 669b729..b71cedd 100644 (file)
@@ -26,27 +26,10 @@ namespace
 {
 // test gif image, resolution: 100*100, 5 frames, delay: 1 second, disposal method: none
 static const char* gGif_100_None = TEST_RESOURCE_DIR "/canvas-none.gif";
-// test gif image, resolution: 100*100, 5 frames, delay: 1 second, disposal method: none for first frame and previous for the rest
-static const char* gGif_100_Prev = TEST_RESOURCE_DIR "/canvas-prev.gif";
-// test gif image, resolution: 100*100, 5 frames, delay: 1 second, disposal method: background
-static const char* gGif_100_Bgnd = TEST_RESOURCE_DIR "/canvas-bgnd.gif";
 
 // this image if not exist, for negative test
 static const char* gGifNonExist = "non-exist.gif";
 
-void VerifyLoad(std::vector<Dali::PixelData>& pixelDataList, Dali::Vector<uint32_t>& frameDelayList, uint32_t frameCount, uint32_t width, uint32_t height, uint32_t delay)
-{
-  DALI_TEST_EQUALS(pixelDataList.size(), frameCount, TEST_LOCATION);
-  DALI_TEST_EQUALS(frameDelayList.Size(), frameCount, TEST_LOCATION);
-
-  for(uint32_t idx = 0; idx < frameCount; idx++)
-  {
-    // Check the image size and delay of each frame
-    DALI_TEST_EQUALS(pixelDataList[idx].GetWidth(), width, TEST_LOCATION);
-    DALI_TEST_EQUALS(pixelDataList[idx].GetHeight(), height, TEST_LOCATION);
-    DALI_TEST_EQUALS(frameDelayList[idx], delay, TEST_LOCATION);
-  }
-}
 } // namespace
 
 void utc_dali_animated_image_loader_startup(void)
@@ -59,72 +42,6 @@ void utc_dali_animated_image_loader_cleanup(void)
   test_return_value = TET_PASS;
 }
 
-int UtcDaliAnimatedImageLoadingP(void)
-{
-  std::vector<Dali::PixelData> pixelDataList;
-  Dali::Vector<uint32_t>       frameDelayList;
-
-  Dali::AnimatedImageLoading animatedImageLoading = Dali::AnimatedImageLoading::New(gGif_100_None, true);
-  bool                       succeed              = animatedImageLoading.LoadNextNFrames(0u, animatedImageLoading.GetImageCount(), pixelDataList);
-  frameDelayList.Clear();
-  frameDelayList.Resize(animatedImageLoading.GetImageCount(), 0);
-  for(uint32_t i = 0; i < animatedImageLoading.GetImageCount(); ++i)
-  {
-    frameDelayList[i] = animatedImageLoading.GetFrameInterval(i);
-  }
-
-  // Check that the loading succeed
-  DALI_TEST_CHECK(succeed);
-  VerifyLoad(pixelDataList, frameDelayList, 5u, 100u, 100u, 1000u);
-
-  pixelDataList.clear();
-  animatedImageLoading = Dali::AnimatedImageLoading::New(gGif_100_Prev, true);
-  succeed              = animatedImageLoading.LoadNextNFrames(0u, animatedImageLoading.GetImageCount(), pixelDataList);
-  frameDelayList.Clear();
-  frameDelayList.Resize(animatedImageLoading.GetImageCount(), 0);
-  for(uint32_t i = 0; i < animatedImageLoading.GetImageCount(); ++i)
-  {
-    frameDelayList[i] = animatedImageLoading.GetFrameInterval(i);
-  }
-
-  // Check that the loading succeed
-  DALI_TEST_CHECK(succeed);
-  VerifyLoad(pixelDataList, frameDelayList, 5u, 100u, 100u, 1000u);
-
-  pixelDataList.clear();
-  animatedImageLoading = Dali::AnimatedImageLoading::New(gGif_100_Bgnd, true);
-  succeed              = animatedImageLoading.LoadNextNFrames(0u, animatedImageLoading.GetImageCount(), pixelDataList);
-  frameDelayList.Clear();
-  frameDelayList.Resize(animatedImageLoading.GetImageCount(), 0);
-  for(uint32_t i = 0; i < animatedImageLoading.GetImageCount(); ++i)
-  {
-    frameDelayList[i] = animatedImageLoading.GetFrameInterval(i);
-  }
-
-  // Check that the loading succeed
-  DALI_TEST_CHECK(succeed);
-  VerifyLoad(pixelDataList, frameDelayList, 5u, 100u, 100u, 1000u);
-
-  END_TEST;
-}
-
-int UtcDaliAnimatedImageLoadingN(void)
-{
-  std::vector<Dali::PixelData> pixelDataList;
-  Dali::Vector<uint32_t>       frameDelayList;
-
-  Dali::AnimatedImageLoading animatedImageLoading = Dali::AnimatedImageLoading::New(gGifNonExist, true);
-  bool                       succeed              = animatedImageLoading.LoadNextNFrames(0u, animatedImageLoading.GetImageCount(), pixelDataList);
-
-  // Check that the loading failed
-  DALI_TEST_CHECK(!succeed);
-
-  // Check that both pixelDataList and frameDelayList are empty
-  DALI_TEST_EQUALS(pixelDataList.size(), 0u, TEST_LOCATION);
-
-  END_TEST;
-}
-
 int UtcDaliAnimatedImageLoadingGetImageSizeP(void)
 {
   Dali::AnimatedImageLoading animatedImageLoading = Dali::AnimatedImageLoading::New(gGif_100_None, true);
index 1019707..12af8b0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -34,6 +34,9 @@ const char* IMAGE_128_RGB = TEST_RESOURCE_DIR "/gallery-small-1.jpg";
 // resolution: 2000*2560, pixel format: RGB888
 const char* IMAGE_LARGE_EXIF3_RGB = TEST_RESOURCE_DIR "/f-large-exif-3.jpg";
 
+// resolution: 2048*2048, pixel format: RGB888, YUV420
+const char* IMAGE_LARGE_2048_YUV_420 = TEST_RESOURCE_DIR "/lake_front.jpg";
+
 // resolution: 55*64, pixel format: RGB888
 const char* IMAGE_WIDTH_ODD_EXIF1_RGB = TEST_RESOURCE_DIR "/f-odd-exif-1.jpg";
 // resolution: 55*64, pixel format: RGB888
@@ -74,7 +77,7 @@ const char* IMAGENONEXIST = "non-exist.jpg";
 Dali::Vector<uint8_t> FileToMemory(const char* filename)
 {
   Dali::Vector<uint8_t> buffer;
-  FILE *fp;
+  FILE*                 fp;
   fp = fopen(filename, "rb");
   if(fp != NULL)
   {
@@ -418,3 +421,46 @@ int UtcDaliDownloadImageN(void)
 
   END_TEST;
 }
+
+int UtcDaliLoadImagePlanesFromFileP(void)
+{
+  std::vector<Devel::PixelBuffer> pixelBuffers;
+
+  Dali::LoadImagePlanesFromFile(IMAGE_LARGE_2048_YUV_420, pixelBuffers);
+  DALI_TEST_EQUALS(pixelBuffers.size(), 3, TEST_LOCATION);
+  DALI_TEST_EQUALS(pixelBuffers[0].GetWidth(), 2048u, TEST_LOCATION);
+  DALI_TEST_EQUALS(pixelBuffers[0].GetHeight(), 2048u, TEST_LOCATION);
+  DALI_TEST_EQUALS(pixelBuffers[0].GetPixelFormat(), Pixel::L8, TEST_LOCATION);
+  DALI_TEST_EQUALS(pixelBuffers[1].GetPixelFormat(), Pixel::CHROMINANCE_U, TEST_LOCATION);
+  DALI_TEST_EQUALS(pixelBuffers[2].GetPixelFormat(), Pixel::CHROMINANCE_V, TEST_LOCATION);
+
+  pixelBuffers.clear();
+
+  // Test not supported image format: png
+  Dali::LoadImagePlanesFromFile(IMAGE_34_RGBA, pixelBuffers);
+  DALI_TEST_EQUALS(pixelBuffers.size(), 1, TEST_LOCATION);
+  DALI_TEST_EQUALS(pixelBuffers[0].GetWidth(), 34u, TEST_LOCATION);
+  DALI_TEST_EQUALS(pixelBuffers[0].GetHeight(), 34u, TEST_LOCATION);
+  DALI_TEST_EQUALS(pixelBuffers[0].GetPixelFormat(), Pixel::RGBA8888, TEST_LOCATION);
+
+  pixelBuffers.clear();
+
+  // Test notsupported chrominace subsampling case
+  Dali::LoadImagePlanesFromFile(IMAGE_128_RGB, pixelBuffers);
+  DALI_TEST_EQUALS(pixelBuffers.size(), 1, TEST_LOCATION);
+  DALI_TEST_EQUALS(pixelBuffers[0].GetWidth(), 128u, TEST_LOCATION);
+  DALI_TEST_EQUALS(pixelBuffers[0].GetHeight(), 128u, TEST_LOCATION);
+  DALI_TEST_EQUALS(pixelBuffers[0].GetPixelFormat(), Pixel::RGB888, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliLoadImagePlanesFromFileN(void)
+{
+  std::vector<Devel::PixelBuffer> pixelBuffers;
+
+  Dali::LoadImagePlanesFromFile(IMAGENONEXIST, pixelBuffers);
+  DALI_TEST_CHECK(pixelBuffers.empty());
+
+  END_TEST;
+}
index 9958472..bed76e1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -227,6 +227,7 @@ int UtcDaliPixelBufferConvert(void)
     DALI_TEST_CHECK(pixelData);
     DALI_TEST_EQUALS(pixelData.GetWidth(), 10, TEST_LOCATION);
     DALI_TEST_EQUALS(pixelData.GetHeight(), 10, TEST_LOCATION);
+    DALI_TEST_EQUALS(pixelData.GetStride(), 10, TEST_LOCATION);
     DALI_TEST_EQUALS(pixelData.GetPixelFormat(), Pixel::RGB565, TEST_LOCATION);
 
     // Try drawing it
@@ -261,6 +262,7 @@ int UtcDaliPixelBufferGetWidth(void)
   FillCheckerboard(pixbuf);
 
   DALI_TEST_EQUALS(pixbuf.GetWidth(), 10, TEST_LOCATION);
+  DALI_TEST_EQUALS(pixbuf.GetStride(), 10, TEST_LOCATION);
 
   END_TEST;
 }
index 7386246..db45460 100644 (file)
@@ -230,6 +230,23 @@ int UtcDaliWindowIsMaximizedN(void)
   END_TEST;
 }
 
+int UtcDaliWindowSetMaximumSizeN(void)
+{
+  try
+  {
+    Dali::Window    instance;
+    Dali::Window::WindowSize size(100, 100);
+    DevelWindow::SetMaximumSize(instance, size);
+    DALI_TEST_CHECK(false); // Should not reach here!
+  }
+  catch(...)
+  {
+    DALI_TEST_CHECK(true);
+  }
+
+  END_TEST;
+}
+
 int UtcDaliWindowMinimizeN(void)
 {
   try
@@ -262,6 +279,23 @@ int UtcDaliWindowIsMinimizedN(void)
   END_TEST;
 }
 
+int UtcDaliWindowSetMimimumSizeN(void)
+{
+  try
+  {
+    Dali::Window    instance;
+    Dali::Window::WindowSize size(100, 100);
+    DevelWindow::SetMimimumSize(instance, size);
+    DALI_TEST_CHECK(false); // Should not reach here!
+  }
+  catch(...)
+  {
+    DALI_TEST_CHECK(true);
+  }
+
+  END_TEST;
+}
+
 int UtcDaliWindowAddAvailableOrientationN(void)
 {
   Dali::Window window;
index 7d2da30..70cea5c 100644 (file)
@@ -18,6 +18,7 @@ ENDIF()
 OPTION(ENABLE_PKG_CONFIGURE  "Use pkgconfig" ON)
 OPTION(ENABLE_LINK_TEST      "Enable the link test" ON)
 OPTION(ENABLE_ATSPI          "Enable AT-SPI accessibility" ON)
+OPTION(ENABLE_TRACE          "Enable Trace" OFF)
 
 # Include additional macros
 INCLUDE( common.cmake )
@@ -109,6 +110,10 @@ IF( NOT DALI_ELDBUS_AVAILABLE )
   SET( ENABLE_ATSPI OFF )
 ENDIF()
 
+IF( ENABLE_TRACE )
+  ADD_DEFINITIONS("-DTRACE_ENABLED")
+ENDIF()
+
 # Set up compiler flags and warnings
 IF( UNIX )
   ADD_COMPILE_OPTIONS( -Wall ${DALI_CFLAGS} )# -Wextra -Wno-unused-parameter )# -Wfloat-equal )
@@ -420,6 +425,7 @@ MESSAGE( STATUS "Using Tizen APP FW libraries:     ${ENABLE_APPFW}")
 MESSAGE( STATUS "Use pkg configure:                ${ENABLE_PKG_CONFIGURE}" )
 MESSAGE( STATUS "Enable link test:                 ${ENABLE_LINK_TEST}" )
 MESSAGE( STATUS "Enable AT-SPI:                    ${ENABLE_ATSPI}" )
+MESSAGE( STATUS "Enable Trace:                     ${ENABLE_TRACE}" )
 MESSAGE( STATUS "Tizen Platform Config supported   ${TIZEN_PLATFORM_CONFIG_SUPPORTED_LOGMSG}")
 MESSAGE( STATUS "Compile flags:                    ${CMAKE_CXX_FLAGS}")
 MESSAGE( STATUS "Compile flags:                    ${CMAKE_C_FLAGS}")
index 8eecbda..3ed1b62 100755 (executable)
@@ -103,7 +103,7 @@ CHECK_MODULE_AND_SET( SCREENCONNECTORPROVIDER screen_connector_provider [] )
 CHECK_MODULE_AND_SET( APPFW_WATCH capi-appfw-watch-application watch_available )
 CHECK_MODULE_AND_SET( APPCORE_WATCH appcore-watch [] )
 
-CHECK_MODULE_AND_SET( CAPI_APPFW_APPLICATION appcore-ui [] )
+CHECK_MODULE_AND_SET( CAPI_APPFW_APPLICATION app-core-ui-cpp [] )
 CHECK_MODULE_AND_SET( CAPI_APPFW_WIDGET_BASE appcore-widget-base [] )
 CHECK_MODULE_AND_SET( CAPI_APPFW_COMMON capi-appfw-app-common [] )
 CHECK_MODULE_AND_SET( CAPI_APPFW_CONTROL capi-appfw-app-control [] )
@@ -369,6 +369,7 @@ IF( enable_appfw )
     ${ECORE_IMF_CFLAGS}
     ${FRIBIDI_CFLAGS}
     ${COMPONENT_BASED_CORE_BASE_CFLAGS}
+    ${SCREENCONNECTORPROVIDER_CFLAGS}
   )
 
   SET( DALI_LDFLAGS ${DALI_LDFLAGS}
@@ -384,6 +385,7 @@ IF( enable_appfw )
     ${ECORE_IMF_LDFLAGS}
     ${FRIBIDI_LDFLAGS}
     ${COMPONENT_BASED_CORE_BASE_LDFLAGS}
+    ${SCREENCONNECTORPROVIDER_LDFLAGS}
   )
 ELSE()
   SET( DALI_CFLAGS ${DALI_CFLAGS}
@@ -440,11 +442,9 @@ IF( WEARABLE_PROFILE )
   SET( DALI_CFLAGS ${DALI_CFLAGS}
     ${HAPTIC_CFLAGS}
     ${EFL_ASSIST_CFLAGS}
-    ${SCREENCONNECTORPROVIDER_CFLAGS}
     ${APPCORE_WATCH_CFLAGS}
   )
   SET( DALI_LDFLAGS ${DALI_LDFLAGS}
-    ${SCREENCONNECTORPROVIDER_LDFLAGS}
     ${APPCORE_WATCH_LDFLAGS}
   )
 ENDIF()
index 2606291..d9c0159 100644 (file)
@@ -134,17 +134,9 @@ public:
   // Constructors
 
   /**
-   * @brief Constructs a new BitSet with all bits set to 0.
-   *
-   * Equivalent to the pseudocode:
-   * @code
-   * for(i = 0; i < max; ++i) bits[i] = 0;
-   * @endcode
+   * @brief Constructor.
    */
-  BitSet()
-  {
-    std::fill(mData.begin(), mData.end(), 0u);
-  }
+  BitSet() = default;
 
   BitSet(const BitSet&) = default;
 
@@ -177,6 +169,22 @@ public:
   /**
    * @brief Constructs a new BitSet with all bits initialized with bits from the specified integer.
    *
+   * This constructor is only available for BitSets with 32-bit capacity. Equivalent to the pseudocode:
+   * @code
+   * for(i = 0; i < 32; ++i) bits[i] = (data >> i) & 0x1;
+   * @endcode
+   *
+   * @param data 32-bit integer with the initial values.
+   */
+  template<std::size_t I = N, typename = std::enable_if_t<(I == N && N == 1u)>>
+  explicit BitSet(std::uint32_t data)
+  {
+    mData[0] = data;
+  }
+
+  /**
+   * @brief Constructs a new BitSet with all bits initialized with bits from the specified integer.
+   *
    * This constructor is only available for BitSets with 64-bit capacity. Equivalent to the pseudocode:
    * @code
    * for(i = 0; i < 64; ++i) bits[i] = (data >> i) & 0x1;
@@ -368,6 +376,21 @@ public:
   /**
    * @brief Obtains a copy of the internal storage serialized as a single integer.
    *
+   * This method is only available for BitSets with 32-bit capacity.
+   *
+   * @return A copy of the internal storage.
+   *
+   * @see BitSet::BitSet(std::uint32_t)
+   */
+  template<std::size_t I = N, typename = std::enable_if_t<(I == N && N == 1u)>>
+  std::uint32_t GetRawData32() const
+  {
+    return mData[0];
+  }
+
+  /**
+   * @brief Obtains a copy of the internal storage serialized as a single integer.
+   *
    * This method is only available for BitSets with 64-bit capacity.
    *
    * @return A copy of the internal storage.
@@ -398,7 +421,7 @@ private:
     return result;
   }
 
-  ArrayType mData;
+  ArrayType mData{};
 };
 
 /**
@@ -432,6 +455,38 @@ public:
   // Operators
 
   /**
+   * @copydoc BitSet::operator~() const
+   */
+  EnumBitSet operator~() const
+  {
+    return BitSet<N>::operator~();
+  }
+
+  /**
+   * @copydoc BitSet::operator|(const BitSet&) const
+   */
+  EnumBitSet operator|(const EnumBitSet& other) const
+  {
+    return BitSet<N>::operator|(other);
+  }
+
+  /**
+   * @copydoc BitSet::operator&(const BitSet&) const
+   */
+  EnumBitSet operator&(const EnumBitSet& other) const
+  {
+    return BitSet<N>::operator&(other);
+  }
+
+  /**
+   * @copydoc BitSet::operator^(const BitSet&) const
+   */
+  EnumBitSet operator^(const EnumBitSet& other) const
+  {
+    return BitSet<N>::operator^(other);
+  }
+
+  /**
    * @copydoc BitSet::operator[](IndexType) const
    */
   bool operator[](Enum index) const
@@ -448,6 +503,12 @@ public:
   }
 
 private:
+  // For operators '~|&^'
+  EnumBitSet(BitSet<N>&& bitSet)
+  : BitSet<N>(bitSet)
+  {
+  }
+
   // No data members (non-virtual destructor)
 };
 
index ba26501..1b59436 100644 (file)
@@ -132,6 +132,15 @@ struct DALI_ADAPTOR_API Bridge
   virtual void SetApplicationName(std::string name) = 0;
 
   /**
+   * @brief Sets the name of the GUI toolkit that AT-SPI clients can query.
+   *
+   * The default name is "dali".
+   *
+   * @param toolkitName The toolkit name
+   */
+  virtual void SetToolkitName(std::string_view toolkitName) = 0;
+
+  /**
    * @brief Gets object being root of accessibility tree.
    *
    * @return handler to accessibility object
@@ -249,6 +258,13 @@ struct DALI_ADAPTOR_API Bridge
   virtual void EmitMovedOutOfScreen(Accessible* obj, ScreenRelativeMoveType type) = 0;
 
   /**
+   * @brief Emits "org.a11y.atspi.Socket.Available" event on AT-SPI bus.
+   *
+   * @param obj Accessible object
+   */
+  virtual void EmitSocketAvailable(Accessible* obj) = 0;
+
+  /**
    * @brief Emits state-changed event on at-spi bus.
    *
    * @param[in] obj The accessible object
@@ -350,6 +366,41 @@ struct DALI_ADAPTOR_API Bridge
   virtual bool IsEnabled() = 0;
 
   /**
+   * @brief Calls socket.Embed(plug) via D-Bus.
+   *
+   * @param[in] plug The plug
+   * @param[in] socket The socket
+   *
+   * @return Address returned by the D-Bus call.
+   *
+   * @note Remote object pointed to by 'socket' must implement 'org.a11y.atspi.Socket'.
+   * @see UnembedSocket()
+   */
+  virtual Address EmbedSocket(const Address& plug, const Address& socket) = 0;
+
+  /**
+   * @brief Calls socket.Embedded(plug) via D-Bus.
+   *
+   * The "Embedded" D-Bus method is an ATK extension.
+   * See 'impl_Embedded' in AT_SPI2_ATK/atk-adaptor/adaptors/socket-adaptor.c for more information.
+   *
+   * @param[in] plug The plug
+   * @param[in] socket The socket
+   */
+  virtual void EmbedAtkSocket(const Address& plug, const Address& socket) = 0;
+
+  /**
+   * @brief Calls socket.Unmbed(plug) via D-Bus.
+   *
+   * @param[in] plug The plug
+   * @param[in] socket The socket
+   *
+   * @note Remote object pointed to by 'socket' must implement 'org.a11y.atspi.Socket'.
+   * @see EmbedSocket()
+   */
+  virtual void UnembedSocket(const Address& plug, const Address& socket) = 0;
+
+  /**
    * @brief Returns instance of bridge singleton object.
    *
    * @return The current bridge object
@@ -394,6 +445,16 @@ struct DALI_ADAPTOR_API Bridge
     return mDisabledSignal;
   }
 
+  static Signal<void()>& ScreenReaderEnabledSignal()
+  {
+    return mScreenReaderEnabledSignal;
+  }
+
+  static Signal<void()>& ScreenReaderDisabledSignal()
+  {
+    return mScreenReaderDisabledSignal;
+  }
+
 protected:
   struct Data
   {
@@ -416,6 +477,8 @@ protected:
 
   inline static Signal<void()> mEnabledSignal;
   inline static Signal<void()> mDisabledSignal;
+  inline static Signal<void()> mScreenReaderEnabledSignal;
+  inline static Signal<void()> mScreenReaderDisabledSignal;
 
   /**
    * @brief Registers accessible object to be known in bridge object.
index cea55f3..b058328 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020  Samsung Electronics Co., Ltd
+ * Copyright 2022  Samsung Electronics Co., Ltd
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #include <dali/devel-api/adaptor-framework/proxy-accessible.h>
 #include <dali/devel-api/adaptor-framework/window-devel.h>
 #include <dali/devel-api/atspi-interfaces/accessible.h>
+#include <dali/devel-api/atspi-interfaces/action.h>
+#include <dali/devel-api/atspi-interfaces/application.h>
 #include <dali/devel-api/atspi-interfaces/collection.h>
 #include <dali/devel-api/atspi-interfaces/component.h>
+#include <dali/devel-api/atspi-interfaces/editable-text.h>
+#include <dali/devel-api/atspi-interfaces/hyperlink.h>
+#include <dali/devel-api/atspi-interfaces/hypertext.h>
+#include <dali/devel-api/atspi-interfaces/selection.h>
+#include <dali/devel-api/atspi-interfaces/socket.h>
+#include <dali/devel-api/atspi-interfaces/text.h>
+#include <dali/devel-api/atspi-interfaces/value.h>
 #include <dali/internal/adaptor/common/adaptor-impl.h>
+#include <dali/internal/window-system/common/window-impl.h>
 #include <dali/public-api/dali-adaptor-common.h>
 
 using namespace Dali::Accessibility;
@@ -185,6 +195,100 @@ std::string Accessible::GetRoleName() const
   return std::string{it->second};
 }
 
+AtspiInterfaces Accessible::GetInterfaces() const
+{
+  if(!mInterfaces)
+  {
+    mInterfaces = DoGetInterfaces();
+    DALI_ASSERT_DEBUG(mInterfaces); // There has to be at least AtspiInterface::ACCESSIBLE
+  }
+
+  return mInterfaces;
+}
+
+std::vector<std::string> Accessible::GetInterfacesAsStrings() const
+{
+  std::vector<std::string> ret;
+  AtspiInterfaces          interfaces = GetInterfaces();
+
+  for(std::size_t i = 0u; i < static_cast<std::size_t>(AtspiInterface::MAX_COUNT); ++i)
+  {
+    auto interface = static_cast<AtspiInterface>(i);
+
+    if(interfaces[interface])
+    {
+      auto name = GetInterfaceName(interface);
+
+      DALI_ASSERT_DEBUG(!name.empty());
+      ret.emplace_back(std::move(name));
+    }
+  }
+
+  return ret;
+}
+
+AtspiInterfaces Accessible::DoGetInterfaces() const
+{
+  AtspiInterfaces interfaces;
+
+  interfaces[AtspiInterface::ACCESSIBLE]    = true;
+  interfaces[AtspiInterface::ACTION]        = dynamic_cast<const Action*>(this);
+  interfaces[AtspiInterface::APPLICATION]   = dynamic_cast<const Application*>(this);
+  interfaces[AtspiInterface::COLLECTION]    = dynamic_cast<const Collection*>(this);
+  interfaces[AtspiInterface::COMPONENT]     = dynamic_cast<const Component*>(this);
+  interfaces[AtspiInterface::EDITABLE_TEXT] = dynamic_cast<const EditableText*>(this);
+  interfaces[AtspiInterface::HYPERLINK]     = dynamic_cast<const Hyperlink*>(this);
+  interfaces[AtspiInterface::HYPERTEXT]     = dynamic_cast<const Hypertext*>(this);
+  interfaces[AtspiInterface::SELECTION]     = dynamic_cast<const Selection*>(this);
+  interfaces[AtspiInterface::SOCKET]        = dynamic_cast<const Socket*>(this);
+  interfaces[AtspiInterface::TEXT]          = dynamic_cast<const Text*>(this);
+  interfaces[AtspiInterface::VALUE]         = dynamic_cast<const Value*>(this);
+
+  return interfaces;
+}
+
+std::string Accessible::GetInterfaceName(AtspiInterface interface)
+{
+  static const std::unordered_map<AtspiInterface, std::string_view> interfaceMap{
+    {AtspiInterface::ACCESSIBLE, "org.a11y.atspi.Accessible"},
+    {AtspiInterface::ACTION, "org.a11y.atspi.Action"},
+    {AtspiInterface::APPLICATION, "org.a11y.atspi.Application"},
+    {AtspiInterface::CACHE, "org.a11y.atspi.Cache"},
+    {AtspiInterface::COLLECTION, "org.a11y.atspi.Collection"},
+    {AtspiInterface::COMPONENT, "org.a11y.atspi.Component"},
+    {AtspiInterface::DEVICE_EVENT_CONTROLLER, "org.a11y.atspi.DeviceEventController"},
+    {AtspiInterface::DEVICE_EVENT_LISTENER, "org.a11y.atspi.DeviceEventListener"},
+    {AtspiInterface::DOCUMENT, "org.a11y.atspi.Document"},
+    {AtspiInterface::EDITABLE_TEXT, "org.a11y.atspi.EditableText"},
+    {AtspiInterface::EVENT_DOCUMENT, "org.a11y.atspi.Event.Document"},
+    {AtspiInterface::EVENT_FOCUS, "org.a11y.atspi.Event.Focus"},
+    {AtspiInterface::EVENT_KEYBOARD, "org.a11y.atspi.Event.Keyboard"},
+    {AtspiInterface::EVENT_MOUSE, "org.a11y.atspi.Event.Mouse"},
+    {AtspiInterface::EVENT_OBJECT, "org.a11y.atspi.Event.Object"},
+    {AtspiInterface::EVENT_TERMINAL, "org.a11y.atspi.Event.Terminal"},
+    {AtspiInterface::EVENT_WINDOW, "org.a11y.atspi.Event.Window"},
+    {AtspiInterface::HYPERLINK, "org.a11y.atspi.Hyperlink"},
+    {AtspiInterface::HYPERTEXT, "org.a11y.atspi.Hypertext"},
+    {AtspiInterface::IMAGE, "org.a11y.atspi.Image"},
+    {AtspiInterface::REGISTRY, "org.a11y.atspi.Registry"},
+    {AtspiInterface::SELECTION, "org.a11y.atspi.Selection"},
+    {AtspiInterface::SOCKET, "org.a11y.atspi.Socket"},
+    {AtspiInterface::TABLE, "org.a11y.atspi.Table"},
+    {AtspiInterface::TABLE_CELL, "org.a11y.atspi.TableCell"},
+    {AtspiInterface::TEXT, "org.a11y.atspi.Text"},
+    {AtspiInterface::VALUE, "org.a11y.atspi.Value"},
+  };
+
+  auto it = interfaceMap.find(interface);
+
+  if(it == interfaceMap.end())
+  {
+    return {};
+  }
+
+  return std::string{it->second};
+}
+
 Dali::Actor Accessible::GetCurrentlyHighlightedActor()
 {
   return IsUp() ? Bridge::GetCurrentBridge()->mData->mCurrentlyHighlightedActor : Dali::Actor{};
@@ -251,12 +355,69 @@ public:
 
   bool GrabHighlight() override
   {
-    return false;
+    if(!IsUp())
+    {
+      return false;
+    }
+
+    // Only window accessible is able to grab and clear highlight
+    if(!mRoot)
+    {
+      return false;
+    }
+
+    auto self = Self();
+    auto oldHighlightedActor = GetCurrentlyHighlightedActor();
+    if(self == oldHighlightedActor)
+    {
+      return true;
+    }
+
+    // Clear the old highlight.
+    if(oldHighlightedActor)
+    {
+      auto oldHighlightedObject = Dali::Accessibility::Component::DownCast(Accessible::Get(oldHighlightedActor));
+      if(oldHighlightedObject)
+      {
+        oldHighlightedObject->ClearHighlight();
+      }
+    }
+
+    SetCurrentlyHighlightedActor(self);
+
+    auto window                                 = Dali::DevelWindow::Get(self);
+    Dali::Internal::Adaptor::Window& windowImpl = Dali::GetImplementation(window);
+    windowImpl.EmitAccessibilityHighlightSignal(true);
+
+    return true;
   }
 
   bool ClearHighlight() override
   {
-    return false;
+    if(!IsUp())
+    {
+      return false;
+    }
+
+    // Only window accessible is able to grab and clear highlight
+    if(!mRoot)
+    {
+      return false;
+    }
+
+    auto self = Self();
+    if(self != GetCurrentlyHighlightedActor())
+    {
+      return false;
+    }
+
+    SetCurrentlyHighlightedActor({});
+
+    auto window                                 = Dali::DevelWindow::Get(self);
+    Dali::Internal::Adaptor::Window& windowImpl = Dali::GetImplementation(window);
+    windowImpl.EmitAccessibilityHighlightSignal(false);
+
+    return true;
   }
 
   Role GetRole() const override
@@ -288,11 +449,20 @@ public:
 
   Attributes GetAttributes() const override
   {
+    Attributes attributes;
+
+    if(mRoot)
+    {
+      Dali::Window window                         = Dali::DevelWindow::Get(Self());
+      Dali::Internal::Adaptor::Window& windowImpl = Dali::GetImplementation(window);
+      attributes["resID"]                         = windowImpl.GetNativeResourceId();
+    }
+
     Dali::TypeInfo type;
     Self().GetTypeInfo(type);
-    return {
-      {"class", type.GetName()},
-    };
+    attributes["class"] = type.GetName();
+
+    return attributes;
   }
 
   bool DoGesture(const GestureInfo& gestureInfo) override
@@ -331,7 +501,7 @@ void Accessible::RegisterExternalAccessibleGetter(std::function<Accessible*(Dali
   convertingFunctor = functor;
 }
 
-Accessible* Accessible::Get(Dali::Actor actor, bool isRoot)
+Accessible* Accessible::Get(Dali::Actor actor)
 {
   if(!actor)
   {
@@ -344,6 +514,12 @@ Accessible* Accessible::Get(Dali::Actor actor, bool isRoot)
     auto pair = gAdaptorAccessibles.emplace(&actor.GetBaseObject(), nullptr);
     if(pair.second)
     {
+      bool isRoot                    = false;
+      Dali::Integration::Scene scene = Dali::Integration::Scene::Get(actor);
+      if(scene)
+      {
+        isRoot = (actor == scene.GetRootLayer());
+      }
       pair.first->second.reset(new AdaptorAccessible(actor, isRoot));
     }
     accessible = pair.first->second.get();
index ef54cd3..77c7257 100644 (file)
@@ -30,6 +30,8 @@ namespace Dali
 {\r
 namespace Accessibility\r
 {\r
+class Accessible;\r
+\r
 /**\r
  * @brief Enumeration describing type of object move relative to the screen. Only outgoing moves are signalled to AT-clients.\r
  */\r
@@ -428,9 +430,108 @@ enum class ReadingInfoType
   MAX_COUNT\r
 };\r
 \r
-using ReadingInfoTypes = EnumBitSet<ReadingInfoType, ReadingInfoType::MAX_COUNT>;\r
-using States           = EnumBitSet<State, State::MAX_COUNT>;\r
-using Attributes       = std::unordered_map<std::string, std::string>;\r
+/**\r
+ * @brief Enumeration of all AT-SPI interfaces.\r
+ *\r
+ * @see Dali::Accessibility::Accessible::GetInterfaceName()\r
+ * @see Dali::Accessibility::AtspiInterfaceType\r
+ */\r
+enum class AtspiInterface\r
+{\r
+  ACCESSIBLE,\r
+  ACTION,\r
+  APPLICATION,\r
+  CACHE,\r
+  COLLECTION,\r
+  COMPONENT,\r
+  DEVICE_EVENT_CONTROLLER,\r
+  DEVICE_EVENT_LISTENER,\r
+  DOCUMENT,\r
+  EDITABLE_TEXT,\r
+  EVENT_DOCUMENT,\r
+  EVENT_FOCUS,\r
+  EVENT_KEYBOARD,\r
+  EVENT_MOUSE,\r
+  EVENT_OBJECT,\r
+  EVENT_TERMINAL,\r
+  EVENT_WINDOW,\r
+  HYPERLINK,\r
+  HYPERTEXT,\r
+  IMAGE,\r
+  REGISTRY,\r
+  SELECTION,\r
+  SOCKET,\r
+  TABLE,\r
+  TABLE_CELL,\r
+  TEXT,\r
+  VALUE,\r
+  MAX_COUNT\r
+};\r
+\r
+/**\r
+ * @brief Enumeration of all AT-SPI events.\r
+ */\r
+enum class AtspiEvent\r
+{\r
+  PROPERTY_CHANGED,\r
+  BOUNDS_CHANGED,\r
+  LINK_SELECTED,\r
+  STATE_CHANGED,\r
+  CHILDREN_CHANGED,\r
+  VISIBLE_DATA_CHANGED,\r
+  SELECTION_CHANGED,\r
+  MODEL_CHANGED,\r
+  ACTIVE_DESCENDANT_CHANGED,\r
+  ROW_INSERTED,\r
+  ROW_REORDERED,\r
+  ROW_DELETED,\r
+  COLUMN_INSERTED,\r
+  COLUMN_REORDERED,\r
+  COLUMN_DELETED,\r
+  TEXT_BOUNDS_CHANGED,\r
+  TEXT_SELECTION_CHANGED,\r
+  TEXT_CHANGED,\r
+  TEXT_ATTRIBUTES_CHANGED,\r
+  TEXT_CARET_MOVED,\r
+  ATTRIBUTES_CHANGED,\r
+  MOVED_OUT,\r
+  WINDOW_CHANGED,\r
+  MAX_COUNT\r
+};\r
+\r
+using AtspiInterfaces   = EnumBitSet<AtspiInterface, AtspiInterface::MAX_COUNT>;\r
+using AtspiEvents       = EnumBitSet<AtspiEvent, AtspiEvent::MAX_COUNT>;\r
+using ReadingInfoTypes  = EnumBitSet<ReadingInfoType, ReadingInfoType::MAX_COUNT>;\r
+using States            = EnumBitSet<State, State::MAX_COUNT>;\r
+using Attributes        = std::unordered_map<std::string, std::string>;\r
+\r
+namespace Internal\r
+{\r
+/*\r
+ * AT-SPI interfaces exposed as native C++ types should specialize this like so:\r
+ *\r
+ * template<>\r
+ * struct AtspiInterfaceTypeHelper<AtspiInterface::ACCESSIBLE>\r
+ * {\r
+ *   using Type = Dali::Accessibility::Accessible;\r
+ * };\r
+ */\r
+template<AtspiInterface I>\r
+struct AtspiInterfaceTypeHelper; // no default definition\r
+\r
+} // namespace Internal\r
+\r
+/**\r
+ * @brief Resolves to the native C++ type that represents the given AT-SPI interface.\r
+ *\r
+ * For example, @code AtspiInterfaceType<AtspiInterface::ACCESSIBLE> @endcode is the same as\r
+ * @code Dali::Accessibility::Accessible @endcode. Not all AT-SPI interfaces have native C++\r
+ * representations (in which case, such an expression will not compile).\r
+ *\r
+ * @tparam I Enumeration value indicating the requested AT-SPI interface.\r
+ */\r
+template<AtspiInterface I>\r
+using AtspiInterfaceType = typename Internal::AtspiInterfaceTypeHelper<I>::Type;\r
 \r
 /**\r
  * @brief Class representing unique object address on accessibility bus\r
@@ -612,22 +713,26 @@ struct DALI_ADAPTOR_API GestureInfo
 \r
 /**\r
  * @brief Class representing accessibility relations\r
+ *\r
  * Class connecting one source object with multiple target objects with usage\r
  * of specific relation type.\r
- * @note std::string representing source and targets are string values of Accessibility::Address\r
- * @see Dali::Accessibility::Accessible::Address\r
+ *\r
+ * A remote target object (i.e. one belonging to a different process) can be\r
+ * represented in terms of a ProxyAccessible.\r
+ *\r
+ * @see Dali::Accessibility::Accessible::Accessible\r
  * @see Dali::Accessibility::Accessible::RelationType\r
  */\r
 struct DALI_ADAPTOR_API Relation\r
 {\r
-  Relation(RelationType relationType, std::vector<Address> targets)\r
-  : relationType(relationType),\r
-    targets(targets)\r
+  Relation(RelationType relationType, const std::vector<Accessible*>& targets)\r
+  : mRelationType(relationType),\r
+    mTargets(targets)\r
   {\r
   }\r
 \r
-  RelationType         relationType;\r
-  std::vector<Address> targets;\r
+  RelationType             mRelationType;\r
+  std::vector<Accessible*> mTargets;\r
 };\r
 \r
 } // namespace Accessibility\r
index 8f6a118..6f8b3b9 100644 (file)
@@ -60,12 +60,6 @@ AnimatedImageLoading AnimatedImageLoading::DownCast(BaseHandle handle)
 AnimatedImageLoading::~AnimatedImageLoading()
 {
 }
-
-bool AnimatedImageLoading::LoadNextNFrames(uint32_t frameStartIndex, int count, std::vector<Dali::PixelData>& pixelData)
-{
-  return GetImplementation(*this).LoadNextNFrames(frameStartIndex, count, pixelData);
-}
-
 Dali::Devel::PixelBuffer AnimatedImageLoading::LoadFrame(uint32_t frameIndex)
 {
   return GetImplementation(*this).LoadFrame(frameIndex);
index 92d825c..da72e3f 100644 (file)
@@ -100,18 +100,6 @@ public:
   ~AnimatedImageLoading();
 
   /**
-   * @brief Load the next N Frames of the animated image.
-   *
-   * @note This function will load the entire animated image into memory if not already loaded.
-   * @param[in] frameStartIndex The frame counter to start from. Will usually be the next frame
-   * after the previous invocation of this method, or 0 to start.
-   * @param[in] count The number of frames to load
-   * @param[out] pixelData The vector in which to return the frame data
-   * @return True if the frame data was successfully loaded
-   */
-  bool LoadNextNFrames(uint32_t frameStartIndex, int count, std::vector<Dali::PixelData>& pixelData);
-
-  /**
    * @brief Load a frame of the animated image.
    *
    * @note This function will load the entire animated image into memory if not already loaded.
index 50f5772..533a68c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,7 +18,9 @@
 // INTERNAL INCLUDES
 #include <dali/devel-api/adaptor-framework/application-devel.h>
 #include <dali/integration-api/adaptor-framework/scene-holder.h>
+#include <dali/internal/adaptor/common/adaptor-impl.h>
 #include <dali/internal/adaptor/common/application-impl.h>
+#include <dali/internal/network/common/network-service-impl.h>
 
 namespace Dali
 {
@@ -44,8 +46,7 @@ Application New(int* argc, char** argv[], const std::string& stylesheet, Applica
 
     //Store only the value before adaptor is created
     internal->StoreWindowPositionSize(positionSize);
-  }
-  else
+  } else
   {
     internal = Internal::Adaptor::Application::New(argc, argv, stylesheet, windowMode, positionSize, Internal::Adaptor::Framework::NORMAL, type);
   }
@@ -67,6 +68,17 @@ Application DownCast(Dali::RefObject* refObject)
   return Application(dynamic_cast<Dali::Internal::Adaptor::Application*>(refObject));
 }
 
+CustomCommandReceivedSignalType& CustomCommandReceivedSignal(Application application)
+{
+  DALI_ASSERT_ALWAYS(Adaptor::IsAvailable() && "Adaptor is not available")
+
+  Internal::Adaptor::NetworkServicePtr networkService = Internal::Adaptor::NetworkService::Get();
+
+  DALI_ASSERT_ALWAYS(networkService && "Network Service Unavailable");
+
+  return networkService->CustomCommandReceivedSignal();
+}
+
 } // namespace DevelApplication
 
 } // namespace Dali
index e82281c..095c252 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_APPLICATION_DEVEL_H
 
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 // INTERNAL INCLUDES
 #include <dali/public-api/adaptor-framework/application.h>
+#include <dali/public-api/dali-adaptor-common.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/signals/dali-signal.h>
 
 namespace Dali
 {
 namespace DevelApplication
 {
+
+using CustomCommandReceivedSignalType = Signal<void(const std::string&)>; ///< Signal signature for CustomCommandReceivedSignal
+
 /**
    * @brief This is the constructor for applications.
    * Especially, it is for keyboard application.
@@ -76,6 +83,22 @@ DALI_ADAPTOR_API std::string GetDataPath();
  */
 DALI_ADAPTOR_API Application DownCast(Dali::RefObject* refObject);
 
+/**
+ * @brief This signal will be triggered when a custom command is received.
+ *
+ * For this signal to be triggered, the adaptor must be built with -DENABLE_NETWORK_LOGGING=ON
+ * and when running, DALI_NETWORK_CONTROL=1 must also be set.
+ *
+ * A callback of the following type may be connected:
+ * @code
+ *   void YourCallbackName(const std::string&);
+ * @endcode
+ *
+ * @param[in] application A handle to the Application
+ * @return The signal when a custom command is received
+ */
+DALI_ADAPTOR_API CustomCommandReceivedSignalType& CustomCommandReceivedSignal(Application application);
+
 } // namespace DevelApplication
 
 } // namespace Dali
index 53a230d..1adebe7 100644 (file)
@@ -118,3 +118,8 @@ bool Dali::AtspiAccessibility::IsEnabled()
 {
   return Dali::Accessibility::IsUp();
 }
+
+bool Dali::AtspiAccessibility::IsScreenReaderEnabled()
+{
+  return Dali::Accessibility::Bridge::GetCurrentBridge()->GetScreenReaderEnabled();
+}
\ No newline at end of file
index 16f1e37..3ee0674 100644 (file)
@@ -87,6 +87,13 @@ DALI_ADAPTOR_API int GetStatus();
  */
 DALI_ADAPTOR_API bool IsEnabled();
 
+/**
+ * @brief Returns whether the state of Screen Reader is enabled or not.
+ *
+ * @return True if Screen Reader is enabled, false otherwise.
+ */
+DALI_ADAPTOR_API bool IsScreenReaderEnabled();
+
 } //namespace AtspiAccessibility
 } //namespace Dali
 
index 541d116..707f691 100644 (file)
@@ -39,9 +39,9 @@ DragAndDrop DragAndDrop::Get()
   return Internal::Adaptor::GetDragAndDrop();
 }
 
-bool DragAndDrop::StartDragAndDrop(Dali::Actor source, Dali::Actor shadow, const std::string& dragData)
+bool DragAndDrop::StartDragAndDrop(Dali::Actor source, Dali::Window shadowWindow, const DragData& dragData, Dali::DragAndDrop::SourceFunction callback)
 {
-  return GetImplementation(*this).StartDragAndDrop(source, shadow, dragData);
+  return GetImplementation(*this).StartDragAndDrop(source, shadowWindow, dragData, callback);
 }
 
 bool DragAndDrop::AddListener(Dali::Actor target, DragAndDropFunction callback)
@@ -49,4 +49,9 @@ bool DragAndDrop::AddListener(Dali::Actor target, DragAndDropFunction callback)
   return GetImplementation(*this).AddListener(target, callback);
 }
 
+bool DragAndDrop::RemoveListener(Dali::Actor target)
+{
+  return GetImplementation(*this).RemoveListener(target);
+}
+
 } // namespace Dali
index 32f4d89..eb2dc89 100644 (file)
@@ -19,6 +19,7 @@
  */
 
 // EXTERNAL INCLUDES
+#include <dali/public-api/adaptor-framework/window.h>
 #include <dali/public-api/actors/actor.h>
 #include <dali/public-api/math/rect.h>
 #include <dali/public-api/object/base-handle.h>
@@ -47,6 +48,17 @@ class DALI_ADAPTOR_API DragAndDrop : public BaseHandle
 {
 public:
   /**
+   * @brief Enumeration for the drag source event type in the source object
+   */
+  enum class SourceEventType
+  {
+    START,   ///< Drag and drop is started.
+    CANCEL,  ///< Drag and drop is cancelled.
+    ACCEPT,  ///< Drag and drop is accepted.
+    FINISH   ///< Drag and drop is finished.
+  };
+
+  /**
    * @brief Enumeration for the drag event type in the target object
    */
   enum class DragType
@@ -64,12 +76,14 @@ public:
   {
     DragEvent()
     {
+      this->mimeType = nullptr;
       this->data = nullptr;
     }
-    DragEvent(DragType type, Dali::Vector2 position, char* data = nullptr)
+    DragEvent(DragType type, Dali::Vector2 position, const char* mimeType = nullptr, char* data = nullptr)
     {
       this->type     = type;
       this->position = position;
+      this->mimeType = mimeType;
       this->data     = data;
     }
 
@@ -89,11 +103,19 @@ public:
     {
       return position;
     }
+    void SetMimeType(const char* mimeType)
+    {
+      this->mimeType = mimeType;
+    }
+    const char* GetMimeType()
+    {
+      return mimeType;
+    }
     void SetData(char* data)
     {
       this->data = data;
     }
-    char* GetData()
+    char* GetData() const
     {
       return data;
     }
@@ -101,10 +123,39 @@ public:
   private:
     DragType      type{DragType::DROP}; ///< The drag event type.
     Dali::Vector2 position;             ///< The position of drag object.
+    const char*   mimeType;             ///< The mime type of drag object.
     char*         data{nullptr};        ///< The data of drag object.
   };
 
+  /**
+   * @brief Structure that contains information about the drag data information.
+   */
+  struct DragData
+  {
+     void SetMimeType(const char* mimeType)
+     {
+       this->mimeType = mimeType;
+     }
+     const char* GetMimeType() const
+     {
+       return mimeType;
+     }
+     void SetData(const char* data)
+     {
+       this->data = data;
+     }
+     const char* GetData() const
+     {
+       return data;
+     }
+
+  private:
+     const char* mimeType{nullptr}; ///<The mime type of drag data.
+     const char* data{nullptr};     ///<The drag data.
+  };
+
   using DragAndDropFunction = std::function<void(const DragEvent&)>;
+  using SourceFunction = std::function<void(enum SourceEventType)>;
 
   /**
    * @brief Create an uninitialized DragAndDrop.
@@ -136,11 +187,12 @@ public:
    * @brief Start the drag operation.
    *
    * @param[in] source The drag source object.
-   * @param[in] shadow The shadow object for drag object.
+   * @param[in] shadowWindow The shadow window for drag object.
    * @param[in] dragData The data to send to target object.
+   * @param[in] callback The drag source event callback.
    * @return bool true if the drag operation is started successfully.
    */
-  bool StartDragAndDrop(Dali::Actor source, Dali::Actor shadow, const std::string& dragData);
+  bool StartDragAndDrop(Dali::Actor source, Dali::Window shadowWindow, const DragData& dragData, Dali::DragAndDrop::SourceFunction callback);
 
   /**
    * @brief Add the listener for receiving the drag and drop events.
@@ -151,6 +203,14 @@ public:
    */
   bool AddListener(Dali::Actor target, DragAndDropFunction callback);
 
+  /**
+   * @brief Remove the listener.
+   *
+   * @param[in] target The drop target object.
+   * @return bool true if the listener is removed successfully.
+   */
+  bool RemoveListener(Dali::Actor target);
+
 public:
   /**
    * @brief This constructor is used by Adaptor::GetDragAndDrop().
index 830b33c..80d7b61 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TIZEN_PLATFORM_IMAGE_LOADER_INPUT_H
 
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -63,6 +63,7 @@ struct Input
 };
 
 using LoadBitmapFunction       = bool (*)(const Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& pixelData);
+using LoadPlanesFunction       = bool (*)(const Dali::ImageLoader::Input& input, std::vector<Dali::Devel::PixelBuffer>& pixelBuffers);
 using LoadBitmapHeaderFunction = bool (*)(const Dali::ImageLoader::Input& input, unsigned int& width, unsigned int& height);
 
 /**
@@ -70,12 +71,13 @@ using LoadBitmapHeaderFunction = bool (*)(const Dali::ImageLoader::Input& input,
  */
 struct BitmapLoader
 {
-  unsigned char                      magicByte1; ///< The first byte in the file should be this
-  unsigned char                      magicByte2; ///< The second byte in the file should be this
-  LoadBitmapFunction                 loader;     ///< The function which decodes the file
-  LoadBitmapHeaderFunction           header;     ///< The function which decodes the header of the file
-  Dali::Integration::Bitmap::Profile profile;    ///< The kind of bitmap to be created
-                                                 ///  (addressable packed pixels or an opaque compressed blob).
+  unsigned char                      magicByte1;    ///< The first byte in the file should be this
+  unsigned char                      magicByte2;    ///< The second byte in the file should be this
+  LoadBitmapFunction                 loader;        ///< The function which decodes the file
+  LoadPlanesFunction                 planeLoader;   ///< The function which decodes the file to each plane
+  LoadBitmapHeaderFunction           header;        ///< The function which decodes the header of the file
+  Dali::Integration::Bitmap::Profile profile;       ///< The kind of bitmap to be created
+                                                    ///  (addressable packed pixels or an opaque compressed blob).
 };
 
 } // namespace ImageLoader
index cfaaa12..207b79a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -51,6 +51,18 @@ Devel::PixelBuffer LoadImageFromFile(const std::string& url, ImageDimensions siz
   return Dali::Devel::PixelBuffer();
 }
 
+void LoadImagePlanesFromFile(const std::string& url, std::vector<Devel::PixelBuffer>& buffers, ImageDimensions size, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection)
+{
+  Integration::BitmapResourceType resourceType(size, fittingMode, samplingMode, orientationCorrection);
+
+  Internal::Platform::FileReader fileReader(url);
+  FILE* const                    fp = fileReader.GetFile();
+  if(fp != NULL)
+  {
+    TizenPlatform::ImageLoader::ConvertStreamToPlanes(resourceType, url, fp, buffers);
+  }
+}
+
 Devel::PixelBuffer LoadImageFromBuffer(const Dali::Vector<uint8_t>& buffer, ImageDimensions size, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection)
 {
   if(buffer.Empty())
@@ -66,7 +78,7 @@ Devel::PixelBuffer LoadImageFromBuffer(const Dali::Vector<uint8_t>& buffer, Imag
   {
     Dali::Devel::PixelBuffer bitmap;
     // Make path as empty string. Path information just for file format hint.
-    bool                     success = TizenPlatform::ImageLoader::ConvertStreamToBitmap(resourceType, std::string(""), fp, bitmap);
+    bool success = TizenPlatform::ImageLoader::ConvertStreamToBitmap(resourceType, std::string(""), fp, bitmap);
     if(success && bitmap)
     {
       return bitmap;
index c1f7ad8..53e07df 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_IMAGE_LOADING_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -47,6 +47,27 @@ DALI_ADAPTOR_API Devel::PixelBuffer LoadImageFromFile(
   bool               orientationCorrection = true);
 
 /**
+ * @brief Load an image and save each plane to a separate buffer synchronously from local file.
+ *
+ * @note This method is thread safe, i.e. can be called from any thread.
+ *       If the image file doesn't support to load planes, this method returns a bitmap image instead.
+ *
+ * @param [in] url The URL of the image file to load.
+ * @param [out] buffers The loaded PixelBuffer object list or an empty list in case loading failed.
+ * @param [in] size The width and height to fit the loaded image to, 0.0 means whole image
+ * @param [in] fittingMode The method used to fit the shape of the image before loading to the shape defined by the size parameter.
+ * @param [in] samplingMode The filtering method used when sampling pixels from the input image while fitting it to desired size.
+ * @param [in] orientationCorrection Reorient the image to respect any orientation metadata in its header.
+ */
+DALI_ADAPTOR_API void LoadImagePlanesFromFile(
+  const std::string&               url,
+  std::vector<Devel::PixelBuffer>& buffers,
+  ImageDimensions                  size                  = ImageDimensions(0, 0),
+  FittingMode::Type                fittingMode           = FittingMode::DEFAULT,
+  SamplingMode::Type               samplingMode          = SamplingMode::BOX_THEN_LINEAR,
+  bool                             orientationCorrection = true);
+
+/**
  * @brief Load an image synchronously from encoded buffer.
  *
  * @note This method is thread safe, i.e. can be called from any thread.
index 78556d8..0487b06 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INPUT_METHOD_CONTEXT_H
 
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -66,7 +66,8 @@ public:
     COMMIT,             ///< Commit recieved
     DELETE_SURROUNDING, ///< Event to delete a range of characters from the string
     GET_SURROUNDING,    ///< Event to query string and cursor position
-    PRIVATE_COMMAND     ///< Private command sent from the input panel
+    PRIVATE_COMMAND,    ///< Private command sent from the input panel
+    SELECTION_SET       ///< input method needs to set the selection
   };
 
   /**
@@ -142,7 +143,9 @@ public:
     : predictiveString(),
       eventName(VOID),
       cursorOffset(0),
-      numberOfChars(0){};
+      numberOfChars(0),
+      startIndex(0),
+      endIndex(0){};
 
     /**
      * @brief Constructor
@@ -156,7 +159,26 @@ public:
     : predictiveString(aPredictiveString),
       eventName(aEventName),
       cursorOffset(aCursorOffset),
-      numberOfChars(aNumberOfChars)
+      numberOfChars(aNumberOfChars),
+      startIndex(0),
+      endIndex(0)
+    {
+    }
+
+    /**
+     * @brief Constructor
+     *
+     * @param[in] aEventName The name of the event from the InputMethodContext.
+     * @param[in] aStartIndex The start index of selection.
+     * @param[in] aEndIndex The end index of selection.
+     */
+    EventData(EventType aEventName, int aStartIndex, int aEndIndex)
+    : predictiveString(),
+      eventName(aEventName),
+      cursorOffset(0),
+      numberOfChars(0),
+      startIndex(aStartIndex),
+      endIndex(aEndIndex)
     {
     }
 
@@ -165,6 +187,8 @@ public:
     EventType   eventName;        ///< The name of the event from the InputMethodContext.
     int         cursorOffset;     ///< Start position from the current cursor position to start deleting characters.
     int         numberOfChars;    ///< number of characters to delete from the cursorOffset.
+    int         startIndex;       ///< The start index of selection.
+    int         endIndex;         ///< The end index of selection.
   };
 
   /**
index d55e178..9655a5a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -38,7 +38,7 @@ NativeImageSourceQueuePtr NativeImageSourceQueue::New(uint32_t width, uint32_t h
 NativeImageSourceQueuePtr NativeImageSourceQueue::New(Any nativeImageSourceQueue)
 {
   //ColorFormat will be ignored.
-  NativeImageSourceQueuePtr image = new NativeImageSourceQueue(0, 0, ColorFormat::RGBA8888, nativeImageSourceQueue);
+  NativeImageSourceQueuePtr image = new NativeImageSourceQueue(0, 0, ColorFormat::BGRA8888, nativeImageSourceQueue);
   if(image->mImpl)
   {
     return image;
index cb62fc1..01ca473 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_NATIVE_IMAGE_SOURCE_QUEUE_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -61,12 +61,16 @@ class DALI_ADAPTOR_API NativeImageSourceQueue : public NativeImageInterface
 public:
   /**
     * @brief Enumeration for the instance when creating a native image, the color depth has to be specified.
+    * @note This ColorFormat follows pixel byte order.
     */
   enum class ColorFormat
   {
     RGB888,   /// 8 red bits, 8 green bits, 8 blue bits
     RGBA8888, /// 8 red bits, 8 green bits, 8 blue bits, alpha 8 bits
-    RGBX8888  /// 8 red bits, 8 green bits, 8 blue bits, and 8 ignored bits
+    RGBX8888, /// 8 red bits, 8 green bits, 8 blue bits, and 8 ignored bits
+    BGR888,   /// 8 blue bits, 8 green bits, 8 red bits
+    BGRA8888, /// 8 blue bits, 8 green bits, 8 red bits, alpha 8 bits
+    BGRX8888, /// 8 blue bits, 8 green bits, 8 red bits, and 8 ignored bits
   };
 
   /**
index e5856c3..e033afa 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -84,6 +84,11 @@ unsigned int PixelBuffer::GetHeight() const
   return GetImplementation(*this).GetHeight();
 }
 
+unsigned int PixelBuffer::GetStride() const
+{
+  return GetImplementation(*this).GetStride();
+}
+
 Pixel::Format PixelBuffer::GetPixelFormat() const
 {
   return GetImplementation(*this).GetPixelFormat();
index 9e6f58a..51c6739 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_PIXEL_BUFFER_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -157,6 +157,14 @@ public:
   unsigned int GetHeight() const;
 
   /**
+   * @brief Gets the stride of the buffer in pixels.
+   *
+   * @SINCE_2_1.17
+   * @return The stride of the buffer in pixels. 0 means the buffer is tightly packed.
+   */
+  unsigned int GetStride() const;
+
+  /**
    * @brief Gets the pixel format.
    *
    * @SINCE_1_2.46
index e60c7e1..33e6b1b 100644 (file)
@@ -24,6 +24,7 @@
 // INTERNAL INCLUDES
 #include <dali/devel-api/adaptor-framework/accessibility.h>
 #include <dali/devel-api/atspi-interfaces/accessible.h>
+#include <dali/devel-api/atspi-interfaces/component.h>
 
 namespace Dali::Accessibility
 {
@@ -32,21 +33,25 @@ namespace Dali::Accessibility
  *
  * To be used as a proxy object, in those situations where you want to return an address in
  * a different bridge (embedding for example), but the object itself isn't planned to be used
- * otherwise. This object has no parent, no children, an empty name and so on.
+ * otherwise. This object has a settable parent, no children, an empty name and so on.
  */
-class DALI_ADAPTOR_API ProxyAccessible : public virtual Accessible
+class DALI_ADAPTOR_API ProxyAccessible : public virtual Accessible, public virtual Component
 {
 public:
-  ProxyAccessible() = default;
-
-  ProxyAccessible(Address address)
-  : mAddress(std::move(address))
+  ProxyAccessible()
+  : mAddress{},
+    mParent{nullptr}
   {
   }
 
   void SetAddress(Address address)
   {
-    this->mAddress = std::move(address);
+    mAddress = std::move(address);
+  }
+
+  void SetParent(Accessible* parent)
+  {
+    mParent = parent;
   }
 
   std::string GetName() const override
@@ -61,7 +66,7 @@ public:
 
   Accessible* GetParent() override
   {
-    return nullptr;
+    return mParent;
   }
 
   size_t GetChildCount() const override
@@ -104,6 +109,11 @@ public:
     return {};
   }
 
+  bool IsProxy() const override
+  {
+    return true;
+  }
+
   Address GetAddress() const override
   {
     return mAddress;
@@ -124,8 +134,51 @@ public:
     return Dali::Actor{};
   }
 
+  Rect<> GetExtents(CoordinateType type) const override
+  {
+    auto* parent = Component::DownCast(mParent);
+
+    return parent ? parent->GetExtents(type) : Rect<>{};
+  }
+
+  ComponentLayer GetLayer() const override
+  {
+    return ComponentLayer::WINDOW;
+  }
+
+  int16_t GetMdiZOrder() const override
+  {
+    return false;
+  }
+
+  bool GrabFocus() override
+  {
+    return false;
+  }
+
+  double GetAlpha() const override
+  {
+    return 0.0;
+  }
+
+  bool GrabHighlight() override
+  {
+    return false;
+  }
+
+  bool ClearHighlight() override
+  {
+    return false;
+  }
+
+  bool IsScrollable() const override
+  {
+    return false;
+  }
+
 private:
-  Address mAddress;
+  Address     mAddress;
+  Accessible* mParent;
 };
 
 } // namespace Dali::Accessibility
diff --git a/dali/devel-api/adaptor-framework/vector-image-renderer-plugin.h b/dali/devel-api/adaptor-framework/vector-image-renderer-plugin.h
deleted file mode 100644 (file)
index 76d78f7..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-#ifndef DALI_VECTOR_IMAGE_RENDERER_PLUGIN_H
-#define DALI_VECTOR_IMAGE_RENDERER_PLUGIN_H
-
-/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// INTERNAL INCLUDES
-#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
-
-namespace Dali
-{
-/**
- * VectorImageRendererPlugin is an abstract interface, used by dali-adaptor to render a vector image(SVG).
- * A concrete implementation must be created for each platform and provided as a dynamic library which
- * will be loaded at run time by the adaptor.
- */
-class VectorImageRendererPlugin
-{
-public:
-  /**
-   * @brief Constructor
-   */
-  VectorImageRendererPlugin()
-  {
-  }
-
-  /**
-   * @brief Destructor
-   */
-  virtual ~VectorImageRendererPlugin()
-  {
-  }
-
-  /**
-   * @brief Load vector image data directly.
-   *
-   * @param[in] data The memory data of vector image
-   * @return True if the load success, false otherwise.
-   */
-  virtual bool Load(const Vector<uint8_t>& data) = 0;
-
-  /**
-   * @brief Rasterizes the content to the target buffer synchronously.
-   *
-   * @param[in] buffer The target buffer
-   * @return True if the rendering succeeds, false otherwise.
-   */
-  virtual bool Rasterize(Dali::Devel::PixelBuffer& buffer) = 0;
-
-  /**
-   * @brief Gets the default size of the file.
-   *
-   * @param[out] width The default width of the file
-   * @param[out] height The default height of the file
-   */
-  virtual void GetDefaultSize(uint32_t& width, uint32_t& height) const = 0;
-
-  /**
-   * @brief Function pointer called in adaptor to create a plugin instance.
-   */
-  using CreateVectorImageRendererFunction = VectorImageRendererPlugin* (*)();
-};
-
-} // namespace Dali
-
-#endif // DALI_VECTOR_IMAGE_RENDERER_PLUGIN_H
index f557cad..79fe80c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -47,9 +47,14 @@ bool VectorImageRenderer::Load(const Vector<uint8_t>& data, float dpi)
   return GetImplementation(*this).Load(data, dpi);
 }
 
-bool VectorImageRenderer::Rasterize(Dali::Devel::PixelBuffer& buffer, float scale)
+bool VectorImageRenderer::IsLoaded() const
 {
-  return GetImplementation(*this).Rasterize(buffer, scale);
+  return GetImplementation(*this).IsLoaded();
+}
+
+Dali::Devel::PixelBuffer VectorImageRenderer::Rasterize(uint32_t width, uint32_t height)
+{
+  return GetImplementation(*this).Rasterize(width, height);
 }
 
 void VectorImageRenderer::GetDefaultSize(uint32_t& width, uint32_t& height) const
index d2343d6..ab59195 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_VECTOR_IMAGE_RENDERER_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -86,13 +86,20 @@ public:
   bool Load(const Vector<uint8_t>& data, float dpi);
 
   /**
-   * @brief Rasterizes the content to the target buffer synchronously.
+   * @brief Query whether the vector image is loaded.
    *
-   * @param[in] buffer The target buffer
-   * @param[in] scale The target image scale factor
-   * @return True if the rendering succeeds, false otherwise.
+   * @return True if the image is loaded, false other wise.
    */
-  bool Rasterize(Dali::Devel::PixelBuffer& buffer, float scale);
+  bool IsLoaded() const;
+
+  /**
+   * @brief Rasterizes the content to the pixel buffer synchronously.
+   *
+   * @param[in] width The pixel buffer width
+   * @param[in] height The pixel buffer height
+   * @return The handle to the rasterized PixelBuffer object or an empty handle in case failed.
+   */
+  Dali::Devel::PixelBuffer Rasterize(uint32_t width, uint32_t height);
 
   /**
    * @brief Gets the default size of the file.
index 7a8aa63..2e30f8c 100644 (file)
@@ -26,6 +26,7 @@
 #include <memory>
 
 // INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/accessibility.h>
 #include <dali/devel-api/adaptor-framework/web-engine-hit-test.h>
 #include <dali/devel-api/common/bitwise-enum.h>
 #include <dali/public-api/adaptor-framework/native-image-source.h>
@@ -677,6 +678,12 @@ public:
   virtual void ActivateAccessibility(bool activated) = 0;
 
   /**
+   * @brief Get the accessibility address (bus and path) for embedding.
+   * @return Accessibility address of the root web content element.
+   */
+  virtual Accessibility::Address GetAccessibilityAddress() = 0;
+
+  /**
    * @brief Request to set the current page's visibility.
    * @param[in] visible Visible or not.
    *
index 50812f6..badddf8 100755 (executable)
@@ -421,6 +421,11 @@ void WebEngine::ActivateAccessibility(bool activated)
   GetImplementation(*this).ActivateAccessibility(activated);
 }
 
+Accessibility::Address WebEngine::GetAccessibilityAddress()
+{
+  return GetImplementation(*this).GetAccessibilityAddress();
+}
+
 bool WebEngine::SetVisibility(bool visible)
 {
   return GetImplementation(*this).SetVisibility(visible);
index d68920e..3d45c08 100755 (executable)
@@ -22,6 +22,7 @@
 #include <dali/public-api/object/base-handle.h>
 
 //INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/accessibility.h>
 #include <dali/devel-api/adaptor-framework/web-engine-plugin.h>
 #include <dali/public-api/dali-adaptor-common.h>
 
@@ -546,6 +547,12 @@ public:
   void ActivateAccessibility(bool activated);
 
   /**
+   * @brief Get the accessibility address (bus and path) for embedding.
+   * @return Accessibility address of the root web content element.
+   */
+  Accessibility::Address GetAccessibilityAddress();
+
+  /**
    * @brief Request to set the current page's visibility.
    * @param[in] visible Visible or not.
    *
index b9aa46c..43565ed 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -106,6 +106,11 @@ AuxiliaryMessageSignalType& AuxiliaryMessageSignal(Window window)
   return GetImplementation(window).AuxiliaryMessageSignal();
 }
 
+AccessibilityHighlightSignalType& AccessibilityHighlightSignal(Window window)
+{
+  return GetImplementation(window).AccessibilityHighlightSignal();
+}
+
 void SetParent(Window window, Window parent)
 {
   GetImplementation(window).SetParent(parent);
@@ -229,6 +234,11 @@ bool IsMaximized(Window window)
   return GetImplementation(window).IsMaximized();
 }
 
+void SetMaximumSize(Window window, Dali::Window::WindowSize size)
+{
+  GetImplementation(window).SetMaximumSize(size);
+}
+
 void Minimize(Window window, bool miniimize)
 {
   GetImplementation(window).Minimize(miniimize);
@@ -239,6 +249,31 @@ bool IsMinimized(Window window)
   return GetImplementation(window).IsMinimized();
 }
 
+void SetMimimumSize(Window window, Dali::Window::WindowSize size)
+{
+  GetImplementation(window).SetMimimumSize(size);
+}
+
+bool IsWindowRotating(Window window)
+{
+  return GetImplementation(window).IsWindowRotating();
+}
+
+const KeyEvent& GetLastKeyEvent(Window window)
+{
+  return GetImplementation(window).GetLastKeyEvent();
+}
+
+const TouchEvent& GetLastTouchEvent(Window window)
+{
+  return GetImplementation(window).GetLastTouchEvent();
+}
+
+InterceptKeyEventSignalType& InterceptKeyEventSignal(Window window)
+{
+  return GetImplementation(window).InterceptKeyEventSignal();
+}
+
 } // namespace DevelWindow
 
 } // namespace Dali
index a4779f7..883cdaa 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_WINDOW_DEVEL_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -36,22 +36,16 @@ struct TouchPoint;
 
 namespace DevelWindow
 {
-
-typedef Signal<void()> EventProcessingFinishedSignalType; ///< Event Processing finished signal type
-
-typedef Signal<void(const KeyEvent&)> KeyEventSignalType; ///< Key event signal type
-
-typedef Signal<void(const TouchEvent&)> TouchEventSignalType; ///< Touch signal type
-
-typedef Signal<void(const WheelEvent&)> WheelEventSignalType; ///< Touched signal type
-
-typedef Signal<void(Window, bool)> VisibilityChangedSignalType; ///< Visibility changed signal type
-
-typedef Signal<void(Window, WindowEffectState, WindowEffectType)> TransitionEffectEventSignalType; ///< Effect signal type and state
-
-typedef Signal<void()> KeyboardRepeatSettingsChangedSignalType; ///< Keyboard repeat settings changed signal type
-
-typedef Signal<void(const std::string&, const std::string&, const Property::Array&)> AuxiliaryMessageSignalType; ///< Auxiliary message signal type
+typedef Signal<void()>                                                               EventProcessingFinishedSignalType;       ///< Event Processing finished signal type
+typedef Signal<void(const KeyEvent&)>                                                KeyEventSignalType;                      ///< Key event signal type
+typedef Signal<void(const TouchEvent&)>                                              TouchEventSignalType;                    ///< Touch signal type
+typedef Signal<void(const WheelEvent&)>                                              WheelEventSignalType;                    ///< Wheel signal type
+typedef Signal<void(Window, bool)>                                                   VisibilityChangedSignalType;             ///< Visibility changed signal type
+typedef Signal<void(Window, WindowEffectState, WindowEffectType)>                    TransitionEffectEventSignalType;         ///< Effect signal type and state
+typedef Signal<void()>                                                               KeyboardRepeatSettingsChangedSignalType; ///< Keyboard repeat settings changed signal type
+typedef Signal<void(const std::string&, const std::string&, const Property::Array&)> AuxiliaryMessageSignalType;              ///< Auxiliary message signal type
+typedef Signal<void(Window, bool)>                                                   AccessibilityHighlightSignalType;        ///< Accessibility Highlight signal type
+typedef Signal<bool(const KeyEvent&)>                                                InterceptKeyEventSignalType;             ///< Intercept Key event signal type
 
 /**
  * @brief Creates an initialized handle to a new Window.
@@ -163,6 +157,25 @@ DALI_ADAPTOR_API KeyboardRepeatSettingsChangedSignalType& KeyboardRepeatSettings
 DALI_ADAPTOR_API AuxiliaryMessageSignalType& AuxiliaryMessageSignal(Window window);
 
 /**
+ * @brief This signal is emitted when the window needs to grab or clear accessibility highlight.
+ * The highlight indicates that it is an object to interact with the user regardless of focus.
+ * After setting the highlight on the object, you can do things that the object can do, such as
+ * giving or losing focus.
+ *
+ * This signal is emitted by Dali::Accessibility::Component::GrabHighlight
+ * and Dali::Accessibility::Component::ClearHighlight
+ *
+ * A callback of the following type may be connected:
+ * @code
+ *   void YourCallbackName( Window window, bool highlight );
+ * @endcode
+ *
+ * @param[in] window The window instance
+ * @return The signal to connect to
+ */
+DALI_ADAPTOR_API AccessibilityHighlightSignalType& AccessibilityHighlightSignal(Window window);
+
+/**
  * @brief Sets parent window of the window.
  *
  * After setting that, these windows do together when raise-up, lower and iconified/deiconified.
@@ -438,6 +451,19 @@ DALI_ADAPTOR_API void Maximize(Window window, bool maximize);
 DALI_ADAPTOR_API bool IsMaximized(Window window);
 
 /**
+ * @brief Sets window's maximum size.
+ *
+ * It is to set the maximized size when window is maximized or the window's size is increased by RequestResizeToServer().
+ * Although the size is set by this function, window's size can be increased over the limitation by SetPositionSize() or SetSize().
+ *
+ * After setting, if Maximize() is called, window is resized with the setting size and move the center.
+ *
+ * @param[in] window The window instance.
+ * @param[in] size the maximum size
+ */
+DALI_ADAPTOR_API void SetMaximumSize(Window window, Dali::Window::WindowSize size);
+
+/**
  * @brief Minimizes window's size.
  * If this function is called with true, window will be iconified.
  * Otherwise window will be activated.
@@ -459,6 +485,53 @@ DALI_ADAPTOR_API void Minimize(Window window, bool minimize);
  */
 DALI_ADAPTOR_API bool IsMinimized(Window window);
 
+/**
+ * @brief Sets window's minimum size.
+ *
+ * It is to set the minimum size when window's size is decreased by RequestResizeToServer().
+ * Although the size is set by this function, window's size can be decreased over the limitation by SetPositionSize() or SetSize().
+ *
+ * @param[in] window The window instance.
+ * @param[in] size the minimum size
+ */
+DALI_ADAPTOR_API void SetMimimumSize(Window window, Dali::Window::WindowSize size);
+
+/**
+ * @brief Query whether window is rotating or not.
+ *
+ * @param[in] window The window instance.
+ * @return true if window is rotating, false otherwise.
+ */
+DALI_ADAPTOR_API bool IsWindowRotating(Window window);
+
+/**
+ * @brief Gets the last key event the window gets.
+ *
+ * @param[in] window The window instance.
+ * @return The last key event the window gets.
+ */
+DALI_ADAPTOR_API const KeyEvent& GetLastKeyEvent(Window window);
+
+/**
+ * @brief Gets the last touch event the window gets.
+ *
+ * @param[in] window The window instance.
+ * @return The last touch event the window gets.
+ * @note It returns the raw event the window gets. There is no hit-actor and local position information.
+ */
+DALI_ADAPTOR_API const TouchEvent& GetLastTouchEvent(Window window);
+
+/**
+ * @brief The user would connect to this signal to intercept a KeyEvent at window.
+ *
+ * Intercepts KeyEvents in the window before dispatching KeyEvents to the control.
+ * If a KeyEvent is consumed, no KeyEvent is delivered to the control.
+ *
+ * @param[in] window The window instance.
+ * @return The signal to connect to
+ */
+DALI_ADAPTOR_API InterceptKeyEventSignalType& InterceptKeyEventSignal(Window window);
+
 } // namespace DevelWindow
 
 } // namespace Dali
index 0eb7794..84fe37c 100644 (file)
@@ -157,6 +157,14 @@ public:
   void EmitMovedOutOfScreen(ScreenRelativeMoveType type);
 
   /**
+   * @brief Emits "org.a11y.atspi.Socket.Available" signal.
+   */
+  // This belongs to Dali::Accessibility::Socket. However, all Emit*() helpers
+  // are here in Accessible, regardless of what interface they belong to (perhaps
+  // to spare a dynamic_cast if used like this: Accessible::Get()->Emit*(...)).
+  void EmitSocketAvailable();
+
+  /**
    * @brief Emits "highlighted" event.
    *
    * @param[in] event The enumerated window event
@@ -327,7 +335,7 @@ public:
   virtual std::vector<Relation> GetRelationSet() = 0;
 
   /**
-   * @brief Gets internal Actor to be saved before.
+   * @brief Gets the Actor associated with this Accessible (if there is one).
    *
    * @return The internal Actor
    */
@@ -336,9 +344,26 @@ public:
   /**
    * @brief Gets all implemented interfaces.
    *
-   * @return The collection of strings with implemented interfaces
+   * Override DoGetInterfaces() to customize the return value of this method.
+   *
+   * @return The collection of implemented interfaces
+   *
+   * @see DoGetInterfaces()
+   */
+  AtspiInterfaces GetInterfaces() const;
+
+  /**
+   * @brief Gets all implemented interfaces.
+   *
+   * Converts all interfaces returned by GetInterfaces() to their DBus names
+   * using GetInterfaceName().
+   *
+   * @return The collection of names of implemented interfaces
+   *
+   * @see GetInterfaces()
+   * @see GetInterfaceName()
    */
-  std::vector<std::string> GetInterfaces() const;
+  std::vector<std::string> GetInterfacesAsStrings() const;
 
   /**
    * @brief Checks if object is on root level.
@@ -350,6 +375,26 @@ public:
     return mIsOnRootLevel;
   }
 
+  /**
+   * @brief Gets all suppressed events.
+   *
+   * @return All suppressed events
+   */
+  AtspiEvents GetSuppressedEvents() const
+  {
+    return mSuppressedEvents;
+  }
+
+  /**
+   * @brief Gets all suppressed events.
+   *
+   * @return All suppressed events
+   */
+  AtspiEvents& GetSuppressedEvents()
+  {
+    return mSuppressedEvents;
+  }
+
 protected:
   Accessible();
   Accessible(const Accessible&)         = delete;
@@ -358,6 +403,20 @@ protected:
   Accessible&                   operator=(Accessible&&) = delete;
   std::shared_ptr<Bridge::Data> GetBridgeData() const;
 
+  /**
+   * @brief Returns the collection of AT-SPI interfaces implemented by this Accessible.
+   *
+   * This method is called only once and its return value is cached. The default implementation
+   * uses dynamic_cast to determine which interfaces are implemented. Override this if you
+   * conceptually provide fewer interfaces than dynamic_cast can see.
+   *
+   * @return The collection of implemented interfaces
+   *
+   * @see GetInterfaces()
+   * @see GetInterfaceName()
+   */
+  virtual AtspiInterfaces DoGetInterfaces() const;
+
 public:
   /**
    * @brief Gets the highlight actor.
@@ -406,20 +465,58 @@ public:
    * @brief Acquires Accessible object from Actor object.
    *
    * @param[in] actor Actor object
-   * @param[in] isRoot True, if it's top level object (window)
    *
    * @return The handle to Accessible object
    */
-  static Accessible* Get(Dali::Actor actor, bool isRoot = false);
+  static Accessible* Get(Dali::Actor actor);
+
+  /**
+   * @brief Obtains the DBus interface name for the specified AT-SPI interface.
+   *
+   * @param interface AT-SPI interface identifier (e.g. AtspiInterface::ACCESSIBLE)
+   * @return AT-SPI interface name (e.g. "org.a11y.atspi.Accessible")
+   */
+  static std::string GetInterfaceName(AtspiInterface interface);
+
+  /**
+   * @brief Downcasts an Accessible pointer to an AT-SPI interface pointer.
+   *
+   * @tparam I Desired AT-SPI interface
+   *
+   * @param obj Object to cast.
+   *
+   * @return Pointer to an AT-SPI interface or null if the interface is not implemented.
+   */
+  template<AtspiInterface I>
+  static AtspiInterfaceType<I>* DownCast(Accessible* obj)
+  {
+    if(!obj || !obj->GetInterfaces()[I])
+    {
+      return nullptr;
+    }
+
+    return dynamic_cast<AtspiInterfaceType<I>*>(obj);
+  }
 
 private:
   friend class Bridge;
 
   mutable std::weak_ptr<Bridge::Data> mBridgeData;
+  mutable AtspiInterfaces             mInterfaces;
+  AtspiEvents                         mSuppressedEvents;
   bool                                mIsOnRootLevel = false;
 
 }; // Accessible class
 
+namespace Internal
+{
+template<>
+struct AtspiInterfaceTypeHelper<AtspiInterface::ACCESSIBLE>
+{
+  using Type = Accessible;
+};
+} // namespace Internal
+
 } // namespace Dali::Accessibility
 
 #endif // DALI_ADAPTOR_ATSPI_ACCESSIBLE_H
index b3d9717..b168f63 100644 (file)
@@ -93,8 +93,32 @@ public:
    * @return true on success, false otherwise
    */
   virtual bool DoAction(const std::string& name) = 0;
+
+  /**
+   * @brief Downcasts an Accessible to an Action.
+   *
+   * @param obj The Accessible
+   * @return An Action or null
+   *
+   * @see Dali::Accessibility::Accessible::DownCast()
+   */
+  static inline Action* DownCast(Accessible* obj);
 };
 
+namespace Internal
+{
+template<>
+struct AtspiInterfaceTypeHelper<AtspiInterface::ACTION>
+{
+  using Type = Action;
+};
+} // namespace Internal
+
+inline Action* Action::DownCast(Accessible* obj)
+{
+  return Accessible::DownCast<AtspiInterface::ACTION>(obj);
+}
+
 } // namespace Dali::Accessibility
 
 #endif // DALI_ADAPTOR_ATSPI_ACTION_H
index 5e37f6b..44b26ba 100644 (file)
@@ -48,8 +48,32 @@ public:
    * @return String with version
    */
   virtual std::string GetVersion() const = 0;
+
+  /**
+   * @brief Downcasts an Accessible to an Application.
+   *
+   * @param obj The Accessible
+   * @return An Application or null
+   *
+   * @see Dali::Accessibility::Accessible::DownCast()
+   */
+  static inline Application* DownCast(Accessible* obj);
 };
 
+namespace Internal
+{
+template<>
+struct AtspiInterfaceTypeHelper<AtspiInterface::APPLICATION>
+{
+  using Type = Application;
+};
+} // namespace Internal
+
+inline Application* Application::DownCast(Accessible* obj)
+{
+  return Accessible::DownCast<AtspiInterface::APPLICATION>(obj);
+}
+
 } // namespace Dali::Accessibility
 
 #endif // DALI_ADAPTOR_ATSPI_APPLICATION_H
index 6452854..7a84079 100644 (file)
@@ -25,13 +25,36 @@ namespace Dali::Accessibility
 /**
  * @brief Interface enabling advanced quering of accessibility objects.
  *
- * @note since all mathods can be implemented inside bridge,
- * none methods have to be overrided
+ * @note Since all methods can be implemented inside bridge,
+ * no methods have to be overriden.
  */
 class DALI_ADAPTOR_API Collection : public virtual Accessible
 {
+  /**
+   * @brief Downcasts an Accessible to a Collection.
+   *
+   * @param obj The Accessible
+   * @return A Collection or null
+   *
+   * @see Dali::Accessibility::Accessible::DownCast()
+   */
+  static inline Collection* DownCast(Accessible* obj);
 };
 
+namespace Internal
+{
+template<>
+struct AtspiInterfaceTypeHelper<AtspiInterface::COLLECTION>
+{
+  using Type = Collection;
+};
+} // namespace Internal
+
+inline Collection* Collection::DownCast(Accessible* obj)
+{
+  return Accessible::DownCast<AtspiInterface::COLLECTION>(obj);
+}
+
 } // namespace Dali::Accessibility
 
 #endif // DALI_ADAPTOR_ATSPI_COLLECTION_H
index 1853313..682b97c 100644 (file)
@@ -131,8 +131,32 @@ public:
    * @see Dali::Accessibility::Point
    */
   virtual bool IsAccessibleContainingPoint(Point point, CoordinateType type) const;
+
+  /**
+   * @brief Downcasts an Accessible to a Component.
+   *
+   * @param obj The Accessible
+   * @return A Component or null
+   *
+   * @see Dali::Accessibility::Accessible::DownCast()
+   */
+  static inline Component* DownCast(Accessible* obj);
 };
 
+namespace Internal
+{
+template<>
+struct AtspiInterfaceTypeHelper<AtspiInterface::COMPONENT>
+{
+  using Type = Component;
+};
+} // namespace Internal
+
+inline Component* Component::DownCast(Accessible* obj)
+{
+  return Accessible::DownCast<AtspiInterface::COMPONENT>(obj);
+}
+
 } // namespace Dali::Accessibility
 
 #endif // DALI_ADAPTOR_ATSPI_COMPONENT_H
index 66c822e..1aa141f 100644 (file)
@@ -84,8 +84,32 @@ public:
    * @return true on success, false otherwise
    */
   virtual bool SetTextContents(std::string newContents) = 0;
+
+  /**
+   * @brief Downcasts an Accessible to an EditableText.
+   *
+   * @param obj The Accessible
+   * @return An EditableText or null
+   *
+   * @see Dali::Accessibility::Accessible::DownCast()
+   */
+  static inline EditableText* DownCast(Accessible* obj);
 };
 
+namespace Internal
+{
+template<>
+struct AtspiInterfaceTypeHelper<AtspiInterface::EDITABLE_TEXT>
+{
+  using Type = EditableText;
+};
+} // namespace Internal
+
+inline EditableText* EditableText::DownCast(Accessible* obj)
+{
+  return Accessible::DownCast<AtspiInterface::EDITABLE_TEXT>(obj);
+}
+
 } // namespace Dali::Accessibility
 
 #endif // DALI_ADAPTOR_ATSPI_EDITABLE_TEXT_H
index 5f7c8f5..aef9f4e 100644 (file)
@@ -77,8 +77,32 @@ public:
    * @return True if hyperlink object is valid, false otherwise
    */
   virtual bool IsValid() const = 0;
+
+  /**
+   * @brief Downcasts an Accessible to a Hyperlink.
+   *
+   * @param obj The Accessible
+   * @return A Hyperlink or null
+   *
+   * @see Dali::Accessibility::Accessible::DownCast()
+   */
+  static inline Hyperlink* DownCast(Accessible* obj);
 };
 
+namespace Internal
+{
+template<>
+struct AtspiInterfaceTypeHelper<AtspiInterface::HYPERLINK>
+{
+  using Type = Hyperlink;
+};
+} // namespace Internal
+
+inline Hyperlink* Hyperlink::DownCast(Accessible* obj)
+{
+  return Accessible::DownCast<AtspiInterface::HYPERLINK>(obj);
+}
+
 } // namespace Dali::Accessibility
 
 #endif // DALI_ADAPTOR_ATSPI_HYPERLINK_H
index e9b4deb..903aebc 100644 (file)
@@ -56,8 +56,32 @@ public:
    * @return The number of hyperlinks (zero if none or -1 if the number cannot be determined)
    */
   virtual std::int32_t GetLinkCount() const = 0;
+
+  /**
+   * @brief Downcasts an Accessible to a Hypertext.
+   *
+   * @param obj The Accessible
+   * @return A Hypertext or null
+   *
+   * @see Dali::Accessibility::Accessible::DownCast()
+   */
+  static inline Hypertext* DownCast(Accessible* obj);
 };
 
+namespace Internal
+{
+template<>
+struct AtspiInterfaceTypeHelper<AtspiInterface::HYPERTEXT>
+{
+  using Type = Hypertext;
+};
+} // namespace Internal
+
+inline Hypertext* Hypertext::DownCast(Accessible* obj)
+{
+  return Accessible::DownCast<AtspiInterface::HYPERTEXT>(obj);
+}
+
 } // namespace Dali::Accessibility
 
 #endif // DALI_ADAPTOR_ATSPI_HYPERTEXT_H
index 2aadd67..0ce68c4 100644 (file)
@@ -103,8 +103,32 @@ public:
    * @see Dali::Accessibility::Selection::DeselectSelectedChild
    */
   virtual bool DeselectChild(int childIndex) = 0;
+
+  /**
+   * @brief Downcasts an Accessible to a Selection.
+   *
+   * @param obj The Accessible
+   * @return A Selection or null
+   *
+   * @see Dali::Accessibility::Accessible::DownCast()
+   */
+  static inline Selection* DownCast(Accessible* obj);
 };
 
+namespace Internal
+{
+template<>
+struct AtspiInterfaceTypeHelper<AtspiInterface::SELECTION>
+{
+  using Type = Selection;
+};
+} // namespace Internal
+
+inline Selection* Selection::DownCast(Accessible* obj)
+{
+  return Accessible::DownCast<AtspiInterface::SELECTION>(obj);
+}
+
 } // namespace Dali::Accessibility
 
 #endif // DALI_ADAPTOR_ATSPI_SELECTION_H
diff --git a/dali/devel-api/atspi-interfaces/socket.h b/dali/devel-api/atspi-interfaces/socket.h
new file mode 100644 (file)
index 0000000..0e74694
--- /dev/null
@@ -0,0 +1,77 @@
+#ifndef DALI_ADAPTOR_ATSPI_SOCKET_H
+#define DALI_ADAPTOR_ATSPI_SOCKET_H
+
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/atspi-interfaces/accessible.h>
+
+namespace Dali::Accessibility
+{
+/**
+ * @brief A Socket is the root of the AT-SPI tree that can be embedded as a subtree
+ * in the tree belonging to another process (the Plug). The Plug initiates the Plug-Socket
+ * connection by calling Embed() and terminates it by calling Unembed().
+ *
+ * See AT_SPI2_CORE/xml/Socket.xml for a description of this interface in XML format.
+ */
+class DALI_ADAPTOR_API Socket : public virtual Accessible
+{
+public:
+  /**
+   * @brief Establishes the Plug-Socket connection.
+   *
+   * @param plug Address of the Plug (remote parent)
+   * @return Address of the Socket
+   */
+  virtual Address Embed(Address plug) = 0;
+
+  /**
+   * @brief Terminates the Plug-Socket connection.
+   *
+   * @param plug Address of the Plug (remote parent)
+   */
+  virtual void Unembed(Address plug) = 0;
+
+  /**
+   * @brief Downcasts an Accessible to a Socket.
+   *
+   * @param obj The Accessible
+   * @return A Socket or null
+   *
+   * @see Dali::Accessibility::Accessible::DownCast()
+   */
+  static inline Socket* DownCast(Accessible* obj);
+};
+
+namespace Internal
+{
+template<>
+struct AtspiInterfaceTypeHelper<AtspiInterface::SOCKET>
+{
+  using Type = Socket;
+};
+} // namespace Internal
+
+inline Socket* Socket::DownCast(Accessible* obj)
+{
+  return Accessible::DownCast<AtspiInterface::SOCKET>(obj);
+}
+
+} // namespace Dali::Accessibility
+
+#endif // DALI_ADAPTOR_ATSPI_SOCKET_H
index bd2981c..0606fc8 100644 (file)
@@ -19,6 +19,7 @@
 
 // EXTERNAL INCLUDES
 #include <string>
+#include <dali/public-api/math/rect.h>
 
 // INTERNAL INCLUDES
 #include <dali/devel-api/adaptor-framework/accessibility.h>
@@ -118,8 +119,44 @@ public:
    * @remarks This method is `SetSelection` in DBus method.
    */
   virtual bool SetRangeOfSelection(std::size_t selectionIndex, std::size_t startOffset, std::size_t endOffset) = 0;
+
+  /**
+   * @brief Gets the bounding box for text within a range in text.
+   *
+   * @param[in] startOffset The index of first character
+   * @param[in] endOffset The index of first character after the last one expected
+   * @param[in] type The enumeration with type of coordinate system
+   *
+   * @return Rect<> giving the position and size of the specified range of text
+   * @remarks This method is `GetRangeExtents` in DBus method.
+   */
+  virtual Rect<> GetRangeExtents(std::size_t startOffset, std::size_t endOffset, CoordinateType type) = 0;
+
+  /**
+   * @brief Downcasts an Accessible to a Text.
+   *
+   * @param obj The Accessible
+   * @return A Text or null
+   *
+   * @see Dali::Accessibility::Accessible::DownCast()
+   */
+  static inline Text* DownCast(Accessible* obj);
 };
 
+namespace Internal
+{
+template<>
+struct AtspiInterfaceTypeHelper<AtspiInterface::TEXT>
+{
+  using Type = Text;
+};
+} // namespace Internal
+
+inline Text* Text::DownCast(Accessible* obj)
+{
+  return Accessible::DownCast<AtspiInterface::TEXT>(obj);
+}
+
 } // namespace Dali::Accessibility
 
 #endif // DALI_ADAPTOR_ATSPI_TEXT_H
index 350e2be..6c9a963 100644 (file)
@@ -64,7 +64,31 @@ public:
    * @return The lowest increment
   */
   virtual double GetMinimumIncrement() const = 0;
+
+  /**
+   * @brief Downcasts an Accessible to a Value.
+   *
+   * @param obj The Accessible
+   * @return A Value or null
+   *
+   * @see Dali::Accessibility::Accessible::DownCast()
+   */
+  static inline Value* DownCast(Accessible* obj);
+};
+
+namespace Internal
+{
+template<>
+struct AtspiInterfaceTypeHelper<AtspiInterface::VALUE>
+{
+  using Type = Value;
 };
+} // namespace Internal
+
+inline Value* Value::DownCast(Accessible* obj)
+{
+  return Accessible::DownCast<AtspiInterface::VALUE>(obj);
+}
 
 } // namespace Dali::Accessibility
 
index 6719a2f..89cb0a9 100755 (executable)
@@ -103,7 +103,6 @@ SET( devel_api_adaptor_framework_header_files
   ${adaptor_devel_api_dir}/adaptor-framework/vector-animation-renderer.h
   ${adaptor_devel_api_dir}/adaptor-framework/vector-animation-renderer-plugin.h
   ${adaptor_devel_api_dir}/adaptor-framework/vector-image-renderer.h
-  ${adaptor_devel_api_dir}/adaptor-framework/vector-image-renderer-plugin.h
   ${adaptor_devel_api_dir}/adaptor-framework/video-player.h
   ${adaptor_devel_api_dir}/adaptor-framework/video-player-plugin.h
   ${adaptor_devel_api_dir}/adaptor-framework/web-engine.h
@@ -151,6 +150,7 @@ SET( devel_api_atspi_interfaces_header_files
   ${adaptor_devel_api_dir}/atspi-interfaces/hyperlink.h
   ${adaptor_devel_api_dir}/atspi-interfaces/hypertext.h
   ${adaptor_devel_api_dir}/atspi-interfaces/selection.h
+  ${adaptor_devel_api_dir}/atspi-interfaces/socket.h
   ${adaptor_devel_api_dir}/atspi-interfaces/text.h
   ${adaptor_devel_api_dir}/atspi-interfaces/value.h
 )
index 7cea697..704469c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@
 #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
@@ -48,6 +49,8 @@ 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},
@@ -55,14 +58,526 @@ FontClient::GlyphBufferData::GlyphBufferData()
   outlineOffsetX{0},
   outlineOffsetY{0},
   format{Pixel::A8},
+  compressionType(CompressionType::NO_COMPRESSION),
   isColorEmoji{false},
-  isColorBitmap{false}
+  isColorBitmap{false},
+  isBufferOwned{false}
 {
 }
 
 FontClient::GlyphBufferData::~GlyphBufferData()
 {
-}
+  if(isBufferOwned)
+  {
+    free(buffer);
+  }
+}
+
+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 = outBufferData.width * outBufferData.height * 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       = outBufferData.height * (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 992f8aa..e21f3e6 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_PLATFORM_TEXT_ABSTRACTION_FONT_CLIENT_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -95,14 +95,59 @@ public:
      */
     ~GlyphBufferData();
 
-    unsigned char* buffer;            ///< The glyph's bitmap buffer data.
-    unsigned int   width;             ///< The width of the bitmap.
-    unsigned int   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.
-    bool           isColorEmoji : 1;  ///< Whether the glyph is an emoji.
-    bool           isColorBitmap : 1; ///< Whether the glyph is a color bitmap.
+    // 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);
+
+    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 : 3; ///< 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.
   };
 
   /**
index 747e802..13e459d 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TEXT_ABSTRACTION_FONT_LIST_H
 
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -152,6 +152,21 @@ struct FontDescription
   {
   }
 
+  FontDescription(const FontPath&         path,
+                  const FontFamily&       family,
+                  const FontWidth::Type&  width,
+                  const FontWeight::Type& weight,
+                  const FontSlant::Type&  slant,
+                  const Type&             type)
+  : path(path),
+    family(family),
+    width(width),
+    weight(weight),
+    slant(slant),
+    type(type)
+  {
+  }
+
   ~FontDescription()
   {
   }
index 7eff6f5..196e0d9 100644 (file)
@@ -249,6 +249,14 @@ public:
   }
 
   /**
+   * @copydoc Dali::Integration::SceneHolder::InterceptKeyEventSignal()
+   */
+  Dali::Integration::SceneHolder::KeyEventGeneratedSignalType& InterceptKeyEventSignal()
+  {
+    return mScene.InterceptKeyEventSignal();
+  }
+
+  /**
    * @copydoc Dali::Integration::SceneHolder::TouchedSignal()
    */
   Dali::Integration::SceneHolder::TouchEventSignalType& TouchedSignal()
index 6d4d282..0fbf66e 100644 (file)
@@ -119,6 +119,11 @@ SceneHolder::KeyEventGeneratedSignalType& SceneHolder::KeyEventGeneratedSignal()
   return GetImplementation(*this).KeyEventGeneratedSignal();
 }
 
+SceneHolder::KeyEventGeneratedSignalType& SceneHolder::InterceptKeyEventSignal()
+{
+  return GetImplementation(*this).InterceptKeyEventSignal();
+}
+
 SceneHolder::TouchEventSignalType& SceneHolder::TouchedSignal()
 {
   return GetImplementation(*this).TouchedSignal();
index d660509..eed2515 100644 (file)
@@ -188,6 +188,19 @@ public:
   KeyEventGeneratedSignalType& KeyEventGeneratedSignal();
 
   /**
+   * @brief This signal is emitted when key event is received.
+   * Intercepts KeyEvents in the window before dispatching KeyEvents to the control.
+   * If a KeyEvent is consumed, no KeyEvent is delivered to the control.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallbackName(const KeyEvent& event);
+   * @endcode
+   * @return The signal to connect to
+   */
+  KeyEventGeneratedSignalType& InterceptKeyEventSignal();
+
+  /**
    * @brief This signal is emitted when the screen is touched and when the touch ends
    * (i.e. the down & up touch events only).
    *
index 4da5e3c..4f61522 100644 (file)
 #include <dali/internal/accessibility/bridge/dbus.h>
 #include <dali/public-api/dali-adaptor-common.h>
 
-/* DBus Interfaces */
+// DBus names
 
 #define A11yDbusName "org.a11y.Bus"
-#define A11yDbusPath "/org/a11y/bus"
 #define A11yDbusStatusInterface "org.a11y.Status"
 #define AtspiDbusNameRegistry "org.a11y.atspi.Registry"
+#define DirectReadingDBusName "org.tizen.ScreenReader"
+#define DirectReadingDBusInterface "org.tizen.DirectReading"
+
+// DBus paths
+
+#define A11yDbusPath "/org/a11y/bus"
+#define AtspiDbusPathCache "/org/a11y/atspi/cache"
+#define AtspiDbusPathDec "/org/a11y/atspi/registry/deviceeventcontroller"
 #define AtspiDbusPathRegistry "/org/a11y/atspi/registry"
-#define AtspiDbusInterfaceRegistry "org.a11y.atspi.Registry"
 #define AtspiDbusPathRoot "/org/a11y/atspi/accessible/root"
-#define AtspiDbusInterfaceSocket "org.a11y.atspi.Socket"
 #define AtspiPath "/org/a11y/atspi/accessible"
-#define AtspiDbusInterfaceAccessible "org.a11y.atspi.Accessible"
-#define AtspiDbusInterfaceAction "org.a11y.atspi.Action"
-#define AtspiDbusInterfaceApplication "org.a11y.atspi.Application"
-#define AtspiDbusInterfaceCache "org.a11y.atspi.Cache"
-#define AtspiDbusPathCache "/org/a11y/atspi/cache"
-#define AtspiDbusInterfaceCollection "org.a11y.atspi.Collection"
-#define AtspiDbusInterfaceComponent "org.a11y.atspi.Component"
-#define AtspiDbusInterfaceDocument "org.a11y.atspi.Document"
-#define AtspiDbusInterfaceEditableText "org.a11y.atspi.EditableText"
-#define AtspiDbusInterfaceEventKeyboard "org.a11y.atspi.Event.Keyboard"
-#define AtspiDbusInterfaceEventMouse "org.a11y.atspi.Event.Mouse"
-#define AtspiDbusInterfaceEventObject "org.a11y.atspi.Event.Object"
-#define AtspiDbusInterfaceHyperlink "org.a11y.atspi.Hyperlink"
-#define AtspiDbusInterfaceHypertext "org.a11y.atspi.Hypertext"
-#define AtspiDbusInterfaceImage "org.a11y.atspi.Image"
-#define AtspiDbusInterfaceSelection "org.a11y.atspi.Selection"
-#define AtspiDbusInterfaceTable "org.a11y.atspi.Table"
-#define AtspiDbusInterfaceTableCell "org.a11y.atspi.TableCell"
-#define AtspiDbusInterfaceText "org.a11y.atspi.Text"
-#define AtspiDbusInterfaceValue "org.a11y.atspi.Value"
-#define AtspiDbusInterfaceSocket "org.a11y.atspi.Socket"
-#define AtspiDbusInterfaceEventWindow "org.a11y.atspi.Event.Window"
-
-#define AtspiDbusPathDec "/org/a11y/atspi/registry/deviceeventcontroller"
-#define AtspiDbusInterfaceDec "org.a11y.atspi.DeviceEventController"
-#define AtspiDbusInterfaceDeviceEventListener "org.a11y.atspi.DeviceEventListener"
-
-#define DirectReadingDBusName "org.tizen.ScreenReader"
 #define DirectReadingDBusPath "/org/tizen/DirectReading"
-#define DirectReadingDBusInterface "org.tizen.DirectReading"
 
 struct ObjectPath;
 
index 26ec0aa..403bcc4 100644 (file)
 
 //INTERNAL INCLUDES
 #include <dali/devel-api/atspi-interfaces/accessible.h>
-#include <dali/devel-api/atspi-interfaces/action.h>
-#include <dali/devel-api/atspi-interfaces/application.h>
-#include <dali/devel-api/atspi-interfaces/collection.h>
-#include <dali/devel-api/atspi-interfaces/component.h>
-#include <dali/devel-api/atspi-interfaces/editable-text.h>
-#include <dali/devel-api/atspi-interfaces/hyperlink.h>
-#include <dali/devel-api/atspi-interfaces/hypertext.h>
-#include <dali/devel-api/atspi-interfaces/selection.h>
-#include <dali/devel-api/atspi-interfaces/text.h>
-#include <dali/devel-api/atspi-interfaces/value.h>
 #include <dali/devel-api/adaptor-framework/accessibility-bridge.h>
+#include <dali/devel-api/atspi-interfaces/socket.h>
 #include <dali/internal/accessibility/bridge/accessibility-common.h>
 #include <third-party/libunibreak/linebreak.h>
 #include <third-party/libunibreak/wordbreak.h>
 
 using namespace Dali::Accessibility;
 
-std::vector<std::string> Accessible::GetInterfaces() const
-{
-  std::vector<std::string> tmp;
-  tmp.push_back(AtspiDbusInterfaceAccessible);
-  if(dynamic_cast<const Collection*>(this))
-  {
-    tmp.push_back(AtspiDbusInterfaceCollection);
-  }
-  if(dynamic_cast<const Text*>(this))
-  {
-    tmp.push_back(AtspiDbusInterfaceText);
-  }
-  if(dynamic_cast<const EditableText*>(this))
-  {
-    tmp.push_back(AtspiDbusInterfaceEditableText);
-  }
-  if(dynamic_cast<const Value*>(this))
-  {
-    tmp.push_back(AtspiDbusInterfaceValue);
-  }
-  if(dynamic_cast<const Component*>(this))
-  {
-    tmp.push_back(AtspiDbusInterfaceComponent);
-  }
-  if(auto action = dynamic_cast<const Action*>(this))
-  {
-    if(action->GetActionCount() > 0)
-    {
-      tmp.push_back(AtspiDbusInterfaceAction);
-    }
-  }
-  if(dynamic_cast<const Selection*>(this))
-  {
-    tmp.push_back(AtspiDbusInterfaceSelection);
-  }
-  if(dynamic_cast<const Hypertext*>(this))
-  {
-    tmp.push_back(AtspiDbusInterfaceHypertext);
-  }
-  if(dynamic_cast<const Hyperlink*>(this))
-  {
-    tmp.push_back(AtspiDbusInterfaceHyperlink);
-  }
-  return tmp;
-}
-
 Accessible::Accessible()
 {
 }
@@ -172,6 +117,16 @@ void Accessible::EmitMovedOutOfScreen(ScreenRelativeMoveType type)
   }
 }
 
+void Accessible::EmitSocketAvailable()
+{
+  DALI_ASSERT_DEBUG(Socket::DownCast(this));
+
+  if(auto bridgeData = GetBridgeData())
+  {
+    bridgeData->mBridge->EmitSocketAvailable(this);
+  }
+}
+
 void Accessible::Emit(WindowEvent event, unsigned int detail)
 {
   if(auto bridgeData = GetBridgeData())
index 59481d3..a7ecf8e 100644 (file)
@@ -107,7 +107,7 @@ static bool AcceptObjectCheckRelations(Component* obj)
 
   for(const auto& it : relations)
   {
-    if(it.relationType == RelationType::CONTROLLED_BY)
+    if(it.mRelationType == RelationType::CONTROLLED_BY)
     {
       return false;
     }
@@ -400,7 +400,7 @@ BridgeAccessible::BridgeAccessible()
 
 void BridgeAccessible::RegisterInterfaces()
 {
-  DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceAccessible};
+  DBus::DBusInterfaceDescription desc{Accessible::GetInterfaceName(AtspiInterface::ACCESSIBLE)};
   AddGetPropertyToInterface(desc, "ChildCount", &BridgeAccessible::GetChildCount);
   AddGetPropertyToInterface(desc, "Name", &BridgeAccessible::GetName);
   AddGetPropertyToInterface(desc, "Description", &BridgeAccessible::GetDescription);
@@ -410,7 +410,7 @@ void BridgeAccessible::RegisterInterfaces()
   AddFunctionToInterface(desc, "GetLocalizedRoleName", &BridgeAccessible::GetLocalizedRoleName);
   AddFunctionToInterface(desc, "GetState", &BridgeAccessible::GetStates);
   AddFunctionToInterface(desc, "GetAttributes", &BridgeAccessible::GetAttributes);
-  AddFunctionToInterface(desc, "GetInterfaces", &BridgeAccessible::GetInterfaces);
+  AddFunctionToInterface(desc, "GetInterfaces", &BridgeAccessible::GetInterfacesAsStrings);
   AddFunctionToInterface(desc, "GetChildAtIndex", &BridgeAccessible::GetChildAtIndex);
   AddFunctionToInterface(desc, "GetChildren", &BridgeAccessible::GetChildren);
   AddFunctionToInterface(desc, "GetIndexInParent", &BridgeAccessible::GetIndexInParent);
@@ -423,6 +423,11 @@ void BridgeAccessible::RegisterInterfaces()
   mDbusServer.addInterface("/", desc, true);
 }
 
+Accessible* BridgeAccessible::FindSelf() const
+{
+  return FindCurrentObject();
+}
+
 Component* BridgeAccessible::GetObjectInRelation(Accessible* obj, RelationType relationType)
 {
   if(!obj)
@@ -432,11 +437,11 @@ Component* BridgeAccessible::GetObjectInRelation(Accessible* obj, RelationType r
 
   for(auto& relation : obj->GetRelationSet())
   {
-    if(relation.relationType == relationType)
+    if(relation.mRelationType == relationType)
     {
-      for(auto& address : relation.targets)
+      for(auto& target : relation.mTargets)
       {
-        auto component = dynamic_cast<Component*>(Find(address));
+        auto component = dynamic_cast<Component*>(target);
         if(component)
         {
           return component;
@@ -499,9 +504,9 @@ BridgeAccessible::ReadingMaterialType BridgeAccessible::GetReadingMaterial()
     auto relation  = std::find_if(relations.begin(),
                                  relations.end(),
                                  [relationType](const Dali::Accessibility::Relation& relation) -> bool {
-                                   return relation.relationType == relationType;
+                                   return relation.mRelationType == relationType;
                                  });
-    return relations.end() != relation && !relation->targets.empty() ? Find(relation->targets.back()) : nullptr;
+    return relations.end() != relation && !relation->mTargets.empty() ? relation->mTargets.back() : nullptr;
   };
 
   auto        labellingObject = findObjectByRelationType(RelationType::LABELLED_BY);
@@ -513,7 +518,7 @@ BridgeAccessible::ReadingMaterialType BridgeAccessible::GetReadingMaterial()
   double minimumIncrement = 0.0;
   double maximumValue     = 0.0;
   double minimumValue     = 0.0;
-  auto*  valueInterface   = dynamic_cast<Dali::Accessibility::Value*>(self);
+  auto*  valueInterface   = Value::DownCast(self);
   if(valueInterface)
   {
     currentValue     = valueInterface->GetCurrent();
@@ -524,7 +529,7 @@ BridgeAccessible::ReadingMaterialType BridgeAccessible::GetReadingMaterial()
 
   int32_t firstSelectedChildIndex = -1;
   int32_t selectedChildCount      = 0;
-  auto*   selfSelectionInterface  = dynamic_cast<Dali::Accessibility::Selection*>(self);
+  auto*   selfSelectionInterface  = Selection::DownCast(self);
   if(selfSelectionInterface)
   {
     selectedChildCount      = selfSelectionInterface->GetSelectedChildrenCount();
@@ -558,7 +563,7 @@ BridgeAccessible::ReadingMaterialType BridgeAccessible::GetReadingMaterial()
     listChildrenCount = GetItemCountOfFirstDescendantContainer(self, Role::POPUP_MENU, Role::MENU_ITEM, false);
   }
 
-  auto*       textInterface         = dynamic_cast<Dali::Accessibility::Text*>(self);
+  auto*       textInterface         = Text::DownCast(self);
   std::string nameFromTextInterface = "";
   if(textInterface)
   {
@@ -578,7 +583,7 @@ BridgeAccessible::ReadingMaterialType BridgeAccessible::GetReadingMaterial()
   auto  parentChildCount         = parent ? static_cast<int32_t>(parent->GetChildCount()) : 0;
   auto  parentStateSet           = parent ? parent->GetStates() : States{};
   bool  isSelectedInParent       = false;
-  auto* parentSelectionInterface = dynamic_cast<Dali::Accessibility::Selection*>(parent);
+  auto* parentSelectionInterface = Selection::DownCast(parent);
   if(parentSelectionInterface)
   {
     isSelectedInParent = parentSelectionInterface->IsChildSelected(indexInParent);
@@ -1014,9 +1019,9 @@ DBus::ValueOrError<std::unordered_map<std::string, std::string>> BridgeAccessibl
   return attributes;
 }
 
-DBus::ValueOrError<std::vector<std::string>> BridgeAccessible::GetInterfaces()
+DBus::ValueOrError<std::vector<std::string>> BridgeAccessible::GetInterfacesAsStrings()
 {
-  return FindSelf()->GetInterfaces();
+  return FindSelf()->GetInterfacesAsStrings();
 }
 
 int BridgeAccessible::GetChildCount()
@@ -1056,7 +1061,7 @@ DBus::ValueOrError<std::vector<BridgeAccessible::Relation>> BridgeAccessible::Ge
 
   for(auto& it : relations)
   {
-    ret.emplace_back(Relation{static_cast<uint32_t>(it.relationType), it.targets});
+    ret.emplace_back(Relation{static_cast<uint32_t>(it.mRelationType), it.mTargets});
   }
 
   return ret;
index 3ca2223..0a3299c 100644 (file)
@@ -45,6 +45,13 @@ protected:
    */
   void RegisterInterfaces();
 
+  /**
+   * @brief Returns the Accessible object of the currently executed DBus method call.
+   *
+   * @return The Accessible object
+   */
+  Dali::Accessibility::Accessible* FindSelf() const;
+
 public:
   /**
    * @brief Enumeration for NeighborSearchMode.
@@ -84,7 +91,7 @@ public:
     Dali::Accessibility::Accessible*  // describedByObject
     >;
 
-  using Relation = std::tuple<uint32_t, std::vector<Dali::Accessibility::Address>>;
+  using Relation = std::tuple<uint32_t, std::vector<Dali::Accessibility::Accessible*>>;
 
   /**
    * @copydoc Dali::Accessibility::Accessible::GetChildCount()
@@ -147,9 +154,9 @@ public:
   DBus::ValueOrError<std::unordered_map<std::string, std::string>> GetAttributes();
 
   /**
-   * @copydoc Dali::Accessibility::Accessible::GetInterfaces()
+   * @copydoc Dali::Accessibility::Accessible::GetInterfacesAsStrings()
    */
-  DBus::ValueOrError<std::vector<std::string>> GetInterfaces();
+  DBus::ValueOrError<std::vector<std::string>> GetInterfacesAsStrings();
 
   /**
    * @brief Gets Accessible object on which surface lies the point with given coordinates.
index 9db679f..90d1674 100644 (file)
 // CLASS HEADER
 #include <dali/internal/accessibility/bridge/bridge-action.h>
 
-// EXTERNAL INCLUDES
-#include <iostream>
-
 using namespace Dali::Accessibility;
 
 void BridgeAction::RegisterInterfaces()
 {
-  DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceAction};
+  DBus::DBusInterfaceDescription desc{Accessible::GetInterfaceName(AtspiInterface::ACTION)};
 
   AddGetPropertyToInterface(desc, "NActions", &BridgeAction::GetActionCount);
 
@@ -40,14 +37,7 @@ void BridgeAction::RegisterInterfaces()
 
 Action* BridgeAction::FindSelf() const
 {
-  auto self = BridgeBase::FindSelf();
-  assert(self);
-  auto actionInterface = dynamic_cast<Action*>(self);
-  if(!actionInterface)
-  {
-    throw std::domain_error{"object " + self->GetAddress().ToString() + " doesn't have Action interface"};
-  }
-  return actionInterface;
+  return FindCurrentObjectWithInterface<Dali::Accessibility::AtspiInterface::ACTION>();
 }
 
 DBus::ValueOrError<std::string> BridgeAction::GetActionName(int32_t index)
index 00e5c19..9806bad 100644 (file)
@@ -25,7 +25,7 @@ using namespace Dali::Accessibility;
 
 void BridgeApplication::RegisterInterfaces()
 {
-  DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceApplication};
+  DBus::DBusInterfaceDescription desc{Accessible::GetInterfaceName(AtspiInterface::APPLICATION)};
   AddGetPropertyToInterface(desc, "ToolkitName", &BridgeApplication::GetToolkitName);
   AddGetPropertyToInterface(desc, "Version", &BridgeApplication::GetVersion);
   mDbusServer.addInterface("/", desc, true);
@@ -33,14 +33,7 @@ void BridgeApplication::RegisterInterfaces()
 
 Application* BridgeApplication::FindSelf() const
 {
-  auto self = BridgeBase::FindSelf();
-  assert(self);
-  auto appInterface = dynamic_cast<Application*>(self);
-  if(!appInterface)
-  {
-    throw std::domain_error{"object " + self->GetAddress().ToString() + " doesn't have Application interface"};
-  }
-  return appInterface;
+  return FindCurrentObjectWithInterface<Dali::Accessibility::AtspiInterface::APPLICATION>();
 }
 
 std::string BridgeApplication::GetToolkitName()
index 8e4f805..9b920d8 100644 (file)
@@ -38,7 +38,6 @@ BridgeBase::BridgeBase()
 BridgeBase::~BridgeBase()
 {
   mApplication.mChildren.clear();
-  mApplication.mWindows.clear();
 }
 
 void BridgeBase::AddFilteredEvent(FilteredEvents kind, Dali::Accessibility::Accessible* obj, float delay, std::function<void()> functor)
@@ -135,17 +134,17 @@ BridgeBase::ForceUpResult BridgeBase::ForceUp()
   mDbusServer     = {mConnectionPtr};
 
   {
-    DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceCache};
+    DBus::DBusInterfaceDescription desc{Accessible::GetInterfaceName(AtspiInterface::CACHE)};
     AddFunctionToInterface(desc, "GetItems", &BridgeBase::GetItems);
     mDbusServer.addInterface(AtspiDbusPathCache, desc);
   }
   {
-    DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceApplication};
+    DBus::DBusInterfaceDescription desc{Accessible::GetInterfaceName(AtspiInterface::APPLICATION)};
     AddGetSetPropertyToInterface(desc, "Id", &BridgeBase::GetId, &BridgeBase::SetId);
     mDbusServer.addInterface(AtspiPath, desc);
   }
 
-  mRegistry = {AtspiDbusNameRegistry, AtspiDbusPathRegistry, AtspiDbusInterfaceRegistry, mConnectionPtr};
+  mRegistry = {AtspiDbusNameRegistry, AtspiDbusPathRegistry, Accessible::GetInterfaceName(AtspiInterface::REGISTRY), mConnectionPtr};
 
   UpdateRegisteredEvents();
 
@@ -186,31 +185,6 @@ Accessible* BridgeBase::FindByPath(const std::string& name) const
   }
 }
 
-void BridgeBase::OnWindowVisibilityChanged(Dali::Window window, bool visible)
-{
-  if(visible)
-  {
-    // TODO : Should we check 'out of screen' here? -> Then, we need an actor of this change.
-    Dali::Accessibility::Bridge::GetCurrentBridge()->WindowShown(window); // Called when Window is shown.
-  }
-  else
-  {
-    Dali::Accessibility::Bridge::GetCurrentBridge()->WindowHidden(window); // Called when Window is hidden and iconified.
-  }
-}
-
-void BridgeBase::OnWindowFocusChanged(Dali::Window window, bool focusIn)
-{
-  if(focusIn)
-  {
-    Dali::Accessibility::Bridge::GetCurrentBridge()->WindowFocused(window); // Called when Window is focused.
-  }
-  else
-  {
-    Dali::Accessibility::Bridge::GetCurrentBridge()->WindowUnfocused(window); // Called when Window is out of focus.
-  }
-}
-
 void BridgeBase::AddTopLevelWindow(Accessible* windowAccessible)
 {
   if(windowAccessible->GetInternalActor() == nullptr)
@@ -230,29 +204,10 @@ void BridgeBase::AddTopLevelWindow(Accessible* windowAccessible)
   SetIsOnRootLevel(windowAccessible);
 
   RegisterDefaultLabel(windowAccessible);
-
-  Dali::Window window = Dali::DevelWindow::Get(windowAccessible->GetInternalActor());
-  if(window)
-  {
-    mApplication.mWindows.push_back(window);
-    Dali::DevelWindow::VisibilityChangedSignal(window).Connect(this, &BridgeBase::OnWindowVisibilityChanged);
-    window.FocusChangeSignal().Connect(this, &BridgeBase::OnWindowFocusChanged);
-  }
 }
 
 void BridgeBase::RemoveTopLevelWindow(Accessible* windowAccessible)
 {
-  for(auto i = 0u; i < mApplication.mWindows.size(); ++i)
-  {
-    if(windowAccessible->GetInternalActor() == mApplication.mWindows[i].GetRootLayer())
-    {
-      Dali::DevelWindow::VisibilityChangedSignal(mApplication.mWindows[i]).Disconnect(this, &BridgeBase::OnWindowVisibilityChanged);
-      mApplication.mWindows[i].FocusChangeSignal().Disconnect(this, &BridgeBase::OnWindowFocusChanged);
-      mApplication.mWindows.erase(mApplication.mWindows.begin() + i);
-      break;
-    }
-  }
-
   UnregisterDefaultLabel(windowAccessible);
 
   for(auto i = 0u; i < mApplication.mChildren.size(); ++i)
@@ -317,7 +272,7 @@ Accessible* BridgeBase::Find(const Address& ptr) const
   return Find(ptr.GetPath());
 }
 
-Accessible* BridgeBase::FindSelf() const
+Accessible* BridgeBase::FindCurrentObject() const
 {
   auto path = DBus::DBusServer::getCurrentObjectPath();
   auto size = strlen(AtspiPath);
@@ -385,7 +340,7 @@ auto BridgeBase::CreateCacheElement(Accessible* item) -> CacheElementType
     root->GetAddress(),
     parent ? parent->GetAddress() : Address{},
     children,
-    item->GetInterfaces(),
+    item->GetInterfacesAsStrings(),
     item->GetName(),
     item->GetRole(),
     item->GetDescription(),
index cdffa9e..2449842 100644 (file)
@@ -40,8 +40,8 @@ class ApplicationAccessible : public virtual Dali::Accessibility::Accessible, pu
 public:
   Dali::Accessibility::ProxyAccessible          mParent;
   std::vector<Dali::Accessibility::Accessible*> mChildren;
-  std::vector<Dali::Window>                     mWindows;
   std::string                                   mName;
+  std::string                                   mToolkitName{"dali"};
 
   std::string GetName() const override
   {
@@ -149,7 +149,7 @@ public:
 
   std::string GetToolkitName() const override
   {
-    return {"dali"};
+    return mToolkitName;
   }
 
   std::string GetVersion() const override
@@ -425,14 +425,52 @@ public:
   /**
    * @brief Returns the target object of the currently executed DBus method call.
    *
-   * And any subclasses redefine `FindSelf` with a different return type as a convenient wrapper around dynamic_cast.
    * @return The Accessible object
    * @note When a DBus method is called on some object, this target object (`currentObject`) is temporarily saved by the bridge,
    * because DBus handles the invocation target separately from the method arguments.
    * We then use the saved object inside the 'glue' method (e.g. BridgeValue::GetMinimum)
    * to call the equivalent method on the respective C++ object (this could be ScrollBar::AccessibleImpl::GetMinimum in the example given).
    */
-  Dali::Accessibility::Accessible* FindSelf() const;
+  Dali::Accessibility::Accessible* FindCurrentObject() const;
+
+  /**
+   * @brief Returns the target object of the currently executed DBus method call.
+   *
+   * This method tries to downcast the return value of FindCurrentObject() to the requested type,
+   * issuing an error reply to the DBus caller if the requested type is not implemented. Whether
+   * a given type is implemented is decided based on the return value of Accessible::GetInterfaces()
+   * for the current object.
+   *
+   * @tparam I The requested AT-SPI interface
+   * @return The Accessible object (cast to a more derived type)
+   *
+   * @see FindCurrentObject()
+   * @see Dali::Accessibility::AtspiInterface
+   * @see Dali::Accessibility::AtspiInterfaceType
+   * @see Dali::Accessibility::Accessible::GetInterfaces()
+   */
+  template<Dali::Accessibility::AtspiInterface I>
+  auto* FindCurrentObjectWithInterface() const
+  {
+    using Type = Dali::Accessibility::AtspiInterfaceType<I>;
+
+    Type* result;
+    auto* currentObject = FindCurrentObject();
+    DALI_ASSERT_DEBUG(currentObject); // FindCurrentObject() throws domain_error
+
+    if(!(result = Dali::Accessibility::Accessible::DownCast<I>(currentObject)))
+    {
+      std::stringstream s;
+
+      s << "Object " << currentObject->GetAddress().ToString();
+      s << " does not implement ";
+      s << Dali::Accessibility::Accessible::GetInterfaceName(I);
+
+      throw std::domain_error{s.str()};
+    }
+
+    return result;
+  }
 
   /**
    * @copydoc Dali::Accessibility::Bridge::FindByPath()
@@ -447,6 +485,14 @@ public:
     mApplication.mName = std::move(name);
   }
 
+  /**
+   * @copydoc Dali::Accessibility::Bridge::SetToolkitName()
+   */
+  void SetToolkitName(std::string_view toolkitName) override
+  {
+    mApplication.mToolkitName = std::string{toolkitName};
+  }
+
 protected:
   mutable ApplicationAccessible                 mApplication;
   std::vector<Dali::Accessibility::Accessible*> mDefaultLabels;
index 413e23c..497863b 100644 (file)
@@ -20,7 +20,6 @@
 
 // EXTERNAL INCLUDES
 #include <algorithm>
-#include <iostream>
 #include <unordered_set>
 #include <vector>
 
@@ -46,21 +45,14 @@ enum class AtspiCollection
 
 void BridgeCollection::RegisterInterfaces()
 {
-  DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceCollection};
+  DBus::DBusInterfaceDescription desc{Accessible::GetInterfaceName(AtspiInterface::COLLECTION)};
   AddFunctionToInterface(desc, "GetMatches", &BridgeCollection::GetMatches);
   mDbusServer.addInterface("/", desc, true);
 }
 
 Collection* BridgeCollection::FindSelf() const
 {
-  auto self = BridgeBase::FindSelf();
-  assert(self);
-  auto collectionInterface = dynamic_cast<Collection*>(self);
-  if(!collectionInterface)
-  {
-    throw std::domain_error{"object " + self->GetAddress().ToString() + " doesn't have Collection interface"};
-  }
-  return collectionInterface;
+  return FindCurrentObjectWithInterface<Dali::Accessibility::AtspiInterface::COLLECTION>();
 }
 
 /**
@@ -128,7 +120,7 @@ struct BridgeCollection::Comparer
     void Update(Accessible* obj)
     {
       mObject.clear();
-      for(auto& interface : obj->GetInterfaces())
+      for(auto& interface : obj->GetInterfacesAsStrings())
       {
         mObject.insert(std::move(interface));
       }
@@ -485,7 +477,7 @@ void BridgeCollection::VisitNodes(Accessible* obj, std::vector<Accessible*>& res
 DBus::ValueOrError<std::vector<Accessible*> > BridgeCollection::GetMatches(MatchRule rule, uint32_t sortBy, int32_t count, bool traverse)
 {
   std::vector<Accessible*> res;
-  auto                     self    = BridgeBase::FindSelf();
+  auto                     self    = BridgeBase::FindCurrentObject();
   auto                     matcher = Comparer{&rule};
   VisitNodes(self, res, matcher, count);
 
index 64694ca..2a297f5 100644 (file)
@@ -18,9 +18,6 @@
 // CLASS HEADER
 #include <dali/internal/accessibility/bridge/bridge-component.h>
 
-// EXTERNAL INCLUDES
-#include <iostream>
-
 #define DBUS_INTERFACE_PROPERTIES "org.freedesktop.DBus.Properties"
 
 using namespace Dali::Accessibility;
@@ -35,7 +32,7 @@ void BridgeComponent::RegisterInterfaces()
   // Screen Reader will call the methods with the exact names as specified in the AT-SPI Component interface:
   // https://gitlab.gnome.org/GNOME/at-spi2-core/-/blob/master/xml/Component.xml
 
-  DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceComponent};
+  DBus::DBusInterfaceDescription desc{Accessible::GetInterfaceName(AtspiInterface::COMPONENT)};
   AddFunctionToInterface(desc, "Contains", &BridgeComponent::IsAccessibleContainingPoint);
   AddFunctionToInterface(desc, "GetAccessibleAtPoint", &BridgeComponent::GetAccessibleAtPoint);
   AddFunctionToInterface(desc, "GetExtents", &BridgeComponent::GetExtents);
@@ -52,14 +49,7 @@ void BridgeComponent::RegisterInterfaces()
 
 Component* BridgeComponent::FindSelf() const
 {
-  auto self = BridgeBase::FindSelf();
-  assert(self);
-  auto componentInterface = dynamic_cast<Component*>(self);
-  if(!componentInterface)
-  {
-    throw std::domain_error{"object " + self->GetAddress().ToString() + " doesn't have Component interface"};
-  }
-  return componentInterface;
+  return FindCurrentObjectWithInterface<Dali::Accessibility::AtspiInterface::COMPONENT>();
 }
 
 DBus::ValueOrError<bool> BridgeComponent::IsAccessibleContainingPoint(int32_t x, int32_t y, uint32_t coordType)
index 3de8dc5..034885a 100644 (file)
@@ -25,7 +25,7 @@ using namespace Dali::Accessibility;
 
 void BridgeEditableText::RegisterInterfaces()
 {
-  DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceEditableText};
+  DBus::DBusInterfaceDescription desc{Accessible::GetInterfaceName(AtspiInterface::EDITABLE_TEXT)};
   AddFunctionToInterface(desc, "CopyText", &BridgeEditableText::CopyText);
   AddFunctionToInterface(desc, "CutText", &BridgeEditableText::CutText);
   AddFunctionToInterface(desc, "DeleteText", &BridgeEditableText::DeleteText);
@@ -37,14 +37,7 @@ void BridgeEditableText::RegisterInterfaces()
 
 EditableText* BridgeEditableText::FindSelf() const
 {
-  auto self = BridgeBase::FindSelf();
-  assert(self);
-  auto editableTextInterface = dynamic_cast<EditableText*>(self);
-  if(!editableTextInterface)
-  {
-    throw std::domain_error{"object " + self->GetAddress().ToString() + " doesn't have Text interface"};
-  }
-  return editableTextInterface;
+  return FindCurrentObjectWithInterface<Dali::Accessibility::AtspiInterface::EDITABLE_TEXT>();
 }
 
 DBus::ValueOrError<bool> BridgeEditableText::CopyText(int32_t startPosition, int32_t endPosition)
index 4395ff0..992d2cf 100644 (file)
@@ -25,7 +25,7 @@ using namespace Dali::Accessibility;
 
 void BridgeHyperlink::RegisterInterfaces()
 {
-  DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceHyperlink};
+  DBus::DBusInterfaceDescription desc{Accessible::GetInterfaceName(AtspiInterface::HYPERLINK)};
   AddGetPropertyToInterface(desc, "NAnchors", &BridgeHyperlink::GetAnchorCount);
   AddGetPropertyToInterface(desc, "StartIndex", &BridgeHyperlink::GetStartIndex);
   AddGetPropertyToInterface(desc, "EndIndex", &BridgeHyperlink::GetEndIndex);
@@ -37,14 +37,7 @@ void BridgeHyperlink::RegisterInterfaces()
 
 Hyperlink* BridgeHyperlink::FindSelf() const
 {
-  auto self = BridgeBase::FindSelf();
-  assert(self);
-  auto hyperlinkInterface = dynamic_cast<Hyperlink*>(self);
-  if(!hyperlinkInterface)
-  {
-    throw std::domain_error{"object " + self->GetAddress().ToString() + " doesn't have Hyperlink interface"};
-  }
-  return hyperlinkInterface;
+  return FindCurrentObjectWithInterface<Dali::Accessibility::AtspiInterface::HYPERLINK>();
 }
 
 DBus::ValueOrError<int32_t> BridgeHyperlink::GetEndIndex()
index 3a42d8d..b5f3b3b 100644 (file)
@@ -25,7 +25,7 @@ using namespace Dali::Accessibility;
 
 void BridgeHypertext::RegisterInterfaces()
 {
-  DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceHypertext};
+  DBus::DBusInterfaceDescription desc{Accessible::GetInterfaceName(AtspiInterface::HYPERTEXT)};
   AddFunctionToInterface(desc, "GetNLinks", &BridgeHypertext::GetLinkCount);
   AddFunctionToInterface(desc, "GetLink", &BridgeHypertext::GetLink);
   AddFunctionToInterface(desc, "GetLinkIndex", &BridgeHypertext::GetLinkIndex);
@@ -34,14 +34,7 @@ void BridgeHypertext::RegisterInterfaces()
 
 Hypertext* BridgeHypertext::FindSelf() const
 {
-  auto self = BridgeBase::FindSelf();
-  assert(self);
-  auto hypertextInterface = dynamic_cast<Hypertext*>(self);
-  if(!hypertextInterface)
-  {
-    throw std::domain_error{"object " + self->GetAddress().ToString() + " doesn't have Hypertext interface"};
-  }
-  return hypertextInterface;
+  return FindCurrentObjectWithInterface<Dali::Accessibility::AtspiInterface::HYPERTEXT>();
 }
 
 DBus::ValueOrError<int32_t> BridgeHypertext::GetLinkCount()
index 0d48895..4cde992 100644 (file)
@@ -36,6 +36,7 @@
 #include <dali/internal/accessibility/bridge/bridge-hyperlink.h>
 #include <dali/internal/accessibility/bridge/bridge-object.h>
 #include <dali/internal/accessibility/bridge/bridge-selection.h>
+#include <dali/internal/accessibility/bridge/bridge-socket.h>
 #include <dali/internal/accessibility/bridge/bridge-text.h>
 #include <dali/internal/accessibility/bridge/bridge-value.h>
 #include <dali/internal/accessibility/bridge/bridge-application.h>
@@ -67,14 +68,14 @@ class BridgeImpl : public virtual BridgeBase,
                    public BridgeSelection,
                    public BridgeApplication,
                    public BridgeHypertext,
-                   public BridgeHyperlink
+                   public BridgeHyperlink,
+                   public BridgeSocket
 {
   DBus::DBusClient                                              mAccessibilityStatusClient;
   DBus::DBusClient                                              mRegistryClient;
   DBus::DBusClient                                              mDirectReadingClient;
   bool                                                          mIsScreenReaderEnabled = false;
   bool                                                          mIsEnabled             = false;
-  bool                                                          mIsShown               = false;
   std::unordered_map<int32_t, std::function<void(std::string)>> mDirectReadingCallbacks;
   Dali::Actor                                                   mHighlightedActor;
   std::function<void(Dali::Actor)>                              mHighlightClearAction;
@@ -142,7 +143,7 @@ public:
     mDirectReadingClient.method<DBus::ValueOrError<void>(bool)>("PauseResume").asyncCall([](DBus::ValueOrError<void> msg) {
       if(!msg)
       {
-        LOG() << "Direct reading command failed (" << msg.getError().message << ")";
+        LOG() << "Direct reading command failed (" << msg.getError().message << ")\n";
       }
     },
                                                                                         true);
@@ -161,7 +162,7 @@ public:
     mDirectReadingClient.method<DBus::ValueOrError<void>(bool)>("PauseResume").asyncCall([](DBus::ValueOrError<void> msg) {
       if(!msg)
       {
-        LOG() << "Direct reading command failed (" << msg.getError().message << ")";
+        LOG() << "Direct reading command failed (" << msg.getError().message << ")\n";
       }
     },
                                                                                         false);
@@ -180,7 +181,7 @@ public:
     mDirectReadingClient.method<DBus::ValueOrError<void>(bool)>("StopReading").asyncCall([](DBus::ValueOrError<void> msg) {
       if(!msg)
       {
-        LOG() << "Direct reading command failed (" << msg.getError().message << ")";
+        LOG() << "Direct reading command failed (" << msg.getError().message << ")\n";
       }
     },
                                                                                         alsoNonDiscardable);
@@ -199,7 +200,7 @@ public:
     mDirectReadingClient.method<DBus::ValueOrError<std::string, bool, int32_t>(std::string, bool)>("ReadCommand").asyncCall([=](DBus::ValueOrError<std::string, bool, int32_t> msg) {
       if(!msg)
       {
-        LOG() << "Direct reading command failed (" << msg.getError().message << ")";
+        LOG() << "Direct reading command failed (" << msg.getError().message << ")\n";
       }
       else if(callback)
       {
@@ -225,7 +226,9 @@ public:
       mData->mHighlightActor            = {};
 
       mDisabledSignal.Emit();
+      UnembedSocket(mApplication.GetAddress(), {AtspiDbusNameRegistry, "root"});
     }
+
     mHighlightedActor     = {};
     mHighlightClearAction = {};
     BridgeAccessible::ForceDown();
@@ -233,7 +236,6 @@ public:
     mDirectReadingClient  = {};
     mDirectReadingCallbacks.clear();
     mApplication.mChildren.clear();
-    mApplication.mWindows.clear();
     ClearTimer();
   }
 
@@ -271,6 +273,11 @@ public:
   {
     if(mData)
     {
+      // The ~Window() after this point cannot emit DESTROY, because Bridge is not available. So emit DESTROY here.
+      for(auto windowAccessible : mApplication.mChildren)
+      {
+        BridgeObject::Emit(windowAccessible, WindowEvent::DESTROY);
+      }
       mData->mCurrentlyHighlightedActor = {};
       mData->mHighlightActor            = {};
     }
@@ -326,10 +333,11 @@ public:
     BridgeApplication::RegisterInterfaces();
     BridgeHypertext::RegisterInterfaces();
     BridgeHyperlink::RegisterInterfaces();
+    BridgeSocket::RegisterInterfaces();
 
     RegisterOnBridge(&mApplication);
 
-    mRegistryClient      = {AtspiDbusNameRegistry, AtspiDbusPathDec, AtspiDbusInterfaceDec, mConnectionPtr};
+    mRegistryClient      = {AtspiDbusNameRegistry, AtspiDbusPathDec, Accessible::GetInterfaceName(AtspiInterface::DEVICE_EVENT_CONTROLLER), mConnectionPtr};
     mDirectReadingClient = DBus::DBusClient{DirectReadingDBusName, DirectReadingDBusPath, DirectReadingDBusInterface, mConnectionPtr};
 
     mDirectReadingClient.addSignal<void(int32_t, std::string)>("ReadingStateChanged", [=](int32_t id, std::string readingState) {
@@ -344,26 +352,10 @@ public:
       }
     });
 
-    auto    proxy = DBus::DBusClient{AtspiDbusNameRegistry, AtspiDbusPathRoot, AtspiDbusInterfaceSocket, mConnectionPtr};
-    Address root{"", "root"};
-    auto    res = proxy.method<Address(Address)>("Embed").call(root);
-    if(!res)
-    {
-      LOG() << "Call to Embed failed: " << res.getError().message;
-    }
-    assert(res);
-
-    mApplication.mParent.SetAddress(std::move(std::get<0>(res)));
-
+    auto parentAddress = EmbedSocket(mApplication.GetAddress(), {AtspiDbusNameRegistry, "root"});
+    mApplication.mParent.SetAddress(std::move(parentAddress));
     mEnabledSignal.Emit();
 
-    if(mIsShown)
-    {
-      auto rootLayer = Dali::Stage::GetCurrent().GetRootLayer();
-      auto window    = Dali::DevelWindow::Get(rootLayer);
-      EmitActivate(window); // Currently, sends a signal that the default window is activated here.
-    }
-
     return ForceUpResult::JUST_STARTED;
   }
 
@@ -432,11 +424,10 @@ public:
    */
   void WindowShown(Dali::Window window) override
   {
-    if(!mIsShown && IsUp())
+    if(IsUp())
     {
       EmitShown(window);
     }
-    mIsShown = true;
   }
 
   /**
@@ -444,11 +435,10 @@ public:
    */
   void WindowHidden(Dali::Window window) override
   {
-    if(mIsShown && IsUp())
+    if(IsUp())
     {
       EmitHidden(window);
     }
-    mIsShown = false;
   }
 
   /**
@@ -456,7 +446,7 @@ public:
    */
   void WindowFocused(Dali::Window window) override
   {
-    if(mIsShown && IsUp())
+    if(IsUp())
     {
       EmitActivate(window);
     }
@@ -467,7 +457,7 @@ public:
    */
   void WindowUnfocused(Dali::Window window) override
   {
-    if(mIsShown && IsUp())
+    if(IsUp())
     {
       EmitDeactivate(window);
     }
@@ -582,10 +572,23 @@ public:
     });
   }
 
+  void EmitScreenReaderEnabledSignal()
+  {
+    if (mIsScreenReaderEnabled)
+    {
+      mScreenReaderEnabledSignal.Emit();
+    }
+    else
+    {
+      mScreenReaderDisabledSignal.Emit();
+    }
+  }
+
   void ListenScreenReaderEnabledProperty()
   {
     mAccessibilityStatusClient.addPropertyChangedEvent<bool>("ScreenReaderEnabled", [this](bool res) {
       mIsScreenReaderEnabled = res;
+      EmitScreenReaderEnabledSignal();
       SwitchBridge();
     });
   }
@@ -680,6 +683,40 @@ public:
   {
     return mIsEnabled;
   }
+
+  Address EmbedSocket(const Address& plug, const Address& socket) override
+  {
+    auto client = CreateSocketClient(socket);
+    auto reply  = client.method<Address(Address)>("Embed").call(plug);
+
+    if(!reply)
+    {
+      DALI_LOG_ERROR("Failed to embed socket %s: %s", socket.ToString().c_str(), reply.getError().message.c_str());
+      return {};
+    }
+
+    return std::get<0>(reply.getValues());
+  }
+
+  void EmbedAtkSocket(const Address& plug, const Address& socket) override
+  {
+    auto client = CreateSocketClient(socket);
+
+    client.method<void(std::string)>("Embedded").call(ATSPI_PREFIX_PATH + plug.GetPath());
+  }
+
+  void UnembedSocket(const Address& plug, const Address& socket) override
+  {
+    auto client = CreateSocketClient(socket);
+
+    client.method<void(Address)>("Unembed").call(plug);
+  }
+
+private:
+  DBus::DBusClient CreateSocketClient(const Address& socket)
+  {
+    return {socket.GetBus(), ATSPI_PREFIX_PATH + socket.GetPath(), Accessible::GetInterfaceName(AtspiInterface::SOCKET), mConnectionPtr};
+  }
 }; // BridgeImpl
 
 namespace // unnamed namespace
@@ -767,7 +804,7 @@ void Bridge::EnableAutoInit()
   auto window          = Dali::DevelWindow::Get(rootLayer);
   auto applicationName = Dali::Internal::Adaptor::Adaptor::GetApplicationPackageName();
 
-  auto accessible = Accessibility::Accessible::Get(rootLayer, true);
+  auto accessible = Accessibility::Accessible::Get(rootLayer);
 
   auto bridge = Bridge::GetCurrentBridge();
   bridge->AddTopLevelWindow(accessible);
index 5a3847c..6490166 100644 (file)
@@ -41,14 +41,14 @@ BridgeObject::BridgeObject()
 
 void BridgeObject::RegisterInterfaces()
 {
-  // DBus::DBusInterfaceDescription desc{ AtspiDbusInterfaceEventObject };
+  // DBus::DBusInterfaceDescription desc{Accessible::GetInterfaceName(AtspiInterface::EVENT_OBJECT)};
   // mStateChanged = addSignal<std::string, int, int, DBus::EldbusVariant<int>, Accessible*>(desc, "StateChanged");
   // mDbusServer.addInterface("/", desc, true);
 }
 
 void BridgeObject::EmitActiveDescendantChanged(Accessible* obj, Accessible* child)
 {
-  if(!IsUp() || obj->IsHidden() || child->IsHidden())
+  if(!IsUp() || obj->IsHidden() || obj->GetSuppressedEvents()[AtspiEvent::ACTIVE_DESCENDANT_CHANGED] || child->IsHidden())
   {
     return;
   }
@@ -57,7 +57,7 @@ void BridgeObject::EmitActiveDescendantChanged(Accessible* obj, Accessible* chil
 
   mDbusServer.emit2<std::string, int, int, DBus::EldbusVariant<Address>, Address>(
     GetAccessiblePath(obj),
-    AtspiDbusInterfaceEventObject,
+    Accessible::GetInterfaceName(AtspiInterface::EVENT_OBJECT),
     "ActiveDescendantChanged",
     "",
     index,
@@ -76,7 +76,7 @@ void BridgeObject::Emit(Accessible* obj, ObjectPropertyChangeEvent event)
     {ObjectPropertyChangeEvent::ROLE, "accessible-role"},
   };
 
-  if(!IsUp() || obj->IsHidden())
+  if(!IsUp() || obj->IsHidden() || obj->GetSuppressedEvents()[AtspiEvent::PROPERTY_CHANGED])
   {
     return;
   }
@@ -87,7 +87,7 @@ void BridgeObject::Emit(Accessible* obj, ObjectPropertyChangeEvent event)
   {
     mDbusServer.emit2<std::string, int, int, DBus::EldbusVariant<int>, Address>(
       GetAccessiblePath(obj),
-      AtspiDbusInterfaceEventObject,
+      Accessible::GetInterfaceName(AtspiInterface::EVENT_OBJECT),
       "PropertyChange",
       std::string{eventName->second},
       0,
@@ -121,7 +121,7 @@ void BridgeObject::Emit(Accessible* obj, WindowEvent event, unsigned int detail)
     {WindowEvent::RESTYLE, "Restyle"},
   };
 
-  if(!IsUp() || obj->IsHidden())
+  if(!IsUp() || obj->IsHidden() || obj->GetSuppressedEvents()[AtspiEvent::WINDOW_CHANGED])
   {
     return;
   }
@@ -132,7 +132,7 @@ void BridgeObject::Emit(Accessible* obj, WindowEvent event, unsigned int detail)
   {
     mDbusServer.emit2<std::string, int, int, DBus::EldbusVariant<int>, Address>(
       GetAccessiblePath(obj),
-      AtspiDbusInterfaceEventWindow,
+      Accessible::GetInterfaceName(AtspiInterface::EVENT_WINDOW),
       std::string{eventName->second},
       "",
       detail,
@@ -193,7 +193,7 @@ void BridgeObject::EmitStateChanged(Accessible* obj, State state, int newValue,
     {State::HIGHLIGHTABLE, "highlightable"},
   };
 
-  if(!IsUp() || obj->IsHidden())
+  if(!IsUp() || obj->IsHidden() || obj->GetSuppressedEvents()[AtspiEvent::STATE_CHANGED]) // separate ?
   {
     return;
   }
@@ -204,7 +204,7 @@ void BridgeObject::EmitStateChanged(Accessible* obj, State state, int newValue,
   {
     mDbusServer.emit2<std::string, int, int, DBus::EldbusVariant<int>, Address>(
       GetAccessiblePath(obj),
-      AtspiDbusInterfaceEventObject,
+      Accessible::GetInterfaceName(AtspiInterface::EVENT_OBJECT),
       "StateChanged",
       std::string{stateName->second},
       newValue,
@@ -216,7 +216,7 @@ void BridgeObject::EmitStateChanged(Accessible* obj, State state, int newValue,
 
 void BridgeObject::EmitBoundsChanged(Accessible* obj, Dali::Rect<> rect)
 {
-  if(!IsUp() || !IsBoundsChangedEventAllowed || obj->IsHidden())
+  if(!IsUp() || !IsBoundsChangedEventAllowed || obj->IsHidden() || obj->GetSuppressedEvents()[AtspiEvent::BOUNDS_CHANGED])
   {
     return;
   }
@@ -227,7 +227,7 @@ void BridgeObject::EmitBoundsChanged(Accessible* obj, Dali::Rect<> rect)
   AddFilteredEvent(FilteredEvents::BOUNDS_CHANGED, obj, 1.0f, [=]() {
     mDbusServer.emit2<std::string, int, int, DBus::EldbusVariant<std::tuple<int32_t, int32_t, int32_t, int32_t> >, Address>(
       GetAccessiblePath(obj),
-      AtspiDbusInterfaceEventObject,
+      Accessible::GetInterfaceName(AtspiInterface::EVENT_OBJECT),
       "BoundsChanged",
       "",
       0,
@@ -239,14 +239,14 @@ void BridgeObject::EmitBoundsChanged(Accessible* obj, Dali::Rect<> rect)
 
 void BridgeObject::EmitCursorMoved(Accessible* obj, unsigned int cursorPosition)
 {
-  if(!IsUp() || obj->IsHidden())
+  if(!IsUp() || obj->IsHidden() || obj->GetSuppressedEvents()[AtspiEvent::TEXT_CARET_MOVED])
   {
     return;
   }
 
   mDbusServer.emit2<std::string, int, int, DBus::EldbusVariant<int>, Address>(
     GetAccessiblePath(obj),
-    AtspiDbusInterfaceEventObject,
+    Accessible::GetInterfaceName(AtspiInterface::EVENT_OBJECT),
     "TextCaretMoved",
     "",
     cursorPosition,
@@ -262,7 +262,7 @@ void BridgeObject::EmitTextChanged(Accessible* obj, TextChangedState state, unsi
     {TextChangedState::DELETED, "delete"},
   };
 
-  if(!IsUp() || obj->IsHidden())
+  if(!IsUp() || obj->IsHidden() || obj->GetSuppressedEvents()[AtspiEvent::TEXT_CHANGED])
   {
     return;
   }
@@ -273,7 +273,7 @@ void BridgeObject::EmitTextChanged(Accessible* obj, TextChangedState state, unsi
   {
     mDbusServer.emit2<std::string, int, int, DBus::EldbusVariant<std::string>, Address>(
       GetAccessiblePath(obj),
-      AtspiDbusInterfaceEventObject,
+      Accessible::GetInterfaceName(AtspiInterface::EVENT_OBJECT),
       "TextChanged",
       std::string{stateName->second},
       position,
@@ -285,14 +285,14 @@ void BridgeObject::EmitTextChanged(Accessible* obj, TextChangedState state, unsi
 
 void BridgeObject::EmitMovedOutOfScreen(Accessible* obj, ScreenRelativeMoveType type)
 {
-  if(!IsUp() || obj->IsHidden())
+  if(!IsUp() || obj->IsHidden() || obj->GetSuppressedEvents()[AtspiEvent::MOVED_OUT])
   {
     return;
   }
 
   mDbusServer.emit2<std::string, int, int, DBus::EldbusVariant<int>, Address>(
     GetAccessiblePath(obj),
-    AtspiDbusInterfaceEventObject,
+    Accessible::GetInterfaceName(AtspiInterface::EVENT_OBJECT),
     "MoveOuted",
     "",
     static_cast<int>(type),
@@ -300,3 +300,18 @@ void BridgeObject::EmitMovedOutOfScreen(Accessible* obj, ScreenRelativeMoveType
     {0},
     {"", "root"});
 }
+
+void BridgeObject::EmitSocketAvailable(Accessible* obj)
+{
+  if(!IsUp() || obj->IsHidden()) //TODO Suppress SocketAvailable event
+  {
+    return;
+  }
+
+  mDbusServer.emit2<Address, Address>(
+    GetAccessiblePath(obj),
+    Accessible::GetInterfaceName(AtspiInterface::SOCKET),
+    "Available",
+    obj->GetAddress(),
+    {"", "root"});
+}
index 69ca828..9784469 100644 (file)
@@ -68,7 +68,7 @@ protected:
   /**
    * @copydoc Dali::Accessibility::Bridge::Emit()
    */
-  void Emit(Dali::Accessibility::Accessible* obj, Dali::Accessibility::WindowEvent event, unsigned int detail) override;
+  void Emit(Dali::Accessibility::Accessible* obj, Dali::Accessibility::WindowEvent event, unsigned int detail = 0) override;
 
   /**
    * @copydoc Dali::Accessibility::Bridge::Emit()
@@ -85,6 +85,11 @@ protected:
    */
   void EmitMovedOutOfScreen(Dali::Accessibility::Accessible* obj, Dali::Accessibility::ScreenRelativeMoveType type) override;
 
+  /**
+   * @copydoc Dali::Accessibility::Bridge::EmitSocketAvailable()
+   */
+  void EmitSocketAvailable(Dali::Accessibility::Accessible* obj) override;
+
 protected:
   DBus::DBusInterfaceDescription::SignalId mStateChanged;
 };
index 942bd97..0713670 100644 (file)
@@ -22,7 +22,7 @@ using namespace Dali::Accessibility;
 
 void BridgeSelection::RegisterInterfaces()
 {
-  DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceSelection};
+  DBus::DBusInterfaceDescription desc{Accessible::GetInterfaceName(AtspiInterface::SELECTION)};
   AddGetPropertyToInterface(desc, "NSelectedChildren", &BridgeSelection::GetSelectedChildrenCount);
   AddFunctionToInterface(desc, "GetSelectedChild", &BridgeSelection::GetSelectedChild);
   AddFunctionToInterface(desc, "SelectChild", &BridgeSelection::SelectChild);
@@ -36,14 +36,7 @@ void BridgeSelection::RegisterInterfaces()
 
 Selection* BridgeSelection::FindSelf() const
 {
-  auto self = BridgeBase::FindSelf();
-  assert(self);
-  auto selectionInterface = dynamic_cast<Selection*>(self);
-  if(!selectionInterface)
-  {
-    throw std::domain_error{"object " + self->GetAddress().ToString() + " doesn't have Selection interface"};
-  }
-  return selectionInterface;
+  return FindCurrentObjectWithInterface<Dali::Accessibility::AtspiInterface::SELECTION>();
 }
 
 DBus::ValueOrError<int32_t> BridgeSelection::GetSelectedChildrenCount()
diff --git a/dali/internal/accessibility/bridge/bridge-socket.cpp b/dali/internal/accessibility/bridge/bridge-socket.cpp
new file mode 100644 (file)
index 0000000..fdbae8c
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/accessibility/bridge/bridge-socket.h>
+
+using namespace Dali::Accessibility;
+
+void BridgeSocket::RegisterInterfaces()
+{
+  DBus::DBusInterfaceDescription desc{Accessible::GetInterfaceName(AtspiInterface::SOCKET)};
+
+  AddFunctionToInterface(desc, "Embed", &BridgeSocket::Embed);
+  AddFunctionToInterface(desc, "Unembed", &BridgeSocket::Unembed);
+
+  mDbusServer.addInterface("/", desc, true);
+}
+
+Socket* BridgeSocket::FindSelf() const
+{
+  return FindCurrentObjectWithInterface<Dali::Accessibility::AtspiInterface::SOCKET>();
+}
+
+DBus::ValueOrError<Address> BridgeSocket::Embed(Address plug)
+{
+  return FindSelf()->Embed(plug);
+}
+
+DBus::ValueOrError<void> BridgeSocket::Unembed(Address plug)
+{
+  FindSelf()->Unembed(plug);
+  return {};
+}
diff --git a/dali/internal/accessibility/bridge/bridge-socket.h b/dali/internal/accessibility/bridge/bridge-socket.h
new file mode 100644 (file)
index 0000000..6034700
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef DALI_INTERNAL_ACCESSIBILITY_BRIDGE_SOCKET_H
+#define DALI_INTERNAL_ACCESSIBILITY_BRIDGE_SOCKET_H
+
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/atspi-interfaces/socket.h>
+#include <dali/internal/accessibility/bridge/bridge-base.h>
+
+/**
+ * @brief The BridgeSocket class contains glue code for Accessibility::Socket.
+ */
+class BridgeSocket : public virtual BridgeBase
+{
+protected:
+  BridgeSocket() = default;
+
+  /**
+   * @brief Registers Socket methods as a DBus interface.
+   */
+  void RegisterInterfaces();
+
+  /**
+   * @brief Returns the Socket object of the currently executed DBus method call.
+   *
+   * @return The Socket object
+   */
+  Dali::Accessibility::Socket* FindSelf() const;
+
+public:
+  /**
+   * @copydoc Dali::Accessibility::Socket::Embed()
+   */
+  DBus::ValueOrError<Dali::Accessibility::Address> Embed(Dali::Accessibility::Address plug);
+
+  /**
+   * @copydoc Dali::Accessibility::Socket::Unembed()
+   */
+  DBus::ValueOrError<void> Unembed(Dali::Accessibility::Address plug);
+};
+
+#endif // DALI_INTERNAL_ACCESSIBILITY_BRIDGE_SOCKET_H
index 1ba0073..2707e44 100644 (file)
@@ -29,7 +29,7 @@ void BridgeText::RegisterInterfaces()
   // Screen Reader will call the methods with the exact names as specified in the AT-SPI Text interface:
   // https://gitlab.gnome.org/GNOME/at-spi2-core/-/blob/master/xml/Text.xml
 
-  DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceText};
+  DBus::DBusInterfaceDescription desc{Accessible::GetInterfaceName(AtspiInterface::TEXT)};
   AddFunctionToInterface(desc, "GetText", &BridgeText::GetText);
   AddGetPropertyToInterface(desc, "CharacterCount", &BridgeText::GetCharacterCount);
   AddGetPropertyToInterface(desc, "CaretOffset", &BridgeText::GetCursorOffset);
@@ -38,19 +38,13 @@ void BridgeText::RegisterInterfaces()
   AddFunctionToInterface(desc, "GetSelection", &BridgeText::GetRangeOfSelection);
   AddFunctionToInterface(desc, "SetSelection", &BridgeText::SetRangeOfSelection);
   AddFunctionToInterface(desc, "RemoveSelection", &BridgeText::RemoveSelection);
+  AddFunctionToInterface(desc, "GetRangeExtents", &BridgeText::GetRangeExtents);
   mDbusServer.addInterface("/", desc, true);
 }
 
 Text* BridgeText::FindSelf() const
 {
-  auto self = BridgeBase::FindSelf();
-  assert(self);
-  auto textInterface = dynamic_cast<Text*>(self);
-  if(!textInterface)
-  {
-    throw std::domain_error{"Object " + self->GetAddress().ToString() + " doesn't have Text interface"};
-  }
-  return textInterface;
+  return FindCurrentObjectWithInterface<Dali::Accessibility::AtspiInterface::TEXT>();
 }
 
 DBus::ValueOrError<std::string> BridgeText::GetText(int startOffset, int endOffset)
@@ -94,3 +88,9 @@ DBus::ValueOrError<bool> BridgeText::SetRangeOfSelection(int32_t selectionIndex,
 {
   return FindSelf()->SetRangeOfSelection(selectionIndex, startOffset, endOffset);
 }
+
+DBus::ValueOrError<int32_t, int32_t, int32_t, int32_t> BridgeText::GetRangeExtents(int32_t startOffset, int32_t endOffset, uint32_t coordType)
+{
+  auto rect = FindSelf()->GetRangeExtents(startOffset, endOffset, static_cast<CoordinateType>(coordType));
+  return {static_cast<int32_t>(rect.x), static_cast<int32_t>(rect.y), static_cast<int32_t>(rect.width), static_cast<int32_t>(rect.height)};
+}
index 737d318..cc50c3f 100644 (file)
@@ -82,6 +82,11 @@ public:
    * @copydoc Dali::Accessibility::Text::SetRangeOfSelection()
    */
   DBus::ValueOrError<bool> SetRangeOfSelection(int32_t selectionIndex, int32_t startOffset, int32_t endOffset);
+
+  /**
+   * @copydoc Dali::Accessibility::Text::GetRangeExtents()
+   */
+  DBus::ValueOrError<int32_t, int32_t, int32_t, int32_t> GetRangeExtents(int32_t startOffset, int32_t endOffset, uint32_t coordType);
 };
 
 #endif // DALI_INTERNAL_ACCESSIBILITY_BRIDGE_TEXT_H
index 7f81a32..8ac9007 100644 (file)
@@ -18,9 +18,6 @@
 // CLASS HEADER
 #include <dali/internal/accessibility/bridge/bridge-value.h>
 
-// EXTERNAL INCLUDES
-#include <iostream>
-
 using namespace Dali::Accessibility;
 
 BridgeValue::BridgeValue()
@@ -29,7 +26,7 @@ BridgeValue::BridgeValue()
 
 void BridgeValue::RegisterInterfaces()
 {
-  DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceValue};
+  DBus::DBusInterfaceDescription desc{Accessible::GetInterfaceName(AtspiInterface::VALUE)};
   AddGetSetPropertyToInterface(desc, "CurrentValue", &BridgeValue::GetCurrentValue, &BridgeValue::SetCurrentValue);
   AddGetPropertyToInterface(desc, "MaximumValue", &BridgeValue::GetMaximumValue);
   AddGetPropertyToInterface(desc, "MinimumIncrement", &BridgeValue::GetMinimumIncrement);
@@ -39,14 +36,7 @@ void BridgeValue::RegisterInterfaces()
 
 Value* BridgeValue::FindSelf() const
 {
-  auto self = BridgeBase::FindSelf();
-  assert(self);
-  auto valueInterface = dynamic_cast<Value*>(self);
-  if(!valueInterface)
-  {
-    throw std::domain_error{"object " + self->GetAddress().ToString() + " doesn't have Value interface"};
-  }
-  return valueInterface;
+  return FindCurrentObjectWithInterface<Dali::Accessibility::AtspiInterface::VALUE>();
 }
 
 double BridgeValue::GetCurrentValue()
index c37840d..3e6b302 100644 (file)
@@ -132,6 +132,10 @@ void Accessibility::Accessible::EmitMovedOutOfScreen(Accessibility::ScreenRelati
 {
 }
 
+void Accessibility::Accessible::EmitSocketAvailable()
+{
+}
+
 void Accessibility::Accessible::FindWordSeparationsUtf8(const utf8_t* string, size_t length, const char* language, char* breaks)
 {
 }
index 81b287d..911b9da 100644 (file)
@@ -63,6 +63,10 @@ struct DummyBridge : Dali::Accessibility::Bridge
   {
   }
 
+  void SetToolkitName(std::string_view toolkitName) override
+  {
+  }
+
   Accessibility::Accessible* GetApplication() const override
   {
     return nullptr;
@@ -122,6 +126,10 @@ struct DummyBridge : Dali::Accessibility::Bridge
   {
   }
 
+  void EmitSocketAvailable(Accessibility::Accessible* obj) override
+  {
+  }
+
   void EmitStateChanged(Accessibility::Accessible* obj, Accessibility::State state, int newValue, int reserved) override
   {
   }
@@ -172,6 +180,19 @@ struct DummyBridge : Dali::Accessibility::Bridge
   {
     return false;
   }
+
+  Address EmbedSocket(const Address& plug, const Address& socket) override
+  {
+    return {};
+  }
+
+  void EmbedAtkSocket(const Address& plug, const Address& socket) override
+  {
+  }
+
+  void UnembedSocket(const Address& plug, const Address& socket) override
+  {
+  }
 };
 
 } // namespace Dali::Accessibility
index 59ffcc2..14a6ba8 100755 (executable)
@@ -61,6 +61,7 @@ SET( adaptor_accessibility_atspi_bridge_src_files
     ${adaptor_accessibility_dir}/bridge/bridge-impl.cpp
     ${adaptor_accessibility_dir}/bridge/bridge-object.cpp
     ${adaptor_accessibility_dir}/bridge/bridge-selection.cpp
+    ${adaptor_accessibility_dir}/bridge/bridge-socket.cpp
     ${adaptor_accessibility_dir}/bridge/bridge-text.cpp
     ${adaptor_accessibility_dir}/bridge/bridge-value.cpp
     ${adaptor_accessibility_dir}/bridge/component.cpp
index d93886e..97a23e0 100644 (file)
@@ -21,6 +21,7 @@
 // EXTERNAL INCLUDES
 #include <dali/devel-api/common/singleton-service.h>
 #include <dali/integration-api/debug.h>
+#include <dali/integration-api/trace.h>
 #include <dali/public-api/object/object-registry.h>
 
 // INTERNAL INCLUDES
@@ -56,6 +57,8 @@ namespace Internal
 {
 namespace Adaptor
 {
+DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_APPLICATION, true);
+
 ApplicationPtr Application::gPreInitializedApplication(NULL);
 
 ApplicationPtr Application::New(
@@ -266,7 +269,9 @@ void Application::OnInit()
   }
 
   // Run the adaptor
+  DALI_TRACE_BEGIN(gTraceFilter, "DALI_APP_ADAPTOR_START");
   mAdaptor->Start();
+  DALI_TRACE_END(gTraceFilter, "DALI_APP_ADAPTOR_START");
   Accessibility::Accessible::SetObjectRegistry(mAdaptor->GetObjectRegistry());
 
   if(!mStylesheet.empty())
@@ -285,7 +290,10 @@ void Application::OnInit()
   LanguageChangedSignal().Connect(&GetImplementation(lifecycleController), &LifecycleController::OnLanguageChanged);
 
   Dali::Application application(this);
+
+  DALI_TRACE_BEGIN(gTraceFilter, "DALI_APP_EMIT_INIT_SIGNAL");
   mInitSignal.Emit(application);
+  DALI_TRACE_END(gTraceFilter, "DALI_APP_EMIT_INIT_SIGNAL");
 
   mAdaptor->NotifySceneCreated();
 }
index 2ebebb6..8a2a150 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_COMBINED_UPDATE_RENDER_CONTROLLER_DEBUG_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@
 
 // EXTERNAL INCLUDES
 #include <dali/integration-api/debug.h>
+#include <dali/integration-api/trace.h>
 
 namespace Dali
 {
@@ -132,6 +133,10 @@ Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_THR
 #define LOG_EVENT_TRACE_FMT(format, ...)
 #endif
 
+DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_COMBINED, false);
+#define TRACE_UPDATE_RENDER_BEGIN(tag) DALI_TRACE_BEGIN(gTraceFilter, tag)
+#define TRACE_UPDATE_RENDER_END(tag) DALI_TRACE_END(gTraceFilter, tag)
+
 } // unnamed namespace
 
 } // namespace Adaptor
index 356cec0..350ab2a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -544,6 +544,10 @@ void CombinedUpdateRenderController::UpdateRenderThread()
   {
     LOG_UPDATE_RENDER_TRACE;
 
+    // For thread safe
+    bool         uploadOnly     = mUploadWithoutRendering;
+    unsigned int surfaceResized = mSurfaceResized;
+
     // Performance statistics are logged upon a VSYNC tick so use this point for a VSync marker
     AddPerformanceMarker(PerformanceInterface::VSYNC);
 
@@ -616,12 +620,15 @@ void CombinedUpdateRenderController::UpdateRenderThread()
     Integration::UpdateStatus updateStatus;
 
     AddPerformanceMarker(PerformanceInterface::UPDATE_START);
+    TRACE_UPDATE_RENDER_BEGIN("DALI_UPDATE");
     mCore.Update(frameDelta,
                  currentTime,
                  nextFrameTime,
                  updateStatus,
                  renderToFboEnabled,
-                 isRenderingToFbo);
+                 isRenderingToFbo,
+                 uploadOnly);
+    TRACE_UPDATE_RENDER_END("DALI_UPDATE");
     AddPerformanceMarker(PerformanceInterface::UPDATE_END);
 
     unsigned int keepUpdatingStatus = updateStatus.KeepUpdating();
@@ -665,11 +672,12 @@ void CombinedUpdateRenderController::UpdateRenderThread()
     Integration::RenderStatus renderStatus;
 
     AddPerformanceMarker(PerformanceInterface::RENDER_START);
+    TRACE_UPDATE_RENDER_BEGIN("DALI_RENDER");
 
     // Upload shared resources
-    mCore.PreRender(renderStatus, mForceClear, mUploadWithoutRendering);
+    mCore.PreRender(renderStatus, mForceClear);
 
-    if(!mUploadWithoutRendering)
+    if(!uploadOnly || surfaceResized)
     {
       // Go through each window
       WindowContainer windows;
@@ -718,12 +726,12 @@ void CombinedUpdateRenderController::UpdateRenderThread()
       }
     }
 
-    if(!mUploadWithoutRendering)
+    if(!uploadOnly)
     {
       graphics.PostRender();
     }
 
-    mCore.PostRender(mUploadWithoutRendering);
+    mCore.PostRender();
 
     //////////////////////////////
     // DELETE SURFACE
@@ -739,6 +747,7 @@ void CombinedUpdateRenderController::UpdateRenderThread()
       SurfaceDeleted();
     }
 
+    TRACE_UPDATE_RENDER_END("DALI_RENDER");
     AddPerformanceMarker(PerformanceInterface::RENDER_END);
 
     mForceClear = false;
index 25a1b58..7db93c7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 // EXTERNAL INCLUDES
 #include <app_common.h>
 #include <app_control_internal.h>
-#include <appcore_ui_base.h>
 #include <bundle.h>
-#include <dali/internal/system/linux/dali-ecore.h>
-
 #include <bundle_internal.h>
 #include <system_info.h>
 #include <system_settings.h>
 #include <widget_base.h>
+#include <app_core_ui_base.hh>
+#include <app_event_internal.hh>
 // CONDITIONAL INCLUDES
 #ifdef APPCORE_WATCH_AVAILABLE
 #include <appcore-watch/watch_app.h>
 #endif
 
 #include <dali/integration-api/debug.h>
+#include <dali/integration-api/trace.h>
 
 // INTERNAL INCLUDES
 #include <dali/internal/system/common/callback-manager.h>
+#include <dali/internal/system/linux/dali-ecore.h>
+
+using namespace tizen_cpp;
 
 namespace Dali
 {
@@ -61,6 +64,7 @@ namespace
 #if defined(DEBUG_ENABLED)
 Integration::Log::Filter* gDBusLogging = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_ADAPTOR_EVENTS_DBUS");
 #endif
+DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_FRAMEWORK, true);
 
 bool IsWidgetFeatureEnabled()
 {
@@ -167,6 +171,44 @@ int AppAddEventHandler(AppEventHandlerPtr* eventHandler, AppEventType eventType,
   }
 }
 
+DeviceStatus::Memory::Status GetMemoryStatus(app_event_low_memory_status_e memoryStatus)
+{
+  switch(memoryStatus)
+  {
+    case APP_EVENT_LOW_MEMORY_SOFT_WARNING: // 0x02
+    {
+      return Dali::DeviceStatus::Memory::Status::LOW;
+    }
+    case APP_EVENT_LOW_MEMORY_HARD_WARNING: // 0x04
+    {
+      return Dali::DeviceStatus::Memory::Status::CRITICALLY_LOW;
+    }
+    default: // APP_EVENT_LOW_MEMORY_NORMAL 0x01
+    {
+      return Dali::DeviceStatus::Memory::Status::NORMAL;
+    }
+  }
+}
+
+DeviceStatus::Battery::Status GetBatteryStatus(app_event_low_battery_status_e batteryStatus)
+{
+  switch(batteryStatus)
+  {
+    case APP_EVENT_LOW_BATTERY_POWER_OFF: // 1
+    {
+      return Dali::DeviceStatus::Battery::Status::POWER_OFF;
+    }
+    case APP_EVENT_LOW_BATTERY_CRITICAL_LOW: // 2
+    {
+      return Dali::DeviceStatus::Battery::Status::CRITICALLY_LOW;
+    }
+    default:
+    {
+      return Dali::DeviceStatus::Battery::Status::NORMAL;
+    }
+  }
+}
+
 } // namespace AppCore
 
 /**
@@ -174,6 +216,243 @@ int AppAddEventHandler(AppEventHandlerPtr* eventHandler, AppEventType eventType,
  */
 struct Framework::Impl
 {
+  class UiAppContext : public AppCoreUiBase
+  {
+  public:
+    explicit UiAppContext(unsigned int hint, Framework* framework)
+    : AppCoreUiBase(hint),
+      mFramework(framework)
+    {
+      mLanguageChanged = std::make_shared<AppEvent>(IAppCore::IEvent::Type::LANG_CHANGE, OnLanguageChanged, this);
+      AddEvent(mLanguageChanged);
+
+      mDeviceOrientationChanged = std::make_shared<AppEvent>(IAppCore::IEvent::Type::DEVICE_ORIENTATION_CHANGED, OnDeviceOrientationChanged, this);
+      AddEvent(mDeviceOrientationChanged);
+
+      mRegionFormatChanged = std::make_shared<AppEvent>(IAppCore::IEvent::Type::REGION_CHANGE, OnRegionFormatChanged, this);
+      AddEvent(mRegionFormatChanged);
+
+      mLowMemory = std::make_shared<AppEvent>(IAppCore::IEvent::Type::LOW_MEMORY, OnLowMemory, this);
+      AddEvent(mLowMemory);
+
+      mLowBattery = std::make_shared<AppEvent>(IAppCore::IEvent::Type::LOW_BATTERY, OnLowBattery, this);
+      AddEvent(mLowBattery);
+    }
+
+    virtual ~UiAppContext()
+    {
+      RemoveEvent(mLowBattery);
+      RemoveEvent(mLowMemory);
+      RemoveEvent(mRegionFormatChanged);
+      RemoveEvent(mDeviceOrientationChanged);
+      RemoveEvent(mLanguageChanged);
+    }
+
+    int OnCreate() override
+    {
+      AppCoreUiBase::OnCreate();
+      mFramework->Create();
+      return 0;
+    }
+
+    int OnTerminate() override
+    {
+      AppCoreUiBase::OnTerminate();
+      auto* observer = &mFramework->mObserver;
+      observer->OnTerminate();
+      return 0;
+    }
+
+    int OnPause() override
+    {
+      AppCoreUiBase::OnPause();
+      auto* observer = &mFramework->mObserver;
+      observer->OnPause();
+      return 0;
+    }
+
+    int OnResume() override
+    {
+      AppCoreUiBase::OnResume();
+      auto* observer = &mFramework->mObserver;
+      observer->OnResume();
+      return 0;
+    }
+
+    int OnControl(tizen_base::Bundle b) override
+    {
+      AppCoreUiBase::OnControl(b);
+
+      app_control_h appControl = nullptr;
+
+      auto* bundleData = b.GetHandle();
+      if(bundleData)
+      {
+        if(app_control_create_event(bundleData, &appControl) != TIZEN_ERROR_NONE)
+        {
+          DALI_LOG_ERROR("Failed to create an app_control handle");
+          return 0;
+        }
+      }
+      else
+      {
+        if(app_control_create(&appControl) != TIZEN_ERROR_NONE)
+        {
+          DALI_LOG_ERROR("Failed to create an app_control handle");
+          return 0;
+        }
+      }
+
+      auto* observer = &mFramework->mObserver;
+      ProcessBundle(mFramework, bundleData);
+      observer->OnReset();
+      observer->OnAppControl(appControl);
+      app_control_destroy(appControl);
+      return 0;
+    }
+
+    void OnLoopInit(int argc, char** argv) override
+    {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+      ecore_init();
+      ecore_app_args_set(argc, (const char**)argv);
+#pragma GCC diagnostic pop
+
+#ifdef DALI_ELDBUS_AVAILABLE
+      // Initialize ElDBus.
+      DALI_LOG_INFO(gDBusLogging, Debug::General, "Starting DBus Initialization\n");
+      eldbus_init();
+#endif
+    }
+
+    void OnLoopFinish() override
+    {
+      ecore_shutdown();
+
+      if(getenv("AUL_LOADER_INIT"))
+      {
+        setenv("AUL_LOADER_INIT", "0", 1);
+        ecore_shutdown();
+      }
+
+#ifdef DALI_ELDBUS_AVAILABLE
+      // Shutdown ELDBus.
+      DALI_LOG_INFO(gDBusLogging, Debug::General, "Shutting down DBus\n");
+      eldbus_shutdown();
+#endif
+    }
+
+    void OnLoopRun() override
+    {
+      ecore_main_loop_begin();
+    }
+
+    void OnLoopExit() override
+    {
+      ecore_main_loop_quit();
+    }
+
+  private:
+    static void OnLanguageChanged(app_event_info_h event_info, void* user_data)
+    {
+      auto*     context   = static_cast<UiAppContext*>(user_data);
+      auto*     framework = context->mFramework;
+      Observer* observer  = &framework->mObserver;
+
+      char* lang = nullptr;
+      app_event_get_language(event_info, &lang);
+      if(lang)
+      {
+        framework->SetLanguage(std::string(lang));
+        observer->OnLanguageChanged();
+        free(lang);
+      }
+      else
+      {
+        DALI_LOG_ERROR("NULL pointer in Language changed event\n");
+      }
+    }
+
+    static void OnDeviceOrientationChanged(app_event_info_h event_info, void* user_data)
+    {
+    }
+
+    static void OnRegionFormatChanged(app_event_info_h event_info, void* user_data)
+    {
+      auto*     context   = static_cast<UiAppContext*>(user_data);
+      auto*     framework = context->mFramework;
+      Observer* observer  = &framework->mObserver;
+
+      char* region = nullptr;
+      app_event_get_region_format(event_info, &region);
+      if(region)
+      {
+        framework->SetRegion(std::string(region));
+        observer->OnRegionChanged();
+        free(region);
+      }
+      else
+      {
+        DALI_LOG_ERROR("NULL pointer in Region changed event\n");
+      }
+    }
+
+    static void OnLowBattery(app_event_info_h event_info, void* user_data)
+    {
+      auto*     context   = static_cast<UiAppContext*>(user_data);
+      auto*     framework = context->mFramework;
+      Observer* observer  = &framework->mObserver;
+
+      app_event_low_battery_status_e status;
+      app_event_get_low_battery_status(event_info, &status);
+      Dali::DeviceStatus::Battery::Status result = AppCore::GetBatteryStatus(status);
+      observer->OnBatteryLow(result);
+    }
+
+    static void OnLowMemory(app_event_info_h event_info, void* user_data)
+    {
+      auto*     context   = static_cast<UiAppContext*>(user_data);
+      auto*     framework = context->mFramework;
+      Observer* observer  = &framework->mObserver;
+
+      app_event_low_memory_status_e status;
+      app_event_get_low_memory_status(event_info, &status);
+      Dali::DeviceStatus::Memory::Status result = AppCore::GetMemoryStatus(status);
+      observer->OnMemoryLow(result);
+    }
+
+    void ProcessBundle(Framework* framework, bundle* bundleData)
+    {
+      if(bundleData == nullptr)
+      {
+        return;
+      }
+
+      // get bundle name
+      char* bundleName = const_cast<char*>(bundle_get_val(bundleData, "name"));
+      if(bundleName != nullptr)
+      {
+        framework->SetBundleName(bundleName);
+      }
+
+      // get bundle? id
+      char* bundleId = const_cast<char*>(bundle_get_val(bundleData, "id"));
+      if(bundleId != nullptr)
+      {
+        framework->SetBundleId(bundleId);
+      }
+    }
+
+  private:
+    Framework*                mFramework;
+    std::shared_ptr<AppEvent> mLanguageChanged;
+    std::shared_ptr<AppEvent> mDeviceOrientationChanged;
+    std::shared_ptr<AppEvent> mRegionFormatChanged;
+    std::shared_ptr<AppEvent> mLowBattery;
+    std::shared_ptr<AppEvent> mLowMemory;
+  };
+
   // Constructor
   Impl(void* data, Type type)
   : mAbortCallBack(NULL),
@@ -193,23 +472,6 @@ struct Framework::Impl
 #endif
     mApplicationType = type;
     mCallbackManager = CallbackManager::New();
-
-    char* region   = nullptr;
-    char* language = nullptr;
-    system_settings_get_value_string(SYSTEM_SETTINGS_KEY_LOCALE_COUNTRY, &region);
-    system_settings_get_value_string(SYSTEM_SETTINGS_KEY_LOCALE_LANGUAGE, &language);
-
-    if(region != nullptr)
-    {
-      mRegion = std::string(region);
-      free(region);
-    }
-
-    if(language != nullptr)
-    {
-      mLanguage = std::string(language);
-      free(language);
-    }
   }
 
   ~Impl()
@@ -224,6 +486,7 @@ struct Framework::Impl
 
   int AppMain()
   {
+    // TODO: The app-core-cpp has to be applied to the other app types.
     int ret;
     switch(mApplicationType)
     {
@@ -292,13 +555,35 @@ struct Framework::Impl
     mRegion = region;
   }
 
-  std::string GetLanguage() const
+  std::string GetLanguage()
   {
+    if(mLanguage.empty())
+    {
+      char* language = nullptr;
+      system_settings_get_value_string(SYSTEM_SETTINGS_KEY_LOCALE_LANGUAGE, &language);
+
+      if(language != nullptr)
+      {
+        mLanguage = std::string(language);
+        free(language);
+      }
+    }
     return mLanguage;
   }
 
-  std::string GetRegion() const
+  std::string GetRegion()
   {
+    if(mRegion.empty())
+    {
+      char* region = nullptr;
+      system_settings_get_value_string(SYSTEM_SETTINGS_KEY_LOCALE_COUNTRY, &region);
+
+      if(region != nullptr)
+      {
+        mRegion = std::string(region);
+        free(region);
+      }
+    }
     return mRegion;
   }
 
@@ -306,52 +591,17 @@ struct Framework::Impl
   Type             mApplicationType;
   CallbackBase*    mAbortCallBack;
   CallbackManager* mCallbackManager;
-  std::string      mLanguage;
-  std::string      mRegion;
+  std::string      mLanguage{};
+  std::string      mRegion{};
 
-  Framework*                  mFramework;
-  AppCore::AppEventHandlerPtr handlers[5];
+  Framework*                    mFramework;
+  AppCore::AppEventHandlerPtr   handlers[5];
+  std::unique_ptr<UiAppContext> mUiAppContext;
 #ifdef APPCORE_WATCH_AVAILABLE
   watch_app_lifecycle_callback_s mWatchCallback;
   app_event_handler_h            watchHandlers[5];
 #endif
 
-  static int AppCreate(void* data)
-  {
-    appcore_ui_base_on_create();
-    return static_cast<int>(static_cast<Framework*>(data)->Create());
-  }
-
-  static int AppTerminate(void* data)
-  {
-    appcore_ui_base_on_terminate();
-    Observer* observer = &static_cast<Framework*>(data)->mObserver;
-
-    observer->OnTerminate();
-
-    return 0;
-  }
-
-  static int AppPause(void* data)
-  {
-    appcore_ui_base_on_pause();
-    Observer* observer = &static_cast<Framework*>(data)->mObserver;
-
-    observer->OnPause();
-
-    return 0;
-  }
-
-  static int AppResume(void* data)
-  {
-    appcore_ui_base_on_resume();
-    Observer* observer = &static_cast<Framework*>(data)->mObserver;
-
-    observer->OnResume();
-
-    return 0;
-  }
-
   static void ProcessBundle(Framework* framework, bundle* bundleData)
   {
     if(bundleData == NULL)
@@ -374,53 +624,19 @@ struct Framework::Impl
     }
   }
 
-  /**
-   * Called by AppCore when the application is launched from another module (e.g. homescreen).
-   * @param[in] b the bundle data which the launcher module sent
-   */
-  static int AppControl(bundle* bundleData, void* data)
-  {
-    app_control_h appControl = NULL;
-
-    appcore_ui_base_on_control(bundleData);
-
-    if(bundleData)
-    {
-      if(app_control_create_event(bundleData, &appControl) != TIZEN_ERROR_NONE)
-      {
-        DALI_LOG_ERROR("Failed to create an app_control handle");
-      }
-    }
-    else
-    {
-      if(app_control_create(&appControl) != TIZEN_ERROR_NONE)
-      {
-        DALI_LOG_ERROR("Failed to create an app_control handle");
-      }
-    }
-
-    Framework* framework = static_cast<Framework*>(data);
-    Observer*  observer  = &framework->mObserver;
-
-    ProcessBundle(framework, bundleData);
-
-    observer->OnReset();
-    observer->OnAppControl(appControl);
-
-    app_control_destroy(appControl);
-
-    return 0;
-  }
-
   static void AppInit(int argc, char** argv, void* data)
   {
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wold-style-cast"
-
     ecore_init();
     ecore_app_args_set(argc, (const char**)argv);
-
 #pragma GCC diagnostic pop
+
+#ifdef DALI_ELDBUS_AVAILABLE
+    // Initialize ElDBus.
+    DALI_LOG_INFO(gDBusLogging, Debug::General, "Starting DBus Initialization\n");
+    eldbus_init();
+#endif
   }
 
   static void AppFinish(void)
@@ -432,6 +648,12 @@ struct Framework::Impl
       setenv("AUL_LOADER_INIT", "0", 1);
       ecore_shutdown();
     }
+
+#ifdef DALI_ELDBUS_AVAILABLE
+    // Shutdown ELDBus.
+    DALI_LOG_INFO(gDBusLogging, Debug::General, "Shutting down DBus\n");
+    eldbus_shutdown();
+#endif
   }
 
   static void AppRun(void* data)
@@ -537,40 +759,29 @@ struct Framework::Impl
 
   int AppNormalMain()
   {
-    int ret;
-
-    AppCore::AppAddEventHandler(&handlers[AppCore::LOW_BATTERY], AppCore::LOW_BATTERY, AppBatteryLow, mFramework);
-    AppCore::AppAddEventHandler(&handlers[AppCore::LOW_MEMORY], AppCore::LOW_MEMORY, AppMemoryLow, mFramework);
-    AppCore::AppAddEventHandler(&handlers[AppCore::DEVICE_ORIENTATION_CHANGED], AppCore::DEVICE_ORIENTATION_CHANGED, AppDeviceRotated, mFramework);
-    AppCore::AppAddEventHandler(&handlers[AppCore::LANGUAGE_CHANGED], AppCore::LANGUAGE_CHANGED, AppLanguageChanged, mFramework);
-    AppCore::AppAddEventHandler(&handlers[AppCore::REGION_FORMAT_CHANGED], AppCore::REGION_FORMAT_CHANGED, AppRegionChanged, mFramework);
-
-    appcore_ui_base_ops ops = appcore_ui_base_get_default_ops();
-
-    /* override methods */
-    ops.base.create    = AppCreate;
-    ops.base.control   = AppControl;
-    ops.base.terminate = AppTerminate;
-    ops.pause          = AppPause;
-    ops.resume         = AppResume;
-    ops.base.init      = AppInit;
-    ops.base.finish    = AppFinish;
-    ops.base.run       = AppRun;
-    ops.base.exit      = AppExit;
-
-    ret = appcore_ui_base_init(ops, *mFramework->mArgc, *mFramework->mArgv, mFramework, APPCORE_UI_BASE_HINT_WINDOW_GROUP_CONTROL | APPCORE_UI_BASE_HINT_WINDOW_STACK_CONTROL | APPCORE_UI_BASE_HINT_BG_LAUNCH_CONTROL | APPCORE_UI_BASE_HINT_HW_ACC_CONTROL | APPCORE_UI_BASE_HINT_WINDOW_AUTO_CONTROL);
-
-    if(ret != TIZEN_ERROR_NONE)
-      return ret;
+    if(mUiAppContext.get() == nullptr)
+    {
+      unsigned int hint = AppCoreUiBase::HINT_WINDOW_GROUP_CONTROL |
+                          AppCoreUiBase::HINT_WINDOW_STACK_CONTROL |
+                          AppCoreUiBase::HINT_BG_LAUNCH_CONTROL |
+                          AppCoreUiBase::HINT_HW_ACC_CONTROL |
+                          AppCoreUiBase::HINT_WINDOW_AUTO_CONTROL;
 
-    appcore_ui_base_fini();
+      mUiAppContext = std::make_unique<UiAppContext>(hint, mFramework);
+    }
 
+    mUiAppContext->Run(*mFramework->mArgc, *mFramework->mArgv);
     return TIZEN_ERROR_NONE;
   }
 
   void AppNormalExit()
   {
-    appcore_ui_base_exit();
+    if(mUiAppContext.get() == nullptr)
+    {
+      return;
+    }
+
+    mUiAppContext->Exit();
   }
 
   void AppWidgetExit()
@@ -796,11 +1007,7 @@ Framework::Framework(Framework::Observer& observer, int* argc, char*** argv, Typ
   {
     set_last_result(TIZEN_ERROR_NOT_SUPPORTED);
   }
-#ifdef DALI_ELDBUS_AVAILABLE
-  // Initialize ElDBus.
-  DALI_LOG_INFO(gDBusLogging, Debug::General, "Starting DBus Initialization\n");
-  eldbus_init();
-#endif
+
   InitThreads();
 
   mImpl = new Impl(this, type);
@@ -813,12 +1020,6 @@ Framework::~Framework()
     Quit();
   }
 
-#ifdef DALI_ELDBUS_AVAILABLE
-  // Shutdown ELDBus.
-  DALI_LOG_INFO(gDBusLogging, Debug::General, "Shutting down DBus\n");
-  eldbus_shutdown();
-#endif
-
   delete mImpl;
 }
 
@@ -834,7 +1035,9 @@ void Framework::Run()
   mRunning = true;
   int ret;
 
+  DALI_TRACE_BEGIN(gTraceFilter, "DALI_APPMAIN");
   ret = mImpl->AppMain();
+  DALI_TRACE_END(gTraceFilter, "DALI_APPMAIN");
   if(ret != APP_ERROR_NONE)
   {
     DALI_LOG_ERROR("Framework::Run(), ui_app_main() is failed. err = %d\n", ret);
@@ -897,7 +1100,7 @@ std::string Framework::GetResourcePath()
     resourcePath += "/";
   }
 
-#endif //TIZEN_PLATFORM_CONFIG_SUPPORTED
+#endif // TIZEN_PLATFORM_CONFIG_SUPPORTED
 
   return resourcePath;
 }
index 6d96d4d..0a8c679 100644 (file)
@@ -50,7 +50,7 @@ public:
   /**
    * @copydoc Dali::DragAndDrop::StartDragAndDrop()
    */
-  virtual bool StartDragAndDrop(Dali::Actor source, Dali::Actor shadow, const std::string& dragData) = 0;
+  virtual bool StartDragAndDrop(Dali::Actor source, Dali::Window shadowWindow, const Dali::DragAndDrop::DragData& data, Dali::DragAndDrop::SourceFunction callback) = 0;
 
   /**
    * @copydoc Dali::DragAndDrop::AddListener()
@@ -58,6 +58,11 @@ public:
   virtual bool AddListener(Dali::Actor target, Dali::DragAndDrop::DragAndDropFunction callback) = 0;
 
   /**
+   * @copydoc Dali::DragAndDrop::RemoveListener()
+   */
+  virtual bool RemoveListener(Dali::Actor target) = 0;
+
+  /**
    * @copydoc Dali::DragAndDrop::SendData()
    */
   virtual void SendData(void* event) = 0;
index 42636bc..18abea7 100644 (file)
@@ -61,7 +61,7 @@ DragAndDropGeneric::~DragAndDropGeneric()
 {
 }
 
-bool DragAndDropGeneric::StartDragAndDrop(Dali::Actor source, Dali::Actor shadow, const std::string& dragData)
+bool DragAndDropGeneric::StartDragAndDrop(Dali::Actor source, Dali::Window shadowWindow, const Dali::DragAndDrop::DragData& dragData, Dali::DragAndDrop::SourceFunction callback)
 {
   return true;
 }
@@ -71,6 +71,11 @@ bool DragAndDropGeneric::AddListener(Dali::Actor target, Dali::DragAndDrop::Drag
   return true;
 }
 
+bool DragAndDropGeneric::RemoveListener(Dali::Actor target)
+{
+  return true;
+}
+
 void DragAndDropGeneric::SendData(void* event)
 {
   return;
index c727c21..434f234 100644 (file)
@@ -49,7 +49,7 @@ public:
   /**
    * @copydoc Dali::DragAndDrop::StartDragAndDrop()
    */
-  bool StartDragAndDrop(Dali::Actor source, Dali::Actor shadow, const std::string& dragData) override;
+  bool StartDragAndDrop(Dali::Actor source, Dali::Window shadowWindow, const Dali::DragAndDrop::DragData& data, Dali::DragAndDrop::SourceFunction callback) override;
 
   /**
    * @copydoc Dali::DragAndDrop::AddListener()
@@ -57,6 +57,11 @@ public:
   bool AddListener(Dali::Actor target, Dali::DragAndDrop::DragAndDropFunction callback) override;
 
   /**
+   * @copydoc Dali::DragAndDrop::RemoveListener()
+   */
+  bool RemoveListener(Dali::Actor target) override;
+
+  /**
    * @copydoc Dali::DragAndDrop::SendData()
    */
   void SendData(void* event) override;
index 7d7166a..b6654e6 100644 (file)
@@ -51,6 +51,29 @@ static Eina_Bool EcoreEventDataSend(void* data, int type, void* event)
   return ECORE_CALLBACK_PASS_ON;
 }
 
+static Eina_Bool EcoreEventDataSourceEnd(void* data, int type, void* event)
+{
+  Ecore_Wl2_Event_Data_Source_End *ev = reinterpret_cast<Ecore_Wl2_Event_Data_Source_End*>(event);
+  DragAndDropEcoreWl* dndImpl = reinterpret_cast<DragAndDropEcoreWl*>(data);
+  if(ev->cancelled)
+  {
+    dndImpl->CallSourceEvent(Dali::DragAndDrop::SourceEventType::CANCEL);
+  }
+  else
+  {
+    dndImpl->CallSourceEvent(Dali::DragAndDrop::SourceEventType::ACCEPT);
+  }
+
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool EcoreEventDataSourceDrop(void* data, int type, void* event)
+{
+  DragAndDropEcoreWl* dndImpl = reinterpret_cast<DragAndDropEcoreWl*>(data);
+  dndImpl->CallSourceEvent(Dali::DragAndDrop::SourceEventType::FINISH);
+  return ECORE_CALLBACK_PASS_ON;
+}
+
 static Eina_Bool EcoreEventOfferDataReady(void* data, int type, void* event)
 {
   DragAndDropEcoreWl* dndImpl = reinterpret_cast<DragAndDropEcoreWl*>(data);
@@ -75,6 +98,23 @@ static Eina_Bool EcoreEventDataDrop(void* data, int type, void* event)
   return ECORE_CALLBACK_PASS_ON;
 }
 
+static Eina_Bool EcoreEventDataEnter(void* data, int type, void* event)
+{
+  Ecore_Wl2_Event_Dnd_Enter* ev = reinterpret_cast<Ecore_Wl2_Event_Dnd_Enter*>(event);
+
+  // Set default offer is reject
+  ecore_wl2_offer_accept(ev->offer, NULL);
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool EcoreEventDataLeave(void* data, int type, void* event)
+{
+  DragAndDropEcoreWl* dndImpl = reinterpret_cast<DragAndDropEcoreWl*>(data);
+  dndImpl->ResetDropTargets();
+
+  return ECORE_CALLBACK_PASS_ON;
+}
+
 Dali::DragAndDrop GetDragAndDrop()
 {
   Dali::DragAndDrop dnd;
@@ -104,44 +144,47 @@ Dali::DragAndDrop GetDragAndDrop()
 
 DragAndDropEcoreWl::DragAndDropEcoreWl()
 {
-  mSendHandler    = ecore_event_handler_add(ECORE_WL2_EVENT_DATA_SOURCE_SEND, EcoreEventDataSend, this);
-  mReceiveHandler = ecore_event_handler_add(ECORE_WL2_EVENT_OFFER_DATA_READY, EcoreEventOfferDataReady, this);
-  mMotionHandler  = ecore_event_handler_add(ECORE_WL2_EVENT_DND_MOTION, EcoreEventDataMotion, this);
-  mDropHandler    = ecore_event_handler_add(ECORE_WL2_EVENT_DND_DROP, EcoreEventDataDrop, this);
+  // Source Events
+  mSendHandler       = ecore_event_handler_add(ECORE_WL2_EVENT_DATA_SOURCE_SEND, EcoreEventDataSend, this);
+  mSourceEndHandler  = ecore_event_handler_add(ECORE_WL2_EVENT_DATA_SOURCE_END, EcoreEventDataSourceEnd, this);
+  mSourceDropHandler = ecore_event_handler_add(ECORE_WL2_EVENT_DATA_SOURCE_DROP, EcoreEventDataSourceDrop, this);
+
+  // Target Events
+  mReceiveHandler    = ecore_event_handler_add(ECORE_WL2_EVENT_OFFER_DATA_READY, EcoreEventOfferDataReady, this);
+  mMotionHandler     = ecore_event_handler_add(ECORE_WL2_EVENT_DND_MOTION, EcoreEventDataMotion, this);
+  mDropHandler       = ecore_event_handler_add(ECORE_WL2_EVENT_DND_DROP, EcoreEventDataDrop, this);
+  mEnterHandler      = ecore_event_handler_add(ECORE_WL2_EVENT_DND_ENTER, EcoreEventDataEnter, this);
+  mLeaveHandler      = ecore_event_handler_add(ECORE_WL2_EVENT_DND_LEAVE, EcoreEventDataLeave, this);
 }
 
 DragAndDropEcoreWl::~DragAndDropEcoreWl()
 {
+  // Source Events
   ecore_event_handler_del(mSendHandler);
+  ecore_event_handler_del(mSourceEndHandler);
+  ecore_event_handler_del(mSourceDropHandler);
+
+  // Target Events
   ecore_event_handler_del(mReceiveHandler);
   ecore_event_handler_del(mMotionHandler);
   ecore_event_handler_del(mDropHandler);
+  ecore_event_handler_del(mEnterHandler);
 }
 
-void DragAndDropEcoreWl::SetData(std::string data)
-{
-  // Save Data
-  mData = data;
-}
-
-bool DragAndDropEcoreWl::StartDragAndDrop(Dali::Actor source, Dali::Actor shadow, const std::string& dragData)
+bool DragAndDropEcoreWl::StartDragAndDrop(Dali::Actor source, Dali::Window shadowWindow, const Dali::DragAndDrop::DragData& data, Dali::DragAndDrop::SourceFunction callback)
 {
   // Get Parent Window
   auto parent = Dali::DevelWindow::Get(source);
 
   // Set Drag Source Data
-  SetData(dragData);
+  mMimeType = data.GetMimeType();
+  mData     = data.GetData();
 
-  // Apply Shadow Property
-  shadow.SetProperty(Dali::Actor::Property::SIZE, Vector2(150, 150));
-  shadow.SetProperty(Dali::Actor::Property::OPACITY, 0.9f);
+  // Set Source Event
+  mSourceCallback = callback;
 
-  // Create Drag Window
-  mDragWindow = Dali::Window::New(Dali::PositionSize(0, 0, 150, 150), "DragWindow", "class", true);
-  mDragWindow.SetTransparency(true);
-  mDragWindow.SetSize(Dali::Window::WindowSize(150, 150));
-  mDragWindow.SetBackgroundColor(Color::TRANSPARENT);
-  mDragWindow.Add(shadow);
+  // Set Drag Window
+  mDragWindow = shadowWindow;
 
   // Start Drag and Drop
   Ecore_Wl2_Window*  parentWindow = AnyCast<Ecore_Wl2_Window*>(parent.GetNativeHandle());
@@ -149,21 +192,37 @@ bool DragAndDropEcoreWl::StartDragAndDrop(Dali::Actor source, Dali::Actor shadow
   Ecore_Wl2_Display* display      = ecore_wl2_connected_display_get(NULL);
   Ecore_Wl2_Input*   input        = ecore_wl2_input_default_input_get(display);
 
-  // TODO: Makes mime-type common
-  char* mimeTypes[2] = {"text/plain"};
-  mimeTypes[1]       = NULL;
+  // Disable Default Cursor
+  ecore_wl2_input_pointer_set(input, NULL, 0, 0);
+
+  // Set mime type for drag and drop
+  const char* mimeTypes[2];
+  mimeTypes[0] = mMimeType.c_str();
+  mimeTypes[1] = NULL;
 
-  // Set mimetype
+  // Set mime type
   ecore_wl2_dnd_drag_types_set(input, (const char**)mimeTypes);
 
   // Start wayland drag and drop
   mSerial = ecore_wl2_dnd_drag_start(input, parentWindow, dragWindow);
 
+  // Call Start Event
+  CallSourceEvent(Dali::DragAndDrop::SourceEventType::START);
+
   return true;
 }
 
 bool DragAndDropEcoreWl::AddListener(Dali::Actor target, Dali::DragAndDrop::DragAndDropFunction callback)
 {
+  std::vector<DropTarget>::iterator itr;
+  for(itr = mDropTargets.begin(); itr < mDropTargets.end(); itr++)
+  {
+    if((*itr).target == target)
+    {
+      return false;
+    }
+  }
+
   DropTarget targetData;
   targetData.target   = target;
   targetData.callback = callback;
@@ -174,6 +233,38 @@ bool DragAndDropEcoreWl::AddListener(Dali::Actor target, Dali::DragAndDrop::Drag
   return true;
 }
 
+bool DragAndDropEcoreWl::RemoveListener(Dali::Actor target)
+{
+  std::vector<DropTarget>::iterator itr;
+  for(itr = mDropTargets.begin(); itr < mDropTargets.end(); itr++)
+  {
+    if((*itr).target == target)
+    {
+      mDropTargets.erase(itr);
+      break;
+    }
+  }
+
+  return true;
+}
+
+void DragAndDropEcoreWl::CallSourceEvent(Dali::DragAndDrop::SourceEventType type)
+{
+  if(mSourceCallback)
+  {
+    mSourceCallback(type);
+  }
+}
+
+void DragAndDropEcoreWl::ResetDropTargets()
+{
+  for(std::size_t i = 0; i < mDropTargets.size(); i++)
+  {
+     mDropTargets[i].inside = false;
+  }
+}
+
+
 void DragAndDropEcoreWl::SendData(void* event)
 {
   Ecore_Wl2_Event_Data_Source_Send* ev = reinterpret_cast<Ecore_Wl2_Event_Data_Source_Send*>(event);
@@ -182,13 +273,30 @@ void DragAndDropEcoreWl::SendData(void* event)
     return;
   }
 
-  int   len = strlen(mData.c_str());
-  char* buf = new char[len + 1];
-  strncpy(buf, mData.c_str(), len);
-  buf[len] = '\0';
+  int dataLength = strlen(mData.c_str());
+  int bufferSize = dataLength;
+  if((mMimeType.find("text") != std::string::npos) ||
+     (mMimeType.find("markup") != std::string::npos) ||
+     (mMimeType.find("image") != std::string::npos))
+  {
+    bufferSize += 1;
+  }
+
+  char* buffer = new char[bufferSize];
+  if(!buffer)
+  {
+    return;
+  }
+
+  memcpy(buffer, mData.c_str(), dataLength);
+  buffer[dataLength] = '\0';
+
+  auto ret = write(ev->fd, buffer, bufferSize);
+  if(DALI_UNLIKELY(ret != bufferSize))
+  {
+    DALI_LOG_ERROR("write(ev->fd) return %d! Pleacse check it\n", static_cast<int>(ret));
+  }
 
-  // Write source object data to target object
-  write(ev->fd, buf, len + 1);
   close(ev->fd);
 
   if(mDragWindow)
@@ -196,10 +304,7 @@ void DragAndDropEcoreWl::SendData(void* event)
     mDragWindow.Hide();
   }
 
-  if(buf)
-  {
-    delete[] buf;
-  }
+  delete[] buffer;
 }
 
 void DragAndDropEcoreWl::ReceiveData(void* event)
@@ -208,9 +313,10 @@ void DragAndDropEcoreWl::ReceiveData(void* event)
 
   if(mTargetIndex != -1)
   {
-    Dali::DragAndDrop::DragEvent dragEvent(Dali::DragAndDrop::DragType::DROP, mPosition, ev->data);
+    Dali::DragAndDrop::DragEvent dragEvent(Dali::DragAndDrop::DragType::DROP, mPosition, ev->mimetype, ev->data);
     mDropTargets[mTargetIndex].callback(dragEvent);
     mDropTargets[mTargetIndex].inside = false;
+    ecore_wl2_offer_finish(ev->offer);
   }
   mTargetIndex = -1;
 }
@@ -222,7 +328,7 @@ bool DragAndDropEcoreWl::CalculateDragEvent(void* event)
   Dali::DragAndDrop::DragEvent dragEvent;
   Dali::Vector2                curPosition(ev->x, ev->y);
 
-  for(int i = 0; i < mDropTargets.size(); i++)
+  for(std::size_t i = 0; i < mDropTargets.size(); i++)
   {
     Vector2 position      = mDropTargets[i].target.GetProperty<Vector2>(Dali::Actor::Property::POSITION);
     Vector2 size          = mDropTargets[i].target.GetProperty<Vector2>(Dali::Actor::Property::SIZE);
@@ -236,6 +342,8 @@ bool DragAndDropEcoreWl::CalculateDragEvent(void* event)
       dragEvent.SetAction(Dali::DragAndDrop::DragType::ENTER);
       dragEvent.SetPosition(curPosition);
       mDropTargets[i].callback(dragEvent);
+      // Accept Offer
+      ecore_wl2_offer_mimes_set(ev->offer, ecore_wl2_offer_mimes_get(ev->offer));
     }
     else if(!currentInside && mDropTargets[i].inside)
     {
@@ -244,6 +352,8 @@ bool DragAndDropEcoreWl::CalculateDragEvent(void* event)
       dragEvent.SetAction(Dali::DragAndDrop::DragType::LEAVE);
       dragEvent.SetPosition(curPosition);
       mDropTargets[i].callback(dragEvent);
+      // Reject Offer
+      ecore_wl2_offer_accept(ev->offer, NULL);
     }
     else if(currentInside && mDropTargets[i].inside)
     {
@@ -264,7 +374,7 @@ bool DragAndDropEcoreWl::CalculateViewRegion(void* event)
   // Check the target object region
   mTargetIndex = -1;
 
-  for(int i = 0; i < mDropTargets.size(); i++)
+  for(std::size_t i = 0; i < mDropTargets.size(); i++)
   {
     Vector2 position = mDropTargets[i].target.GetProperty<Vector2>(Dali::Actor::Property::POSITION);
     Vector2 size     = mDropTargets[i].target.GetProperty<Vector2>(Dali::Actor::Property::SIZE);
@@ -278,7 +388,6 @@ bool DragAndDropEcoreWl::CalculateViewRegion(void* event)
       char* mimetype = (char*)eina_array_data_get(ecore_wl2_offer_mimes_get(ev->offer), 0);
       if(mimetype)
       {
-        ecore_wl2_offer_accept(ev->offer, mimetype);
         ecore_wl2_offer_receive(ev->offer, mimetype);
         Ecore_Wl2_Display* display = ecore_wl2_connected_display_get(NULL);
         Ecore_Wl2_Input*   input   = ecore_wl2_input_default_input_get(display);
index 5cd056b..162c3d0 100644 (file)
@@ -56,7 +56,7 @@ public:
   /**
    * @copydoc Dali::DragAndDrop::StartDragAndDrop()
    */
-  bool StartDragAndDrop(Dali::Actor source, Dali::Actor shadow, const std::string& dragData) override;
+  bool StartDragAndDrop(Dali::Actor source, Dali::Window shadowWindow, const Dali::DragAndDrop::DragData& data, Dali::DragAndDrop::SourceFunction callback) override;
 
   /**
    * @copydoc Dali::DragAndDrop::AddListener()
@@ -64,9 +64,9 @@ public:
   bool AddListener(Dali::Actor target, Dali::DragAndDrop::DragAndDropFunction callback) override;
 
   /**
-   * @copydoc Dali::DragAndDrop::SetData()
+   * @copydoc Dali::DragAndDrop::RemoveListener()
    */
-  void SetData(std::string data);
+  bool RemoveListener(Dali::Actor target) override;
 
   /**
    * @copydoc Dali::DragAndDrop::SendData()
@@ -88,6 +88,16 @@ public:
    */
   bool CalculateViewRegion(void* event) override;
 
+  /**
+   * @brief Call drag source events.
+   */
+  void CallSourceEvent(Dali::DragAndDrop::SourceEventType type);
+
+  /**
+   * @brief Reset drop targets.
+   */
+  void ResetDropTargets();
+
 private:
   DragAndDropEcoreWl(const DragAndDropEcoreWl&) = delete;
   DragAndDropEcoreWl& operator=(DragAndDropEcoreWl&) = delete;
@@ -95,15 +105,22 @@ private:
   DragAndDropEcoreWl& operator=(DragAndDropEcoreWl&&) = delete;
 
 private:
-  Dali::Window            mDragWindow;
-  uint32_t                mSerial{0u};
-  Ecore_Event_Handler*    mSendHandler{nullptr};
-  Ecore_Event_Handler*    mReceiveHandler{nullptr};
-  Ecore_Event_Handler*    mMotionHandler{nullptr};
-  Ecore_Event_Handler*    mDropHandler{nullptr};
-  int                     mTargetIndex{0};
-  Dali::Vector2           mPosition;
-  std::string             mData;
+  Dali::Window                      mDragWindow;
+  uint32_t                          mSerial{0u};
+  Ecore_Event_Handler*              mSendHandler{nullptr};
+  Ecore_Event_Handler*              mSourceEndHandler{nullptr};
+  Ecore_Event_Handler*              mSourceDropHandler{nullptr};
+  Ecore_Event_Handler*              mReceiveHandler{nullptr};
+  Ecore_Event_Handler*              mMotionHandler{nullptr};
+  Ecore_Event_Handler*              mDropHandler{nullptr};
+  Ecore_Event_Handler*              mEnterHandler{nullptr};
+  Ecore_Event_Handler*              mLeaveHandler{nullptr};
+  int                               mTargetIndex{0};
+  std::string                       mMimeType;
+  std::string                       mData;
+  int                               mDataSize{0};
+  Dali::Vector2                     mPosition;
+  Dali::DragAndDrop::SourceFunction mSourceCallback{nullptr};
   std::vector<DropTarget> mDropTargets;
 }; // class DragAndDropEcoreWl
 
index b68f218..5ff8d2c 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_EGL_IMAGE_EXTENSIONS_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -76,6 +76,9 @@ public: // EGLImageKHR extension support
   void InitializeEglImageKHR();
 
 private:
+  struct Impl;
+  Impl* mImpl{nullptr};
+
   EglImplementation* mEglImplementation;
 
   bool mImageKHRInitialized;      ///< Flag for whether extended KHR functions loaded
index 9ee5721..4ac58ae 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -145,6 +145,11 @@ void DumpCommandBuffer(FILE* output, const GLES::CommandBuffer* commandBuffer)
         fprintf(output, "{\"Cmd\":\"DRAW_INDEXED\"}\n");
         break;
       }
+      case GLES::CommandType::DRAW_NATIVE:
+      {
+        fprintf(output, "{\"Cmd\":\"DRAW_NATIVE\"}\n");
+        break;
+      }
       case GLES::CommandType::DRAW_INDEXED_INDIRECT:
       {
         fprintf(output, "{\"Cmd\":\"DRAW_INDEXED_INDIRECT\"}\n");
index 3667844..0a22d9c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -583,6 +583,17 @@ void EglGraphicsController::ProcessCommandBuffer(const GLES::CommandBuffer& comm
         }
         break;
       }
+      case GLES::CommandType::DRAW_NATIVE:
+      {
+        auto* info = &cmd.drawNative.drawNativeInfo;
+
+        mCurrentContext->PrepareForNativeRendering();
+
+        CallbackBase::ExecuteReturn<bool>(*info->callback, info->userData);
+
+        mCurrentContext->RestoreFromNativeRendering();
+        break;
+      }
     }
   }
 }
@@ -652,6 +663,8 @@ void EglGraphicsController::ProcessTextureUpdateQueue()
       }
 
       mGlAbstraction->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
+      mGlAbstraction->PixelStorei(GL_UNPACK_ROW_LENGTH, info.srcStride);
+
       mCurrentContext->BindTexture(bindTarget, texture->GetTextureTypeId(), texture->GetGLTexture());
 
       if(!isSubImage)
@@ -763,7 +776,7 @@ void EglGraphicsController::UpdateTextures(const std::vector<TextureUpdateInfo>&
   }
 
   // If upload buffer exceeds maximum size, flush.
-  if(mTextureUploadTotalCPUMemoryUsed > TEXTURE_UPLOAD_MAX_BUFER_SIZE_MB * 1024)
+  if(mTextureUploadTotalCPUMemoryUsed > TEXTURE_UPLOAD_MAX_BUFER_SIZE_MB * 1024 * 1024)
   {
     Flush();
     mTextureUploadTotalCPUMemoryUsed = 0;
index de5e058..f38ed4a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #include "gles-graphics-render-pass.h"
 #include "gles-graphics-render-target.h"
 
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
 #include <map>
 
+
 namespace Dali::Graphics::GLES
 {
 struct Context::Impl
 {
-  Impl(EglGraphicsController& controller)
+  explicit Impl(EglGraphicsController& controller)
   : mController(controller)
   {
   }
@@ -206,6 +209,12 @@ struct Context::Impl
   GLStateCache                           mGlStateCache{};             ///< GL status cache
 
   bool mGlContextCreated{false}; ///< True if the OpenGL context has been created
+
+  EGLContext mNativeDrawContext{0u}; ///< Native rendering EGL context compatible with window context
+
+  EGLSurface mCacheDrawReadSurface{0u};    ///< cached 'read' surface
+  EGLSurface mCacheDrawWriteSurface{0u};   ///< cached 'write' surface
+  EGLContext mCacheEGLGraphicsContext{0u}; ///< cached window context
 };
 
 Context::Context(EglGraphicsController& controller)
@@ -213,7 +222,15 @@ Context::Context(EglGraphicsController& controller)
   mImpl = std::make_unique<Impl>(controller);
 }
 
-Context::~Context() = default;
+Context::~Context()
+{
+  // Destroy native rendering context if one exists
+  if(mImpl->mNativeDrawContext)
+  {
+    eglDestroyContext(eglGetCurrentDisplay(), mImpl->mNativeDrawContext);
+    mImpl->mNativeDrawContext = EGL_NO_CONTEXT;
+  }
+}
 
 void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall)
 {
@@ -954,4 +971,55 @@ void Context::InvalidateCachedPipeline(GLES::Pipeline* pipeline)
   }
 }
 
+void Context::PrepareForNativeRendering()
+{
+  // this should be pretty much constant
+  auto display     = eglGetCurrentDisplay();
+  auto drawSurface = eglGetCurrentSurface(EGL_DRAW);
+  auto readSurface = eglGetCurrentSurface(EGL_READ);
+  auto context     = eglGetCurrentContext();
+
+  // push the surface and context data to the impl
+  // It's needed to restore context
+  if(!mImpl->mCacheEGLGraphicsContext)
+  {
+    mImpl->mCacheDrawWriteSurface   = drawSurface;
+    mImpl->mCacheDrawReadSurface    = readSurface;
+    mImpl->mCacheEGLGraphicsContext = context;
+  }
+
+  if(!mImpl->mNativeDrawContext)
+  {
+    EGLint configId{0u};
+    EGLint size{0u};
+    eglGetConfigs(display, nullptr, 0, &size);
+    std::vector<EGLConfig> configs;
+    configs.resize(size);
+    eglGetConfigs(display, configs.data(), configs.size(), &size);
+
+    eglQueryContext(display, context, EGL_CONFIG_ID, &configId);
+
+    auto version = int(mImpl->mController.GetGLESVersion());
+
+    std::vector<EGLint> attribs;
+    attribs.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR);
+    attribs.push_back(version / 10);
+    attribs.push_back(EGL_CONTEXT_MINOR_VERSION_KHR);
+    attribs.push_back(version % 10);
+    attribs.push_back(EGL_NONE);
+
+    mImpl->mNativeDrawContext = eglCreateContext(display, configs[configId], EGL_NO_CONTEXT, attribs.data());
+  }
+
+  eglMakeCurrent(display, drawSurface, readSurface, mImpl->mNativeDrawContext);
+}
+
+void Context::RestoreFromNativeRendering()
+{
+  auto display = eglGetCurrentDisplay();
+
+  // bring back original context
+  eglMakeCurrent(display, mImpl->mCacheDrawWriteSurface, mImpl->mCacheDrawReadSurface, mImpl->mCacheEGLGraphicsContext);
+}
+
 } // namespace Dali::Graphics::GLES
index a4c3c8b..12e62cd 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_GRAPHICS_GLES_CONTEXT_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -164,6 +164,25 @@ public:
    */
   void InvalidateCachedPipeline(GLES::Pipeline* pipeline);
 
+  /**
+   * @brief Sets up EGL context for native rendering
+   *
+   * - The native rendering uses dedicated context
+   * - There is one EGL native rendering context per GLES::Context object
+   * - Native rendering context is compatible with the window/surface context
+   * - Native rendering context dies with GLES::Context object
+   *
+   * When native rendering is about to be executed, the dedicated EGL context
+   * is acquired (created or reused) and made current. The Window/Surface context
+   * is cached to be restored afterwards.
+   */
+  void PrepareForNativeRendering();
+
+  /**
+   * @brief Restores window/surface context after native rendering.
+   */
+  void RestoreFromNativeRendering();
+
   void ActiveTexture(uint32_t textureBindingIndex);
   void BindTexture(GLenum target, BoundTextureType textureTypeId, uint32_t textureId);
   void GenerateMipmap(GLenum target);
index 98f4830..177b6b9 100644 (file)
@@ -32,8 +32,8 @@ namespace Dali::Graphics::GLES
 class CommandPool
 {
   static constexpr uint32_t COMMAND_POOL_DEFAULT_INCREMENT = 1024 * 32 / sizeof(Command); // 32kb banks
-  static const     uint32_t MEMORY_POOL_DEFAULT_INCREMENT  = 1024;                        // 1kb memory pool increment
-  static const     uint32_t MEMORY_POOL_DEFAULT_ALIGNMENT  = 64;                          // 64bytes alignment
+  static const uint32_t     MEMORY_POOL_DEFAULT_INCREMENT  = 1024;                        // 1kb memory pool increment
+  static const uint32_t     MEMORY_POOL_DEFAULT_ALIGNMENT  = 64;                          // 64bytes alignment
 
   template<class T>
   struct Block
@@ -234,9 +234,9 @@ CommandBuffer::CommandBuffer(const Graphics::CommandBufferCreateInfo& createInfo
 
 CommandBuffer::~CommandBuffer() = default;
 
-void CommandBuffer::BindVertexBuffers(uint32_t                             firstBinding,
-                                      std::vector<const Graphics::Buffer*> buffers,
-                                      std::vector<uint32_t>                offsets)
+void CommandBuffer::BindVertexBuffers(uint32_t                                    firstBinding,
+                                      const std::vector<const Graphics::Buffer*>& buffers,
+                                      const std::vector<uint32_t>&                offsets)
 {
   auto command                                         = mCommandPool->AllocateCommand(CommandType::BIND_VERTEX_BUFFERS);
   command->bindVertexBuffers.vertexBufferBindingsCount = firstBinding + buffers.size();
@@ -314,7 +314,7 @@ void CommandBuffer::BindPipeline(const Graphics::Pipeline& pipeline)
   command->bindPipeline.pipeline = static_cast<const GLES::Pipeline*>(&pipeline);
 }
 
-void CommandBuffer::BindTextures(std::vector<TextureBinding>& textureBindings)
+void CommandBuffer::BindTextures(const std::vector<TextureBinding>& textureBindings)
 {
   auto  command                        = mCommandPool->AllocateCommand(CommandType::BIND_TEXTURES);
   auto& bindTexturesCmd                = command->bindTextures;
@@ -323,7 +323,7 @@ void CommandBuffer::BindTextures(std::vector<TextureBinding>& textureBindings)
   memcpy(bindTexturesCmd.textureBindings.Ptr(), textureBindings.data(), sizeof(TextureBinding) * textureBindings.size());
 }
 
-void CommandBuffer::BindSamplers(std::vector<SamplerBinding>& samplerBindings)
+void CommandBuffer::BindSamplers(const std::vector<SamplerBinding>& samplerBindings)
 {
   auto  command                        = mCommandPool->AllocateCommand(CommandType::BIND_SAMPLERS);
   auto& bindSamplersCmd                = command->bindSamplers;
@@ -349,10 +349,10 @@ void CommandBuffer::BindIndexBuffer(const Graphics::Buffer& buffer,
 }
 
 void CommandBuffer::BeginRenderPass(
-  Graphics::RenderPass*   renderPass,
-  Graphics::RenderTarget* renderTarget,
-  Rect2D                  renderArea,
-  std::vector<ClearValue> clearValues)
+  Graphics::RenderPass*          renderPass,
+  Graphics::RenderTarget*        renderTarget,
+  Rect2D                         renderArea,
+  const std::vector<ClearValue>& clearValues)
 {
   auto  command                    = mCommandPool->AllocateCommand(CommandType::BEGIN_RENDERPASS);
   auto& cmd                        = *command;
@@ -430,6 +430,13 @@ void CommandBuffer::DrawIndexedIndirect(
   cmd.drawIndexedIndirect.stride    = stride;
 }
 
+void CommandBuffer::DrawNative(const DrawNativeInfo* drawNativeInfo)
+{
+  auto  command = mCommandPool->AllocateCommand(CommandType::DRAW_NATIVE);
+  auto& cmd     = command->drawNative;
+  memcpy(&cmd.drawNativeInfo, drawNativeInfo, sizeof(DrawNativeInfo));
+}
+
 void CommandBuffer::Reset()
 {
   mCommandPool->Rollback(false);
index 8e2aeac..07c5561 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_GRAPHICS_GLES_COMMAND_BUFFER_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -66,6 +66,7 @@ enum class CommandType
   SET_DEPTH_COMPARE_OP,
   SET_DEPTH_TEST_ENABLE,
   SET_DEPTH_WRITE_ENABLE,
+  DRAW_NATIVE,
 };
 
 /**
@@ -215,6 +216,11 @@ struct Command
     {
       bool enabled;
     } colorMask;
+
+    struct
+    {
+      DrawNativeInfo drawNativeInfo;
+    } drawNative;
   };
 };
 
@@ -230,9 +236,9 @@ public:
   /**
    * @copydoc Dali::Graphics::CommandBuffer::BindVertexBuffers
    */
-  void BindVertexBuffers(uint32_t                             firstBinding,
-                         std::vector<const Graphics::Buffer*> buffers,
-                         std::vector<uint32_t>                offsets) override;
+  void BindVertexBuffers(uint32_t                                    firstBinding,
+                         const std::vector<const Graphics::Buffer*>& buffers,
+                         const std::vector<uint32_t>&                offsets) override;
 
   /**
    * @copydoc Dali::Graphics::CommandBuffer::BindUniformBuffers
@@ -247,12 +253,12 @@ public:
   /**
    * @copydoc Dali::Graphics::CommandBuffer::BindTextures
    */
-  void BindTextures(std::vector<TextureBinding>& textureBindings) override;
+  void BindTextures(const std::vector<TextureBinding>& textureBindings) override;
 
   /**
    * @copydoc Dali::Graphics::CommandBuffer::BindSamplers
    */
-  void BindSamplers(std::vector<SamplerBinding>& samplerBindings) override;
+  void BindSamplers(const std::vector<SamplerBinding>& samplerBindings) override;
 
   /**
    * @copydoc Dali::Graphics::CommandBuffer::BindPushConstants
@@ -272,10 +278,10 @@ public:
    * @copydoc Dali::Graphics::CommandBuffer::BeginRenderPass
    */
   void BeginRenderPass(
-    Graphics::RenderPass*   renderPass,
-    Graphics::RenderTarget* renderTarget,
-    Rect2D                  renderArea,
-    std::vector<ClearValue> clearValues) override;
+    Graphics::RenderPass*          renderPass,
+    Graphics::RenderTarget*        renderTarget,
+    Rect2D                         renderArea,
+    const std::vector<ClearValue>& clearValues) override;
 
   /**
    * @copydoc Dali::Graphics::CommandBuffer::EndRenderPass
@@ -316,6 +322,11 @@ public:
     uint32_t          stride) override;
 
   /**
+   * @copydoc Dali::Graphics::CommandBuffer::DrawNative
+   */
+  void DrawNative(const DrawNativeInfo* drawNativeInfo) override;
+
+  /**
    * @copydoc Dali::Graphics::CommandBuffer::Reset
    */
   void Reset() override;
index 05a803d..05776c2 100644 (file)
 
 namespace
 {
+struct StringSize
+{
+  const char* const mString;
+  const uint32_t    mLength;
+
+  template<uint32_t kLength>
+  constexpr StringSize(const char (&string)[kLength])
+  : mString(string),
+    mLength(kLength - 1) // remove terminating null; N.B. there should be no other null.
+  {
+  }
+
+  operator const char*() const
+  {
+    return mString;
+  }
+};
+
+bool operator==(const StringSize& lhs, const char* rhs)
+{
+  return strncmp(lhs.mString, rhs, lhs.mLength) == 0;
+}
+
+const char* const    DELIMITERS = " \t\n";
+constexpr StringSize UNIFORM{"uniform"};
+constexpr StringSize SAMPLER_PREFIX{"sampler"};
+constexpr StringSize SAMPLER_TYPES[]   = {"2D", "Cube", "ExternalOES"};
+constexpr auto       END_SAMPLER_TYPES = SAMPLER_TYPES + std::extent<decltype(SAMPLER_TYPES)>::value;
+
 Dali::Graphics::VertexInputAttributeFormat GetVertexAttributeTypeFormat(GLenum type)
 {
   switch(type)
@@ -94,34 +123,68 @@ bool SortUniformExtraInfoByLocation(Dali::Graphics::GLES::Reflection::UniformExt
   return a.location < b.location;
 }
 
-struct StringSize
+std::string GetShaderSource(Dali::Graphics::ShaderState shaderState)
 {
-  const char* const mString;
-  const uint32_t    mLength;
+  std::vector<uint8_t> data;
+  auto*                shader           = static_cast<const Dali::Graphics::GLES::Shader*>(shaderState.shader);
+  auto&                shaderCreateInfo = shader->GetCreateInfo();
+  data.resize(shaderCreateInfo.sourceSize + 1);
+  std::memcpy(&data[0], shaderCreateInfo.sourceData, shaderCreateInfo.sourceSize);
+  data[shaderCreateInfo.sourceSize] = 0;
 
-  template<uint32_t kLength>
-  constexpr StringSize(const char (&string)[kLength])
-  : mString(string),
-    mLength(kLength - 1) // remove terminating null; N.B. there should be no other null.
-  {
-  }
+  return std::string(reinterpret_cast<char*>(&data[0]));
+}
 
-  operator const char*() const
+void ParseShaderSamplers(std::string shaderSource, std::vector<Dali::Graphics::UniformInfo>& uniformOpaques, int& samplerPosition, std::vector<int>& samplerPositions)
+{
+  if(!shaderSource.empty())
   {
-    return mString;
-  }
-};
+    char* shaderStr = strdup(shaderSource.c_str());
+    char* uniform   = strstr(shaderStr, UNIFORM);
 
-bool operator==(const StringSize& lhs, const char* rhs)
-{
-  return strncmp(lhs.mString, rhs, lhs.mLength) == 0;
-}
+    while(uniform)
+    {
+      char* outerToken = strtok_r(uniform + UNIFORM.mLength, ";", &uniform);
 
-const char* const    DELIMITERS = " \t\n";
-constexpr StringSize UNIFORM{"uniform"};
-constexpr StringSize SAMPLER_PREFIX{"sampler"};
-constexpr StringSize SAMPLER_TYPES[]   = {"2D", "Cube", "ExternalOES"};
-constexpr auto       END_SAMPLER_TYPES = SAMPLER_TYPES + std::extent<decltype(SAMPLER_TYPES)>::value;
+      char* nextPtr = nullptr;
+      char* token   = strtok_r(outerToken, DELIMITERS, &nextPtr);
+      while(token)
+      {
+        if(SAMPLER_PREFIX == token)
+        {
+          token += SAMPLER_PREFIX.mLength;
+          if(std::find(SAMPLER_TYPES, END_SAMPLER_TYPES, token) != END_SAMPLER_TYPES)
+          {
+            bool found(false);
+            token = strtok_r(nullptr, DELIMITERS, &nextPtr);
+
+            for(uint32_t i = 0; i < static_cast<uint32_t>(uniformOpaques.size()); ++i)
+            {
+              if(samplerPositions[i] == -1 &&
+                 strncmp(token, uniformOpaques[i].name.c_str(), uniformOpaques[i].name.size()) == 0)
+              {
+                samplerPositions[i] = uniformOpaques[i].offset = samplerPosition++;
+                found                                          = true;
+                break;
+              }
+            }
+
+            if(!found)
+            {
+              DALI_LOG_ERROR("Sampler uniform %s declared but not used in the shader\n", token);
+            }
+            break;
+          }
+        }
+
+        token = strtok_r(nullptr, DELIMITERS, &nextPtr);
+      }
+
+      uniform = strstr(uniform, UNIFORM);
+    }
+    free(shaderStr);
+  }
+}
 
 } // anonymous namespace
 
@@ -591,71 +654,27 @@ void Reflection::SortOpaques()
   auto& programCreateInfo = mProgram.GetCreateInfo();
 
   std::vector<uint8_t> data;
+  std::string          vertShader;
   std::string          fragShader;
 
   for(auto& shaderState : *programCreateInfo.shaderState)
   {
-    if(shaderState.pipelineStage == PipelineStage::FRAGMENT_SHADER)
+    if(shaderState.pipelineStage == PipelineStage::VERTEX_SHADER)
     {
-      auto* shader           = static_cast<const GLES::Shader*>(shaderState.shader);
-      auto& shaderCreateInfo = shader->GetCreateInfo();
-      data.resize(shaderCreateInfo.sourceSize + 1);
-      std::memcpy(&data[0], shaderCreateInfo.sourceData, shaderCreateInfo.sourceSize);
-      data[shaderCreateInfo.sourceSize] = 0;
-      fragShader                        = std::string(reinterpret_cast<char*>(&data[0]));
-      break;
+      vertShader = GetShaderSource(shaderState);
     }
-  }
-
-  if(!fragShader.empty())
-  {
-    char*            shaderStr       = strdup(fragShader.c_str());
-    char*            uniform         = strstr(shaderStr, UNIFORM);
-    int              samplerPosition = 0;
-    std::vector<int> samplerPositions(mUniformOpaques.size(), -1);
-
-    while(uniform)
+    else if(shaderState.pipelineStage == PipelineStage::FRAGMENT_SHADER)
     {
-      char* outerToken = strtok_r(uniform + UNIFORM.mLength, ";", &uniform);
-
-      char* nextPtr = nullptr;
-      char* token   = strtok_r(outerToken, DELIMITERS, &nextPtr);
-      while(token)
-      {
-        if(SAMPLER_PREFIX == token)
-        {
-          token += SAMPLER_PREFIX.mLength;
-          if(std::find(SAMPLER_TYPES, END_SAMPLER_TYPES, token) != END_SAMPLER_TYPES)
-          {
-            bool found(false);
-            token = strtok_r(nullptr, DELIMITERS, &nextPtr);
-
-            for(uint32_t i = 0; i < static_cast<uint32_t>(mUniformOpaques.size()); ++i)
-            {
-              if(samplerPositions[i] == -1 &&
-                 strncmp(token, mUniformOpaques[i].name.c_str(), mUniformOpaques[i].name.size()) == 0)
-              {
-                samplerPositions[i] = mUniformOpaques[i].offset = samplerPosition++;
-                found                                           = true;
-                break;
-              }
-            }
+      fragShader = GetShaderSource(shaderState);
+    }
+  }
 
-            if(!found)
-            {
-              DALI_LOG_ERROR("Sampler uniform %s declared but not used in the shader\n", token);
-            }
-            break;
-          }
-        }
+  int              samplerPosition = 0;
+  std::vector<int> samplerPositions(mUniformOpaques.size(), -1);
 
-        token = strtok_r(nullptr, DELIMITERS, &nextPtr);
-      }
+  ParseShaderSamplers(vertShader, mUniformOpaques, samplerPosition, samplerPositions);
+  ParseShaderSamplers(fragShader, mUniformOpaques, samplerPosition, samplerPositions);
 
-      uniform = strstr(uniform, UNIFORM);
-    }
-    free(shaderStr);
-  }
   std::sort(mUniformOpaques.begin(), mUniformOpaques.end(), [](const UniformInfo& a, const UniformInfo& b) { return a.offset < b.offset; });
 }
 
index 18069eb..dc90a98 100644 (file)
@@ -1527,7 +1527,7 @@ struct DrawCallDescriptor
   {
     DRAW,
     DRAW_INDEXED,
-    DRAW_INDEXED_INDIRECT
+    DRAW_INDEXED_INDIRECT,
   };
 
   Type type{}; ///< Type of the draw call
index b850f77..6187d19 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@
 
 // EXTERNAL INCLUDES
 #include <dali/integration-api/debug.h>
+#include <dali/integration-api/trace.h>
 #include <dali/public-api/common/dali-vector.h>
 #include <sstream>
 
@@ -42,6 +43,7 @@ const std::string EGL_KHR_CREATE_CONTEXT                  = "EGL_KHR_create_cont
 const std::string EGL_KHR_PARTIAL_UPDATE                  = "EGL_KHR_partial_update";
 const std::string EGL_KHR_SWAP_BUFFERS_WITH_DAMAGE        = "EGL_KHR_swap_buffers_with_damage";
 
+DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_EGL, true);
 } // namespace
 
 namespace Dali
@@ -385,6 +387,7 @@ void EglImplementation::SwapBuffers(EGLSurface& eglSurface)
     if(mSwapBufferCountAfterResume < THRESHOLD_SWAPBUFFER_COUNT)
     {
       DALI_LOG_RELEASE_INFO("EglImplementation::eglSwapBuffers started. eglSurface(%p)\n", eglSurface);
+      DALI_TRACE_BEGIN(gTraceFilter, "DALI_EGL_SWAP_BUFFERS");
     }
 #endif //DALI_PROFILE_UBUNTU
 
@@ -394,6 +397,7 @@ void EglImplementation::SwapBuffers(EGLSurface& eglSurface)
 #ifndef DALI_PROFILE_UBUNTU
     if(mSwapBufferCountAfterResume < THRESHOLD_SWAPBUFFER_COUNT)
     {
+      DALI_TRACE_END(gTraceFilter, "DALI_EGL_SWAP_BUFFERS");
       DALI_LOG_RELEASE_INFO("EglImplementation::eglSwapBuffers finished.\n");
       mSwapBufferCountAfterResume++;
     }
@@ -410,15 +414,6 @@ EGLint EglImplementation::GetBufferAge(EGLSurface& eglSurface) const
     DALI_LOG_ERROR("eglQuerySurface(%d)\n", eglGetError());
     age = 0;
   }
-
-  // 0 - invalid buffer
-  // 1, 2, 3
-  if(age > 3)
-  {
-    DALI_LOG_ERROR("EglImplementation::GetBufferAge() buffer age %d > 3\n", age);
-    age = 0; // shoudn't be more than 3 back buffers, if there is just reset, I don't want to add extra history level
-  }
-
   return age;
 }
 
@@ -453,6 +448,7 @@ void EglImplementation::SwapBuffers(EGLSurface& eglSurface, const std::vector<Re
     if(mSwapBufferCountAfterResume < THRESHOLD_SWAPBUFFER_COUNT)
     {
       DALI_LOG_RELEASE_INFO("EglImplementation::eglSwapBuffersWithDamageKHR started. eglSurface(%p)\n", eglSurface);
+      DALI_TRACE_BEGIN(gTraceFilter, "DALI_EGL_SWAP_BUFFERS_KHR");
     }
 #endif //DALI_PROFILE_UBUNTU
 
@@ -465,6 +461,7 @@ void EglImplementation::SwapBuffers(EGLSurface& eglSurface, const std::vector<Re
 #ifndef DALI_PROFILE_UBUNTU
     if(mSwapBufferCountAfterResume < THRESHOLD_SWAPBUFFER_COUNT)
     {
+      DALI_TRACE_END(gTraceFilter, "DALI_EGL_SWAP_BUFFERS_KHR");
       DALI_LOG_RELEASE_INFO("EglImplementation::eglSwapBuffersWithDamageKHR finished.\n");
       mSwapBufferCountAfterResume++;
     }
index e60fb8f..b7551a4 100644 (file)
@@ -49,9 +49,11 @@ static constexpr const char* KHR_BLEND_EQUATION_ADVANCED                  = "GL_
 static constexpr const char* DEFAULT_SAMPLER_TYPE = "sampler2D";
 
 static constexpr const char* FRAGMENT_SHADER_ADVANCED_BLEND_EQUATION_PREFIX =
+  "#ifdef GL_KHR_blend_equation_advanced\n"
   "#extension GL_KHR_blend_equation_advanced : enable\n"
+  "#endif\n"
 
-  "#if GL_KHR_blend_equation_advanced==1 || __VERSION__>=320\n"
+  "#if defined(GL_KHR_blend_equation_advanced) || __VERSION__>=320\n"
   "  layout(blend_support_all_equations) out;\n"
   "#endif\n";
 
index 9beaccc..cf79bdb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 #include <EGL/eglext.h>
 
+#include <tbm_bufmgr.h>
+#include <tbm_surface.h>
+#include <tbm_surface_internal.h>
+
 #include <dali/integration-api/debug.h>
 
 // INTERNAL INCLUDES
@@ -41,6 +45,10 @@ namespace
 PFNEGLCREATEIMAGEKHRPROC            eglCreateImageKHRProc            = 0;
 PFNEGLDESTROYIMAGEKHRPROC           eglDestroyImageKHRProc           = 0;
 PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOESProc = 0;
+
+const std::string EGL_TIZEN_IMAGE_NATIVE_SURFACE = "EGL_TIZEN_image_native_surface";
+const std::string EGL_EXT_IMAGE_DMA_BUF_IMPORT   = "EGL_EXT_image_dma_buf_import";
+
 } // unnamed namespace
 
 namespace Dali
@@ -49,8 +57,15 @@ namespace Internal
 {
 namespace Adaptor
 {
+struct EglImageExtensions::Impl
+{
+  bool mIsTizenImageNativeSurfaceSupported{false};
+  bool mIsExtImageDmaBufImportSupported{false};
+};
+
 EglImageExtensions::EglImageExtensions(EglImplementation* eglImpl)
-: mEglImplementation(eglImpl),
+: mImpl(new Impl()),
+  mEglImplementation(eglImpl),
   mImageKHRInitialized(false),
   mImageKHRInitializeFailed(false)
 {
@@ -59,6 +74,7 @@ EglImageExtensions::EglImageExtensions(EglImplementation* eglImpl)
 
 EglImageExtensions::~EglImageExtensions()
 {
+  delete mImpl;
 }
 
 void* EglImageExtensions::CreateImageKHR(EGLClientBuffer clientBuffer)
@@ -73,16 +89,55 @@ void* EglImageExtensions::CreateImageKHR(EGLClientBuffer clientBuffer)
     return NULL;
   }
 
+  EGLImageKHR eglImage = EGL_NO_IMAGE_KHR;
+
   // Use the EGL image extension
-  const EGLint attribs[] =
+  if(mImpl->mIsTizenImageNativeSurfaceSupported)
+  {
+    // If EGL_TIZEN_image_native_surface is supported
+    const EGLint attribs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
+
+    eglImage = eglCreateImageKHRProc(mEglImplementation->GetDisplay(),
+                                     EGL_NO_CONTEXT,
+                                     EGL_NATIVE_SURFACE_TIZEN,
+                                     clientBuffer,
+                                     attribs);
+  }
+  else if(mImpl->mIsExtImageDmaBufImportSupported)
+  {
+    // Else then use EGL_EXT_image_dma_buf_import
+    tbm_surface_info_s info;
+    tbm_surface_h      tbmSurface = reinterpret_cast<tbm_surface_h>(clientBuffer);
+
+    if(tbm_surface_get_info(tbmSurface, &info) != TBM_SURFACE_ERROR_NONE)
     {
-      EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
+      return NULL;
+    }
+
+    // We support only 1 plane
+    tbm_bo tbmBo = tbm_surface_internal_get_bo(tbmSurface, tbm_surface_internal_get_plane_bo_idx(tbmSurface, 0));
 
-  EGLImageKHR eglImage = eglCreateImageKHRProc(mEglImplementation->GetDisplay(),
-                                               EGL_NO_CONTEXT,
-                                               EGL_NATIVE_SURFACE_TIZEN,
-                                               clientBuffer,
-                                               attribs);
+    // clang-format off
+    const EGLint attribs[] = {EGL_WIDTH, static_cast<EGLint>(info.width),
+                              EGL_HEIGHT, static_cast<EGLint>(info.height),
+                              EGL_LINUX_DRM_FOURCC_EXT, static_cast<EGLint>(info.format),
+                              EGL_DMA_BUF_PLANE0_FD_EXT, static_cast<EGLint>(reinterpret_cast<size_t>(tbm_bo_get_handle(tbmBo, TBM_DEVICE_3D).ptr)),
+                              EGL_DMA_BUF_PLANE0_OFFSET_EXT, static_cast<EGLint>(info.planes[0].offset),
+                              EGL_DMA_BUF_PLANE0_PITCH_EXT, static_cast<EGLint>(info.planes[0].stride),
+                              EGL_NONE};
+    // clang-format on
+
+    eglImage = eglCreateImageKHRProc(mEglImplementation->GetDisplay(),
+                                     EGL_NO_CONTEXT,
+                                     EGL_LINUX_DMA_BUF_EXT,
+                                     nullptr,
+                                     attribs);
+  }
+  else
+  {
+    DALI_LOG_ERROR("Not supported\n");
+    return EGL_NO_IMAGE_KHR;
+  }
 
   if(EGL_NO_IMAGE_KHR == eglImage)
   {
@@ -220,6 +275,20 @@ void EglImageExtensions::InitializeEglImageKHR()
   {
     mImageKHRInitializeFailed = true;
   }
+
+  std::string extensionStr = eglQueryString(mEglImplementation->GetDisplay(), EGL_EXTENSIONS);
+
+  auto found = extensionStr.find(EGL_TIZEN_IMAGE_NATIVE_SURFACE);
+  if(found != std::string::npos)
+  {
+    mImpl->mIsTizenImageNativeSurfaceSupported = true;
+  }
+
+  found = extensionStr.find(EGL_EXT_IMAGE_DMA_BUF_IMPORT);
+  if(found != std::string::npos)
+  {
+    mImpl->mIsExtImageDmaBufImportSupported = true;
+  }
 }
 
 } // namespace Adaptor
index d7f7016..276751a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,7 +18,7 @@
 #include <dali/internal/imaging/common/image-operations.h>
 #include <dali/internal/imaging/common/pixel-buffer-impl.h>
 #include <dali/internal/imaging/common/pixel-manipulation.h>
-#include <dali/public-api/images/image-operations.h> // For ImageDimensions
+#include <dali/public-api/images/image-operations.h> // For ImageDimensions and MultiplyAndNormalizeColor
 
 namespace Dali
 {
@@ -51,34 +51,55 @@ void ApplyMaskToAlphaChannel(PixelBuffer& buffer, const PixelBuffer& mask)
   unsigned char* destBuffer       = buffer.GetBuffer();
 
   unsigned int destBytesPerPixel = Dali::Pixel::GetBytesPerPixel(buffer.GetPixelFormat());
-
-  int srcOffset  = 0;
-  int destOffset = 0;
-
-  float srcAlphaValue = 1.0f;
+  unsigned int srcStrideBytes    = mask.GetStride() * srcBytesPerPixel;
+  unsigned int destStrideBytes   = buffer.GetStride() * destBytesPerPixel;
 
   // if image is premultiplied, the other channels of the image need to multiply by alpha.
   if(buffer.IsAlphaPreMultiplied())
   {
-    for(unsigned int row = 0; row < buffer.GetHeight(); ++row)
+    // Collect all valid channel list before lookup whole buffer
+    std::vector<Channel> validChannelList;
+    for(const Channel& channel : {Adaptor::RED, Adaptor::GREEN, Adaptor::BLUE, Adaptor::LUMINANCE, Adaptor::ALPHA})
     {
-      for(unsigned int col = 0; col < buffer.GetWidth(); ++col)
+      if(HasChannel(destPixelFormat, channel))
       {
-        auto srcAlpha      = ReadChannel(srcBuffer + srcOffset, srcPixelFormat, Adaptor::ALPHA);
-        auto destRed       = ReadChannel(destBuffer + destOffset, destPixelFormat, Adaptor::RED);
-        auto destGreen     = ReadChannel(destBuffer + destOffset, destPixelFormat, Adaptor::GREEN);
-        auto destBlue      = ReadChannel(destBuffer + destOffset, destPixelFormat, Adaptor::BLUE);
-        auto destLuminance = ReadChannel(destBuffer + destOffset, destPixelFormat, Adaptor::LUMINANCE);
-        auto destAlpha     = ReadChannel(destBuffer + destOffset, destPixelFormat, Adaptor::ALPHA);
-
-        WriteChannel(destBuffer + destOffset, destPixelFormat, Adaptor::RED, destRed * srcAlpha / 255);
-        WriteChannel(destBuffer + destOffset, destPixelFormat, Adaptor::GREEN, destGreen * srcAlpha / 255);
-        WriteChannel(destBuffer + destOffset, destPixelFormat, Adaptor::BLUE, destBlue * srcAlpha / 255);
-        WriteChannel(destBuffer + destOffset, destPixelFormat, Adaptor::LUMINANCE, destLuminance * srcAlpha / 255);
-        WriteChannel(destBuffer + destOffset, destPixelFormat, Adaptor::ALPHA, destAlpha * srcAlpha / 255);
-
-        srcOffset += srcBytesPerPixel;
-        destOffset += destBytesPerPixel;
+        validChannelList.emplace_back(channel);
+      }
+    }
+    if(DALI_LIKELY(!validChannelList.empty()))
+    {
+      for(unsigned int row = 0; row < buffer.GetHeight(); ++row)
+      {
+        int srcOffset  = 0;
+        int destOffset = 0;
+
+        for(unsigned int col = 0; col < buffer.GetWidth(); ++col)
+        {
+          auto srcAlpha = srcBuffer[srcOffset + srcAlphaByteOffset] & srcAlphaMask;
+          if(srcAlpha < 255)
+          {
+            // If alpha is 255, we don't need to change color. Skip current pixel
+            // But if alpha is not 255, we should change color.
+            if(srcAlpha > 0)
+            {
+              for(const Channel& channel : validChannelList)
+              {
+                auto color = ReadChannel(destBuffer + destOffset, destPixelFormat, channel);
+                WriteChannel(destBuffer + destOffset, destPixelFormat, channel, Platform::MultiplyAndNormalizeColor(color, srcAlpha));
+              }
+            }
+            else
+            {
+              // If alpha is 0, just set all pixel as zero.
+              memset(destBuffer + destOffset, 0, destBytesPerPixel);
+            }
+          }
+
+          srcOffset += srcBytesPerPixel;
+          destOffset += destBytesPerPixel;
+        }
+        srcBuffer += srcStrideBytes;
+        destBuffer += destStrideBytes;
       }
     }
   }
@@ -86,20 +107,24 @@ void ApplyMaskToAlphaChannel(PixelBuffer& buffer, const PixelBuffer& mask)
   {
     for(unsigned int row = 0; row < buffer.GetHeight(); ++row)
     {
+      int srcOffset  = 0;
+      int destOffset = 0;
+
       for(unsigned int col = 0; col < buffer.GetWidth(); ++col)
       {
-        unsigned char alpha = srcBuffer[srcOffset + srcAlphaByteOffset] & srcAlphaMask;
-        srcAlphaValue       = float(alpha) / 255.0f;
+        uint8_t srcAlpha  = srcBuffer[srcOffset + srcAlphaByteOffset] & srcAlphaMask;
+        uint8_t destAlpha = destBuffer[destOffset + destAlphaByteOffset] & destAlphaMask;
+
+        destAlpha = Platform::MultiplyAndNormalizeColor(srcAlpha, destAlpha);
 
-        unsigned char destAlpha      = destBuffer[destOffset + destAlphaByteOffset] & destAlphaMask;
-        float         destAlphaValue = Clamp(float(destAlpha) * srcAlphaValue, 0.0f, 255.0f);
-        destAlpha                    = destAlphaValue;
         destBuffer[destOffset + destAlphaByteOffset] &= ~destAlphaMask;
         destBuffer[destOffset + destAlphaByteOffset] |= (destAlpha & destAlphaMask);
 
         srcOffset += srcBytesPerPixel;
         destOffset += destBytesPerPixel;
       }
+      srcBuffer += srcStrideBytes;
+      destBuffer += destStrideBytes;
     }
   }
 }
@@ -120,12 +145,14 @@ PixelBufferPtr CreateNewMaskedBuffer(const PixelBuffer& buffer, const PixelBuffe
     srcAlphaMask = 0xFF;
   }
 
-  unsigned int   srcBytesPerPixel = Dali::Pixel::GetBytesPerPixel(srcPixelFormat);
   unsigned char* srcBuffer        = mask.GetBuffer();
+  unsigned int   srcBytesPerPixel = Dali::Pixel::GetBytesPerPixel(srcPixelFormat);
+  unsigned int   srcStrideBytes   = mask.GetStride() * srcBytesPerPixel;
 
   // Set up source color offsets
   Dali::Pixel::Format srcColorPixelFormat   = buffer.GetPixelFormat();
   unsigned int        srcColorBytesPerPixel = Dali::Pixel::GetBytesPerPixel(srcColorPixelFormat);
+  unsigned int        srcColorStrideBytes   = buffer.GetStride() * srcColorBytesPerPixel;
 
   // Setup destination offsets
   Dali::Pixel::Format destPixelFormat     = Dali::Pixel::RGBA8888;
@@ -134,36 +161,34 @@ PixelBufferPtr CreateNewMaskedBuffer(const PixelBuffer& buffer, const PixelBuffe
   int                 destAlphaMask       = 0;
   Dali::Pixel::GetAlphaOffsetAndMask(destPixelFormat, destAlphaByteOffset, destAlphaMask);
 
-  PixelBufferPtr newPixelBuffer = PixelBuffer::New(buffer.GetWidth(), buffer.GetHeight(), destPixelFormat);
-  unsigned char* destBuffer     = newPixelBuffer->GetBuffer();
-  unsigned char* oldBuffer      = buffer.GetBuffer();
+  PixelBufferPtr newPixelBuffer  = PixelBuffer::New(buffer.GetWidth(), buffer.GetHeight(), destPixelFormat);
+  unsigned char* destBuffer      = newPixelBuffer->GetBuffer();
+  unsigned char* oldBuffer       = buffer.GetBuffer();
+  unsigned int   destStrideBytes = newPixelBuffer->GetStride() * destBytesPerPixel;
 
-  int  srcAlphaOffset = 0;
-  int  srcColorOffset = 0;
-  int  destOffset     = 0;
-  bool hasAlpha       = Dali::Pixel::HasAlpha(buffer.GetPixelFormat());
+  bool hasAlpha = Dali::Pixel::HasAlpha(buffer.GetPixelFormat());
 
-  float         srcAlphaValue = 1.0f;
-  unsigned char destAlpha     = 0;
+  unsigned char destAlpha = 0;
 
   for(unsigned int row = 0; row < buffer.GetHeight(); ++row)
   {
+    int srcAlphaOffset = 0;
+    int srcColorOffset = 0;
+    int destOffset     = 0;
     for(unsigned int col = 0; col < buffer.GetWidth(); ++col)
     {
-      unsigned char alpha = srcBuffer[srcAlphaOffset + srcAlphaByteOffset] & srcAlphaMask;
-      srcAlphaValue       = float(alpha) / 255.0f;
+      unsigned char srcAlpha = srcBuffer[srcAlphaOffset + srcAlphaByteOffset] & srcAlphaMask;
 
       ConvertColorChannelsToRGBA8888(oldBuffer, srcColorOffset, srcColorPixelFormat, destBuffer, destOffset);
 
       if(hasAlpha)
       {
-        destAlpha            = ConvertAlphaChannelToA8(oldBuffer, srcColorOffset, srcColorPixelFormat);
-        float destAlphaValue = Clamp(float(destAlpha) * srcAlphaValue, 0.0f, 255.0f);
-        destAlpha            = destAlphaValue;
+        destAlpha = ConvertAlphaChannelToA8(oldBuffer, srcColorOffset, srcColorPixelFormat);
+        destAlpha = Platform::MultiplyAndNormalizeColor(srcAlpha, destAlpha);
       }
       else
       {
-        destAlpha = floorf(Clamp(srcAlphaValue * 255.0f, 0.0f, 255.0f));
+        destAlpha = srcAlpha;
       }
 
       destBuffer[destOffset + destAlphaByteOffset] &= ~destAlphaMask;
@@ -173,6 +198,9 @@ PixelBufferPtr CreateNewMaskedBuffer(const PixelBuffer& buffer, const PixelBuffe
       srcAlphaOffset += srcBytesPerPixel;
       destOffset += destBytesPerPixel;
     }
+    oldBuffer += srcColorStrideBytes;
+    srcBuffer += srcStrideBytes;
+    destBuffer += destStrideBytes;
   }
 
   return newPixelBuffer;
index 44f8c03..8caaca5 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_ADAPTOR_ALPHA_MASK_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -25,17 +25,19 @@ namespace Internal
 namespace Adaptor
 {
 /**
- * Apply the mask to a buffer's alpha channel
+ * @brief Apply the mask to a buffer's alpha channel
+ * @note It works well only if mask's alpha mask is 8bit
  * @param[in] buffer The buffer to apply the mask to
  * @param[in] mask The mask to apply
  */
 void ApplyMaskToAlphaChannel(PixelBuffer& buffer, const PixelBuffer& mask);
 
 /**
- * Create a new PixelBuffer with an alpha channel large enough to handle the alpha from
+ * @brief Create a new PixelBuffer with an alpha channel large enough to handle the alpha from
  * the mask, converting the color values to the new size, and either multiplying the mask's
  * alpha into the existing alpha value, or writing the mask's alpha value directly into
  * the new buffer's alpha channel.
+ * @note It works well only if mask's alpha mask is 8bit
  *
  * @param[in] buffer The buffer to apply the mask to
  * @param[in] mask The mask to apply
index d2a624c..5517fc9 100644 (file)
@@ -66,11 +66,6 @@ public:
   ~AnimatedImageLoading() override = default;
 
   /**
-   * @copydoc Dali::AnimatedImageLoading::LoadNextNFrames()
-   */
-  virtual bool LoadNextNFrames(uint32_t frameStartIndex, int count, std::vector<Dali::PixelData>& pixelData) = 0;
-
-  /**
    * @copydoc Dali::AnimatedImageLoading::LoadFrame()
    */
   virtual Dali::Devel::PixelBuffer LoadFrame(uint32_t frameIndex) = 0;
index 1967bcb..2f1a799 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 // CLASS HEADER
 #include "encoded-image-buffer-impl.h"
 
+// EXTERNAL INCLUDE
+#include <dali/devel-api/common/hash.h>
+
 namespace Dali
 {
 namespace Internal
 {
-
 EncodedImageBuffer::EncodedImageBuffer(const RawBufferType& buffer)
 : mBuffer(buffer)
 {
+  mBufferHash = CalculateHash(mBuffer);
 }
 
 EncodedImageBuffer::~EncodedImageBuffer()
@@ -44,6 +47,11 @@ const EncodedImageBuffer::RawBufferType& EncodedImageBuffer::GetRawBuffer() cons
   return mBuffer;
 }
 
+const std::size_t EncodedImageBuffer::GetHash() const
+{
+  return mBufferHash;
+}
+
 } // namespace Internal
 
 } // namespace Dali
index 2ea471f..2c8e924 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_ENCODED_IMAGE_BUFFER_IMPL_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  */
 
 // EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
 #include <dali/public-api/common/intrusive-ptr.h>
 #include <dali/public-api/object/base-object.h>
-#include <dali/public-api/common/dali-vector.h>
 
 // INTERNAL INCLUDES
-#include <dali/public-api/dali-adaptor-common.h>
 #include <dali/public-api/adaptor-framework/encoded-image-buffer.h>
+#include <dali/public-api/dali-adaptor-common.h>
 
 namespace Dali
 {
@@ -51,6 +51,11 @@ public:
    */
   const RawBufferType& GetRawBuffer() const;
 
+  /**
+   * @copydoc Dali::EncodedImageBuffer::GetHash
+   */
+  const std::size_t GetHash() const;
+
 protected:
   /**
    * Destructor
@@ -66,6 +71,7 @@ private:
 
 private:
   Dali::Vector<uint8_t> mBuffer;
+  std::size_t           mBufferHash;
 };
 
 } // namespace Internal
index 3866e36..f566757 100644 (file)
@@ -145,11 +145,14 @@ CURLcode DownloadFileDataByChunk(CURL* curlHandle, Dali::Vector<uint8_t>& dataBu
   }
   dataBuffer.ResizeUninitialized(dataSize);
 
-  size_t offset = 0;
-  for(size_t i = 0; i < chunks.size(); ++i)
+  if(DALI_LIKELY(dataSize > 0))
   {
-    memcpy(&dataBuffer[offset], &chunks[i].data[0], chunks[i].data.capacity());
-    offset += chunks[i].data.capacity();
+    std::uint8_t* dataBufferPtr = dataBuffer.Begin();
+    for(size_t i = 0; i < chunks.size(); ++i)
+    {
+      memcpy(dataBufferPtr, &chunks[i].data[0], chunks[i].data.capacity());
+      dataBufferPtr += chunks[i].data.capacity();
+    }
   }
 
   return result;
index c10c577..01b5b5b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,6 +15,7 @@
  */
 
 // EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
 #include <memory.h>
 #include <cmath>
 
@@ -32,6 +33,8 @@ void ConvoluteAndTranspose(unsigned char*     inBuffer,
                            unsigned char*     outBuffer,
                            const unsigned int bufferWidth,
                            const unsigned int bufferHeight,
+                           const unsigned int inBufferStride,
+                           const unsigned int outBufferStride,
                            const float        blurRadius)
 {
   // Calculate the weights for gaussian blur
@@ -73,7 +76,7 @@ void ConvoluteAndTranspose(unsigned char*     inBuffer,
   for(unsigned int y = 0; y < bufferHeight; y++)
   {
     unsigned int targetPixelIndex = y;
-    unsigned int ioffset          = y * bufferWidth;
+    unsigned int ioffset          = y * inBufferStride;
     for(unsigned int x = 0; x < bufferWidth; x++)
     {
       float r = 0.0f, g = 0.0f, b = 0.0f, a = 0.0f;
@@ -98,7 +101,7 @@ void ConvoluteAndTranspose(unsigned char*     inBuffer,
       outBuffer[targetPixelIndex * 4 + 2] = std::max(0, std::min(static_cast<int>(b + 0.5f), 255));
       outBuffer[targetPixelIndex * 4 + 3] = std::max(0, std::min(static_cast<int>(a + 0.5f), 255));
 
-      targetPixelIndex += bufferHeight;
+      targetPixelIndex += outBufferStride;
     }
   }
 
@@ -109,18 +112,24 @@ void PerformGaussianBlurRGBA(PixelBuffer& buffer, const float blurRadius)
 {
   unsigned int bufferWidth  = buffer.GetWidth();
   unsigned int bufferHeight = buffer.GetHeight();
+  unsigned int bufferStride = buffer.GetStride();
+
+  if(bufferWidth == 0 || bufferHeight == 0 || bufferStride == 0 || buffer.GetPixelFormat() != Pixel::RGBA8888)
+  {
+    DALI_LOG_ERROR("Invalid buffer!\n");
+    return;
+  }
 
   // Create a temporary buffer for the two-pass blur
   PixelBufferPtr softShadowImageBuffer = PixelBuffer::New(bufferWidth, bufferHeight, Pixel::RGBA8888);
-  memcpy(softShadowImageBuffer->GetBuffer(), buffer.GetBuffer(), 4u * bufferWidth * bufferHeight);
 
   // We perform the blur first but write its output image buffer transposed, so that we
   // can just do it in two passes. The first pass blurs horizontally and transposes, the
   // second pass does the same, but as the image is now transposed, it's really doing a
   // vertical blur. The second transposition makes the image the right way up again. This
   // is much faster than doing a 2D convolution.
-  ConvoluteAndTranspose(buffer.GetBuffer(), softShadowImageBuffer->GetBuffer(), bufferWidth, bufferHeight, blurRadius);
-  ConvoluteAndTranspose(softShadowImageBuffer->GetBuffer(), buffer.GetBuffer(), bufferHeight, bufferWidth, blurRadius);
+  ConvoluteAndTranspose(buffer.GetBuffer(), softShadowImageBuffer->GetBuffer(), bufferWidth, bufferHeight, bufferStride, bufferHeight, blurRadius);
+  ConvoluteAndTranspose(softShadowImageBuffer->GetBuffer(), buffer.GetBuffer(), bufferHeight, bufferWidth, bufferHeight, bufferStride, blurRadius);
 
   // On leaving scope, softShadowImageBuffer will get destroyed.
 }
index a142447..4ca7dd4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -61,6 +61,8 @@ Debug::Filter* gGifLoadingLogFilter = Debug::Filter::New(Debug::NoLogging, false
 const int        IMG_MAX_SIZE                = 65000;
 constexpr size_t MAXIMUM_DOWNLOAD_IMAGE_SIZE = 50 * 1024 * 1024;
 
+constexpr int LOCAL_CACHED_COLOR_GENERATE_THRESHOLD = 64; ///< Generate color map optimize only if colorCount * threshold < width * height, So we don't loop if image is small
+
 #if GIFLIB_MAJOR < 5
 const int DISPOSE_BACKGROUND = 2; /* Set area too background color */
 const int DISPOSE_PREVIOUS   = 3; /* Restore to previous content */
@@ -131,6 +133,15 @@ struct GifAnimationData
   bool                    animated;
 };
 
+struct GifCachedColorData
+{
+  GifCachedColorData() = default;
+
+  // precalculated colormap table
+  std::vector<std::uint32_t> globalCachedColor{};
+  std::vector<std::uint32_t> localCachedColor{};
+};
+
 // Forward declaration
 struct GifAccessor;
 
@@ -187,6 +198,7 @@ struct LoaderInfo
 
   FileData                     fileData;
   GifAnimationData             animated;
+  GifCachedColorData           cachedColor;
   std::unique_ptr<GifAccessor> gifAccessor{nullptr};
   int                          imageNumber{0};
   FileInfo                     fileInfo;
@@ -247,7 +259,7 @@ struct GifAccessor
   {
     LoaderInfo::FileInfo* fi = reinterpret_cast<LoaderInfo::FileInfo*>(gifFileType->UserData);
 
-    if(fi->position >= fi->length)
+    if(DALI_UNLIKELY(fi->position >= fi->length))
     {
       return 0; // if at or past end - no
     }
@@ -281,23 +293,23 @@ bool LoaderInfo::FileData::LoadLocalFile()
 {
   Internal::Platform::FileReader fileReader(fileName);
   FILE*                          fp = fileReader.GetFile();
-  if(fp == NULL)
+  if(DALI_UNLIKELY(fp == NULL))
   {
     return false;
   }
 
-  if(fseek(fp, 0, SEEK_END) <= -1)
+  if(DALI_UNLIKELY(fseek(fp, 0, SEEK_END) <= -1))
   {
     return false;
   }
 
   length = ftell(fp);
-  if(length <= -1)
+  if(DALI_UNLIKELY(length <= -1))
   {
     return false;
   }
 
-  if((!fseek(fp, 0, SEEK_SET)))
+  if(DALI_LIKELY(!fseek(fp, 0, SEEK_SET)))
   {
     globalMap = reinterpret_cast<GifByteType*>(malloc(sizeof(GifByteType) * length));
     length    = fread(globalMap, sizeof(GifByteType), length, fp);
@@ -317,17 +329,17 @@ bool LoaderInfo::FileData::LoadRemoteFile()
   size_t                dataSize;
 
   succeeded = TizenPlatform::Network::DownloadRemoteFileIntoMemory(fileName, dataBuffer, dataSize, MAXIMUM_DOWNLOAD_IMAGE_SIZE);
-  if(succeeded)
+  if(DALI_LIKELY(succeeded))
   {
     size_t blobSize = dataBuffer.Size();
-    if(blobSize > 0U)
+    if(DALI_LIKELY(blobSize > 0U))
     {
       // Open a file handle on the memory buffer:
       Dali::Internal::Platform::FileReader fileReader(dataBuffer, blobSize);
       FILE* const                          fp = fileReader.GetFile();
-      if(NULL != fp)
+      if(DALI_LIKELY(NULL != fp))
       {
-        if((!fseek(fp, 0, SEEK_SET)))
+        if(DALI_LIKELY(!fseek(fp, 0, SEEK_SET)))
         {
           globalMap = reinterpret_cast<GifByteType*>(malloc(sizeof(GifByteType) * blobSize));
           length    = fread(globalMap, sizeof(GifByteType), blobSize, fp);
@@ -353,19 +365,53 @@ bool LoaderInfo::FileData::LoadRemoteFile()
  *
  * @param[in] animated A structure containing GIF animation data
  * @param[in] index Frame index to be searched in GIF
- * @return A pointer to the ImageFrame.
+ * @return single 32-bit (ABGR) value.
  */
-inline int CombinePixelABGR(int a, int r, int g, int b)
+inline std::uint32_t CombinePixelABGR(const std::uint32_t& a, const std::uint32_t& r, const std::uint32_t& g, const std::uint32_t& b)
 {
   return (((a) << 24) + ((b) << 16) + ((g) << 8) + (r));
 }
 
-inline int PixelLookup(ColorMapObject* colorMap, int index)
+inline std::uint32_t PixelLookup(const ColorMapObject* const& colorMap, int index)
 {
   return CombinePixelABGR(0xFF, colorMap->Colors[index].Red, colorMap->Colors[index].Green, colorMap->Colors[index].Blue);
 }
 
 /**
+ * @brief Get the Background Color from frameInfo
+ *
+ * @param[in] gif A pointer pointing to GIF File Type
+ * @param[in] frameInfo A pointer pointing to Frame Information data
+ * @return single 32-bit (ABGR) value. of background color
+ */
+std::uint32_t GetBackgroundColor(GifFileType* gif, FrameInfo* frameInfo)
+{
+  if(frameInfo->transparent < 0)
+  {
+    ColorMapObject* colorMap;
+    int             backGroundColor;
+
+    // work out color to use from colorMap
+    if(gif->Image.ColorMap)
+    {
+      colorMap = gif->Image.ColorMap;
+    }
+    else
+    {
+      colorMap = gif->SColorMap;
+    }
+    backGroundColor = gif->SBackGroundColor;
+    // Get background color from colormap
+    return PixelLookup(colorMap, backGroundColor);
+  }
+  else
+  {
+    // transparent
+    return 0;
+  }
+}
+
+/**
  * @brief Brute force find frame index - gifs are normally small so ok for now.
  *
  * @param[in] animated A structure containing GIF animation data
@@ -388,66 +434,48 @@ ImageFrame* FindFrame(const GifAnimationData& animated, int index)
  * @brief Fill in an image with a specific rgba color value.
  *
  * @param[in] data A pointer pointing to an image data
- * @param[in] row A int containing the number of rows in an image
+ * @param[in] stride A int containing the number of stride in an image
  * @param[in] val A uint32_t containing rgba color value
  * @param[in] x X-coordinate used an offset to calculate pixel position
  * @param[in] y Y-coordinate used an offset to calculate pixel position
  * @param[in] width Width of the image
  * @param[in] height Height of the image
  */
-void FillImage(uint32_t* data, int row, uint32_t val, int x, int y, int width, int height)
+void FillImage(uint32_t* data, int stride, uint32_t val, int x, int y, int width, int height)
 {
-  int       xAxis, yAxis;
   uint32_t* pixelPosition;
 
-  for(yAxis = 0; yAxis < height; yAxis++)
-  {
-    pixelPosition = data + ((y + yAxis) * row) + x;
-    for(xAxis = 0; xAxis < width; xAxis++)
-    {
-      *pixelPosition = val;
-      pixelPosition++;
-    }
-  }
-}
-
-/**
- * @brief Fill a rgba data pixle blob with a frame color (bg or trans)
- *
- * @param[in] data A pointer pointing to an image data
- * @param[in] row A int containing the number of rows in an image
- * @param[in] gif A pointer pointing to GIF File Type
- * @param[in] frameInfo A pointer pointing to Frame Information data
- * @param[in] x X-coordinate used an offset to calculate pixel position
- * @param[in] y Y-coordinate used an offset to calculate pixel position
- * @param[in] width Width of the image
- * @param[in] height Height of the image
- */
-void FillFrame(uint32_t* data, int row, GifFileType* gif, FrameInfo* frameInfo, int x, int y, int w, int h)
-{
-  // solid color fill for pre frame region
-  if(frameInfo->transparent < 0)
+  // Boost time if stride == width and x == 0. We can assume that all pointer is continuous.
+  if(x == 0 && stride == width)
   {
-    ColorMapObject* colorMap;
-    int             backGroundColor;
-
-    // work out color to use from colorMap
-    if(gif->Image.ColorMap)
+    pixelPosition = data + (y * stride);
+    // Clear as white or transparent
+    // Special case. we can use memset.
+    if(val == 0x00 || val == 0xffffffffu)
     {
-      colorMap = gif->Image.ColorMap;
+      const std::int8_t setupVal = val & 0xff;
+      memset(pixelPosition, setupVal, width * height * sizeof(std::uint32_t));
     }
     else
     {
-      colorMap = gif->SColorMap;
+      for(int byteCount = 0; byteCount < width * height; ++byteCount)
+      {
+        *pixelPosition = val;
+        ++pixelPosition;
+      }
     }
-    backGroundColor = gif->SBackGroundColor;
-    // and do the fill
-    FillImage(data, row, CombinePixelABGR(0xff, colorMap->Colors[backGroundColor].Red, colorMap->Colors[backGroundColor].Green, colorMap->Colors[backGroundColor].Blue), x, y, w, h);
   }
-  // fill in region with 0 (transparent)
   else
   {
-    FillImage(data, row, 0, x, y, w, h);
+    for(int yAxis = 0; yAxis < height; ++yAxis)
+    {
+      pixelPosition = data + ((y + yAxis) * stride) + x;
+      for(int xAxis = 0; xAxis < width; ++xAxis)
+      {
+        *pixelPosition = val;
+        ++pixelPosition;
+      }
+    }
   }
 }
 
@@ -617,7 +645,7 @@ FrameInfo* NewFrame(GifAnimationData& animated, int transparent, int dispose, in
  * @brief Decode a gif image into rows then expand to 32bit into the destination
  * data pointer.
  */
-bool DecodeImage(GifFileType* gif, uint32_t* data, int rowpix, int xin, int yin, int transparent, int x, int y, int w, int h, bool fill)
+bool DecodeImage(GifFileType* gif, GifCachedColorData& gifCachedColor, uint32_t* data, int rowpix, int xin, int yin, int transparent, int x, int y, int w, int h, bool fill, uint32_t fillColor = 0u)
 {
   int             intoffset[] = {0, 4, 2, 1};
   int             intjump[]   = {8, 8, 4, 2};
@@ -627,6 +655,9 @@ bool DecodeImage(GifFileType* gif, uint32_t* data, int rowpix, int xin, int yin,
   ColorMapObject* colorMap;
   uint32_t*       p;
 
+  // cached color data.
+  const std::uint32_t* cachedColorPtr = nullptr;
+
   // what we need is image size.
   SavedImage* sp;
   sp = &gif->SavedImages[gif->ImageCount - 1];
@@ -634,7 +665,7 @@ bool DecodeImage(GifFileType* gif, uint32_t* data, int rowpix, int xin, int yin,
   gifW = sp->ImageDesc.Width;
   gifH = sp->ImageDesc.Height;
 
-  if((gifW < w) || (gifH < h))
+  if(DALI_UNLIKELY((gifW < w) || (gifH < h)))
   {
     DALI_LOG_ERROR("gifW : %d, w : %d, gifH : %d, h : %d\n", gifW, w, gifH, h);
     DALI_ASSERT_DEBUG(false && "Dimensions are bigger than the Gif image size");
@@ -644,7 +675,7 @@ bool DecodeImage(GifFileType* gif, uint32_t* data, int rowpix, int xin, int yin,
   // build a blob of memory to have pointers to rows of pixels
   // AND store the decoded gif pixels (1 byte per pixel) as welll
   rows = static_cast<GifRowType*>(malloc((gifH * sizeof(GifRowType)) + (gifW * gifH * sizeof(GifPixelType))));
-  if(!rows)
+  if(DALI_UNLIKELY(!rows))
   {
     goto on_error;
   }
@@ -662,7 +693,7 @@ bool DecodeImage(GifFileType* gif, uint32_t* data, int rowpix, int xin, int yin,
     {
       for(yy = intoffset[i]; yy < gifH; yy += intjump[i])
       {
-        if(DGifGetLine(gif, rows[yy], gifW) != GIF_OK)
+        if(DALI_UNLIKELY(DGifGetLine(gif, rows[yy], gifW) != GIF_OK))
         {
           goto on_error;
         }
@@ -674,7 +705,7 @@ bool DecodeImage(GifFileType* gif, uint32_t* data, int rowpix, int xin, int yin,
   {
     for(yy = 0; yy < gifH; yy++)
     {
-      if(DGifGetLine(gif, rows[yy], gifW) != GIF_OK)
+      if(DALI_UNLIKELY(DGifGetLine(gif, rows[yy], gifW) != GIF_OK))
       {
         goto on_error;
       }
@@ -685,65 +716,143 @@ bool DecodeImage(GifFileType* gif, uint32_t* data, int rowpix, int xin, int yin,
   if(gif->Image.ColorMap)
   {
     colorMap = gif->Image.ColorMap;
+    // if w * h is big enough, generate local cached color.
+    if(colorMap->ColorCount * LOCAL_CACHED_COLOR_GENERATE_THRESHOLD < w * h)
+    {
+      gifCachedColor.localCachedColor.resize(colorMap->ColorCount);
+      for(i = 0; i < colorMap->ColorCount; ++i)
+      {
+        gifCachedColor.localCachedColor[i] = PixelLookup(colorMap, i);
+      }
+
+      cachedColorPtr = gifCachedColor.localCachedColor.data();
+    }
   }
   else
   {
-    colorMap = gif->SColorMap;
+    colorMap       = gif->SColorMap;
+    cachedColorPtr = gifCachedColor.globalCachedColor.data();
   }
 
+  // HARD-CODING optimize
   // if we need to deal with transparent pixels at all...
   if(transparent >= 0)
   {
     // if we are told to FILL (overwrite with transparency kept)
     if(fill)
     {
-      for(yy = 0; yy < h; yy++)
+      // if we use cachedColor, use it
+      if(cachedColorPtr)
       {
-        p = data + ((y + yy) * rowpix) + x;
-        for(xx = 0; xx < w; xx++)
+        for(yy = 0; yy < h; yy++)
         {
-          pix = rows[yin + yy][xin + xx];
-          if(pix != transparent)
+          p = data + ((y + yy) * rowpix) + x;
+          for(xx = 0; xx < w; xx++)
           {
-            *p = PixelLookup(colorMap, pix);
+            pix = rows[yin + yy][xin + xx];
+            if(pix != transparent)
+            {
+              *p = cachedColorPtr[pix];
+            }
+            else
+            {
+              *p = fillColor;
+            }
+            p++;
           }
-          else
+        }
+      }
+      // we don't have cachedColor. use PixelLookup function.
+      else
+      {
+        for(yy = 0; yy < h; yy++)
+        {
+          p = data + ((y + yy) * rowpix) + x;
+          for(xx = 0; xx < w; xx++)
           {
-            *p = 0;
+            pix = rows[yin + yy][xin + xx];
+            if(pix != transparent)
+            {
+              *p = PixelLookup(colorMap, pix);
+            }
+            else
+            {
+              *p = fillColor;
+            }
+            p++;
           }
-          p++;
         }
       }
     }
     // paste on top with transparent pixels untouched
     else
     {
-      for(yy = 0; yy < h; yy++)
+      // if we use cachedColor, use it
+      if(cachedColorPtr)
       {
-        p = data + ((y + yy) * rowpix) + x;
-        for(xx = 0; xx < w; xx++)
+        for(yy = 0; yy < h; yy++)
         {
-          pix = rows[yin + yy][xin + xx];
-          if(pix != transparent)
+          p = data + ((y + yy) * rowpix) + x;
+          for(xx = 0; xx < w; xx++)
           {
-            *p = PixelLookup(colorMap, pix);
+            pix = rows[yin + yy][xin + xx];
+            if(pix != transparent)
+            {
+              *p = cachedColorPtr[pix];
+            }
+            p++;
+          }
+        }
+      }
+      // we don't have cachedColor. use PixelLookup function.
+      else
+      {
+        for(yy = 0; yy < h; yy++)
+        {
+          p = data + ((y + yy) * rowpix) + x;
+          for(xx = 0; xx < w; xx++)
+          {
+            pix = rows[yin + yy][xin + xx];
+            if(pix != transparent)
+            {
+              *p = PixelLookup(colorMap, pix);
+            }
+            p++;
           }
-          p++;
         }
       }
     }
   }
   else
   {
-    // walk pixels without worring about transparency at all
-    for(yy = 0; yy < h; yy++)
+    // if we use cachedColor, use it
+    if(cachedColorPtr)
+    {
+      // walk pixels without worring about transparency at all
+      for(yy = 0; yy < h; yy++)
+      {
+        p = data + ((y + yy) * rowpix) + x;
+        for(xx = 0; xx < w; xx++)
+        {
+          pix = rows[yin + yy][xin + xx];
+          *p  = cachedColorPtr[pix];
+          p++;
+        }
+      }
+    }
+    // we don't have cachedColor. use PixelLookup function.
+    else
     {
-      p = data + ((y + yy) * rowpix) + x;
-      for(xx = 0; xx < w; xx++)
+      // walk pixels without worring about transparency at all
+      for(yy = 0; yy < h; yy++)
       {
-        pix = rows[yin + yy][xin + xx];
-        *p  = PixelLookup(colorMap, pix);
-        p++;
+        p = data + ((y + yy) * rowpix) + x;
+        for(xx = 0; xx < w; xx++)
+        {
+          pix = rows[yin + yy][xin + xx];
+          *p  = PixelLookup(colorMap, pix);
+          p++;
+        }
       }
     }
   }
@@ -762,16 +871,15 @@ on_error:
  *
  * @param[in] loaderInfo A LoaderInfo structure containing file descriptor and other data about GIF.
  * @param[out] prop A ImageProperties structure for storing information about GIF data.
- * @param[out] error Error code
  * @return The true or false whether reading was successful or not.
  */
 bool ReadHeader(LoaderInfo&      loaderInfo,
-                ImageProperties& prop, //output struct
-                int*             error)
+                ImageProperties& prop)
 {
-  GifAnimationData&     animated = loaderInfo.animated;
-  LoaderInfo::FileData& fileData = loaderInfo.fileData;
-  bool                  success  = false;
+  GifAnimationData&     animated    = loaderInfo.animated;
+  GifCachedColorData&   cachedColor = loaderInfo.cachedColor;
+  LoaderInfo::FileData& fileData    = loaderInfo.fileData;
+  bool                  success     = false;
   LoaderInfo::FileInfo  fileInfo;
   GifRecordType         rec;
 
@@ -783,7 +891,7 @@ bool ReadHeader(LoaderInfo&      loaderInfo,
   bool       full        = true;
 
   success = fileData.LoadFile();
-  if(!success || !fileData.globalMap)
+  if(DALI_UNLIKELY(!success || !fileData.globalMap))
   {
     success = false;
     DALI_LOG_ERROR("LOAD_ERROR_CORRUPT_FILE\n");
@@ -802,7 +910,7 @@ bool ReadHeader(LoaderInfo&      loaderInfo,
       prop.h = gifAccessor.gif->SHeight;
 
       // if size is invalid - abort here
-      if((prop.w < 1) || (prop.h < 1) || (prop.w > IMG_MAX_SIZE) || (prop.h > IMG_MAX_SIZE) || IMG_TOO_BIG(prop.w, prop.h))
+      if(DALI_UNLIKELY((prop.w < 1) || (prop.h < 1) || (prop.w > IMG_MAX_SIZE) || (prop.h > IMG_MAX_SIZE) || IMG_TOO_BIG(prop.w, prop.h)))
       {
         if(IMG_TOO_BIG(prop.w, prop.h))
         {
@@ -844,14 +952,14 @@ bool ReadHeader(LoaderInfo&      loaderInfo,
             GifByteType* img;
 
             // get image desc
-            if(DGifGetImageDesc(gifAccessor.gif) == GIF_ERROR)
+            if(DALI_UNLIKELY(DGifGetImageDesc(gifAccessor.gif) == GIF_ERROR))
             {
               success = false;
               DALI_LOG_ERROR("LOAD_ERROR_UNKNOWN_FORMAT\n");
               break;
             }
             // skip decoding and just walk image to next
-            if(DGifGetCode(gifAccessor.gif, &img_code, &img) == GIF_ERROR)
+            if(DALI_UNLIKELY(DGifGetCode(gifAccessor.gif, &img_code, &img) == GIF_ERROR))
             {
               success = false;
               DALI_LOG_ERROR("LOAD_ERROR_UNKNOWN_FORMAT\n");
@@ -874,7 +982,7 @@ bool ReadHeader(LoaderInfo&      loaderInfo,
             {
               // allocate and save frame with field data
               frameInfo = NewFrame(animated, -1, 0, 0, imageNumber + 1);
-              if(!frameInfo)
+              if(DALI_UNLIKELY(!frameInfo))
               {
                 success = false;
                 DALI_LOG_ERROR("LOAD_ERROR_RESOURCE_ALLOCATION_FAILED");
@@ -906,7 +1014,7 @@ bool ReadHeader(LoaderInfo&      loaderInfo,
                 int disposeMode       = (ext[1] >> 2) & 0x7;
                 int delay             = (int(ext[3]) << 8) | int(ext[2]);
                 frameInfo             = NewFrame(animated, transparencyIndex, disposeMode, delay, imageNumber + 1);
-                if(!frameInfo)
+                if(DALI_UNLIKELY(!frameInfo))
                 {
                   success = false;
                   DALI_LOG_ERROR("LOAD_ERROR_RESOURCE_ALLOCATION_FAILED");
@@ -957,8 +1065,16 @@ bool ReadHeader(LoaderInfo&      loaderInfo,
 
           animated.currentFrame = 1;
 
-          // no errors in header scan etc. so set err and return value
-          *error = 0;
+          // cache global color map
+          ColorMapObject* colorMap = gifAccessor.gif->SColorMap;
+          if(colorMap)
+          {
+            cachedColor.globalCachedColor.resize(colorMap->ColorCount);
+            for(int i = 0; i < colorMap->ColorCount; ++i)
+            {
+              cachedColor.globalCachedColor[i] = PixelLookup(colorMap, i);
+            }
+          }
         }
       }
     }
@@ -991,7 +1107,7 @@ bool ReadNextFrame(LoaderInfo& loaderInfo, ImageProperties& prop, //  use for w
   index = animated.currentFrame;
 
   // if index is invalid for animated image - error out
-  if((animated.animated) && ((index <= 0) || (index > animated.frameCount)))
+  if(DALI_UNLIKELY((animated.animated) && ((index <= 0) || (index > animated.frameCount))))
   {
     DALI_LOG_ERROR("LOAD_ERROR_GENERIC");
     return false;
@@ -999,7 +1115,7 @@ bool ReadNextFrame(LoaderInfo& loaderInfo, ImageProperties& prop, //  use for w
 
   // find the given frame index
   frame = FindFrame(animated, index);
-  if(!frame)
+  if(DALI_UNLIKELY(!frame))
   {
     DALI_LOG_ERROR("LOAD_ERROR_CORRUPT_FILE\n");
     return false;
@@ -1024,13 +1140,13 @@ bool ReadNextFrame(LoaderInfo& loaderInfo, ImageProperties& prop, //  use for w
       loaderInfo.fileInfo.map      = fileData.globalMap;
       loaderInfo.fileInfo.length   = fileData.length;
       loaderInfo.fileInfo.position = 0;
-      if(!loaderInfo.fileInfo.map)
+      if(DALI_UNLIKELY(!loaderInfo.fileInfo.map))
       {
         DALI_LOG_ERROR("LOAD_ERROR_CORRUPT_FILE\n");
         return false;
       }
       std::unique_ptr<GifAccessor> gifAccessor = std::make_unique<GifAccessor>(loaderInfo.fileInfo);
-      if(!gifAccessor->gif)
+      if(DALI_UNLIKELY(!gifAccessor->gif))
       {
         DALI_LOG_ERROR("LOAD_ERROR_UNKNOWN_FORMAT\n");
         return false;
@@ -1045,7 +1161,7 @@ bool ReadNextFrame(LoaderInfo& loaderInfo, ImageProperties& prop, //  use for w
     // walk through gif records in file to figure out info
     do
     {
-      if(DGifGetRecordType(loaderInfo.gifAccessor->gif, &rec) == GIF_ERROR)
+      if(DALI_UNLIKELY(DGifGetRecordType(loaderInfo.gifAccessor->gif, &rec) == GIF_ERROR))
       {
         DALI_LOG_ERROR("LOAD_ERROR_UNKNOWN_FORMAT\n");
         return false;
@@ -1073,7 +1189,7 @@ bool ReadNextFrame(LoaderInfo& loaderInfo, ImageProperties& prop, //  use for w
         ImageFrame*  thisFrame     = NULL;
 
         // get image desc
-        if(DGifGetImageDesc(loaderInfo.gifAccessor->gif) == GIF_ERROR)
+        if(DALI_UNLIKELY(DGifGetImageDesc(loaderInfo.gifAccessor->gif) == GIF_ERROR))
         {
           DALI_LOG_ERROR("LOAD_ERROR_UNKNOWN_FORMAT\n");
           return false;
@@ -1091,18 +1207,36 @@ bool ReadNextFrame(LoaderInfo& loaderInfo, ImageProperties& prop, //  use for w
           // allocate it
           thisFrame->data = new uint32_t[prop.w * prop.h];
 
-          if(!thisFrame->data)
+          if(DALI_UNLIKELY(!thisFrame->data))
           {
             DALI_LOG_ERROR("LOAD_ERROR_RESOURCE_ALLOCATION_FAILED");
             return false;
           }
 
+          // Lazy fill background color feature.
+          // DecodeImage function draw range is EQUAL with previous FillImage range,
+          // We don't need to fill background that time.
+          // It will try to reduce the number of FillImage API call
+          // Note : We might check overlapping. But that operation looks expensive
+          // So, just optimize only if EQUAL case.
+          bool     updateBackgroundColorLazy = false;
+          uint32_t backgroundColor           = 0u;
+          int      prevX                     = 0;
+          int      prevY                     = 0;
+          int      prevW                     = 0;
+          int      prevH                     = 0;
+
           // if we have no prior frame OR prior frame data... empty
           if((!previousFrame) || (!previousFrame->data))
           {
-            first     = true;
-            frameInfo = &(thisFrame->info);
-            memset(thisFrame->data, 0, prop.w * prop.h * sizeof(uint32_t));
+            first                     = true;
+            frameInfo                 = &(thisFrame->info);
+            updateBackgroundColorLazy = true;
+            backgroundColor           = 0u;
+            prevX                     = 0;
+            prevY                     = 0;
+            prevW                     = prop.w;
+            prevH                     = prop.h;
           }
           // we have a prior frame to copy data from...
           else
@@ -1121,7 +1255,12 @@ bool ReadNextFrame(LoaderInfo& loaderInfo, ImageProperties& prop, //  use for w
             // if dispose mode is "background" then fill with bg
             if(frameInfo->dispose == DISPOSE_BACKGROUND)
             {
-              FillFrame(thisFrame->data, prop.w, loaderInfo.gifAccessor->gif, frameInfo, x, y, w, h);
+              updateBackgroundColorLazy = true;
+              backgroundColor           = GetBackgroundColor(loaderInfo.gifAccessor->gif, frameInfo);
+              prevX                     = x;
+              prevY                     = y;
+              prevW                     = w;
+              prevH                     = h;
             }
             else if(frameInfo->dispose == DISPOSE_PREVIOUS) // GIF_DISPOSE_RESTORE
             {
@@ -1130,7 +1269,7 @@ bool ReadNextFrame(LoaderInfo& loaderInfo, ImageProperties& prop, //  use for w
               {
                 // Find last preserved frame.
                 lastPreservedFrame = FindFrame(animated, imageNumber - prevIndex);
-                if(!lastPreservedFrame)
+                if(DALI_UNLIKELY(!lastPreservedFrame))
                 {
                   DALI_LOG_ERROR("LOAD_ERROR_LAST_PRESERVED_FRAME_NOT_FOUND");
                   return false;
@@ -1147,7 +1286,18 @@ bool ReadNextFrame(LoaderInfo& loaderInfo, ImageProperties& prop, //  use for w
           // now draw this frame on top
           frameInfo = &(thisFrame->info);
           ClipCoordinates(prop.w, prop.h, &xin, &yin, frameInfo->x, frameInfo->y, frameInfo->w, frameInfo->h, &x, &y, &w, &h);
-          if(!DecodeImage(loaderInfo.gifAccessor->gif, thisFrame->data, prop.w, xin, yin, frameInfo->transparent, x, y, w, h, first))
+
+          if(updateBackgroundColorLazy)
+          {
+            // If this frame's x,y,w,h is not equal with previous x,y,w,h, FillImage. else, don't fill
+            if(prevX != x || prevY != y || prevW != w || prevH != h)
+            {
+              FillImage(thisFrame->data, prop.w, backgroundColor, prevX, prevY, prevW, prevH);
+              // Don't send background color information to DecodeImage function.
+              updateBackgroundColorLazy = false;
+            }
+          }
+          if(DALI_UNLIKELY(!DecodeImage(loaderInfo.gifAccessor->gif, loaderInfo.cachedColor, thisFrame->data, prop.w, xin, yin, frameInfo->transparent, x, y, w, h, first || updateBackgroundColorLazy, backgroundColor)))
           {
             DALI_LOG_ERROR("LOAD_ERROR_CORRUPT_FILE\n");
             return false;
@@ -1169,11 +1319,15 @@ bool ReadNextFrame(LoaderInfo& loaderInfo, ImageProperties& prop, //  use for w
             frameInfo = &(thisFrame->info);
             ClipCoordinates(prop.w, prop.h, &xin, &yin, frameInfo->x, frameInfo->y, frameInfo->w, frameInfo->h, &x, &y, &w, &h);
 
-            // clear out all pixels
-            FillFrame(reinterpret_cast<uint32_t*>(pixels), prop.w, loaderInfo.gifAccessor->gif, frameInfo, 0, 0, prop.w, prop.h);
+            // clear out all pixels only if x,y,w,h is not whole image.
+            if(x != 0 || y != 0 || w != static_cast<int>(prop.w) || h != static_cast<int>(prop.h))
+            {
+              const std::uint32_t backgroundColor = GetBackgroundColor(loaderInfo.gifAccessor->gif, frameInfo);
+              FillImage(reinterpret_cast<uint32_t*>(pixels), prop.w, backgroundColor, 0, 0, prop.w, prop.h);
+            }
 
             // and decode the gif with overwriting
-            if(!DecodeImage(loaderInfo.gifAccessor->gif, reinterpret_cast<uint32_t*>(pixels), prop.w, xin, yin, frameInfo->transparent, x, y, w, h, true))
+            if(DALI_UNLIKELY(!DecodeImage(loaderInfo.gifAccessor->gif, loaderInfo.cachedColor, reinterpret_cast<uint32_t*>(pixels), prop.w, xin, yin, frameInfo->transparent, x, y, w, h, true, 0u)))
             {
               DALI_LOG_ERROR("LOAD_ERROR_CORRUPT_FILE\n");
               return false;
@@ -1187,7 +1341,7 @@ bool ReadNextFrame(LoaderInfo& loaderInfo, ImageProperties& prop, //  use for w
         else
         {
           // skip decoding and just walk image to next
-          if(DGifGetCode(loaderInfo.gifAccessor->gif, &img_code, &img) == GIF_ERROR)
+          if(DALI_UNLIKELY(DGifGetCode(loaderInfo.gifAccessor->gif, &img_code, &img) == GIF_ERROR))
           {
             DALI_LOG_ERROR("LOAD_ERROR_UNKNOWN_FORMAT\n");
             return false;
@@ -1239,15 +1393,25 @@ struct GifLoading::Impl
 public:
   Impl(const std::string& url, bool isLocalResource)
   : mUrl(url),
-    mLoadSucceeded(true),
+    mLoadSucceeded(false),
     mMutex()
   {
     loaderInfo.gifAccessor = nullptr;
-    int error;
     loaderInfo.fileData.fileName        = mUrl.c_str();
     loaderInfo.fileData.isLocalResource = isLocalResource;
+  }
 
-    mLoadSucceeded = ReadHeader(loaderInfo, imageProperties, &error);
+  bool LoadGifInformation()
+  {
+    // Block to do not load this file again.
+    Mutex::ScopedLock lock(mMutex);
+    if(DALI_LIKELY(mLoadSucceeded))
+    {
+      return mLoadSucceeded;
+    }
+
+    mLoadSucceeded = ReadHeader(loaderInfo, imageProperties);
+    return mLoadSucceeded;
   }
 
   // Moveable but not copyable
@@ -1278,52 +1442,20 @@ GifLoading::~GifLoading()
   delete mImpl;
 }
 
-bool GifLoading::LoadNextNFrames(uint32_t frameStartIndex, int count, std::vector<Dali::PixelData>& pixelData)
-{
-  int  error;
-  bool ret = false;
-
-  Mutex::ScopedLock lock(mImpl->mMutex);
-  if(!mImpl->mLoadSucceeded)
-  {
-    return false;
-  }
-
-  const int bufferSize = mImpl->imageProperties.w * mImpl->imageProperties.h * sizeof(uint32_t);
-
-  DALI_LOG_INFO(gGifLoadingLogFilter, Debug::Concise, "LoadNextNFrames( frameStartIndex:%d, count:%d )\n", frameStartIndex, count);
-
-  for(int i = 0; i < count; ++i)
-  {
-    auto pixelBuffer = new unsigned char[bufferSize];
-
-    mImpl->loaderInfo.animated.currentFrame = 1 + ((frameStartIndex + i) % mImpl->loaderInfo.animated.frameCount);
-
-    if(ReadNextFrame(mImpl->loaderInfo, mImpl->imageProperties, pixelBuffer, &error))
-    {
-      if(pixelBuffer)
-      {
-        pixelData.push_back(Dali::PixelData::New(pixelBuffer, bufferSize, mImpl->imageProperties.w, mImpl->imageProperties.h, Dali::Pixel::RGBA8888, Dali::PixelData::DELETE_ARRAY));
-        ret = true;
-      }
-    }
-  }
-
-  return ret;
-}
-
 Dali::Devel::PixelBuffer GifLoading::LoadFrame(uint32_t frameIndex)
 {
   int                      error;
   Dali::Devel::PixelBuffer pixelBuffer;
-  if(!mImpl->mLoadSucceeded)
+
+  DALI_LOG_INFO(gGifLoadingLogFilter, Debug::Concise, "LoadFrame( frameIndex:%d )\n", frameIndex);
+
+  // If Gif file is still not loaded, Load the information.
+  if(DALI_UNLIKELY(!mImpl->LoadGifInformation()))
   {
     return pixelBuffer;
   }
 
   Mutex::ScopedLock lock(mImpl->mMutex);
-  DALI_LOG_INFO(gGifLoadingLogFilter, Debug::Concise, "LoadFrame( frameIndex:%d )\n", frameIndex);
-
   pixelBuffer = Dali::Devel::PixelBuffer::New(mImpl->imageProperties.w, mImpl->imageProperties.h, Dali::Pixel::RGBA8888);
 
   mImpl->loaderInfo.animated.currentFrame = 1 + (frameIndex % mImpl->loaderInfo.animated.frameCount);
@@ -1338,17 +1470,35 @@ Dali::Devel::PixelBuffer GifLoading::LoadFrame(uint32_t frameIndex)
 
 ImageDimensions GifLoading::GetImageSize() const
 {
+  if(DALI_UNLIKELY(!mImpl->mLoadSucceeded))
+  {
+    mImpl->LoadGifInformation();
+  }
   return ImageDimensions(mImpl->imageProperties.w, mImpl->imageProperties.h);
 }
 
 uint32_t GifLoading::GetImageCount() const
 {
+  if(DALI_UNLIKELY(!mImpl->mLoadSucceeded))
+  {
+    mImpl->LoadGifInformation();
+  }
   return mImpl->loaderInfo.animated.frameCount;
 }
 
 uint32_t GifLoading::GetFrameInterval(uint32_t frameIndex) const
 {
-  return mImpl->loaderInfo.animated.frames[frameIndex].info.delay * 10;
+  if(DALI_UNLIKELY(!mImpl->mLoadSucceeded))
+  {
+    mImpl->LoadGifInformation();
+  }
+
+  uint32_t interval = 0u;
+  if(DALI_LIKELY(mImpl->mLoadSucceeded))
+  {
+    interval = mImpl->loaderInfo.animated.frames[frameIndex].info.delay * 10;
+  }
+  return interval;
 }
 
 std::string GifLoading::GetUrl() const
index 6797938..2de8ead 100644 (file)
@@ -68,18 +68,6 @@ public:
   ~GifLoading() override;
 
   /**
-   * @brief Load the next N Frames of the gif.
-   *
-   * @note This function will load the entire gif into memory if not already loaded.
-   * @param[in] frameStartIndex The frame counter to start from. Will usually be the next frame
-   * after the previous invocation of this method, or 0 to start.
-   * @param[in] count The number of frames to load
-   * @param[out] pixelData The vector in which to return the frame data
-   * @return True if the frame data was successfully loaded
-   */
-  bool LoadNextNFrames(uint32_t frameStartIndex, int count, std::vector<Dali::PixelData>& pixelData) override;
-
-  /**
    * @brief Load the next Frame of the animated image.
    *
    * @note This function will load the entire animated image into memory if not already loaded.
index 8c7139d..9f9db11 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -80,15 +80,15 @@ enum FileFormats
 // clang-format off
 const Dali::ImageLoader::BitmapLoader BITMAP_LOADER_LOOKUP_TABLE[FORMAT_TOTAL_COUNT] =
   {
-    {Png::MAGIC_BYTE_1,  Png::MAGIC_BYTE_2,  LoadBitmapFromPng,  LoadPngHeader,  Bitmap::BITMAP_2D_PACKED_PIXELS},
-    {Jpeg::MAGIC_BYTE_1, Jpeg::MAGIC_BYTE_2, LoadBitmapFromJpeg, LoadJpegHeader, Bitmap::BITMAP_2D_PACKED_PIXELS},
-    {Bmp::MAGIC_BYTE_1,  Bmp::MAGIC_BYTE_2,  LoadBitmapFromBmp,  LoadBmpHeader,  Bitmap::BITMAP_2D_PACKED_PIXELS},
-    {Gif::MAGIC_BYTE_1,  Gif::MAGIC_BYTE_2,  LoadBitmapFromGif,  LoadGifHeader,  Bitmap::BITMAP_2D_PACKED_PIXELS},
-    {Webp::MAGIC_BYTE_1, Webp::MAGIC_BYTE_2, LoadBitmapFromWebp, LoadWebpHeader, Bitmap::BITMAP_2D_PACKED_PIXELS},
-    {Ktx::MAGIC_BYTE_1,  Ktx::MAGIC_BYTE_2,  LoadBitmapFromKtx,  LoadKtxHeader,  Bitmap::BITMAP_COMPRESSED      },
-    {Astc::MAGIC_BYTE_1, Astc::MAGIC_BYTE_2, LoadBitmapFromAstc, LoadAstcHeader, Bitmap::BITMAP_COMPRESSED      },
-    {Ico::MAGIC_BYTE_1,  Ico::MAGIC_BYTE_2,  LoadBitmapFromIco,  LoadIcoHeader,  Bitmap::BITMAP_2D_PACKED_PIXELS},
-    {0x0,                0x0,                LoadBitmapFromWbmp, LoadWbmpHeader, Bitmap::BITMAP_2D_PACKED_PIXELS},
+    {Png::MAGIC_BYTE_1,  Png::MAGIC_BYTE_2,  LoadBitmapFromPng,  nullptr, LoadPngHeader,  Bitmap::BITMAP_2D_PACKED_PIXELS},
+    {Jpeg::MAGIC_BYTE_1, Jpeg::MAGIC_BYTE_2, LoadBitmapFromJpeg, LoadPlanesFromJpeg, LoadJpegHeader, Bitmap::BITMAP_2D_PACKED_PIXELS},
+    {Bmp::MAGIC_BYTE_1,  Bmp::MAGIC_BYTE_2,  LoadBitmapFromBmp,  nullptr, LoadBmpHeader,  Bitmap::BITMAP_2D_PACKED_PIXELS},
+    {Gif::MAGIC_BYTE_1,  Gif::MAGIC_BYTE_2,  LoadBitmapFromGif,  nullptr, LoadGifHeader,  Bitmap::BITMAP_2D_PACKED_PIXELS},
+    {Webp::MAGIC_BYTE_1, Webp::MAGIC_BYTE_2, LoadBitmapFromWebp, nullptr, LoadWebpHeader, Bitmap::BITMAP_2D_PACKED_PIXELS},
+    {Ktx::MAGIC_BYTE_1,  Ktx::MAGIC_BYTE_2,  LoadBitmapFromKtx,  nullptr, LoadKtxHeader,  Bitmap::BITMAP_COMPRESSED      },
+    {Astc::MAGIC_BYTE_1, Astc::MAGIC_BYTE_2, LoadBitmapFromAstc, nullptr, LoadAstcHeader, Bitmap::BITMAP_COMPRESSED      },
+    {Ico::MAGIC_BYTE_1,  Ico::MAGIC_BYTE_2,  LoadBitmapFromIco,  nullptr, LoadIcoHeader,  Bitmap::BITMAP_2D_PACKED_PIXELS},
+    {0x0,                0x0,                LoadBitmapFromWbmp, nullptr, LoadWbmpHeader, Bitmap::BITMAP_2D_PACKED_PIXELS},
   };
 // clang-format on
 
@@ -151,6 +151,7 @@ FileFormats GetFormatHint(const std::string& filename)
 bool GetBitmapLoaderFunctions(FILE*                                        fp,
                               FileFormats                                  format,
                               Dali::ImageLoader::LoadBitmapFunction&       loader,
+                              Dali::ImageLoader::LoadPlanesFunction&       planeLoader,
                               Dali::ImageLoader::LoadBitmapHeaderFunction& header,
                               Bitmap::Profile&                             profile,
                               const std::string&                           filename)
@@ -238,9 +239,10 @@ bool GetBitmapLoaderFunctions(FILE*                                        fp,
   // if a loader was found set the outputs
   if(loaderFound)
   {
-    loader  = lookupPtr->loader;
-    header  = lookupPtr->header;
-    profile = lookupPtr->profile;
+    loader      = lookupPtr->loader;
+    planeLoader = lookupPtr->planeLoader;
+    header      = lookupPtr->header;
+    profile     = lookupPtr->profile;
   }
 
   // Reset to the start of the file.
@@ -256,7 +258,7 @@ bool GetBitmapLoaderFunctions(FILE*                                        fp,
 
 namespace ImageLoader
 {
-bool ConvertStreamToBitmap(const BitmapResourceType& resource, std::string path, FILE* const fp, Dali::Devel::PixelBuffer& pixelBuffer)
+bool ConvertStreamToBitmap(const BitmapResourceType& resource, const std::string& path, FILE* const fp, Dali::Devel::PixelBuffer& pixelBuffer)
 {
   DALI_LOG_TRACE_METHOD(gLogFilter);
 
@@ -265,6 +267,7 @@ bool ConvertStreamToBitmap(const BitmapResourceType& resource, std::string path,
   if(fp != NULL)
   {
     Dali::ImageLoader::LoadBitmapFunction       function;
+    Dali::ImageLoader::LoadPlanesFunction       planeLoader;
     Dali::ImageLoader::LoadBitmapHeaderFunction header;
 
     Bitmap::Profile profile;
@@ -272,6 +275,7 @@ bool ConvertStreamToBitmap(const BitmapResourceType& resource, std::string path,
     if(GetBitmapLoaderFunctions(fp,
                                 GetFormatHint(path),
                                 function,
+                                planeLoader,
                                 header,
                                 profile,
                                 path))
@@ -299,6 +303,73 @@ bool ConvertStreamToBitmap(const BitmapResourceType& resource, std::string path,
   return result;
 }
 
+bool ConvertStreamToPlanes(const Integration::BitmapResourceType& resource, const std::string& path, FILE* const fp, std::vector<Dali::Devel::PixelBuffer>& pixelBuffers)
+{
+  DALI_LOG_TRACE_METHOD(gLogFilter);
+
+  bool result = false;
+
+  if(fp != NULL)
+  {
+    Dali::ImageLoader::LoadBitmapFunction       loader;
+    Dali::ImageLoader::LoadPlanesFunction       planeLoader;
+    Dali::ImageLoader::LoadBitmapHeaderFunction header;
+
+    Bitmap::Profile profile;
+
+    if(GetBitmapLoaderFunctions(fp,
+                                GetFormatHint(path),
+                                loader,
+                                planeLoader,
+                                header,
+                                profile,
+                                path))
+    {
+      const Dali::ImageLoader::ScalingParameters scalingParameters(resource.size, resource.scalingMode, resource.samplingMode);
+      const Dali::ImageLoader::Input             input(fp, scalingParameters, resource.orientationCorrection);
+
+      pixelBuffers.clear();
+
+      // Run the image type decoder:
+      if(planeLoader)
+      {
+        result = planeLoader(input, pixelBuffers);
+        if(!result)
+        {
+          DALI_LOG_ERROR("Unable to convert %s\n", path.c_str());
+        }
+      }
+      else
+      {
+        Dali::Devel::PixelBuffer pixelBuffer;
+        result = loader(input, pixelBuffer);
+        if(!result)
+        {
+          DALI_LOG_ERROR("Unable to convert %s\n", path.c_str());
+          return false;
+        }
+
+        pixelBuffer = Internal::Platform::ApplyAttributesToBitmap(pixelBuffer, resource.size, resource.scalingMode, resource.samplingMode);
+        if(pixelBuffer)
+        {
+          pixelBuffers.push_back(pixelBuffer);
+        }
+        else
+        {
+          DALI_LOG_ERROR("ApplyAttributesToBitmap is failed [%s]\n", path.c_str());
+          return false;
+        }
+      }
+    }
+    else
+    {
+      DALI_LOG_ERROR("Image Decoder for %s unavailable\n", path.c_str());
+    }
+  }
+
+  return result;
+}
+
 ResourcePointer LoadImageSynchronously(const Integration::BitmapResourceType& resource, const std::string& path)
 {
   ResourcePointer          result;
@@ -349,12 +420,14 @@ ImageDimensions GetClosestImageSize(const std::string& filename,
   if(fp != NULL)
   {
     Dali::ImageLoader::LoadBitmapFunction       loaderFunction;
+    Dali::ImageLoader::LoadPlanesFunction       planeLoader;
     Dali::ImageLoader::LoadBitmapHeaderFunction headerFunction;
     Bitmap::Profile                             profile;
 
     if(GetBitmapLoaderFunctions(fp,
                                 GetFormatHint(filename),
                                 loaderFunction,
+                                planeLoader,
                                 headerFunction,
                                 profile,
                                 filename))
@@ -398,12 +471,14 @@ ImageDimensions GetClosestImageSize(Integration::ResourcePointer resourceBuffer,
       if(fp != NULL)
       {
         Dali::ImageLoader::LoadBitmapFunction       loaderFunction;
+        Dali::ImageLoader::LoadPlanesFunction       planeLoader;
         Dali::ImageLoader::LoadBitmapHeaderFunction headerFunction;
         Bitmap::Profile                             profile;
 
         if(GetBitmapLoaderFunctions(fp,
                                     FORMAT_UNKNOWN,
                                     loaderFunction,
+                                    planeLoader,
                                     headerFunction,
                                     profile,
                                     ""))
index f63b186..b0d490f 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TIZEN_PLATFORM_IMAGE_LOADER_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -44,16 +44,18 @@ namespace ImageLoader
  * @param[out] bitmap Pointer to write bitmap to
  * @return true on success, false on failure
  */
-bool ConvertStreamToBitmap(const Integration::BitmapResourceType& resource, std::string path, FILE* const fp, Dali::Devel::PixelBuffer& pixelBuffer);
+bool ConvertStreamToBitmap(const Integration::BitmapResourceType& resource, const std::string& path, FILE* const fp, Dali::Devel::PixelBuffer& pixelBuffer);
 
 /**
- * Convert a bitmap and write to a file stream.
+ * Convert a file stream into image planes.
+ * @param[in] resource The resource to convert.
  * @param[in] path The path to the resource.
  * @param[in] fp File Pointer. Closed on exit.
- * @param[out] pixelData Reference to PixelData object.
+ * @param[out] pixelBuffers Pointer to write buffer to
  * @return true on success, false on failure
+ * @note If the image file doesn't support to load planes, this method returns one RGB bitmap image.
  */
-bool ConvertBitmapToStream(std::string path, FILE* const fp, Dali::Devel::PixelBuffer& pixelBuffer);
+bool ConvertStreamToPlanes(const Integration::BitmapResourceType& resource, const std::string& path, FILE* const fp, std::vector<Dali::Devel::PixelBuffer>& pixelBuffers);
 
 /**
  * Loads an image synchronously
index 0d29c47..675388e 100644 (file)
@@ -57,7 +57,7 @@ const float RAD_315 = RAD_225 + Math::PI_2;    ///< 315 degrees in radians;
 
 using Integration::Bitmap;
 using Integration::BitmapPtr;
-typedef unsigned char PixelBuffer;
+typedef uint8_t PixelBuffer;
 
 /**
  * @brief 4 byte pixel structure.
@@ -505,6 +505,7 @@ ImageDimensions CalculateDesiredDimensions(unsigned int bitmapWidth, unsigned in
  * @param[in] pixelsIn The input buffer.
  * @param[in] widthIn The width of the input buffer.
  * @param[in] heightIn The height of the input buffer.
+ * @param[in] strideIn The stride of the input buffer.
  * @param[in] pixelSize The size of the pixel.
  * @param[out] pixelsOut The rotated output buffer.
  * @param[out] widthOut The width of the output buffer.
@@ -515,6 +516,7 @@ ImageDimensions CalculateDesiredDimensions(unsigned int bitmapWidth, unsigned in
 bool Rotate90(const uint8_t* const pixelsIn,
               unsigned int         widthIn,
               unsigned int         heightIn,
+              unsigned int         strideIn,
               unsigned int         pixelSize,
               uint8_t*&            pixelsOut,
               unsigned int&        widthOut,
@@ -525,6 +527,7 @@ bool Rotate90(const uint8_t* const pixelsIn,
   heightOut = widthIn;
 
   // Allocate memory for the rotated buffer.
+  // Output buffer is tightly packed
   pixelsOut = static_cast<uint8_t*>(malloc(widthOut * heightOut * pixelSize));
   if(nullptr == pixelsOut)
   {
@@ -538,7 +541,7 @@ bool Rotate90(const uint8_t* const pixelsIn,
   // Rotate the buffer.
   for(unsigned int y = 0u; y < heightIn; ++y)
   {
-    const unsigned int srcLineIndex = y * widthIn;
+    const unsigned int srcLineIndex = y * strideIn;
     const unsigned int dstX         = y;
     for(unsigned int x = 0u; x < widthIn; ++x)
     {
@@ -566,6 +569,7 @@ bool Rotate90(const uint8_t* const pixelsIn,
  * @param[in] pixelsIn The input buffer.
  * @param[in] widthIn The width of the input buffer.
  * @param[in] heightIn The height of the input buffer.
+ * @param[in] strideIn The stride of the input buffer.
  * @param[in] pixelSize The size of the pixel.
  * @param[out] pixelsOut The rotated output buffer.
  *
@@ -574,10 +578,12 @@ bool Rotate90(const uint8_t* const pixelsIn,
 bool Rotate180(const uint8_t* const pixelsIn,
                unsigned int         widthIn,
                unsigned int         heightIn,
+               unsigned int         strideIn,
                unsigned int         pixelSize,
                uint8_t*&            pixelsOut)
 {
   // Allocate memory for the rotated buffer.
+  // Output buffer is tightly packed
   pixelsOut = static_cast<uint8_t*>(malloc(widthIn * heightIn * pixelSize));
   if(nullptr == pixelsOut)
   {
@@ -588,7 +594,7 @@ bool Rotate180(const uint8_t* const pixelsIn,
   // Rotate the buffer.
   for(unsigned int y = 0u; y < heightIn; ++y)
   {
-    const unsigned int srcLineIndex = y * widthIn;
+    const unsigned int srcLineIndex = y * strideIn;
     const unsigned int dstY         = heightIn - y - 1u;
     for(unsigned int x = 0u; x < widthIn; ++x)
     {
@@ -616,6 +622,7 @@ bool Rotate180(const uint8_t* const pixelsIn,
  * @param[in] pixelsIn The input buffer.
  * @param[in] widthIn The width of the input buffer.
  * @param[in] heightIn The height of the input buffer.
+ * @param[in] strideIn The stride of the input buffer.
  * @param[in] pixelSize The size of the pixel.
  * @param[out] pixelsOut The rotated output buffer.
  * @param[out] widthOut The width of the output buffer.
@@ -626,6 +633,7 @@ bool Rotate180(const uint8_t* const pixelsIn,
 bool Rotate270(const uint8_t* const pixelsIn,
                unsigned int         widthIn,
                unsigned int         heightIn,
+               unsigned int         strideIn,
                unsigned int         pixelSize,
                uint8_t*&            pixelsOut,
                unsigned int&        widthOut,
@@ -636,6 +644,7 @@ bool Rotate270(const uint8_t* const pixelsIn,
   heightOut = widthIn;
 
   // Allocate memory for the rotated buffer.
+  // Output buffer is tightly packed
   pixelsOut = static_cast<uint8_t*>(malloc(widthOut * heightOut * pixelSize));
   if(nullptr == pixelsOut)
   {
@@ -649,7 +658,7 @@ bool Rotate270(const uint8_t* const pixelsIn,
   // Rotate the buffer.
   for(unsigned int y = 0u; y < heightIn; ++y)
   {
-    const unsigned int srcLineIndex = y * widthIn;
+    const unsigned int srcLineIndex = y * strideIn;
     const unsigned int dstX         = widthOut - y - 1u;
     for(unsigned int x = 0u; x < widthIn; ++x)
     {
@@ -675,6 +684,7 @@ bool Rotate270(const uint8_t* const pixelsIn,
  *
  * @param[in] srcBufferPtr Pointer to the input pixel buffer.
  * @param[in] srcWidth The width of the input pixel buffer.
+ * @param[in] srcStride The stride of the input pixel buffer.
  * @param[in] pixelSize The size of the pixel.
  * @param[in,out] dstPixelBuffer Pointer to the output pixel buffer.
  * @param[in] dstWidth The width of the output pixel buffer.
@@ -684,6 +694,7 @@ bool Rotate270(const uint8_t* const pixelsIn,
  */
 void HorizontalSkew(const uint8_t* const srcBufferPtr,
                     int                  srcWidth,
+                    int                  srcStride,
                     unsigned int         pixelSize,
                     uint8_t*&            dstBufferPtr,
                     int                  dstWidth,
@@ -703,7 +714,7 @@ void HorizontalSkew(const uint8_t* const srcBufferPtr,
   for(i = 0u; i < srcWidth; ++i)
   {
     // Loop through row pixels
-    const unsigned int srcIndex = pixelSize * (row * srcWidth + i);
+    const unsigned int srcIndex = pixelSize * (row * srcStride + i);
 
     unsigned char src[4u] = {0u, 0u, 0u, 0u};
     for(unsigned int channel = 0u; channel < pixelSize; ++channel)
@@ -766,6 +777,7 @@ void HorizontalSkew(const uint8_t* const srcBufferPtr,
  * @param[in] srcBufferPtr Pointer to the input pixel buffer.
  * @param[in] srcWidth The width of the input pixel buffer.
  * @param[in] srcHeight The height of the input pixel buffer.
+ * @param[in] srcStride The stride of the input pixel buffer.
  * @param[in] pixelSize The size of the pixel.
  * @param[in,out] dstPixelBuffer Pointer to the output pixel buffer.
  * @param[in] dstWidth The width of the output pixel buffer.
@@ -777,6 +789,7 @@ void HorizontalSkew(const uint8_t* const srcBufferPtr,
 void VerticalSkew(const uint8_t* const srcBufferPtr,
                   int                  srcWidth,
                   int                  srcHeight,
+                  int                  srcStride,
                   unsigned int         pixelSize,
                   uint8_t*&            dstBufferPtr,
                   int                  dstWidth,
@@ -803,7 +816,7 @@ void VerticalSkew(const uint8_t* const srcBufferPtr,
   for(i = 0; i < srcHeight; ++i)
   {
     // Loop through column pixels
-    const unsigned int srcIndex = pixelSize * (i * srcWidth + column);
+    const unsigned int srcIndex = pixelSize * (i * srcStride + column);
 
     unsigned char src[4u] = {0u, 0u, 0u, 0u};
     for(unsigned int channel = 0u; channel < pixelSize; ++channel)
@@ -932,6 +945,7 @@ Dali::Devel::PixelBuffer CropAndPadForFittingMode(Dali::Devel::PixelBuffer& bitm
 {
   const unsigned int inputWidth  = bitmap.GetWidth();
   const unsigned int inputHeight = bitmap.GetHeight();
+  const unsigned int inputStride = bitmap.GetStride();
 
   if(desiredDimensions.GetWidth() < 1u || desiredDimensions.GetHeight() < 1u)
   {
@@ -984,7 +998,7 @@ Dali::Devel::PixelBuffer CropAndPadForFittingMode(Dali::Devel::PixelBuffer& bitm
       // Add some pre-calculated offsets to the bitmap pointers so this is not done within a loop.
       // The cropping is added to the source pointer, and the padding is added to the destination.
       const auto               bytesPerPixel      = Pixel::GetBytesPerPixel(pixelFormat);
-      const PixelBuffer* const sourcePixels       = bitmap.GetBuffer() + ((((scanlinesToCrop / 2) * inputWidth) + (columnsToCrop / 2)) * bytesPerPixel);
+      const PixelBuffer* const sourcePixels       = bitmap.GetBuffer() + ((((scanlinesToCrop / 2) * inputStride) + (columnsToCrop / 2)) * bytesPerPixel);
       PixelBuffer* const       targetPixels       = croppedBitmap.GetBuffer();
       PixelBuffer* const       targetPixelsActive = targetPixels + ((((scanlinesToPad / 2) * desiredWidth) + (columnsToPad / 2)) * bytesPerPixel);
       DALI_ASSERT_DEBUG(sourcePixels && targetPixels);
@@ -992,7 +1006,7 @@ Dali::Devel::PixelBuffer CropAndPadForFittingMode(Dali::Devel::PixelBuffer& bitm
       // Copy the image data to the new bitmap.
       // Optimize to a single memcpy if the left and right edges don't need a crop or a pad.
       unsigned int outputSpan(desiredWidth * bytesPerPixel);
-      if(columnsToCrop == 0 && columnsToPad == 0)
+      if(columnsToCrop == 0 && columnsToPad == 0 && inputStride == inputWidth)
       {
         memcpy(targetPixelsActive, sourcePixels, (desiredHeight - scanlinesToPad) * outputSpan);
       }
@@ -1000,7 +1014,7 @@ Dali::Devel::PixelBuffer CropAndPadForFittingMode(Dali::Devel::PixelBuffer& bitm
       {
         // The width needs to change (due to either a crop or a pad), so we copy a scanline at a time.
         // Precalculate any constants to optimize the inner loop.
-        const unsigned int inputSpan(inputWidth * bytesPerPixel);
+        const unsigned int inputSpan(inputStride * bytesPerPixel);
         const unsigned int copySpan((desiredWidth - columnsToPad) * bytesPerPixel);
         const unsigned int scanlinesToCopy(desiredHeight - scanlinesToPad);
 
@@ -1078,6 +1092,7 @@ Dali::Devel::PixelBuffer DownscaleBitmap(Dali::Devel::PixelBuffer bitmap,
   // Source dimensions as loaded from resources (e.g. filesystem):
   auto bitmapWidth  = bitmap.GetWidth();
   auto bitmapHeight = bitmap.GetHeight();
+  auto bitmapStride = bitmap.GetStride();
   // Desired dimensions (the rectangle to fit the source image to):
   auto desiredWidth  = desired.GetWidth();
   auto desiredHeight = desired.GetHeight();
@@ -1092,8 +1107,8 @@ Dali::Devel::PixelBuffer DownscaleBitmap(Dali::Devel::PixelBuffer bitmap,
     auto pixelFormat = bitmap.GetPixelFormat();
 
     // Do the fast power of 2 iterated box filter to get to roughly the right side if the filter mode requests that:
-    unsigned int shrunkWidth = -1, shrunkHeight = -1;
-    DownscaleInPlacePow2(bitmap.GetBuffer(), pixelFormat, bitmapWidth, bitmapHeight, desiredWidth, desiredHeight, fittingMode, samplingMode, shrunkWidth, shrunkHeight);
+    unsigned int shrunkWidth = -1, shrunkHeight = -1, outStride = -1;
+    DownscaleInPlacePow2(bitmap.GetBuffer(), pixelFormat, bitmapWidth, bitmapHeight, bitmapStride, desiredWidth, desiredHeight, fittingMode, samplingMode, shrunkWidth, shrunkHeight, outStride);
 
     // Work out the dimensions of the downscaled bitmap, given the scaling mode and desired dimensions:
     const ImageDimensions filteredDimensions = FitToScalingMode(ImageDimensions(desiredWidth, desiredHeight), ImageDimensions(shrunkWidth, shrunkHeight), fittingMode);
@@ -1113,11 +1128,11 @@ Dali::Devel::PixelBuffer DownscaleBitmap(Dali::Devel::PixelBuffer bitmap,
         {
           if(samplingMode == SamplingMode::LINEAR || samplingMode == SamplingMode::BOX_THEN_LINEAR)
           {
-            LinearSample(bitmap.GetBuffer(), ImageDimensions(shrunkWidth, shrunkHeight), pixelFormat, outputBitmap.GetBuffer(), filteredDimensions);
+            LinearSample(bitmap.GetBuffer(), ImageDimensions(shrunkWidth, shrunkHeight), outStride, pixelFormat, outputBitmap.GetBuffer(), filteredDimensions);
           }
           else
           {
-            PointSample(bitmap.GetBuffer(), shrunkWidth, shrunkHeight, pixelFormat, outputBitmap.GetBuffer(), filteredWidth, filteredHeight);
+            PointSample(bitmap.GetBuffer(), shrunkWidth, shrunkHeight, outStride, pixelFormat, outputBitmap.GetBuffer(), filteredWidth, filteredHeight);
           }
           filtered = true;
         }
@@ -1126,6 +1141,7 @@ Dali::Devel::PixelBuffer DownscaleBitmap(Dali::Devel::PixelBuffer bitmap,
     // Copy out the 2^x downscaled, box-filtered pixels if no secondary filter (point or linear) was applied:
     if(filtered == false && (shrunkWidth < bitmapWidth || shrunkHeight < bitmapHeight))
     {
+      // The buffer is downscaled and it is tightly packed. We don't need to set a stride.
       outputBitmap = MakePixelBuffer(bitmap.GetBuffer(), pixelFormat, shrunkWidth, shrunkHeight);
     }
   }
@@ -1195,11 +1211,13 @@ template<
 void DownscaleInPlacePow2Generic(unsigned char* const pixels,
                                  const unsigned int   inputWidth,
                                  const unsigned int   inputHeight,
+                                 const unsigned int   inputStride,
                                  const unsigned int   desiredWidth,
                                  const unsigned int   desiredHeight,
                                  BoxDimensionTest     dimensionTest,
                                  unsigned&            outWidth,
-                                 unsigned&            outHeight)
+                                 unsigned&            outHeight,
+                                 unsigned&            outStride)
 {
   if(pixels == 0)
   {
@@ -1209,12 +1227,14 @@ void DownscaleInPlacePow2Generic(unsigned char* const pixels,
 
   // Scale the image until it would be smaller than desired, stopping if the
   // resulting height or width would be less than 1:
-  unsigned int scaledWidth = inputWidth, scaledHeight = inputHeight;
+  unsigned int scaledWidth = inputWidth, scaledHeight = inputHeight, stride = inputStride;
   while(ContinueScaling(dimensionTest, scaledWidth, scaledHeight, desiredWidth, desiredHeight))
   {
-    const unsigned int lastWidth = scaledWidth;
+    const unsigned int lastWidth  = scaledWidth;
+    const unsigned int lastStride = stride;
     scaledWidth >>= 1u;
     scaledHeight >>= 1u;
+    stride = scaledWidth;
 
     DALI_LOG_INFO(gImageOpsLogFilter, Dali::Integration::Log::Verbose, "Scaling to %u\t%u.\n", scaledWidth, scaledHeight);
 
@@ -1224,8 +1244,8 @@ void DownscaleInPlacePow2Generic(unsigned char* const pixels,
     for(unsigned int y = 0; y <= lastScanlinePair; ++y)
     {
       // Scale two scanlines horizontally:
-      HalveScanlineInPlace(&pixels[y * 2 * lastWidth * BYTES_PER_PIXEL], lastWidth);
-      HalveScanlineInPlace(&pixels[(y * 2 + 1) * lastWidth * BYTES_PER_PIXEL], lastWidth);
+      HalveScanlineInPlace(&pixels[y * 2 * lastStride * BYTES_PER_PIXEL], lastWidth);
+      HalveScanlineInPlace(&pixels[(y * 2 + 1) * lastStride * BYTES_PER_PIXEL], lastWidth);
 
       // Scale vertical pairs of pixels while the last two scanlines are still warm in
       // the CPU cache(s):
@@ -1233,8 +1253,8 @@ void DownscaleInPlacePow2Generic(unsigned char* const pixels,
       // images but even a 4k wide RGB888 image will use just 24kB of cache (4k pixels
       // * 3 Bpp * 2 scanlines) for two scanlines on the first iteration.
       AverageScanlines(
-        &pixels[y * 2 * lastWidth * BYTES_PER_PIXEL],
-        &pixels[(y * 2 + 1) * lastWidth * BYTES_PER_PIXEL],
+        &pixels[y * 2 * lastStride * BYTES_PER_PIXEL],
+        &pixels[(y * 2 + 1) * lastStride * BYTES_PER_PIXEL],
         &pixels[y * scaledWidth * BYTES_PER_PIXEL],
         scaledWidth);
     }
@@ -1243,6 +1263,7 @@ void DownscaleInPlacePow2Generic(unsigned char* const pixels,
   ///@note: we could finish off with one of two mutually exclusive passes, one squashing horizontally as far as possible, and the other vertically, if we knew a following cpu point or bilinear filter would restore the desired aspect ratio.
   outWidth  = scaledWidth;
   outHeight = scaledHeight;
+  outStride = stride;
 }
 
 } // namespace
@@ -1253,20 +1274,35 @@ void HalveScanlineInPlaceRGB888(unsigned char* const pixels, const unsigned int
 
   const unsigned int lastPair = EvenDown(width - 2);
 
-  for(unsigned int pixel = 0, outPixel = 0; pixel <= lastPair; pixel += 2, ++outPixel)
-  {
-    // Load all the byte pixel components we need:
-    const unsigned int c11 = pixels[pixel * 3];
-    const unsigned int c12 = pixels[pixel * 3 + 1];
-    const unsigned int c13 = pixels[pixel * 3 + 2];
-    const unsigned int c21 = pixels[pixel * 3 + 3];
-    const unsigned int c22 = pixels[pixel * 3 + 4];
-    const unsigned int c23 = pixels[pixel * 3 + 5];
-
-    // Save the averaged byte pixel components:
-    pixels[outPixel * 3]     = static_cast<unsigned char>(AverageComponent(c11, c21));
-    pixels[outPixel * 3 + 1] = static_cast<unsigned char>(AverageComponent(c12, c22));
-    pixels[outPixel * 3 + 2] = static_cast<unsigned char>(AverageComponent(c13, c23));
+  /**
+   * @code
+   *  for(unsigned int pixel = 0, outPixel = 0; pixel <= lastPair; pixel += 2, ++outPixel)
+   * {
+   *   // Load all the byte pixel components we need:
+   *   const unsigned int c11 = pixels[pixel * 3];
+   *   const unsigned int c12 = pixels[pixel * 3 + 1];
+   *   const unsigned int c13 = pixels[pixel * 3 + 2];
+   *   const unsigned int c21 = pixels[pixel * 3 + 3];
+   *   const unsigned int c22 = pixels[pixel * 3 + 4];
+   *   const unsigned int c23 = pixels[pixel * 3 + 5];
+   *
+   *   // Save the averaged byte pixel components:
+   *   pixels[outPixel * 3]     = static_cast<unsigned char>(AverageComponent(c11, c21));
+   *   pixels[outPixel * 3 + 1] = static_cast<unsigned char>(AverageComponent(c12, c22));
+   *   pixels[outPixel * 3 + 2] = static_cast<unsigned char>(AverageComponent(c13, c23));
+   * }
+   *   @endcode
+   */
+  //@ToDo : Fix here if we found that collect 12 bytes == 3 uint32_t with 4 colors, and calculate in one-operation
+  std::uint8_t* inPixelPtr  = pixels;
+  std::uint8_t* outPixelPtr = pixels;
+  for(std::uint32_t scanedPixelCount = 0; scanedPixelCount <= lastPair; scanedPixelCount += 2)
+  {
+    *(outPixelPtr + 0) = ((*(inPixelPtr + 0) ^ *(inPixelPtr + 3)) >> 1) + (*(inPixelPtr + 0) & *(inPixelPtr + 3));
+    *(outPixelPtr + 1) = ((*(inPixelPtr + 1) ^ *(inPixelPtr + 4)) >> 1) + (*(inPixelPtr + 1) & *(inPixelPtr + 4));
+    *(outPixelPtr + 2) = ((*(inPixelPtr + 2) ^ *(inPixelPtr + 5)) >> 1) + (*(inPixelPtr + 2) & *(inPixelPtr + 5));
+    inPixelPtr += 6;
+    outPixelPtr += 3;
   }
 }
 
@@ -1297,7 +1333,7 @@ void HalveScanlineInPlaceRGB565(unsigned char* pixels, unsigned int width)
 
   for(unsigned int pixel = 0, outPixel = 0; pixel <= lastPair; pixel += 2, ++outPixel)
   {
-    const uint32_t averaged = AveragePixelRGB565(alignedPixels[pixel], alignedPixels[pixel + 1]);
+    const uint16_t averaged = AveragePixelRGB565(alignedPixels[pixel], alignedPixels[pixel + 1]);
     alignedPixels[outPixel] = averaged;
   }
 }
@@ -1310,15 +1346,22 @@ void HalveScanlineInPlace2Bytes(unsigned char* const pixels, const unsigned int
 
   for(unsigned int pixel = 0, outPixel = 0; pixel <= lastPair; pixel += 2, ++outPixel)
   {
-    // Load all the byte pixel components we need:
-    const unsigned int c11 = pixels[pixel * 2];
-    const unsigned int c12 = pixels[pixel * 2 + 1];
-    const unsigned int c21 = pixels[pixel * 2 + 2];
-    const unsigned int c22 = pixels[pixel * 2 + 3];
-
-    // Save the averaged byte pixel components:
-    pixels[outPixel * 2]     = static_cast<unsigned char>(AverageComponent(c11, c21));
-    pixels[outPixel * 2 + 1] = static_cast<unsigned char>(AverageComponent(c12, c22));
+    /**
+     * @code
+     * // Load all the byte pixel components we need:
+     * const unsigned int c11 = pixels[pixel * 2];
+     * const unsigned int c12 = pixels[pixel * 2 + 1];
+     * const unsigned int c21 = pixels[pixel * 2 + 2];
+     * const unsigned int c22 = pixels[pixel * 2 + 3];
+     *
+     * // Save the averaged byte pixel components:
+     * pixels[outPixel * 2]     = static_cast<unsigned char>(AverageComponent(c11, c21));
+     * pixels[outPixel * 2 + 1] = static_cast<unsigned char>(AverageComponent(c12, c22));
+     * @endcode
+     */
+    // Note : We can assume that pixel is even number. So we can use | operation instead of + operation.
+    pixels[(outPixel << 1)]     = ((pixels[(pixel << 1)] ^ pixels[(pixel << 1) | 2]) >> 1) + (pixels[(pixel << 1)] & pixels[(pixel << 1) | 2]);
+    pixels[(outPixel << 1) | 1] = ((pixels[(pixel << 1) | 1] ^ pixels[(pixel << 1) | 3]) >> 1) + (pixels[(pixel << 1) | 1] & pixels[(pixel << 1) | 3]);
   }
 }
 
@@ -1330,19 +1373,74 @@ void HalveScanlineInPlace1Byte(unsigned char* const pixels, const unsigned int w
 
   for(unsigned int pixel = 0, outPixel = 0; pixel <= lastPair; pixel += 2, ++outPixel)
   {
-    // Load all the byte pixel components we need:
-    const unsigned int c1 = pixels[pixel];
-    const unsigned int c2 = pixels[pixel + 1];
-
-    // Save the averaged byte pixel component:
-    pixels[outPixel] = static_cast<unsigned char>(AverageComponent(c1, c2));
+    /**
+     * @code
+     * // Load all the byte pixel components we need:
+     * const unsigned int c1 = pixels[pixel];
+     * const unsigned int c2 = pixels[pixel + 1];
+     *
+     * // Save the averaged byte pixel component:
+     * pixels[outPixel] = static_cast<unsigned char>(AverageComponent(c1, c2));
+     * @endcode
+     */
+    // Note : We can assume that pixel is even number. So we can use | operation instead of + operation.
+    pixels[outPixel] = ((pixels[pixel] ^ pixels[pixel | 1]) >> 1) + (pixels[pixel] & pixels[pixel | 1]);
   }
 }
 
+// AverageScanline
+
+namespace
+{
 /**
- * @ToDo: Optimise for ARM using a 4 bytes at a time loop wrapped around the single ARMV6 instruction: UHADD8  R4, R0, R5. Note, this is not neon. It runs in the normal integer pipeline so there is no downside like a stall moving between integer and copro, or extra power for clocking-up the idle copro.
- * if (widthInComponents >= 7) { word32* aligned1 = scanline1 + 3 & 3; word32* aligned1_end = scanline1 + widthInPixels & 3; while(aligned1 < aligned1_end) { UHADD8  *aligned1++, *aligned2++, *alignedoutput++ } .. + 0 to 3 spare pixels at each end.
+ * @copydoc AverageScanlines1
+ * @note This API average eight components in one operation.
+ * @note Only possible if each scanline pointer's address aligned
+ * It will give performance benifit.
  */
+inline void AverageScanlinesWithEightComponents(
+  const unsigned char* const scanline1,
+  const unsigned char* const __restrict__ scanline2,
+  unsigned char* const outputScanline,
+  const unsigned int   totalComponentCount)
+{
+  unsigned int component = 0;
+  if(DALI_LIKELY(totalComponentCount >= 8))
+  {
+    // Note reinsterpret_cast from uint8_t to uint64_t and read/write only allowed
+    // If pointer of data is aligned well.
+    if(((reinterpret_cast<std::ptrdiff_t>(scanline1) & (sizeof(std::uint64_t) - 1)) == 0) &&
+       ((reinterpret_cast<std::ptrdiff_t>(scanline2) & (sizeof(std::uint64_t) - 1)) == 0) &&
+       ((reinterpret_cast<std::ptrdiff_t>(outputScanline) & (sizeof(std::uint64_t) - 1)) == 0))
+    {
+      // Jump 8 components in one step
+      const std::uint64_t* const scanline18Step = reinterpret_cast<const std::uint64_t* const>(scanline1);
+      const std::uint64_t* const scanline28Step = reinterpret_cast<const std::uint64_t* const>(scanline2);
+      std::uint64_t* const       output8step    = reinterpret_cast<std::uint64_t* const>(outputScanline);
+
+      const std::uint32_t totalStepCount = (totalComponentCount) >> 3;
+      component                          = totalStepCount << 3;
+
+      // and for each step, calculate average of 8 bytes.
+      for(std::uint32_t i = 0; i < totalStepCount; ++i)
+      {
+        const auto& c1     = *(scanline18Step + i);
+        const auto& c2     = *(scanline28Step + i);
+        *(output8step + i) = static_cast<std::uint64_t>((((c1 ^ c2) & 0xfefefefefefefefeull) >> 1) + (c1 & c2));
+      }
+    }
+  }
+  // remaining components calculate
+  for(; component < totalComponentCount; ++component)
+  {
+    const auto& c1            = scanline1[component];
+    const auto& c2            = scanline2[component];
+    outputScanline[component] = static_cast<std::uint8_t>(((c1 ^ c2) >> 1) + (c1 & c2));
+  }
+}
+
+} // namespace
+
 void AverageScanlines1(const unsigned char* const scanline1,
                        const unsigned char* const __restrict__ scanline2,
                        unsigned char* const outputScanline,
@@ -1350,10 +1448,15 @@ void AverageScanlines1(const unsigned char* const scanline1,
 {
   DebugAssertDualScanlineParameters(scanline1, scanline2, outputScanline, width);
 
-  for(unsigned int component = 0; component < width; ++component)
-  {
-    outputScanline[component] = static_cast<unsigned char>(AverageComponent(scanline1[component], scanline2[component]));
-  }
+  /**
+   * @code
+   * for(unsigned int component = 0; component < width; ++component)
+   * {
+   *   outputScanline[component] = static_cast<unsigned char>(AverageComponent(scanline1[component], scanline2[component]));
+   * }
+   * @endcode
+   */
+  AverageScanlinesWithEightComponents(scanline1, scanline2, outputScanline, width);
 }
 
 void AverageScanlines2(const unsigned char* const scanline1,
@@ -1363,10 +1466,15 @@ void AverageScanlines2(const unsigned char* const scanline1,
 {
   DebugAssertDualScanlineParameters(scanline1, scanline2, outputScanline, width * 2);
 
-  for(unsigned int component = 0; component < width * 2; ++component)
-  {
-    outputScanline[component] = static_cast<unsigned char>(AverageComponent(scanline1[component], scanline2[component]));
-  }
+  /**
+   * @code
+   * for(unsigned int component = 0; component < width * 2; ++component)
+   * {
+   *   outputScanline[component] = static_cast<unsigned char>(AverageComponent(scanline1[component], scanline2[component]));
+   * }
+   * @endcode
+   */
+  AverageScanlinesWithEightComponents(scanline1, scanline2, outputScanline, width * 2);
 }
 
 void AverageScanlines3(const unsigned char* const scanline1,
@@ -1376,10 +1484,15 @@ void AverageScanlines3(const unsigned char* const scanline1,
 {
   DebugAssertDualScanlineParameters(scanline1, scanline2, outputScanline, width * 3);
 
-  for(unsigned int component = 0; component < width * 3; ++component)
-  {
-    outputScanline[component] = static_cast<unsigned char>(AverageComponent(scanline1[component], scanline2[component]));
-  }
+  /**
+   * @code
+   * for(unsigned int component = 0; component < width * 3; ++component)
+   * {
+   *   outputScanline[component] = static_cast<unsigned char>(AverageComponent(scanline1[component], scanline2[component]));
+   * }
+   * @endcode
+   */
+  AverageScanlinesWithEightComponents(scanline1, scanline2, outputScanline, width * 3);
 }
 
 void AverageScanlinesRGBA8888(const unsigned char* const scanline1,
@@ -1427,15 +1540,18 @@ void DownscaleInPlacePow2(unsigned char* const pixels,
                           Pixel::Format        pixelFormat,
                           unsigned int         inputWidth,
                           unsigned int         inputHeight,
+                          unsigned int         inputStride,
                           unsigned int         desiredWidth,
                           unsigned int         desiredHeight,
                           FittingMode::Type    fittingMode,
                           SamplingMode::Type   samplingMode,
                           unsigned&            outWidth,
-                          unsigned&            outHeight)
+                          unsigned&            outHeight,
+                          unsigned&            outStride)
 {
   outWidth  = inputWidth;
   outHeight = inputHeight;
+  outStride = inputStride;
   // Perform power of 2 iterated 4:1 box filtering if the requested filter mode requires it:
   if(samplingMode == SamplingMode::BOX || samplingMode == SamplingMode::BOX_THEN_NEAREST || samplingMode == SamplingMode::BOX_THEN_LINEAR)
   {
@@ -1444,29 +1560,38 @@ void DownscaleInPlacePow2(unsigned char* const pixels,
     {
       const BoxDimensionTest dimensionTest = DimensionTestForScalingMode(fittingMode);
 
-      if(pixelFormat == Pixel::RGBA8888)
-      {
-        Internal::Platform::DownscaleInPlacePow2RGBA8888(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight);
-      }
-      else if(pixelFormat == Pixel::RGB888)
-      {
-        Internal::Platform::DownscaleInPlacePow2RGB888(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight);
-      }
-      else if(pixelFormat == Pixel::RGB565)
-      {
-        Internal::Platform::DownscaleInPlacePow2RGB565(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight);
-      }
-      else if(pixelFormat == Pixel::LA88)
-      {
-        Internal::Platform::DownscaleInPlacePow2ComponentPair(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight);
-      }
-      else if(pixelFormat == Pixel::L8 || pixelFormat == Pixel::A8)
-      {
-        Internal::Platform::DownscaleInPlacePow2SingleBytePerPixel(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight);
-      }
-      else
+      switch(pixelFormat)
       {
-        DALI_ASSERT_DEBUG(false && "Inner branch conditions don't match outer branch.");
+        case Pixel::RGBA8888:
+        {
+          Internal::Platform::DownscaleInPlacePow2RGBA8888(pixels, inputWidth, inputHeight, inputStride, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight, outStride);
+          break;
+        }
+        case Pixel::RGB888:
+        {
+          Internal::Platform::DownscaleInPlacePow2RGB888(pixels, inputWidth, inputHeight, inputStride, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight, outStride);
+          break;
+        }
+        case Pixel::RGB565:
+        {
+          Internal::Platform::DownscaleInPlacePow2RGB565(pixels, inputWidth, inputHeight, inputStride, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight, outStride);
+          break;
+        }
+        case Pixel::LA88:
+        {
+          Internal::Platform::DownscaleInPlacePow2ComponentPair(pixels, inputWidth, inputHeight, inputStride, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight, outStride);
+          break;
+        }
+        case Pixel::L8:
+        case Pixel::A8:
+        {
+          Internal::Platform::DownscaleInPlacePow2SingleBytePerPixel(pixels, inputWidth, inputHeight, inputStride, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight, outStride);
+          break;
+        }
+        default:
+        {
+          DALI_ASSERT_DEBUG(false && "Inner branch conditions don't match outer branch.");
+        }
       }
     }
   }
@@ -1479,38 +1604,44 @@ void DownscaleInPlacePow2(unsigned char* const pixels,
 void DownscaleInPlacePow2RGB888(unsigned char*   pixels,
                                 unsigned int     inputWidth,
                                 unsigned int     inputHeight,
+                                unsigned int     inputStride,
                                 unsigned int     desiredWidth,
                                 unsigned int     desiredHeight,
                                 BoxDimensionTest dimensionTest,
                                 unsigned&        outWidth,
-                                unsigned&        outHeight)
+                                unsigned&        outHeight,
+                                unsigned&        outStride)
 {
-  DownscaleInPlacePow2Generic<3, HalveScanlineInPlaceRGB888, AverageScanlines3>(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight);
+  DownscaleInPlacePow2Generic<3, HalveScanlineInPlaceRGB888, AverageScanlines3>(pixels, inputWidth, inputHeight, inputStride, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight, outStride);
 }
 
 void DownscaleInPlacePow2RGBA8888(unsigned char*   pixels,
                                   unsigned int     inputWidth,
                                   unsigned int     inputHeight,
+                                  unsigned int     inputStride,
                                   unsigned int     desiredWidth,
                                   unsigned int     desiredHeight,
                                   BoxDimensionTest dimensionTest,
                                   unsigned&        outWidth,
-                                  unsigned&        outHeight)
+                                  unsigned&        outHeight,
+                                  unsigned&        outStride)
 {
   DALI_ASSERT_DEBUG(((reinterpret_cast<ptrdiff_t>(pixels) & 3u) == 0u) && "Pointer should be 4-byte aligned for performance on some platforms.");
-  DownscaleInPlacePow2Generic<4, HalveScanlineInPlaceRGBA8888, AverageScanlinesRGBA8888>(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight);
+  DownscaleInPlacePow2Generic<4, HalveScanlineInPlaceRGBA8888, AverageScanlinesRGBA8888>(pixels, inputWidth, inputHeight, inputStride, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight, outStride);
 }
 
 void DownscaleInPlacePow2RGB565(unsigned char*   pixels,
                                 unsigned int     inputWidth,
                                 unsigned int     inputHeight,
+                                unsigned int     inputStride,
                                 unsigned int     desiredWidth,
                                 unsigned int     desiredHeight,
                                 BoxDimensionTest dimensionTest,
                                 unsigned int&    outWidth,
-                                unsigned int&    outHeight)
+                                unsigned int&    outHeight,
+                                unsigned int&    outStride)
 {
-  DownscaleInPlacePow2Generic<2, HalveScanlineInPlaceRGB565, AverageScanlinesRGB565>(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight);
+  DownscaleInPlacePow2Generic<2, HalveScanlineInPlaceRGB565, AverageScanlinesRGB565>(pixels, inputWidth, inputHeight, inputStride, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight, outStride);
 }
 
 /**
@@ -1521,27 +1652,33 @@ void DownscaleInPlacePow2RGB565(unsigned char*   pixels,
 void DownscaleInPlacePow2ComponentPair(unsigned char*   pixels,
                                        unsigned int     inputWidth,
                                        unsigned int     inputHeight,
+                                       unsigned int     inputStride,
                                        unsigned int     desiredWidth,
                                        unsigned int     desiredHeight,
                                        BoxDimensionTest dimensionTest,
                                        unsigned&        outWidth,
-                                       unsigned&        outHeight)
+                                       unsigned&        outHeight,
+                                       unsigned&        outStride)
 {
-  DownscaleInPlacePow2Generic<2, HalveScanlineInPlace2Bytes, AverageScanlines2>(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight);
+  DownscaleInPlacePow2Generic<2, HalveScanlineInPlace2Bytes, AverageScanlines2>(pixels, inputWidth, inputHeight, inputStride, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight, outStride);
 }
 
 void DownscaleInPlacePow2SingleBytePerPixel(unsigned char*   pixels,
                                             unsigned int     inputWidth,
                                             unsigned int     inputHeight,
+                                            unsigned int     inputStride,
                                             unsigned int     desiredWidth,
                                             unsigned int     desiredHeight,
                                             BoxDimensionTest dimensionTest,
                                             unsigned int&    outWidth,
-                                            unsigned int&    outHeight)
+                                            unsigned int&    outHeight,
+                                            unsigned int&    outStride)
 {
-  DownscaleInPlacePow2Generic<1, HalveScanlineInPlace1Byte, AverageScanlines1>(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight);
+  DownscaleInPlacePow2Generic<1, HalveScanlineInPlace1Byte, AverageScanlines1>(pixels, inputWidth, inputHeight, inputStride, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight, outStride);
 }
 
+// Point sampling group below
+
 namespace
 {
 /**
@@ -1555,12 +1692,13 @@ template<typename PIXEL>
 inline void PointSampleAddressablePixels(const uint8_t* inPixels,
                                          unsigned int   inputWidth,
                                          unsigned int   inputHeight,
+                                         unsigned int   inputStride,
                                          uint8_t*       outPixels,
                                          unsigned int   desiredWidth,
                                          unsigned int   desiredHeight)
 {
   DALI_ASSERT_DEBUG(((desiredWidth <= inputWidth && desiredHeight <= inputHeight) ||
-                     outPixels >= inPixels + inputWidth * inputHeight * sizeof(PIXEL) || outPixels <= inPixels - desiredWidth * desiredHeight * sizeof(PIXEL)) &&
+                     outPixels >= inPixels + inputStride * inputHeight * sizeof(PIXEL) || outPixels <= inPixels - desiredWidth * desiredHeight * sizeof(PIXEL)) &&
                     "The input and output buffers must not overlap for an upscaling.");
   DALI_ASSERT_DEBUG(reinterpret_cast<uint64_t>(inPixels) % sizeof(PIXEL) == 0 && "Pixel pointers need to be aligned to the size of the pixels (E.g., 4 bytes for RGBA, 2 bytes for RGB565, ...).");
   DALI_ASSERT_DEBUG(reinterpret_cast<uint64_t>(outPixels) % sizeof(PIXEL) == 0 && "Pixel pointers need to be aligned to the size of the pixels (E.g., 4 bytes for RGBA, 2 bytes for RGB565, ...).");
@@ -1579,11 +1717,11 @@ inline void PointSampleAddressablePixels(const uint8_t* inPixels,
   {
     // Round fixed point y coordinate to nearest integer:
     const unsigned int integerY    = (inY + (1u << 15u)) >> 16u;
-    const PIXEL* const inScanline  = &inAligned[inputWidth * integerY];
+    const PIXEL* const inScanline  = &inAligned[inputStride * integerY];
     PIXEL* const       outScanline = &outAligned[desiredWidth * outY];
 
     DALI_ASSERT_DEBUG(integerY < inputHeight);
-    DALI_ASSERT_DEBUG(reinterpret_cast<const uint8_t*>(inScanline) < (inPixels + inputWidth * inputHeight * sizeof(PIXEL)));
+    DALI_ASSERT_DEBUG(reinterpret_cast<const uint8_t*>(inScanline) < (inPixels + inputStride * inputHeight * sizeof(PIXEL)));
     DALI_ASSERT_DEBUG(reinterpret_cast<uint8_t*>(outScanline) < (outPixels + desiredWidth * desiredHeight * sizeof(PIXEL)));
 
     unsigned int inX = 0;
@@ -1606,33 +1744,36 @@ inline void PointSampleAddressablePixels(const uint8_t* inPixels,
 void PointSample4BPP(const unsigned char* inPixels,
                      unsigned int         inputWidth,
                      unsigned int         inputHeight,
+                     unsigned int         inputStride,
                      unsigned char*       outPixels,
                      unsigned int         desiredWidth,
                      unsigned int         desiredHeight)
 {
-  PointSampleAddressablePixels<uint32_t>(inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight);
+  PointSampleAddressablePixels<uint32_t>(inPixels, inputWidth, inputHeight, inputStride, outPixels, desiredWidth, desiredHeight);
 }
 
 // RGB565, LA88
 void PointSample2BPP(const unsigned char* inPixels,
                      unsigned int         inputWidth,
                      unsigned int         inputHeight,
+                     unsigned int         inputStride,
                      unsigned char*       outPixels,
                      unsigned int         desiredWidth,
                      unsigned int         desiredHeight)
 {
-  PointSampleAddressablePixels<uint16_t>(inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight);
+  PointSampleAddressablePixels<uint16_t>(inPixels, inputWidth, inputHeight, inputStride, outPixels, desiredWidth, desiredHeight);
 }
 
 // L8, A8
 void PointSample1BPP(const unsigned char* inPixels,
                      unsigned int         inputWidth,
                      unsigned int         inputHeight,
+                     unsigned int         inputStride,
                      unsigned char*       outPixels,
                      unsigned int         desiredWidth,
                      unsigned int         desiredHeight)
 {
-  PointSampleAddressablePixels<uint8_t>(inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight);
+  PointSampleAddressablePixels<uint8_t>(inPixels, inputWidth, inputHeight, inputStride, outPixels, desiredWidth, desiredHeight);
 }
 
 /* RGB888
@@ -1641,6 +1782,7 @@ void PointSample1BPP(const unsigned char* inPixels,
 void PointSample3BPP(const uint8_t* inPixels,
                      unsigned int   inputWidth,
                      unsigned int   inputHeight,
+                     unsigned int   inputStride,
                      uint8_t*       outPixels,
                      unsigned int   desiredWidth,
                      unsigned int   desiredHeight)
@@ -1662,7 +1804,7 @@ void PointSample3BPP(const uint8_t* inPixels,
   for(unsigned int outY = 0; outY < desiredHeight; ++outY)
   {
     const unsigned int   integerY    = (inY + (1u << 15u)) >> 16u;
-    const uint8_t* const inScanline  = &inPixels[inputWidth * integerY * BYTES_PER_PIXEL];
+    const uint8_t* const inScanline  = &inPixels[inputStride * integerY * BYTES_PER_PIXEL];
     uint8_t* const       outScanline = &outPixels[desiredWidth * outY * BYTES_PER_PIXEL];
     unsigned int         inX         = 0; //< 16.16 fixed-point input image x-coord.
 
@@ -1695,6 +1837,7 @@ void PointSample3BPP(const uint8_t* inPixels,
 void PointSample(const unsigned char* inPixels,
                  unsigned int         inputWidth,
                  unsigned int         inputHeight,
+                 unsigned int         inputStride,
                  Pixel::Format        pixelFormat,
                  unsigned char*       outPixels,
                  unsigned int         desiredWidth,
@@ -1703,25 +1846,34 @@ void PointSample(const unsigned char* inPixels,
   // Check the pixel format is one that is supported:
   if(pixelFormat == Pixel::RGBA8888 || pixelFormat == Pixel::RGB888 || pixelFormat == Pixel::RGB565 || pixelFormat == Pixel::LA88 || pixelFormat == Pixel::L8 || pixelFormat == Pixel::A8)
   {
-    if(pixelFormat == Pixel::RGB888)
-    {
-      PointSample3BPP(inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight);
-    }
-    else if(pixelFormat == Pixel::RGBA8888)
-    {
-      PointSample4BPP(inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight);
-    }
-    else if(pixelFormat == Pixel::RGB565 || pixelFormat == Pixel::LA88)
-    {
-      PointSample2BPP(inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight);
-    }
-    else if(pixelFormat == Pixel::L8 || pixelFormat == Pixel::A8)
-    {
-      PointSample1BPP(inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight);
-    }
-    else
+    switch(pixelFormat)
     {
-      DALI_ASSERT_DEBUG(0 == "Inner branch conditions don't match outer branch.");
+      case Pixel::RGB888:
+      {
+        PointSample3BPP(inPixels, inputWidth, inputHeight, inputStride, outPixels, desiredWidth, desiredHeight);
+        break;
+      }
+      case Pixel::RGBA8888:
+      {
+        PointSample4BPP(inPixels, inputWidth, inputHeight, inputStride, outPixels, desiredWidth, desiredHeight);
+        break;
+      }
+      case Pixel::RGB565:
+      case Pixel::LA88:
+      {
+        PointSample2BPP(inPixels, inputWidth, inputHeight, inputStride, outPixels, desiredWidth, desiredHeight);
+        break;
+      }
+      case Pixel::L8:
+      case Pixel::A8:
+      {
+        PointSample1BPP(inPixels, inputWidth, inputHeight, inputStride, outPixels, desiredWidth, desiredHeight);
+        break;
+      }
+      default:
+      {
+        DALI_ASSERT_DEBUG(0 == "Inner branch conditions don't match outer branch.");
+      }
     }
   }
   else
@@ -1790,6 +1942,7 @@ template<
   bool DEBUG_ASSERT_ALIGNMENT>
 inline void LinearSampleGeneric(const unsigned char* __restrict__ inPixels,
                                 ImageDimensions inputDimensions,
+                                unsigned int    inputStride,
                                 unsigned char* __restrict__ outPixels,
                                 ImageDimensions desiredDimensions)
 {
@@ -1798,7 +1951,7 @@ inline void LinearSampleGeneric(const unsigned char* __restrict__ inPixels,
   const unsigned int desiredWidth  = desiredDimensions.GetWidth();
   const unsigned int desiredHeight = desiredDimensions.GetHeight();
 
-  DALI_ASSERT_DEBUG(((outPixels >= inPixels + inputWidth * inputHeight * sizeof(PIXEL)) ||
+  DALI_ASSERT_DEBUG(((outPixels >= inPixels + inputStride * inputHeight * sizeof(PIXEL)) ||
                      (inPixels >= outPixels + desiredWidth * desiredHeight * sizeof(PIXEL))) &&
                     "Input and output buffers cannot overlap.");
   if(DEBUG_ASSERT_ALIGNMENT)
@@ -1823,21 +1976,21 @@ inline void LinearSampleGeneric(const unsigned char* __restrict__ inPixels,
 
     // Find the two scanlines to blend and the weight to blend with:
     const unsigned int integerY1    = inY >> 16u;
-    const unsigned int integerY2    = integerY1 >= inputHeight ? integerY1 : integerY1 + 1;
+    const unsigned int integerY2    = integerY1 + 1 >= inputHeight ? integerY1 : integerY1 + 1;
     const unsigned int inputYWeight = inY & 65535u;
 
     DALI_ASSERT_DEBUG(integerY1 < inputHeight);
     DALI_ASSERT_DEBUG(integerY2 < inputHeight);
 
-    const PIXEL* const inScanline1 = &inAligned[inputWidth * integerY1];
-    const PIXEL* const inScanline2 = &inAligned[inputWidth * integerY2];
+    const PIXEL* const inScanline1 = &inAligned[inputStride * integerY1];
+    const PIXEL* const inScanline2 = &inAligned[inputStride * integerY2];
 
     unsigned int inX = 0;
     for(unsigned int outX = 0; outX < desiredWidth; ++outX)
     {
       // Work out the two pixel scanline offsets for this cluster of four samples:
       const unsigned int integerX1 = inX >> 16u;
-      const unsigned int integerX2 = integerX1 >= inputWidth ? integerX1 : integerX1 + 1;
+      const unsigned int integerX2 = integerX1 + 1 >= inputWidth ? integerX1 : integerX1 + 1;
 
       // Execute the loads:
       const PIXEL pixel1 = inScanline1[integerX1];
@@ -1862,46 +2015,103 @@ inline void LinearSampleGeneric(const unsigned char* __restrict__ inPixels,
 
 void LinearSample1BPP(const unsigned char* __restrict__ inPixels,
                       ImageDimensions inputDimensions,
+                      unsigned int    inputStride,
                       unsigned char* __restrict__ outPixels,
                       ImageDimensions desiredDimensions)
 {
-  LinearSampleGeneric<uint8_t, BilinearFilter1BPPByte, false>(inPixels, inputDimensions, outPixels, desiredDimensions);
+  LinearSampleGeneric<uint8_t, BilinearFilter1BPPByte, false>(inPixels, inputDimensions, inputStride, outPixels, desiredDimensions);
 }
 
 void LinearSample2BPP(const unsigned char* __restrict__ inPixels,
                       ImageDimensions inputDimensions,
+                      unsigned int    inputStride,
                       unsigned char* __restrict__ outPixels,
                       ImageDimensions desiredDimensions)
 {
-  LinearSampleGeneric<Pixel2Bytes, BilinearFilter2Bytes, true>(inPixels, inputDimensions, outPixels, desiredDimensions);
+  LinearSampleGeneric<Pixel2Bytes, BilinearFilter2Bytes, true>(inPixels, inputDimensions, inputStride, outPixels, desiredDimensions);
 }
 
 void LinearSampleRGB565(const unsigned char* __restrict__ inPixels,
                         ImageDimensions inputDimensions,
+                        unsigned int    inputStride,
                         unsigned char* __restrict__ outPixels,
                         ImageDimensions desiredDimensions)
 {
-  LinearSampleGeneric<PixelRGB565, BilinearFilterRGB565, true>(inPixels, inputDimensions, outPixels, desiredDimensions);
+  LinearSampleGeneric<PixelRGB565, BilinearFilterRGB565, true>(inPixels, inputDimensions, inputStride, outPixels, desiredDimensions);
 }
 
 void LinearSample3BPP(const unsigned char* __restrict__ inPixels,
                       ImageDimensions inputDimensions,
+                      unsigned int    inputStride,
                       unsigned char* __restrict__ outPixels,
                       ImageDimensions desiredDimensions)
 {
-  LinearSampleGeneric<Pixel3Bytes, BilinearFilterRGB888, false>(inPixels, inputDimensions, outPixels, desiredDimensions);
+  LinearSampleGeneric<Pixel3Bytes, BilinearFilterRGB888, false>(inPixels, inputDimensions, inputStride, outPixels, desiredDimensions);
 }
 
 void LinearSample4BPP(const unsigned char* __restrict__ inPixels,
                       ImageDimensions inputDimensions,
+                      unsigned int    inputStride,
                       unsigned char* __restrict__ outPixels,
                       ImageDimensions desiredDimensions)
 {
-  LinearSampleGeneric<Pixel4Bytes, BilinearFilter4Bytes, true>(inPixels, inputDimensions, outPixels, desiredDimensions);
+  LinearSampleGeneric<Pixel4Bytes, BilinearFilter4Bytes, true>(inPixels, inputDimensions, inputStride, outPixels, desiredDimensions);
+}
+
+// Dispatch to a format-appropriate linear sampling function:
+void LinearSample(const unsigned char* __restrict__ inPixels,
+                  ImageDimensions inDimensions,
+                  unsigned int    inStride,
+                  Pixel::Format   pixelFormat,
+                  unsigned char* __restrict__ outPixels,
+                  ImageDimensions outDimensions)
+{
+  // Check the pixel format is one that is supported:
+  if(pixelFormat == Pixel::RGB888 || pixelFormat == Pixel::RGBA8888 || pixelFormat == Pixel::L8 || pixelFormat == Pixel::A8 || pixelFormat == Pixel::LA88 || pixelFormat == Pixel::RGB565)
+  {
+    switch(pixelFormat)
+    {
+      case Pixel::RGB888:
+      {
+        LinearSample3BPP(inPixels, inDimensions, inStride, outPixels, outDimensions);
+        break;
+      }
+      case Pixel::RGBA8888:
+      {
+        LinearSample4BPP(inPixels, inDimensions, inStride, outPixels, outDimensions);
+        break;
+      }
+      case Pixel::L8:
+      case Pixel::A8:
+      {
+        LinearSample1BPP(inPixels, inDimensions, inStride, outPixels, outDimensions);
+        break;
+      }
+      case Pixel::LA88:
+      {
+        LinearSample2BPP(inPixels, inDimensions, inStride, outPixels, outDimensions);
+        break;
+      }
+      case Pixel::RGB565:
+      {
+        LinearSampleRGB565(inPixels, inDimensions, inStride, outPixels, outDimensions);
+        break;
+      }
+      default:
+      {
+        DALI_ASSERT_DEBUG(0 == "Inner branch conditions don't match outer branch.");
+      }
+    }
+  }
+  else
+  {
+    DALI_LOG_INFO(gImageOpsLogFilter, Dali::Integration::Log::Verbose, "Bitmap was not linear sampled: unsupported pixel format: %u.\n", unsigned(pixelFormat));
+  }
 }
 
 void Resample(const unsigned char* __restrict__ inPixels,
               ImageDimensions inputDimensions,
+              unsigned int    inputStride,
               unsigned char* __restrict__ outPixels,
               ImageDimensions   desiredDimensions,
               Resampler::Filter filterType,
@@ -1985,7 +2195,7 @@ void Resample(const unsigned char* __restrict__ inPixels,
     samples[i].ResizeUninitialized(srcWidth);
   }
 
-  const int srcPitch = srcWidth * numChannels;
+  const int srcPitch = inputStride * numChannels;
   const int dstPitch = dstWidth * numChannels;
   int       dstY     = 0;
 
@@ -2081,65 +2291,64 @@ void Resample(const unsigned char* __restrict__ inPixels,
 
 void LanczosSample4BPP(const unsigned char* __restrict__ inPixels,
                        ImageDimensions inputDimensions,
+                       unsigned int    inputStride,
                        unsigned char* __restrict__ outPixels,
                        ImageDimensions desiredDimensions)
 {
-  Resample(inPixels, inputDimensions, outPixels, desiredDimensions, Resampler::LANCZOS4, 4, true);
+  Resample(inPixels, inputDimensions, inputStride, outPixels, desiredDimensions, Resampler::LANCZOS4, 4, true);
 }
 
 void LanczosSample1BPP(const unsigned char* __restrict__ inPixels,
                        ImageDimensions inputDimensions,
+                       unsigned int    inputStride,
                        unsigned char* __restrict__ outPixels,
                        ImageDimensions desiredDimensions)
 {
   // For L8 images
-  Resample(inPixels, inputDimensions, outPixels, desiredDimensions, Resampler::LANCZOS4, 1, false);
+  Resample(inPixels, inputDimensions, inputStride, outPixels, desiredDimensions, Resampler::LANCZOS4, 1, false);
 }
 
-// Dispatch to a format-appropriate linear sampling function:
-void LinearSample(const unsigned char* __restrict__ inPixels,
-                  ImageDimensions inDimensions,
-                  Pixel::Format   pixelFormat,
-                  unsigned char* __restrict__ outPixels,
-                  ImageDimensions outDimensions)
+// Dispatch to a format-appropriate third-party resampling function:
+void LanczosSample(const unsigned char* __restrict__ inPixels,
+                   ImageDimensions inDimensions,
+                   unsigned int    inStride,
+                   Pixel::Format   pixelFormat,
+                   unsigned char* __restrict__ outPixels,
+                   ImageDimensions outDimensions)
 {
   // Check the pixel format is one that is supported:
-  if(pixelFormat == Pixel::RGB888 || pixelFormat == Pixel::RGBA8888 || pixelFormat == Pixel::L8 || pixelFormat == Pixel::A8 || pixelFormat == Pixel::LA88 || pixelFormat == Pixel::RGB565)
+  if(pixelFormat == Pixel::RGBA8888 || pixelFormat == Pixel::BGRA8888 || pixelFormat == Pixel::L8 || pixelFormat == Pixel::A8)
   {
-    if(pixelFormat == Pixel::RGB888)
-    {
-      LinearSample3BPP(inPixels, inDimensions, outPixels, outDimensions);
-    }
-    else if(pixelFormat == Pixel::RGBA8888)
-    {
-      LinearSample4BPP(inPixels, inDimensions, outPixels, outDimensions);
-    }
-    else if(pixelFormat == Pixel::L8 || pixelFormat == Pixel::A8)
+    switch(pixelFormat)
     {
-      LinearSample1BPP(inPixels, inDimensions, outPixels, outDimensions);
-    }
-    else if(pixelFormat == Pixel::LA88)
-    {
-      LinearSample2BPP(inPixels, inDimensions, outPixels, outDimensions);
-    }
-    else if(pixelFormat == Pixel::RGB565)
-    {
-      LinearSampleRGB565(inPixels, inDimensions, outPixels, outDimensions);
-    }
-    else
-    {
-      DALI_ASSERT_DEBUG(0 == "Inner branch conditions don't match outer branch.");
+      case Pixel::RGBA8888:
+      case Pixel::BGRA8888:
+      {
+        LanczosSample4BPP(inPixels, inDimensions, inStride, outPixels, outDimensions);
+        break;
+      }
+      case Pixel::L8:
+      case Pixel::A8:
+      {
+        LanczosSample1BPP(inPixels, inDimensions, inStride, outPixels, outDimensions);
+        break;
+      }
+      default:
+      {
+        DALI_ASSERT_DEBUG(0 == "Inner branch conditions don't match outer branch.");
+      }
     }
   }
   else
   {
-    DALI_LOG_INFO(gImageOpsLogFilter, Dali::Integration::Log::Verbose, "Bitmap was not linear sampled: unsupported pixel format: %u.\n", unsigned(pixelFormat));
+    DALI_LOG_INFO(gImageOpsLogFilter, Dali::Integration::Log::Verbose, "Bitmap was not lanczos sampled: unsupported pixel format: %u.\n", unsigned(pixelFormat));
   }
 }
 
 void RotateByShear(const uint8_t* const pixelsIn,
                    unsigned int         widthIn,
                    unsigned int         heightIn,
+                   unsigned int         strideIn,
                    unsigned int         pixelSize,
                    float                radians,
                    uint8_t*&            pixelsOut,
@@ -2160,6 +2369,7 @@ void RotateByShear(const uint8_t* const pixelsIn,
     fastRotationPerformed = Rotate90(pixelsIn,
                                      widthIn,
                                      heightIn,
+                                     strideIn,
                                      pixelSize,
                                      pixelsOut,
                                      widthOut,
@@ -2184,6 +2394,7 @@ void RotateByShear(const uint8_t* const pixelsIn,
     fastRotationPerformed = Rotate180(pixelsIn,
                                       widthIn,
                                       heightIn,
+                                      strideIn,
                                       pixelSize,
                                       pixelsOut);
 
@@ -2208,6 +2419,7 @@ void RotateByShear(const uint8_t* const pixelsIn,
     fastRotationPerformed = Rotate270(pixelsIn,
                                       widthIn,
                                       heightIn,
+                                      strideIn,
                                       pixelSize,
                                       pixelsOut,
                                       widthOut,
@@ -2235,6 +2447,8 @@ void RotateByShear(const uint8_t* const pixelsIn,
   const uint8_t* const                      firstHorizontalSkewPixelsIn = fastRotationPerformed ? pixelsOut : pixelsIn;
   std::unique_ptr<uint8_t, void (*)(void*)> tmpPixelsInPtr((fastRotationPerformed ? pixelsOut : nullptr), free);
 
+  unsigned int stride = fastRotationPerformed ? widthOut : strideIn;
+
   // Reset the input/output
   widthIn   = widthOut;
   heightIn  = heightOut;
@@ -2273,7 +2487,7 @@ void RotateByShear(const uint8_t* const pixelsIn,
     const float shear = angleTangent * ((angleTangent >= 0.f) ? (0.5f + static_cast<float>(y)) : (0.5f + static_cast<float>(y) - static_cast<float>(heightOut)));
 
     const int intShear = static_cast<int>(floor(shear));
-    HorizontalSkew(firstHorizontalSkewPixelsIn, widthIn, pixelSize, pixelsOut, widthOut, y, intShear, shear - static_cast<float>(intShear));
+    HorizontalSkew(firstHorizontalSkewPixelsIn, widthIn, stride, pixelSize, pixelsOut, widthOut, y, intShear, shear - static_cast<float>(intShear));
   }
 
   // Reset the 'pixel in' pointer with the output of the 'First Horizontal Skew' and free the memory allocated by the 'Fast Rotations'.
@@ -2312,7 +2526,7 @@ void RotateByShear(const uint8_t* const pixelsIn,
   for(column = 0u; column < widthOut; ++column, offset -= angleSinus)
   {
     const int shear = static_cast<int>(floor(offset));
-    VerticalSkew(tmpPixelsInPtr.get(), tmpWidthIn, tmpHeightIn, pixelSize, pixelsOut, widthOut, heightOut, column, shear, offset - static_cast<float>(shear));
+    VerticalSkew(tmpPixelsInPtr.get(), tmpWidthIn, tmpHeightIn, tmpWidthIn, pixelSize, pixelsOut, widthOut, heightOut, column, shear, offset - static_cast<float>(shear));
   }
   // Reset the 'pixel in' pointer with the output of the 'Vertical Skew' and free the memory allocated by the 'First Horizontal Skew'.
   // Reset the input/output
@@ -2347,7 +2561,7 @@ void RotateByShear(const uint8_t* const pixelsIn,
   for(unsigned int y = 0u; y < heightOut; ++y, offset += angleTangent)
   {
     const int shear = static_cast<int>(floor(offset));
-    HorizontalSkew(tmpPixelsInPtr.get(), tmpWidthIn, pixelSize, pixelsOut, widthOut, y, shear, offset - static_cast<float>(shear));
+    HorizontalSkew(tmpPixelsInPtr.get(), tmpWidthIn, tmpWidthIn, pixelSize, pixelsOut, widthOut, y, shear, offset - static_cast<float>(shear));
   }
 
   // The deleter of the tmpPixelsInPtr unique pointer is called freeing the memory allocated by the 'Vertical Skew'.
@@ -2357,6 +2571,7 @@ void RotateByShear(const uint8_t* const pixelsIn,
 void HorizontalShear(const uint8_t* const pixelsIn,
                      unsigned int         widthIn,
                      unsigned int         heightIn,
+                     unsigned int         strideIn,
                      unsigned int         pixelSize,
                      float                radians,
                      uint8_t*&            pixelsOut,
@@ -2397,7 +2612,7 @@ void HorizontalShear(const uint8_t* const pixelsIn,
     const float shear = radians * ((radians >= 0.f) ? (0.5f + static_cast<float>(y)) : (0.5f + static_cast<float>(y) - static_cast<float>(heightOut)));
 
     const int intShear = static_cast<int>(floor(shear));
-    HorizontalSkew(pixelsIn, widthIn, pixelSize, pixelsOut, widthOut, y, intShear, shear - static_cast<float>(intShear));
+    HorizontalSkew(pixelsIn, widthIn, strideIn, pixelSize, pixelsOut, widthOut, y, intShear, shear - static_cast<float>(intShear));
   }
 }
 
index 81a722c..2d27eac 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -107,21 +107,25 @@ Dali::Devel::PixelBuffer DownscaleBitmap(Dali::Devel::PixelBuffer bitmap,
  * @param[in]     pixelFormat The format of the image pointed at by pixels.
  * @param[in]     inputWidth The width of the input image.
  * @param[in]     inputHeight The height of the input image.
+ * @param[in]     inputStride The stride of the input image.
  * @param[in]     desiredWidth The width the client is requesting.
  * @param[in]     desiredHeight The height the client is requesting.
  * @param[out]    outWidth  The resulting width after downscaling.
  * @param[out]    outHeight The resulting height after downscaling.
+ * @param[out]    outStride The resulting stride after downscaling.
  */
 void DownscaleInPlacePow2(unsigned char* const pixels,
                           Pixel::Format        pixelFormat,
                           unsigned int         inputWidth,
                           unsigned int         inputHeight,
+                          unsigned int         inputStride,
                           unsigned int         desiredWidth,
                           unsigned int         desiredHeight,
                           FittingMode::Type    fittingMode,
                           SamplingMode::Type   samplingMode,
                           unsigned&            outWidth,
-                          unsigned&            outHeight);
+                          unsigned&            outHeight,
+                          unsigned&            outStride);
 
 /**
  * @brief Destructive in-place downscaling by a power of 2 factor.
@@ -132,19 +136,23 @@ void DownscaleInPlacePow2(unsigned char* const pixels,
  * @param[in,out] pixels The buffer both to read from and write the result to.
  * @param[in]     inputWidth The width of the input image.
  * @param[in]     inputHeight The height of the input image.
+ * @param[in]     inputStride The stride of the input image.
  * @param[in]     desiredWidth The width the client is requesting.
  * @param[in]     desiredHeight The height the client is requesting.
  * @param[out]    outWidth  The resulting width after downscaling.
  * @param[out]    outHeight The resulting height after downscaling.
+ * @param[out]    outStride The resulting stride after downscaling.
  */
 void DownscaleInPlacePow2RGB888(unsigned char*   pixels,
                                 unsigned int     inputWidth,
                                 unsigned int     inputHeight,
+                                unsigned int     inputStride,
                                 unsigned int     desiredWidth,
                                 unsigned int     desiredHeight,
                                 BoxDimensionTest dimensionTest,
                                 unsigned int&    outWidth,
-                                unsigned int&    outHeight);
+                                unsigned int&    outHeight,
+                                unsigned int&    outStride);
 
 /**
  * @copydoc DownscaleInPlacePow2RGB888
@@ -152,11 +160,13 @@ void DownscaleInPlacePow2RGB888(unsigned char*   pixels,
 void DownscaleInPlacePow2RGBA8888(unsigned char*   pixels,
                                   unsigned int     inputWidth,
                                   unsigned int     inputHeight,
+                                  unsigned int     inputStride,
                                   unsigned int     desiredWidth,
                                   unsigned int     desiredHeight,
                                   BoxDimensionTest dimensionTest,
                                   unsigned int&    outWidth,
-                                  unsigned int&    outHeight);
+                                  unsigned int&    outHeight,
+                                  unsigned int&    outStride);
 
 /**
  * @copydoc DownscaleInPlacePow2RGB888
@@ -166,11 +176,13 @@ void DownscaleInPlacePow2RGBA8888(unsigned char*   pixels,
 void DownscaleInPlacePow2RGB565(unsigned char*   pixels,
                                 unsigned int     inputWidth,
                                 unsigned int     inputHeight,
+                                unsigned int     inputStride,
                                 unsigned int     desiredWidth,
                                 unsigned int     desiredHeight,
                                 BoxDimensionTest dimensionTest,
                                 unsigned int&    outWidth,
-                                unsigned int&    outHeight);
+                                unsigned int&    outHeight,
+                                unsigned int&    outStride);
 
 /**
  * @copydoc DownscaleInPlacePow2RGB888
@@ -180,11 +192,13 @@ void DownscaleInPlacePow2RGB565(unsigned char*   pixels,
 void DownscaleInPlacePow2ComponentPair(unsigned char*   pixels,
                                        unsigned int     inputWidth,
                                        unsigned int     inputHeight,
+                                       unsigned int     inputStride,
                                        unsigned int     desiredWidth,
                                        unsigned int     desiredHeight,
                                        BoxDimensionTest dimensionTest,
                                        unsigned int&    outWidth,
-                                       unsigned int&    outHeight);
+                                       unsigned int&    outHeight,
+                                       unsigned int&    outStride);
 
 /**
  * @copydoc DownscaleInPlacePow2RGB888
@@ -194,11 +208,13 @@ void DownscaleInPlacePow2ComponentPair(unsigned char*   pixels,
 void DownscaleInPlacePow2SingleBytePerPixel(unsigned char*   pixels,
                                             unsigned int     inputWidth,
                                             unsigned int     inputHeight,
+                                            unsigned int     inputStride,
                                             unsigned int     desiredWidth,
                                             unsigned int     desiredHeight,
                                             BoxDimensionTest dimensionTest,
                                             unsigned int&    outWidth,
-                                            unsigned int&    outHeight);
+                                            unsigned int&    outHeight,
+                                            unsigned int&    outStride);
 
 /**
  * @brief Rescales an input image into the exact output dimensions passed-in.
@@ -211,6 +227,7 @@ void DownscaleInPlacePow2SingleBytePerPixel(unsigned char*   pixels,
 void PointSample(const unsigned char* inPixels,
                  unsigned int         inputWidth,
                  unsigned int         inputHeight,
+                 unsigned int         inputStride,
                  Pixel::Format        pixelFormat,
                  unsigned char*       outPixels,
                  unsigned int         desiredWidth,
@@ -224,6 +241,7 @@ void PointSample(const unsigned char* inPixels,
 void PointSample4BPP(const unsigned char* inPixels,
                      unsigned int         inputWidth,
                      unsigned int         inputHeight,
+                     unsigned int         inputStride,
                      unsigned char*       outPixels,
                      unsigned int         desiredWidth,
                      unsigned int         desiredHeight);
@@ -236,6 +254,7 @@ void PointSample4BPP(const unsigned char* inPixels,
 void PointSample3BPP(const unsigned char* inPixels,
                      unsigned int         inputWidth,
                      unsigned int         inputHeight,
+                     unsigned int         inputStride,
                      unsigned char*       outPixels,
                      unsigned int         desiredWidth,
                      unsigned int         desiredHeight);
@@ -248,6 +267,7 @@ void PointSample3BPP(const unsigned char* inPixels,
 void PointSample2BPP(const unsigned char* inPixels,
                      unsigned int         inputWidth,
                      unsigned int         inputHeight,
+                     unsigned int         inputStride,
                      unsigned char*       outPixels,
                      unsigned int         desiredWidth,
                      unsigned int         desiredHeight);
@@ -260,6 +280,7 @@ void PointSample2BPP(const unsigned char* inPixels,
 void PointSample1BPP(const unsigned char* inPixels,
                      unsigned int         inputWidth,
                      unsigned int         inputHeight,
+                     unsigned int         inputStride,
                      unsigned char*       outPixels,
                      unsigned int         desiredWidth,
                      unsigned int         desiredHeight);
@@ -274,6 +295,7 @@ void PointSample1BPP(const unsigned char* inPixels,
  */
 void LinearSample(const unsigned char* __restrict__ inPixels,
                   ImageDimensions inDimensions,
+                  unsigned int    inStride,
                   Pixel::Format   pixelFormat,
                   unsigned char* __restrict__ outPixels,
                   ImageDimensions outDimensions);
@@ -285,6 +307,7 @@ void LinearSample(const unsigned char* __restrict__ inPixels,
  */
 void LinearSample1BPP(const unsigned char* __restrict__ inPixels,
                       ImageDimensions inputDimensions,
+                      unsigned int    inputStride,
                       unsigned char* __restrict__ outPixels,
                       ImageDimensions desiredDimensions);
 
@@ -295,6 +318,7 @@ void LinearSample1BPP(const unsigned char* __restrict__ inPixels,
  */
 void LinearSample2BPP(const unsigned char* __restrict__ inPixels,
                       ImageDimensions inputDimensions,
+                      unsigned int    inputStride,
                       unsigned char* __restrict__ outPixels,
                       ImageDimensions desiredDimensions);
 
@@ -305,6 +329,7 @@ void LinearSample2BPP(const unsigned char* __restrict__ inPixels,
  */
 void LinearSampleRGB565(const unsigned char* __restrict__ inPixels,
                         ImageDimensions inputDimensions,
+                        unsigned int    inputStride,
                         unsigned char* __restrict__ outPixels,
                         ImageDimensions desiredDimensions);
 
@@ -315,6 +340,7 @@ void LinearSampleRGB565(const unsigned char* __restrict__ inPixels,
  */
 void LinearSample3BPP(const unsigned char* __restrict__ inPixels,
                       ImageDimensions inputDimensions,
+                      unsigned int    inputStride,
                       unsigned char* __restrict__ outPixels,
                       ImageDimensions desiredDimensions);
 
@@ -326,10 +352,31 @@ void LinearSample3BPP(const unsigned char* __restrict__ inPixels,
  */
 void LinearSample4BPP(const unsigned char* __restrict__ inPixels,
                       ImageDimensions inputDimensions,
+                      unsigned int    inputStride,
                       unsigned char* __restrict__ outPixels,
                       ImageDimensions desiredDimensions);
 
 /**
+ * @brief Resample input image to output image using a Lanczos algorithm.
+ *
+ * @pre @p inPixels must not alias @p outPixels. The input image should be a totally
+ * separate buffer from the output buffer.
+ *
+ * @param[in] inPixels Pointer to the input image buffer.
+ * @param[in] inputDimensions The input dimensions of the image.
+ * @param[in] inputStride The input stride of the image.
+ * @param[in] pixelFormat The format of the image pointed at by pixels.
+ * @param[out] outPixels Pointer to the output image buffer.
+ * @param[in] desiredDimensions The output dimensions of the image.
+ */
+void LanczosSample(const unsigned char* __restrict__ inPixels,
+                   ImageDimensions inDimensions,
+                   unsigned int    inStride,
+                   Pixel::Format   pixelFormat,
+                   unsigned char* __restrict__ outPixels,
+                   ImageDimensions outDimensions);
+
+/**
  * @brief Resamples the input image with the Lanczos algorithm.
  *
  * @pre @p inPixels must not alias @p outPixels. The input image should be a totally
@@ -337,11 +384,13 @@ void LinearSample4BPP(const unsigned char* __restrict__ inPixels,
  *
  * @param[in] inPixels Pointer to the input image buffer.
  * @param[in] inputDimensions The input dimensions of the image.
+ * @param[in] inputStride The input stride of the image.
  * @param[out] outPixels Pointer to the output image buffer.
  * @param[in] desiredDimensions The output dimensions of the image.
  */
 void LanczosSample4BPP(const unsigned char* __restrict__ inPixels,
                        ImageDimensions inputDimensions,
+                       unsigned int    inputStride,
                        unsigned char* __restrict__ outPixels,
                        ImageDimensions desiredDimensions);
 
@@ -353,11 +402,13 @@ void LanczosSample4BPP(const unsigned char* __restrict__ inPixels,
  *
  * @param[in] inPixels Pointer to the input image buffer.
  * @param[in] inputDimensions The input dimensions of the image.
+ * @param[in] inputStride The input stride of the image.
  * @param[out] outPixels Pointer to the output image buffer.
  * @param[in] desiredDimensions The output dimensions of the image.
  */
 void LanczosSample1BPP(const unsigned char* __restrict__ inPixels,
                        ImageDimensions inputDimensions,
+                       unsigned int    inputStride,
                        unsigned char* __restrict__ outPixels,
                        ImageDimensions desiredDimensions);
 
@@ -369,11 +420,13 @@ void LanczosSample1BPP(const unsigned char* __restrict__ inPixels,
  *
  * @param[in] inPixels Pointer to the input image buffer.
  * @param[in] inputDimensions The input dimensions of the image.
+ * @param[in] inputStride The input stride of the image.
  * @param[out] outPixels Pointer to the output image buffer.
  * @param[in] desiredDimensions The output dimensions of the image.
  */
 void Resample(const unsigned char* __restrict__ inPixels,
               ImageDimensions inputDimensions,
+              unsigned int    inputStride,
               unsigned char* __restrict__ outPixels,
               ImageDimensions   desiredDimensions,
               Resampler::Filter filterType,
@@ -391,6 +444,7 @@ void Resample(const unsigned char* __restrict__ inPixels,
  * @param[in] pixelsIn The input buffer.
  * @param[in] widthIn The width of the input buffer.
  * @param[in] heightIn The height of the input buffer.
+ * @param[in] strideIn The stride of the input buffer.
  * @param[in] pixelSize The size of the pixel.
  * @param[in] radians The rotation angle in radians.
  * @param[out] pixelsOut The rotated output buffer.
@@ -400,6 +454,7 @@ void Resample(const unsigned char* __restrict__ inPixels,
 void RotateByShear(const uint8_t* const pixelsIn,
                    unsigned int         widthIn,
                    unsigned int         heightIn,
+                   unsigned int         strideIn,
                    unsigned int         pixelSize,
                    float                radians,
                    uint8_t*&            pixelsOut,
@@ -418,6 +473,7 @@ void RotateByShear(const uint8_t* const pixelsIn,
  * @param[in] pixelsIn The input buffer.
  * @param[in] widthIn The width of the input buffer.
  * @param[in] heightIn The height of the input buffer.
+ * @param[in] strideIn The stride of the input buffer.
  * @param[in] pixelSize The size of the pixel.
  * @param[in] radians The shear angle in radians.
  * @param[out] pixelsOut The rotated output buffer.
@@ -427,6 +483,7 @@ void RotateByShear(const uint8_t* const pixelsIn,
 void HorizontalShear(const uint8_t* const pixelsIn,
                      unsigned int         widthIn,
                      unsigned int         heightIn,
+                     unsigned int         strideIn,
                      unsigned int         pixelSize,
                      float                radians,
                      uint8_t*&            pixelsOut,
@@ -542,13 +599,17 @@ inline unsigned int AverageComponent(unsigned int a, unsigned int b)
  **/
 inline uint32_t AveragePixelRGBA8888(uint32_t a, uint32_t b)
 {
-  const unsigned int avg =
-    ((AverageComponent((a & 0xff000000) >> 1u, (b & 0xff000000) >> 1u) << 1u) & 0xff000000) +
-    (AverageComponent(a & 0x00ff0000, b & 0x00ff0000) & 0x00ff0000) +
-    (AverageComponent(a & 0x0000ff00, b & 0x0000ff00) & 0x0000ff00) +
-    (AverageComponent(a & 0x000000ff, b & 0x000000ff));
-  return avg;
-  ///@ToDo: Optimise by trying return (((a ^ b) & 0xfefefefeUL) >> 1) + (a & b);
+  /**
+   * @code
+   * const unsigned int avg =
+   *   (AverageComponent((a & 0xff000000) >> 1u, (b & 0xff000000) >> 1u) << 1u) & 0xff000000) +
+   *   (AverageComponent(a & 0x00ff0000, b & 0x00ff0000) & 0x00ff0000) +
+   *   (AverageComponent(a & 0x0000ff00, b & 0x0000ff00) & 0x0000ff00) +
+   *   (AverageComponent(a & 0x000000ff, b & 0x000000ff);
+   * return avg;
+   * @endcode
+   */
+  return (((a ^ b) & 0xfefefefeu) >> 1) + (a & b);
   ///@ToDo: Optimise for ARM using the single ARMV6 instruction: UHADD8  R4, R0, R5. This is not Neon. It runs in the normal integer pipeline so there is no downside like a stall moving between integer and copro.
 }
 
@@ -560,20 +621,30 @@ inline uint32_t AveragePixelRGBA8888(uint32_t a, uint32_t b)
  **/
 inline uint32_t AveragePixelRGB565(uint32_t a, uint32_t b)
 {
-  const unsigned int avg =
-    (AverageComponent(a & 0xf800, b & 0xf800) & 0xf800) +
-    (AverageComponent(a & 0x7e0, b & 0x7e0) & 0x7e0) +
-    (AverageComponent(a & 0x1f, b & 0x1f));
-  return avg;
+  /**
+   * @code
+   * const unsigned int avg =
+   *   (AverageComponent(a & 0xf800, b & 0xf800) & 0xf800) +
+   *   (AverageComponent(a & 0x7e0, b & 0x7e0) & 0x7e0) +
+   *   (AverageComponent(a & 0x1f, b & 0x1f));
+   * return avg;
+   * @endcode
+   */
+  return (((a ^ b) & 0xf7deu) >> 1) + (a & b);
 }
 
 /** @return The weighted blend of two integers as a 16.16 fixed-point number, given a 0.16 fixed-point blending factor. */
 inline unsigned int WeightedBlendIntToFixed1616(unsigned int a, unsigned int b, unsigned int fractBlend)
 {
   DALI_ASSERT_DEBUG(fractBlend <= 65535u && "Factor should be in 0.16 fixed-point.");
-  const unsigned int weightedAFixed = a * (65535u - fractBlend);
-  const unsigned int weightedBFixed = b * fractBlend;
-  const unsigned     blended        = (weightedAFixed + weightedBFixed);
+  /**
+   * @code
+   * const unsigned int weightedAFixed = a * (65535u - fractBlend);
+   * const unsigned int weightedBFixed = b * fractBlend;
+   * const unsigned     blended        = (weightedAFixed + weightedBFixed);
+   * @endcode
+   */
+  const unsigned int blended = (a << 16) - a + (static_cast<int32_t>(b) - static_cast<int32_t>(a)) * fractBlend;
   return blended;
 }
 
@@ -581,10 +652,15 @@ inline unsigned int WeightedBlendIntToFixed1616(unsigned int a, unsigned int b,
 inline uint64_t WeightedBlendFixed1616ToFixed1632(unsigned int a, unsigned int b, unsigned int fractBlend)
 {
   DALI_ASSERT_DEBUG(fractBlend <= 65535u && "Factor should be in 0.16 fixed-point.");
-  // Blend while promoting intermediates to 16.32 fixed point:
-  const uint64_t weightedAFixed = uint64_t(a) * (65535u - fractBlend);
-  const uint64_t weightedBFixed = uint64_t(b) * fractBlend;
-  const uint64_t blended        = (weightedAFixed + weightedBFixed);
+  /**
+   * @code
+   * // Blend while promoting intermediates to 16.32 fixed point:
+   * const uint64_t weightedAFixed = uint64_t(a) * (65535u - fractBlend);
+   * const uint64_t weightedBFixed = uint64_t(b) * fractBlend;
+   * const uint64_t blended        = (weightedAFixed + weightedBFixed);
+   * @endcode
+   */
+  const uint64_t blended = (static_cast<uint64_t>(a) << 16) - a + (static_cast<int64_t>(b) - static_cast<int64_t>(a)) * fractBlend;
   return blended;
 }
 
@@ -596,13 +672,72 @@ inline unsigned int BilinearFilter1Component(unsigned int tl, unsigned int tr, u
   DALI_ASSERT_DEBUG(fractBlendHorizontal <= 65535u && "Factor should be in 0.16 fixed-point.");
   DALI_ASSERT_DEBUG(fractBlendVertical <= 65535u && "Factor should be in 0.16 fixed-point.");
 
-  const unsigned int topBlend   = WeightedBlendIntToFixed1616(tl, tr, fractBlendHorizontal);
-  const unsigned int botBlend   = WeightedBlendIntToFixed1616(bl, br, fractBlendHorizontal);
-  const uint64_t     blended2x2 = WeightedBlendFixed1616ToFixed1632(topBlend, botBlend, fractBlendVertical);
+  /**
+   * @code
+   * const unsigned int topBlend   = WeightedBlendIntToFixed1616(tl, tr, fractBlendHorizontal);
+   * const unsigned int botBlend   = WeightedBlendIntToFixed1616(bl, br, fractBlendHorizontal);
+   * const uint64_t     blended2x2 = WeightedBlendFixed1616ToFixed1632(topBlend, botBlend, fractBlendVertical);
+   * const unsigned int rounded    = (blended2x2 + (1u << 31u)) >> 32u;
+   * @endcode
+   */
+
+  /**
+   * Hard-coding optimize!
+   *
+   * Let p = 65536, s.t we can optimze it as << 16.
+   * Let x = fractBlendHorizontal, y = fractBlendVertical.
+   * topBlend = (tl*p - tl - tl*x + tr*x)
+   * botBlend = (bl*p - bl - bl*x + br*x)
+   * blended2x2 = topBlend*p - topBlend - topBlend*y + botBlend*y
+   *
+   * And now we can split all values.
+   * tl*p*p - tl*p - tl*x*p + tr*x*p  -  tl*p + tl + tl*x - tr*x  -  tl*y*p + tl*y + tl*x*y - tr*x*y  +  bl*y*p - bl*y - bl*x*y + br*x*y;
+   * --> (collect by p, x, and y)
+   * (tl)*p*p + (-2tl + (-tl + tr)*x + (-tl+bl)*y)*p + tl + (tl - tr)*x + (tl - bl)*y + (tl - tr - bl + br)*x*y
+   *
+   * A = (tl - tr) * x;
+   * B = (tl - bl) * y;
+   * C = (tl - tr - bl + br) * x * y;
+   * D = (2*tl + A + B)
+   * -->
+   * (tl << 32) - (D << 16) + tl + A + B + C
+   *
+   * Becareful of overflow and negative value.
+   */
+  const int32_t A = (static_cast<int32_t>(tl) - static_cast<int32_t>(tr)) * static_cast<int32_t>(fractBlendHorizontal);
+  const int32_t B = (static_cast<int32_t>(tl) - static_cast<int32_t>(bl)) * static_cast<int32_t>(fractBlendVertical);
+  const int64_t C = (static_cast<int64_t>(tl) - static_cast<int64_t>(tr) - static_cast<int64_t>(bl) + static_cast<int64_t>(br)) * static_cast<int64_t>(fractBlendHorizontal) * static_cast<int64_t>(fractBlendVertical);
+  const int64_t D = ((static_cast<int64_t>(tl) << 1) + A + B);
+
+  const uint64_t     blended2x2 = (static_cast<int64_t>(tl) << 32u) - (D << 16u) + tl + A + B + C;
   const unsigned int rounded    = (blended2x2 + (1u << 31u)) >> 32u;
   return rounded;
 }
 
+/**
+ * @brief Fast multiply & divide by 255. It wiil be useful when we applying alpha value in color
+ *
+ * @param x The value between [0..255]
+ * @param y The value between [0..255]
+ * @return (x*y)/255
+ */
+inline uint8_t MultiplyAndNormalizeColor(const uint8_t x, const uint8_t y) noexcept
+{
+  const uint32_t xy = static_cast<const uint32_t>(x) * y;
+  return ((xy << 15) + (xy << 7) + xy) >> 23;
+}
+
+/**
+ * @brief Fast division by 17 and roundup. It will be useful when we compress 8bit luminance value as 4bit for text glyph.
+ *
+ * @param x The value between [0..255]
+ * @return round(x / 17.0f).(same as (x+8)/17)
+ */
+inline uint8_t CompressBitPerPixel8To4(const uint8_t x) noexcept
+{
+  return ((((static_cast<const uint16_t>(x) << 4) - x + (x >> 4)) >> 7) + 1) >> 1;
+}
+
 /**@}*/
 
 } /* namespace Platform */
index 4ab6d67..7cd2271 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -115,14 +115,14 @@ bool LoadAstcHeader(FILE* const filePointer, unsigned int& width, unsigned int&
 {
   // Pull the bytes of the file header in as a block:
   const unsigned int readLength = sizeof(AstcFileHeader);
-  if(fread(&fileHeader, 1, readLength, filePointer) != readLength)
+  if(DALI_UNLIKELY(fread(&fileHeader, 1, readLength, filePointer) != readLength))
   {
     return false;
   }
 
   // Check the header contains the ASTC native file identifier.
   bool headerIsValid = memcmp(fileHeader.magic, FileIdentifier, sizeof(fileHeader.magic)) == 0;
-  if(!headerIsValid)
+  if(DALI_UNLIKELY(!headerIsValid))
   {
     DALI_LOG_ERROR("File is not a valid ASTC native file\n");
     // Return here as otherwise, if not a valid ASTC file, we are likely to pick up other header errors spuriously.
@@ -136,14 +136,14 @@ bool LoadAstcHeader(FILE* const filePointer, unsigned int& width, unsigned int&
   const unsigned int zDepth = static_cast<unsigned int>(fileHeader.zsize[0]) + (static_cast<unsigned int>(fileHeader.zsize[1]) << 8) + (static_cast<unsigned int>(fileHeader.zsize[2]) << 16);
 
   // Check image dimensions are within limits.
-  if((width > MAX_TEXTURE_DIMENSION) || (height > MAX_TEXTURE_DIMENSION))
+  if(DALI_UNLIKELY((width > MAX_TEXTURE_DIMENSION) || (height > MAX_TEXTURE_DIMENSION)))
   {
     DALI_LOG_ERROR("ASTC file has larger than supported dimensions: %d,%d\n", width, height);
     headerIsValid = false;
   }
 
   // Confirm the ASTC block does not have any Z depth.
-  if(zDepth != 1)
+  if(DALI_UNLIKELY(zDepth != 1))
   {
     DALI_LOG_ERROR("ASTC files with z size other than 1 are not supported. Z size is: %d\n", zDepth);
     headerIsValid = false;
@@ -165,7 +165,7 @@ bool LoadAstcHeader(const Dali::ImageLoader::Input& input, unsigned int& width,
 bool LoadBitmapFromAstc(const Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& bitmap)
 {
   FILE* const filePointer = input.file;
-  if(!filePointer)
+  if(DALI_UNLIKELY(!filePointer))
   {
     DALI_LOG_ERROR("Null file handle passed to ASTC compressed bitmap file loader.\n");
     return false;
@@ -175,7 +175,7 @@ bool LoadBitmapFromAstc(const Dali::ImageLoader::Input& input, Dali::Devel::Pixe
   AstcFileHeader fileHeader;
   unsigned int   width, height;
 
-  if(!LoadAstcHeader(filePointer, width, height, fileHeader))
+  if(DALI_UNLIKELY(!LoadAstcHeader(filePointer, width, height, fileHeader)))
   {
     DALI_LOG_ERROR("Could not load ASTC Header from file.\n");
     return false;
@@ -183,27 +183,27 @@ bool LoadBitmapFromAstc(const Dali::ImageLoader::Input& input, Dali::Devel::Pixe
 
   // Retrieve the pixel format from the ASTC block size.
   Pixel::Format pixelFormat = GetAstcPixelFormat(fileHeader);
-  if(pixelFormat == Pixel::INVALID)
+  if(DALI_UNLIKELY(pixelFormat == Pixel::INVALID))
   {
     DALI_LOG_ERROR("No internal pixel format supported for ASTC file pixel format.\n");
     return false;
   }
 
   // Retrieve the file size.
-  if(fseek(filePointer, 0L, SEEK_END))
+  if(DALI_UNLIKELY(fseek(filePointer, 0L, SEEK_END)))
   {
     DALI_LOG_ERROR("Could not seek through file.\n");
     return false;
   }
 
   off_t fileSize = ftell(filePointer);
-  if(fileSize == -1L)
+  if(DALI_UNLIKELY(fileSize == -1L))
   {
     DALI_LOG_ERROR("Could not determine ASTC file size.\n");
     return false;
   }
 
-  if(fseek(filePointer, sizeof(AstcFileHeader), SEEK_SET))
+  if(DALI_UNLIKELY(fseek(filePointer, sizeof(AstcFileHeader), SEEK_SET)))
   {
     DALI_LOG_ERROR("Could not seek through file.\n");
     return false;
@@ -213,7 +213,7 @@ bool LoadBitmapFromAstc(const Dali::ImageLoader::Input& input, Dali::Devel::Pixe
   size_t imageByteCount = fileSize - sizeof(AstcFileHeader);
 
   // Sanity-check the image data is not too large and that it is at less than 2 bytes per texel:
-  if((imageByteCount > MAX_IMAGE_DATA_SIZE) || (imageByteCount > ((static_cast<size_t>(width) * height) << 1)))
+  if(DALI_UNLIKELY((imageByteCount > MAX_IMAGE_DATA_SIZE) || (imageByteCount > ((static_cast<size_t>(width) * height) << 1))))
   {
     DALI_LOG_ERROR("ASTC file has too large image-data field.\n");
     return false;
@@ -236,7 +236,7 @@ bool LoadBitmapFromAstc(const Dali::ImageLoader::Input& input, Dali::Devel::Pixe
   const size_t bytesRead = fread(pixels, 1, imageByteCount, filePointer);
 
   // Check the size of loaded data is what we expected.
-  if(bytesRead != imageByteCount)
+  if(DALI_UNLIKELY(bytesRead != imageByteCount))
   {
     DALI_LOG_ERROR("Read of image pixel data failed.\n");
     return false;
index fe87cf9..05d0518 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -82,7 +82,7 @@ inline bool ReadHeader(FILE* fp, T& header)
   const unsigned int readLength = sizeof(T);
 
   // Load the information directly into our structure
-  if(fread(&header, 1, readLength, fp) != readLength)
+  if(DALI_UNLIKELY(fread(&header, 1, readLength, fp) != readLength))
   {
     return false;
   }
@@ -92,13 +92,13 @@ inline bool ReadHeader(FILE* fp, T& header)
 
 bool LoadBmpHeader(FILE* fp, unsigned int& width, unsigned int& height, BmpFileHeader& fileHeader, BmpInfoHeader& infoHeader)
 {
-  if(!ReadHeader(fp, fileHeader))
+  if(DALI_UNLIKELY(!ReadHeader(fp, fileHeader)))
   {
     DALI_LOG_ERROR("File header read failed\n");
     return false;
   }
 
-  if(!ReadHeader(fp, infoHeader))
+  if(DALI_UNLIKELY(!ReadHeader(fp, infoHeader)))
   {
     DALI_LOG_ERROR("Info header read failed\n");
     return false;
@@ -107,7 +107,7 @@ bool LoadBmpHeader(FILE* fp, unsigned int& width, unsigned int& height, BmpFileH
   width  = infoHeader.width;
   height = abs(infoHeader.height);
 
-  if(infoHeader.width == 0)
+  if(DALI_UNLIKELY(infoHeader.width == 0))
   {
     DALI_LOG_ERROR("Invalid header size\n");
     return false;
@@ -136,20 +136,20 @@ bool DecodeRGB24V5(FILE*          fp,
                    unsigned int   rowStride,
                    unsigned int   padding)
 {
-  if(fp == NULL || pixels == NULL)
+  if(DALI_UNLIKELY(fp == NULL || pixels == NULL))
   {
     DALI_LOG_ERROR("Error decoding BMP_RGB24V5 format\n");
     return false;
   }
-  if(fseek(fp, offset, SEEK_SET))
+  if(DALI_UNLIKELY(fseek(fp, offset, SEEK_SET)))
   {
     DALI_LOG_ERROR("Error seeking BMP_RGB24V5 data\n");
     return false;
   }
 
-  for(unsigned int yPos = 0; yPos < height; yPos++)
+  for(std::uint32_t yPos = 0; yPos < height; ++yPos)
   {
-    unsigned char* pixelsPtr = NULL;
+    std::uint8_t* pixelsPtr = NULL;
     if(topDown)
     {
       pixelsPtr = pixels + (yPos * rowStride);
@@ -158,22 +158,22 @@ bool DecodeRGB24V5(FILE*          fp,
     {
       pixelsPtr = pixels + (((height - 1) - yPos) * rowStride);
     }
-    if(fread(pixelsPtr, 1, rowStride, fp) != rowStride)
+    if(DALI_UNLIKELY(fread(pixelsPtr, 1, rowStride, fp) != rowStride))
     {
       DALI_LOG_ERROR("Error reading the BMP image\n");
       return false;
     }
-    for(unsigned int i = 0; i < rowStride; i += 3)
+    for(std::uint32_t i = 0; i < rowStride; i += 3)
     {
-      unsigned char temp = pixelsPtr[i];
-      pixelsPtr[i]       = pixelsPtr[i + 2];
-      pixelsPtr[i + 2]   = temp;
+      std::uint8_t temp = pixelsPtr[i];
+      pixelsPtr[i]      = pixelsPtr[i + 2];
+      pixelsPtr[i + 2]  = temp;
     }
 
     if(padding)
     {
       // move past the padding.
-      if(fseek(fp, padding, SEEK_CUR))
+      if(DALI_UNLIKELY(fseek(fp, padding, SEEK_CUR)))
       {
         DALI_LOG_ERROR("Error moving past BMP_RGB24V5 padding\n");
       }
@@ -203,20 +203,20 @@ bool DecodeBF32V4(FILE*          fp,
                   unsigned int   rowStride,
                   unsigned int   padding)
 {
-  if(fp == NULL || pixels == NULL)
+  if(DALI_UNLIKELY(fp == NULL || pixels == NULL))
   {
     DALI_LOG_ERROR("Error decoding BMP_BITFIELDS32V4 format\n");
     return false;
   }
-  if(fseek(fp, offset, SEEK_SET))
+  if(DALI_UNLIKELY(fseek(fp, offset, SEEK_SET)))
   {
     DALI_LOG_ERROR("Error seeking BMP_BITFIELDS32V4 data\n");
     return false;
   }
 
-  for(unsigned int yPos = 0; yPos < height; yPos++)
+  for(std::uint32_t yPos = 0; yPos < height; ++yPos)
   {
-    unsigned char* pixelsPtr = NULL;
+    std::uint8_t* pixelsPtr = NULL;
     if(topDown)
     {
       pixelsPtr = pixels + (yPos * rowStride);
@@ -225,21 +225,21 @@ bool DecodeBF32V4(FILE*          fp,
     {
       pixelsPtr = pixels + (((height - 1) - yPos) * rowStride);
     }
-    if(fread(pixelsPtr, 1, rowStride, fp) != rowStride)
+    if(DALI_UNLIKELY(fread(pixelsPtr, 1, rowStride, fp) != rowStride))
     {
       DALI_LOG_ERROR("Error reading the BMP image\n");
       return false;
     }
-    for(unsigned int i = 0; i < rowStride; i += 4)
+    for(std::uint32_t i = 0; i < rowStride; i += 4)
     {
-      unsigned char temp = pixelsPtr[i];
-      pixelsPtr[i]       = pixelsPtr[i + 2];
-      pixelsPtr[i + 2]   = temp;
+      std::uint8_t temp = pixelsPtr[i];
+      pixelsPtr[i]      = pixelsPtr[i + 2];
+      pixelsPtr[i + 2]  = temp;
     }
     if(padding)
     {
       // move past the padding.
-      if(fseek(fp, padding, SEEK_CUR))
+      if(DALI_UNLIKELY(fseek(fp, padding, SEEK_CUR)))
       {
         DALI_LOG_ERROR("Error moving past BMP_BITFIELDS32V4 padding\n");
       }
@@ -269,20 +269,20 @@ bool DecodeBF32(FILE*          fp,
                 unsigned int   rowStride,
                 unsigned int   padding)
 {
-  if(fp == NULL || pixels == NULL)
+  if(DALI_UNLIKELY(fp == NULL || pixels == NULL))
   {
     DALI_LOG_ERROR("Error decoding BMP_BITFIELDS32 format\n");
     return false;
   }
-  if(fseek(fp, offset, SEEK_SET))
+  if(DALI_UNLIKELY(fseek(fp, offset, SEEK_SET)))
   {
     DALI_LOG_ERROR("Error seeking BMP_BITFIELDS32 data\n");
     return false;
   }
 
-  for(unsigned int yPos = 0; yPos < height; yPos++)
+  for(std::uint32_t yPos = 0; yPos < height; ++yPos)
   {
-    unsigned char* pixelsPtr;
+    std::uint8_t* pixelsPtr;
     if(topDown)
     {
       // the data in the file is top down, and we store the data top down
@@ -294,22 +294,22 @@ bool DecodeBF32(FILE*          fp,
       pixelsPtr = pixels + (((height - 1) - yPos) * rowStride);
     }
 
-    if(fread(pixelsPtr, 1, rowStride, fp) != rowStride)
+    if(DALI_UNLIKELY(fread(pixelsPtr, 1, rowStride, fp) != rowStride))
     {
       DALI_LOG_ERROR("Error reading the BMP image\n");
       return false;
     }
-    for(unsigned int i = 0; i < rowStride; i += 4)
+    for(std::uint32_t i = 0; i < rowStride; i += 4)
     {
-      unsigned char temp = pixelsPtr[i];
-      pixelsPtr[i]       = pixelsPtr[i + 2];
-      pixelsPtr[i + 2]   = temp;
+      std::uint8_t temp = pixelsPtr[i];
+      pixelsPtr[i]      = pixelsPtr[i + 2];
+      pixelsPtr[i + 2]  = temp;
     }
 
     if(padding)
     {
       // move past the padding.
-      if(fseek(fp, padding, SEEK_CUR))
+      if(DALI_UNLIKELY(fseek(fp, padding, SEEK_CUR)))
       {
         DALI_LOG_ERROR("Error moving past BMP_BITFIELDS32 padding\n");
       }
@@ -335,23 +335,23 @@ bool DecodeBF565(FILE*          fp,
                  unsigned int   offset,
                  bool           topDown)
 {
-  if(fp == NULL || pixels == NULL)
+  if(DALI_UNLIKELY(fp == NULL || pixels == NULL))
   {
     DALI_LOG_ERROR("Error decoding RGB565 format\n");
     return false;
   }
-  if(fseek(fp, offset, SEEK_SET))
+  if(DALI_UNLIKELY(fseek(fp, offset, SEEK_SET)))
   {
     DALI_LOG_ERROR("Error seeking RGB565 data\n");
     return false;
   }
 
-  width                  = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
-  unsigned int rowStride = width * 2;
+  width                   = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
+  std::uint32_t rowStride = width * 2;
 
-  for(unsigned int i = 0; i < height; i++)
+  for(std::uint32_t i = 0; i < height; ++i)
   {
-    unsigned char* pixelsPtr = NULL;
+    std::uint8_t* pixelsPtr = NULL;
     if(topDown)
     {
       // the data in the file is top down, and we store the data top down
@@ -362,7 +362,7 @@ bool DecodeBF565(FILE*          fp,
       // the data in the file is bottom up, and we store the data top down
       pixelsPtr = pixels + (((height - 1) - i) * rowStride);
     }
-    if(fread(pixelsPtr, 1, rowStride, fp) != rowStride)
+    if(DALI_UNLIKELY(fread(pixelsPtr, 1, rowStride, fp) != rowStride))
     {
       return false;
     }
@@ -388,13 +388,13 @@ bool DecodeBF555(FILE*          fp,
                  unsigned int   offset,
                  bool           topDown)
 {
-  if(fp == NULL || pixels == NULL)
+  if(DALI_UNLIKELY(fp == NULL || pixels == NULL))
   {
     DALI_LOG_ERROR("Error decoding BMP_BITFIELDS555 format\n");
     return false;
   }
 
-  if(fseek(fp, offset, SEEK_SET))
+  if(DALI_UNLIKELY(fseek(fp, offset, SEEK_SET)))
   {
     DALI_LOG_ERROR("Error seeking BMP_BITFIELDS555 data\n");
     return false;
@@ -402,23 +402,23 @@ bool DecodeBF555(FILE*          fp,
 
   width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
 
-  std::vector<char> raw(width * height * 2);
-  unsigned int      rawStride = width * 2;
-  unsigned int      rowStride = width * 3;
+  std::vector<std::uint8_t> raw(width * height * 2);
+  std::uint32_t             rawStride = width * 2;
+  std::uint32_t             rowStride = width * 3;
 
-  char* rawPtr = NULL;
-  for(unsigned int j = 0; j < height; j++)
+  std::uint8_t* rawPtr = NULL;
+  for(std::uint32_t j = 0; j < height; ++j)
   {
     rawPtr = &raw[0] + (j * rawStride);
-    if(fread(rawPtr, 1, rawStride, fp) != rawStride)
+    if(DALI_UNLIKELY(fread(rawPtr, 1, rawStride, fp) != rawStride))
     {
       return false;
     }
   }
 
-  for(unsigned int yPos = 0; yPos < height; yPos++)
+  for(std::uint32_t yPos = 0; yPos < height; ++yPos)
   {
-    unsigned char* pixelsPtr = NULL;
+    std::uint8_t* pixelsPtr = NULL;
     if(topDown)
     {
       // the data in the file is top down, and we store the data top down
@@ -430,9 +430,9 @@ bool DecodeBF555(FILE*          fp,
       pixelsPtr = pixels + (((height - 1) - yPos) * rowStride);
     }
 
-    for(unsigned int k = 0; k < width; k++)
+    for(std::uint32_t k = 0; k < width; ++k)
     {
-      int index            = yPos * rawStride + 2 * k;
+      std::uint32_t index  = yPos * rawStride + 2 * k;
       pixelsPtr[3 * k]     = ((raw[index + 1] >> 2) & 0x1F) * 0xFF / 0x1F;
       pixelsPtr[3 * k + 1] = (((raw[index + 1] & 0x03) << 3) | (raw[index] >> 5)) * 0xFF / 0x1F;
       pixelsPtr[3 * k + 2] = (raw[index] & 0x1F) * 0xFF / 0x1F;
@@ -458,34 +458,34 @@ bool DecodeRGB555(FILE*          fp,
                   unsigned int   offset,
                   bool           topDown)
 {
-  if(fp == NULL || pixels == NULL)
+  if(DALI_UNLIKELY(fp == NULL || pixels == NULL))
   {
     DALI_LOG_ERROR("Error decoding BMP_RGB555 format\n");
     return false;
   }
-  if(fseek(fp, offset, SEEK_SET))
+  if(DALI_UNLIKELY(fseek(fp, offset, SEEK_SET)))
   {
     DALI_LOG_ERROR("Error seeking BMP_RGB555 data\n");
     return false;
   }
 
   width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
-  std::vector<char> raw(width * height * 2);
-  unsigned int      rawStride = width * 2;
-  unsigned int      rowStride = width * 3;
+  std::vector<std::uint8_t> raw(width * height * 2);
+  std::uint32_t             rawStride = width * 2;
+  std::uint32_t             rowStride = width * 3;
 
-  char* rawPtr = NULL;
-  for(unsigned int j = 0; j < height; j++)
+  std::uint8_t* rawPtr = NULL;
+  for(std::uint32_t j = 0; j < height; ++j)
   {
     rawPtr = &raw[0] + (j * rawStride);
-    if(fread(rawPtr, 1, rawStride, fp) != rawStride)
+    if(DALI_UNLIKELY(fread(rawPtr, 1, rawStride, fp) != rawStride))
     {
       return false;
     }
   }
-  for(unsigned int i = 0; i < height; i++)
+  for(std::uint32_t i = 0; i < height; ++i)
   {
-    unsigned char* pixelsPtr = NULL;
+    std::uint8_t* pixelsPtr = NULL;
     if(topDown)
     {
       // the data in the file is top down, and we store the data top down
@@ -496,9 +496,9 @@ bool DecodeRGB555(FILE*          fp,
       // the data in the file is bottom up, and we store the data top down
       pixelsPtr = pixels + (((height - 1) - i) * rowStride);
     }
-    for(unsigned int k = 0; k < width; k++)
+    for(std::uint32_t k = 0; k < width; ++k)
     {
-      int index            = i * rawStride + 2 * k;
+      std::uint32_t index  = i * rawStride + 2 * k;
       pixelsPtr[3 * k]     = ((raw[index + 1] >> 2) & 0x1F) * 0xFF / 0x1F;
       pixelsPtr[3 * k + 1] = (((raw[index + 1] & 0x03) << 3) | (raw[index] >> 5)) * 0xFF / 0x1F;
       pixelsPtr[3 * k + 2] = (raw[index] & 0x1F) * 0xFF / 0x1F;
@@ -524,31 +524,31 @@ bool DecodeRGB1(FILE*          fp,
                 unsigned int   offset,
                 bool           topDown)
 {
-  if(fp == NULL || pixels == NULL)
+  if(DALI_UNLIKELY(fp == NULL || pixels == NULL))
   {
     DALI_LOG_ERROR("Error decoding BMP_RGB1 format\n");
     return false;
   }
-  if(fseek(fp, offset, SEEK_SET))
+  if(DALI_UNLIKELY(fseek(fp, offset, SEEK_SET)))
   {
     DALI_LOG_ERROR("Error seeking BMP_RGB1 data\n");
     return false;
   }
 
-  unsigned char     colorTable[8] = {0};
-  char              cmd;
-  unsigned int      fillw = ((width & 63) != 0) ? width + 64 - (width & 63) : width;
-  std::vector<char> colorIndex(fillw * height);
-  unsigned int      rowStride = fillw * 3; // RGB
+  std::uint8_t              colorTable[8] = {0};
+  std::uint8_t              cmd;
+  std::uint32_t             fillw = ((width & 63) != 0) ? width + 64 - (width & 63) : width;
+  std::vector<std::uint8_t> colorIndex(fillw * height);
+  std::uint32_t             rowStride = fillw * 3; // RGB
 
-  if(fread(colorTable, 1, 8, fp) != 8)
+  if(DALI_UNLIKELY(fread(colorTable, 1, 8, fp) != 8))
   {
     return false;
   }
 
-  for(unsigned int i = 0; i < fillw * height; i += 8)
+  for(std::uint32_t i = 0; i < fillw * height; i += 8)
   {
-    if(fread(&cmd, 1, 1, fp) != 1)
+    if(DALI_UNLIKELY(fread(&cmd, 1, 1, fp) != 1))
     {
       return false;
     }
@@ -563,9 +563,9 @@ bool DecodeRGB1(FILE*          fp,
     colorIndex[i + 7] = (cmd & 0x01);
   }
 
-  for(unsigned int index = 0; index < height; index = index + 1)
+  for(std::uint32_t index = 0; index < height; ++index)
   {
-    unsigned char* pixelsPtr = NULL;
+    std::uint8_t* pixelsPtr = NULL;
     if(topDown)
     {
       // the data in the file is top down, and we store the data top down
@@ -576,9 +576,9 @@ bool DecodeRGB1(FILE*          fp,
       // the data in the file is bottom up, and we store the data top down
       pixelsPtr = pixels + (((height - 1) - index) * rowStride);
     }
-    for(unsigned int j = 0; j < fillw; j++)
+    for(std::uint32_t j = 0; j < fillw; ++j)
     {
-      unsigned int ctIndex = 0;
+      std::uint32_t ctIndex = 0;
       if((fillw * index + j) < (fillw * height))
       {
         ctIndex = colorIndex[fillw * index + j];
@@ -616,31 +616,31 @@ bool DecodeRGB4(FILE*          fp,
                 unsigned int   offset,
                 bool           topDown)
 {
-  if(fp == NULL || pixels == NULL)
+  if(DALI_UNLIKELY(fp == NULL || pixels == NULL))
   {
     DALI_LOG_ERROR("Error decoding BMP_RGB4 format\n");
     return false;
   }
-  if(fseek(fp, offset, SEEK_SET))
+  if(DALI_UNLIKELY(fseek(fp, offset, SEEK_SET)))
   {
     DALI_LOG_ERROR("Error seeking BMP_RGB4 data\n");
     return false;
   }
 
-  char              colorTable[64];
-  char              cmd;
-  unsigned int      fillw = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
-  std::vector<char> colorIndex(fillw * height);
-  unsigned int      rowStride = fillw * 3;
+  std::uint8_t              colorTable[64];
+  std::uint8_t              cmd;
+  std::uint32_t             fillw = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
+  std::vector<std::uint8_t> colorIndex(fillw * height);
+  std::uint32_t             rowStride = fillw * 3;
 
-  if(fread(colorTable, 1, 64, fp) != 64)
+  if(DALI_UNLIKELY(fread(colorTable, 1, 64, fp) != 64))
   {
     return false;
   }
 
-  for(unsigned int i = 0; i < fillw * height; i += 2)
+  for(std::uint32_t i = 0; i < fillw * height; i += 2)
   {
-    if(fread(&cmd, 1, 1, fp) != 1)
+    if(DALI_UNLIKELY(fread(&cmd, 1, 1, fp) != 1))
     {
       return false;
     }
@@ -648,11 +648,11 @@ bool DecodeRGB4(FILE*          fp,
     colorIndex[i]     = cmd >> 4;
     colorIndex[i + 1] = cmd & (0x0F);
   }
-  unsigned int ctIndex = 0;
+  std::uint32_t ctIndex = 0;
 
-  for(unsigned int index = 0; index < height; index = index + 1)
+  for(std::uint32_t index = 0; index < height; ++index)
   {
-    unsigned char* pixelsPtr = NULL;
+    std::uint8_t* pixelsPtr = NULL;
     if(topDown)
     {
       // the data in the file is top down, and we store the data top down
@@ -663,7 +663,7 @@ bool DecodeRGB4(FILE*          fp,
       // the data in the file is bottom up, and we store the data top down
       pixelsPtr = pixels + (((height - 1) - index) * rowStride);
     }
-    for(unsigned int j = 0; j < fillw; j++)
+    for(std::uint32_t j = 0; j < fillw; ++j)
     {
       ctIndex                = colorIndex[fillw * index + j];
       pixelsPtr[3 * j]       = colorTable[4 * ctIndex + 2];
@@ -692,40 +692,34 @@ bool DecodeRGB8(FILE*          fp,
                 unsigned int   offset,
                 bool           topDown)
 {
-  if(fp == NULL || pixels == NULL)
+  if(DALI_UNLIKELY(fp == NULL || pixels == NULL))
   {
     DALI_LOG_ERROR("Error decoding BMP_RGB8 format\n");
     return false;
   }
-  if(fseek(fp, offset, SEEK_SET))
+  if(DALI_UNLIKELY(fseek(fp, offset, SEEK_SET)))
   {
     DALI_LOG_ERROR("Error seeking BMP_RGB8 data\n");
     return false;
   }
 
-  std::vector<char> colorTable(1024);
+  std::vector<std::uint8_t> colorTable(1024);
   width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
-  char              cmd;
-  std::vector<char> colorIndex(width * height);
-  unsigned int      rowStride = width * 3; //RGB8->RGB24
+  std::vector<std::uint8_t> colorIndex(width * height);
+  std::uint32_t             rowStride = width * 3; //RGB8->RGB24
 
-  if(fread(&colorTable[0], 1, 1024, fp) != 1024)
+  if(DALI_UNLIKELY(fread(&colorTable[0], 1, 1024, fp) != 1024))
   {
     return false;
   }
-  for(unsigned int i = 0; i < width * height; i++)
+  if(DALI_UNLIKELY(fread(&colorIndex[0], 1, width * height, fp) != width * height))
   {
-    if(fread(&cmd, 1, 1, fp) != 1)
-    {
-      return false;
-    }
-
-    colorIndex[i] = cmd;
+    return false;
   }
-  unsigned int ctIndex = 0;
-  for(unsigned int index = 0; index < height; index = index + 1)
+  std::uint8_t ctIndex = 0;
+  for(std::uint32_t index = 0; index < height; ++index)
   {
-    unsigned char* pixelsPtr = NULL;
+    std::uint8_t* pixelsPtr = NULL;
     if(topDown)
     {
       // the data in the file is top down, and we store the data top down
@@ -736,7 +730,7 @@ bool DecodeRGB8(FILE*          fp,
       // the data in the file is bottom up, and we store the data top down
       pixelsPtr = pixels + (((height - 1) - index) * rowStride);
     }
-    for(unsigned int j = 0; j < width; j++)
+    for(std::uint8_t j = 0; j < width; ++j)
     {
       ctIndex                = colorIndex[width * index + j];
       pixelsPtr[3 * j]       = colorTable[4 * ctIndex + 2];
@@ -764,34 +758,34 @@ bool DecodeRLE4(FILE*          fp,
                 unsigned int   offset,
                 bool           topDown)
 {
-  if(fp == NULL || pixels == NULL)
+  if(DALI_UNLIKELY(fp == NULL || pixels == NULL))
   {
     DALI_LOG_ERROR("Error decoding BMP_RLE4 format\n");
     return false;
   }
-  unsigned char* pixelsPtr = pixels;
-  width                    = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
-  char              cmd[2];
-  unsigned int      cmdStride = 2;
-  char              colorTable[64];
-  std::vector<char> colorIndex(width * height >> 1);
-  std::vector<char> run;
-  unsigned int      x  = 0;
-  unsigned int      y  = 0;
-  unsigned int      dx = 0;
-  unsigned int      dy = 0;
+  std::uint8_t* pixelsPtr = pixels;
+  width                   = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
+  std::uint8_t              cmd[2];
+  std::uint32_t             cmdStride = 2;
+  std::uint8_t              colorTable[64];
+  std::vector<std::uint8_t> colorIndex(width * height >> 1);
+  std::vector<std::uint8_t> run;
+  std::uint32_t             x  = 0;
+  std::uint32_t             y  = 0;
+  std::uint32_t             dx = 0;
+  std::uint32_t             dy = 0;
   width += (width & 1);
   width = width >> 1;
 
   bool finish = false;
 
-  if(fseek(fp, offset, SEEK_SET))
+  if(DALI_UNLIKELY(fseek(fp, offset, SEEK_SET)))
   {
     DALI_LOG_ERROR("Error seeking BMP_RLE4 data\n");
     return false;
   }
 
-  if(fread(colorTable, 1, 64, fp) != 64)
+  if(DALI_UNLIKELY(fread(colorTable, 1, 64, fp) != 64))
   {
     return false;
   }
@@ -802,7 +796,7 @@ bool DecodeRLE4(FILE*          fp,
     {
       break;
     }
-    if(fread(cmd, 1, cmdStride, fp) != cmdStride)
+    if(DALI_UNLIKELY(fread(cmd, 1, cmdStride, fp) != cmdStride))
     {
       return false;
     }
@@ -818,7 +812,7 @@ bool DecodeRLE4(FILE*          fp,
           y++;
           break;
         case 2: // delta
-          if(fread(cmd, 1, cmdStride, fp) != cmdStride)
+          if(DALI_UNLIKELY(fread(cmd, 1, cmdStride, fp) != cmdStride))
           {
             DALI_LOG_ERROR("Error reading the BMP image\n");
             return false;
@@ -830,14 +824,14 @@ bool DecodeRLE4(FILE*          fp,
           break;
         default:
           // decode a literal run
-          unsigned int length = cmd[1] & (0xFF);
+          std::uint32_t length = cmd[1] & (0xFF);
           //size of run, which is word aligned
-          unsigned int bytesize = length;
+          std::uint32_t bytesize = length;
           bytesize += (bytesize & 1);
           bytesize >>= 1;
           bytesize += (bytesize & 1);
           run.resize(bytesize);
-          if(fread(&run[0], 1, bytesize, fp) != bytesize)
+          if(DALI_UNLIKELY(fread(&run[0], 1, bytesize, fp) != bytesize))
           {
             DALI_LOG_ERROR("Error reading the BMP image\n");
             return false;
@@ -846,14 +840,14 @@ bool DecodeRLE4(FILE*          fp,
           {
             length += (length & 1);
             length >>= 1;
-            for(unsigned int i = 0; i < length; i += 1)
+            for(std::uint32_t i = 0; i < length; ++i)
             {
               colorIndex[(x >> 1) + width * (height - y - 1) + i] = run[i];
             }
           }
           else
           {
-            for(unsigned int i = 0; i < length; i++)
+            for(std::uint32_t i = 0; i < length; ++i)
             {
               if((i & 1) == 0) //copy high to low
               {
@@ -871,19 +865,19 @@ bool DecodeRLE4(FILE*          fp,
     }
     else
     {
-      unsigned int length = cmd[0] & (0xFF);
+      std::uint32_t length = cmd[0] & (0xFF);
       if((x & 1) == 0)
       {
         length += (length & 1);
         length >>= 1;
-        for(unsigned int i = 0; i < length; i++)
+        for(std::uint32_t i = 0; i < length; ++i)
         {
           colorIndex[(height - y - 1) * width + i + (x >> 1)] = cmd[1];
         }
       }
       else
       {
-        for(unsigned int i = 0; i < length; i++)
+        for(std::uint32_t i = 0; i < length; ++i)
         {
           if((i & 1) == 0)
           {
@@ -899,9 +893,9 @@ bool DecodeRLE4(FILE*          fp,
     }
   }
 
-  int ctIndexHigh = 0;
-  int ctIndexLow  = 0;
-  for(unsigned int index = 0; index < (width * height); index = index + 1)
+  std::uint32_t ctIndexHigh = 0;
+  std::uint32_t ctIndexLow  = 0;
+  for(std::uint32_t index = 0; index < (width * height); ++index)
   {
     ctIndexHigh              = colorIndex[index] >> 4;
     ctIndexLow               = colorIndex[index] & (0x0F);
@@ -932,45 +926,45 @@ bool DecodeRLE8(FILE*          fp,
                 unsigned int   offset,
                 bool           topDown)
 {
-  if(fp == NULL || pixels == NULL)
+  if(DALI_UNLIKELY(fp == NULL || pixels == NULL))
   {
     DALI_LOG_ERROR("Error decoding BMP_RLE8 format\n");
     return false;
   }
-  unsigned char* pixelsPtr = pixels;
-  unsigned int   x         = 0;
-  unsigned int   y         = 0;
-  unsigned int   cmdStride = 2;
+  std::uint8_t* pixelsPtr = pixels;
+  std::uint32_t x         = 0;
+  std::uint32_t y         = 0;
+  std::uint32_t cmdStride = 2;
 
   width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
-  std::vector<char> colorTable(1024);
-  char              cmd[2];
-  std::vector<char> colorIndex(width * height);
+  std::vector<std::uint8_t> colorTable(1024);
+  std::uint8_t              cmd[2];
+  std::vector<std::uint8_t> colorIndex(width * height);
 
-  if(fseek(fp, offset, SEEK_SET))
+  if(DALI_UNLIKELY(fseek(fp, offset, SEEK_SET)))
   {
     DALI_LOG_ERROR("Error seeking BMP_RLE8 data\n");
     return false;
   }
 
-  if(fread(&colorTable[0], 1, 1024, fp) != 1024)
+  if(DALI_UNLIKELY(fread(&colorTable[0], 1, 1024, fp) != 1024))
   {
     return false;
   }
 
-  unsigned int      dx         = 0;
-  unsigned int      dy         = 0;
-  bool              finish     = false;
-  unsigned int      length     = 0;
-  unsigned int      copylength = 0;
-  std::vector<char> run;
+  std::uint32_t             dx         = 0;
+  std::uint32_t             dy         = 0;
+  bool                      finish     = false;
+  std::uint32_t             length     = 0;
+  std::uint32_t             copylength = 0;
+  std::vector<std::uint8_t> run;
   while((x + y * width) < width * height)
   {
-    if(finish)
+    if(DALI_UNLIKELY(finish))
     {
       break;
     }
-    if(fread(cmd, 1, cmdStride, fp) != cmdStride)
+    if(DALI_UNLIKELY(fread(cmd, 1, cmdStride, fp) != cmdStride))
     {
       return false;
     }
@@ -987,7 +981,7 @@ bool DecodeRLE8(FILE*          fp,
           y++;
           break;
         case 2: // delta
-          if(fread(cmd, 1, cmdStride, fp) != cmdStride)
+          if(DALI_UNLIKELY(fread(cmd, 1, cmdStride, fp) != cmdStride))
           {
             DALI_LOG_ERROR("Error reading the BMP image\n");
             return false;
@@ -1004,13 +998,13 @@ bool DecodeRLE8(FILE*          fp,
           //absolute mode must be word-aligned
           length += (length & 1);
           run.resize(length);
-          if(fread(&run[0], 1, length, fp) != length)
+          if(DALI_UNLIKELY(fread(&run[0], 1, length, fp) != length))
           {
             DALI_LOG_ERROR("Error reading the BMP image\n");
             return false;
           }
 
-          for(unsigned int i = 0; i < length; i += 1)
+          for(std::uint32_t i = 0; i < length; ++i)
           {
             colorIndex[x + width * (height - y - 1) + i] = run[i];
           }
@@ -1021,15 +1015,15 @@ bool DecodeRLE8(FILE*          fp,
     else
     {
       length = cmd[0] & (0xFF);
-      for(unsigned int i = 0; i < length; i++)
+      for(std::uint32_t i = 0; i < length; ++i)
       {
         colorIndex[(height - y - 1) * width + x] = cmd[1];
         x++;
       }
     }
   }
-  int ctIndex = 0;
-  for(unsigned int index = 0; index < width * height; index = index + 1)
+  std::uint32_t ctIndex = 0;
+  for(std::uint32_t index = 0; index < width * height; ++index)
   {
     ctIndex                  = colorIndex[index];
     pixelsPtr[3 * index]     = colorTable[4 * ctIndex + 2];
@@ -1055,7 +1049,7 @@ bool LoadBitmapFromBmp(const Dali::ImageLoader::Input& input, Dali::Devel::Pixel
 {
   //DALI_ASSERT_DEBUG( bitmap.GetPackedPixelsProfile() != 0 && "Need a packed pixel bitmap to load into." );
   FILE* const fp = input.file;
-  if(fp == NULL)
+  if(DALI_UNLIKELY(fp == NULL))
   {
     DALI_LOG_ERROR("Error loading bitmap\n");
     return false;
@@ -1067,7 +1061,7 @@ bool LoadBitmapFromBmp(const Dali::ImageLoader::Input& input, Dali::Devel::Pixel
   // Load the header info
   unsigned int width, height;
 
-  if(!LoadBmpHeader(fp, width, height, fileHeader, infoHeader))
+  if(DALI_UNLIKELY(!LoadBmpHeader(fp, width, height, fileHeader, infoHeader)))
   {
     return false;
   }
@@ -1133,13 +1127,13 @@ bool LoadBitmapFromBmp(const Dali::ImageLoader::Input& input, Dali::Devel::Pixel
     {
       if(infoHeader.bitsPerPixel == 16)
       {
-        if(fseek(fp, 14 + infoHeader.infoHeaderSize + 1, SEEK_SET))
+        if(DALI_UNLIKELY(fseek(fp, 14 + infoHeader.infoHeaderSize + 1, SEEK_SET)))
         {
           return false;
         }
 
         char mask;
-        if(fread(&mask, 1, 1, fp) != 1)
+        if(DALI_UNLIKELY(fread(&mask, 1, 1, fp) != 1))
         {
           return false;
         }
@@ -1328,7 +1322,7 @@ bool LoadBitmapFromBmp(const Dali::ImageLoader::Input& input, Dali::Devel::Pixel
             pixelsIterator = pixels + (((height - 1) - yPos) * rowStride);
           }
 
-          if(fread(pixelsIterator, 1, rowStride, fp) != rowStride)
+          if(DALI_UNLIKELY(fread(pixelsIterator, 1, rowStride, fp) != rowStride))
           {
             DALI_LOG_ERROR("Error reading the BMP image\n");
             break;
@@ -1348,7 +1342,7 @@ bool LoadBitmapFromBmp(const Dali::ImageLoader::Input& input, Dali::Devel::Pixel
 
           if(padding)
           {
-            if(fseek(fp, padding, SEEK_CUR)) // move past the padding.
+            if(DALI_UNLIKELY(fseek(fp, padding, SEEK_CUR))) // move past the padding.
             {
               DALI_LOG_ERROR("Error moving past BMP padding\n");
             }
@@ -1360,7 +1354,7 @@ bool LoadBitmapFromBmp(const Dali::ImageLoader::Input& input, Dali::Devel::Pixel
     }
   } // switch
 
-  if(!decodeResult)
+  if(DALI_UNLIKELY(!decodeResult))
   {
     DALI_LOG_ERROR("Decoding failed\n");
     return false;
index 57da14f..c8e9091 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -100,7 +100,7 @@ bool LoadGifHeader(FILE* fp, unsigned int& width, unsigned int& height, GifFileT
   *gifInfo = DGifOpen(reinterpret_cast<void*>(fp), ReadDataFromGif);
 #endif
 
-  if(!(*gifInfo) || errorCode)
+  if(DALI_UNLIKELY(!(*gifInfo) || errorCode))
   {
     DALI_LOG_ERROR("GIF Loader: DGifOpen Error. Code: %d\n", errorCode);
     return false;
@@ -110,7 +110,7 @@ bool LoadGifHeader(FILE* fp, unsigned int& width, unsigned int& height, GifFileT
   height = (*gifInfo)->SHeight;
 
   // No proper size in GIF.
-  if(width <= 0 || height <= 0)
+  if(DALI_UNLIKELY(width <= 0 || height <= 0))
   {
     return false;
   }
@@ -131,7 +131,7 @@ bool DecodeImage(GifFileType* gifInfo, unsigned char* decodedData, const unsigne
       for(unsigned int currentByte = interlacePairPtr->startingByte; currentByte < height; currentByte += interlacePairPtr->incrementalByte)
       {
         unsigned char* row = decodedData + currentByte * bytesPerRow;
-        if(DGifGetLine(gifInfo, row, width) == GIF_ERROR)
+        if(DALI_UNLIKELY(DGifGetLine(gifInfo, row, width) == GIF_ERROR))
         {
           DALI_LOG_ERROR("GIF Loader: Error reading Interlaced GIF\n");
           return false;
@@ -146,7 +146,7 @@ bool DecodeImage(GifFileType* gifInfo, unsigned char* decodedData, const unsigne
 
     for(unsigned int row = 0; row < height; ++row)
     {
-      if(DGifGetLine(gifInfo, decodedDataPtr, width) == GIF_ERROR)
+      if(DALI_UNLIKELY(DGifGetLine(gifInfo, decodedDataPtr, width) == GIF_ERROR))
       {
         DALI_LOG_ERROR("GIF Loader: Error reading non-interlaced GIF\n");
         return false;
@@ -176,14 +176,14 @@ GifColorType* GetImageColors(SavedImage* image, GifFileType* gifInfo)
 /// Called when we want to handle IMAGE_DESC_RECORD_TYPE
 bool HandleImageDescriptionRecordType(Dali::Devel::PixelBuffer& bitmap, GifFileType* gifInfo, unsigned int width, unsigned int height, bool& finished)
 {
-  if(DGifGetImageDesc(gifInfo) == GIF_ERROR)
+  if(DALI_UNLIKELY(DGifGetImageDesc(gifInfo) == GIF_ERROR))
   {
     DALI_LOG_ERROR("GIF Loader: Error getting Image Description\n");
     return false;
   }
 
   // Ensure there is at least 1 image in the GIF.
-  if(gifInfo->ImageCount < 1)
+  if(DALI_UNLIKELY(gifInfo->ImageCount < 1))
   {
     DALI_LOG_ERROR("GIF Loader: No Images\n");
     return false;
@@ -206,7 +206,7 @@ bool HandleImageDescriptionRecordType(Dali::Devel::PixelBuffer& bitmap, GifFileT
   bitmap = Dali::Devel::PixelBuffer::New(actualWidth, actualHeight, pixelFormat);
 
   // Decode the GIF Image
-  if(!DecodeImage(gifInfo, decodedData, actualWidth, actualHeight, bytesPerRow))
+  if(DALI_UNLIKELY(!DecodeImage(gifInfo, decodedData, actualWidth, actualHeight, bytesPerRow)))
   {
     return false;
   }
@@ -256,7 +256,7 @@ bool HandleExtensionRecordType(GifFileType* gifInfo)
       extensionByte != NULL;
       extRetCode = DGifGetExtensionNext(gifInfo, &extensionByte))
   {
-    if(extRetCode == GIF_ERROR)
+    if(DALI_UNLIKELY(extRetCode == GIF_ERROR))
     {
       DALI_LOG_ERROR("GIF Loader: Error reading GIF Extension record.\n");
       return false;
@@ -285,7 +285,7 @@ bool LoadBitmapFromGif(const Dali::ImageLoader::Input& input, Dali::Devel::Pixel
   GifFileType* gifInfo(NULL);
   unsigned int width(0);
   unsigned int height(0);
-  if(!LoadGifHeader(fp, width, height, &gifInfo))
+  if(DALI_UNLIKELY(!LoadGifHeader(fp, width, height, &gifInfo)))
   {
     return false;
   }
@@ -299,7 +299,7 @@ bool LoadBitmapFromGif(const Dali::ImageLoader::Input& input, Dali::Devel::Pixel
       !finished && recordType != TERMINATE_RECORD_TYPE;
       returnCode = DGifGetRecordType(gifInfo, &recordType))
   {
-    if(returnCode == GIF_ERROR)
+    if(DALI_UNLIKELY(returnCode == GIF_ERROR))
     {
       DALI_LOG_ERROR("GIF Loader: Error getting Record Type\n");
       return false;
@@ -307,14 +307,14 @@ bool LoadBitmapFromGif(const Dali::ImageLoader::Input& input, Dali::Devel::Pixel
 
     if(IMAGE_DESC_RECORD_TYPE == recordType)
     {
-      if(!HandleImageDescriptionRecordType(bitmap, gifInfo, width, height, finished))
+      if(DALI_UNLIKELY(!HandleImageDescriptionRecordType(bitmap, gifInfo, width, height, finished)))
       {
         return false;
       }
     }
     else if(EXTENSION_RECORD_TYPE == recordType)
     {
-      if(!HandleExtensionRecordType(gifInfo))
+      if(DALI_UNLIKELY(!HandleExtensionRecordType(gifInfo)))
       {
         return false;
       }
index ac68291..b23eaee 100644 (file)
@@ -80,11 +80,11 @@ typedef unsigned char DATA8;
 #define ARGB_JOIN(a, r, g, b) \
   (((a) << 24) + ((r) << 16) + ((g) << 8) + (b))
 
-bool read_ushort(unsigned char* map, size_t length, size_t* position, unsigned short* ret)
+bool read_ushort(const unsigned char* const& map, size_t length, size_t* position, unsigned short* ret)
 {
   unsigned char b[2];
 
-  if(*position + 2 > length)
+  if(DALI_UNLIKELY(*position + 2 > length))
   {
     return false;
   }
@@ -94,12 +94,12 @@ bool read_ushort(unsigned char* map, size_t length, size_t* position, unsigned s
   return true;
 }
 
-bool read_uint(unsigned char* map, size_t length, size_t* position, unsigned int* ret)
+bool read_uint(const unsigned char* const& map, size_t length, size_t* position, unsigned int* ret)
 {
   unsigned char b[4];
   unsigned int  i;
 
-  if(*position + 4 > length)
+  if(DALI_UNLIKELY(*position + 4 > length))
   {
     return false;
   }
@@ -111,9 +111,9 @@ bool read_uint(unsigned char* map, size_t length, size_t* position, unsigned int
   return true;
 }
 
-bool read_uchar(unsigned char* map, size_t length, size_t* position, unsigned char* ret)
+bool read_uchar(const unsigned char* const& map, size_t length, size_t* position, unsigned char* ret)
 {
-  if(*position + 1 > length)
+  if(DALI_UNLIKELY(*position + 1 > length))
   {
     return false;
   }
@@ -121,9 +121,9 @@ bool read_uchar(unsigned char* map, size_t length, size_t* position, unsigned ch
   return true;
 }
 
-bool read_mem(unsigned char* map, size_t length, size_t* position, void* buffer, int size)
+bool read_mem(const unsigned char* const& map, size_t length, size_t* position, void* buffer, int size)
 {
-  if(*position + size > length)
+  if(DALI_UNLIKELY(*position + size > length))
   {
     return false;
   }
@@ -163,7 +163,7 @@ bool LoadIcoHeaderHelper(FILE*                        fp,
 {
   memset(&chosen, 0, sizeof(chosen));
 
-  if(fp == NULL)
+  if(DALI_UNLIKELY(fp == NULL))
   {
     DALI_LOG_ERROR("Error loading bitmap\n");
     return false;
@@ -172,7 +172,7 @@ bool LoadIcoHeaderHelper(FILE*                        fp,
   unsigned short word;
   unsigned char  byte;
 
-  if(fseek(fp, 0, SEEK_END))
+  if(DALI_UNLIKELY(fseek(fp, 0, SEEK_END)))
   {
     DALI_LOG_ERROR("Error seeking ICO data\n");
     return false;
@@ -186,45 +186,46 @@ bool LoadIcoHeaderHelper(FILE*                        fp,
     fsize = static_cast<unsigned int>(positionIndicator);
   }
 
-  if(0u == fsize)
+  if(DALI_UNLIKELY(0u == fsize))
   {
     return false;
   }
 
-  if(fseek(fp, 0, SEEK_SET))
+  if(DALI_UNLIKELY(fseek(fp, 0, SEEK_SET)))
   {
     DALI_LOG_ERROR("Error seeking ICO data\n");
     return false;
   }
 
-  if(fsize < (ICO_FILE_HEADER + ICO_IMAGE_INFO_HEADER)) //6 + 16 + 40
+  if(DALI_UNLIKELY(fsize < (ICO_FILE_HEADER + ICO_IMAGE_INFO_HEADER))) //6 + 16 + 40
   {
     return false;
   }
   map.ResizeUninitialized(fsize);
-
-  if(fread(&map[0], 1, fsize, fp) != fsize)
+  if(DALI_UNLIKELY(fread(&map[0], 1, fsize, fp) != fsize))
   {
     DALI_LOG_WARNING("image file read opeation error!\n");
     return false;
   }
 
+  const std::uint8_t* const inputBufferPtr = &map[0];
+
   int            search = BIGGEST;
   unsigned short reserved, type, count;
-  if(!read_ushort(&map[0], fsize, &position, &reserved))
+  if(DALI_UNLIKELY(!read_ushort(inputBufferPtr, fsize, &position, &reserved)))
   {
     return false;
   }
-  if(!read_ushort(&map[0], fsize, &position, &type))
+  if(DALI_UNLIKELY(!read_ushort(inputBufferPtr, fsize, &position, &type)))
   {
     return false;
   }
-  if(!read_ushort(&map[0], fsize, &position, &count))
+  if(DALI_UNLIKELY(!read_ushort(inputBufferPtr, fsize, &position, &count)))
   {
     return false;
   }
-  if(!((reserved == 0) &&
-       ((type == ICON) || (type == CURSOR)) && (count != 0)))
+  if(DALI_UNLIKELY(!((reserved == 0) &&
+                     ((type == ICON) || (type == CURSOR)) && (count != 0))))
   {
     return false;
   }
@@ -235,7 +236,7 @@ bool LoadIcoHeaderHelper(FILE*                        fp,
   for(unsigned short i = 0; i < count; i++)
   {
     unsigned char tw = 0, th = 0, tcols = 0;
-    if(!read_uchar(&map[0], fsize, &position, &tw))
+    if(DALI_UNLIKELY(!read_uchar(inputBufferPtr, fsize, &position, &tw)))
     {
       return false;
     }
@@ -244,7 +245,7 @@ bool LoadIcoHeaderHelper(FILE*                        fp,
     {
       w = 256;
     }
-    if(!read_uchar(&map[0], fsize, &position, &th))
+    if(DALI_UNLIKELY(!read_uchar(inputBufferPtr, fsize, &position, &th)))
     {
       return false;
     }
@@ -253,16 +254,16 @@ bool LoadIcoHeaderHelper(FILE*                        fp,
     {
       h = 256;
     }
-    if(!read_uchar(&map[0], fsize, &position, &tcols))
+    if(DALI_UNLIKELY(!read_uchar(inputBufferPtr, fsize, &position, &tcols)))
     {
       return false;
     }
     int cols = tcols;
-    if(!read_uchar(&map[0], fsize, &position, &byte))
+    if(DALI_UNLIKELY(!read_uchar(inputBufferPtr, fsize, &position, &byte)))
     {
       return false;
     }
-    if(!read_ushort(&map[0], fsize, &position, &word))
+    if(DALI_UNLIKELY(!read_ushort(inputBufferPtr, fsize, &position, &word)))
     {
       return false;
     }
@@ -272,7 +273,7 @@ bool LoadIcoHeaderHelper(FILE*                        fp,
       planes = word;
     }
     //else hot_x = word;
-    if(!read_ushort(&map[0], fsize, &position, &word))
+    if(DALI_UNLIKELY(!read_ushort(inputBufferPtr, fsize, &position, &word)))
     {
       return false;
     }
@@ -291,15 +292,15 @@ bool LoadIcoHeaderHelper(FILE*                        fp,
 
     //else hot_y = word;
     unsigned int bmoffset, bmsize;
-    if(!read_uint(&map[0], fsize, &position, &bmsize))
+    if(DALI_UNLIKELY(!read_uint(inputBufferPtr, fsize, &position, &bmsize)))
     {
       return false;
     }
-    if(!read_uint(&map[0], fsize, &position, &bmoffset))
+    if(DALI_UNLIKELY(!read_uint(inputBufferPtr, fsize, &position, &bmoffset)))
     {
       return false;
     }
-    if((bmsize <= 0) || (bmoffset <= 0) || (bmoffset >= fsize))
+    if(DALI_UNLIKELY((bmsize <= 0) || (bmoffset <= 0) || (bmoffset >= fsize)))
     {
       return false;
     }
@@ -324,7 +325,7 @@ bool LoadIcoHeaderHelper(FILE*                        fp,
     }
   }
 
-  if(chosen.bmoffset == 0)
+  if(DALI_UNLIKELY(chosen.bmoffset == 0))
   {
     return false;
   }
@@ -335,9 +336,9 @@ bool LoadIcoHeaderHelper(FILE*                        fp,
 /**
  * @brief Handle the different bits per pixel
  * @param[in] bitcount The bit count
- * @param[in/out] map The map to use/set
+ * @param[in] inputBufferPtr The map to use
  * @param[in/out] pix A reference to the pointer to the pix buffer
- * @param[in/out] surface A reference to the surface buffer
+ * @param[in/out] outputBufferPtr A reference to the surface buffer
  * @param[in] width The width
  * @param[in] height The height
  * @param[in] fsize The file size
@@ -348,24 +349,28 @@ bool LoadIcoHeaderHelper(FILE*                        fp,
  */
 bool HandleBitsPerPixel(
   const unsigned int                bitcount,
-  Dali::Vector<unsigned char>&      map,
+  const std::uint8_t* const&        inputBufferPtr,
   unsigned int*&                    pix,
-  Dali::Vector<unsigned int>&       surface,
+  std::uint32_t* const&             outputBufferPtr,
   const unsigned int                width,
   const unsigned int                height,
   const unsigned int                fsize,
   size_t&                           position,
-  Dali::Vector<unsigned char>&      pixbuf,
   const unsigned int                stride,
   const Dali::Vector<unsigned int>& palette)
 {
+  // Pixbuf only ever contains one scanline worth of data.
+  Dali::Vector<std::uint8_t> pixbuf;
+  pixbuf.ResizeUninitialized(stride);
+  std::uint8_t* lineBufferPtr = &pixbuf[0];
+
   // Note: Switch is in order of most common format first.
   switch(bitcount)
   {
     case 32:
     {
-      unsigned char* p = &map[position];
-      pix              = &surface[0] + ((height - 1) * width);
+      const std::uint8_t* p = inputBufferPtr + position;
+      pix                   = outputBufferPtr + ((height - 1) * width);
 
       for(unsigned int i = 0; i < height; i++)
       {
@@ -384,12 +389,12 @@ bool HandleBitsPerPixel(
     {
       for(unsigned int i = 0; i < height; i++)
       {
-        pix = &surface[0] + ((height - 1 - i) * width);
-        if(!read_mem(&map[0], fsize, &position, &pixbuf[0], stride))
+        pix = outputBufferPtr + ((height - 1 - i) * width);
+        if(DALI_UNLIKELY(!read_mem(inputBufferPtr, fsize, &position, lineBufferPtr, stride)))
         {
           return false;
         }
-        unsigned char* p = &pixbuf[0];
+        const std::uint8_t* p = lineBufferPtr;
         for(unsigned int j = 0; j < width; j++)
         {
           *pix++ = ARGB_JOIN(0xff, p[0], p[1], p[2]);
@@ -403,12 +408,12 @@ bool HandleBitsPerPixel(
     {
       for(unsigned int i = 0; i < height; i++)
       {
-        pix = &surface[0] + ((height - 1 - i) * width);
-        if(!read_mem(&map[0], fsize, &position, &pixbuf[0], stride))
+        pix = outputBufferPtr + ((height - 1 - i) * width);
+        if(DALI_UNLIKELY(!read_mem(inputBufferPtr, fsize, &position, lineBufferPtr, stride)))
         {
           return false;
         }
-        unsigned char* p = &pixbuf[0];
+        const std::uint8_t* p = lineBufferPtr;
         for(unsigned int j = 0; j < width; j++)
         {
           *pix++ = palette[*p++];
@@ -421,12 +426,12 @@ bool HandleBitsPerPixel(
     {
       for(unsigned int i = 0; i < height; i++)
       {
-        pix = &surface[0] + ((height - 1 - i) * width);
-        if(!read_mem(&map[0], fsize, &position, &pixbuf[0], stride))
+        pix = outputBufferPtr + ((height - 1 - i) * width);
+        if(DALI_UNLIKELY(!read_mem(inputBufferPtr, fsize, &position, lineBufferPtr, stride)))
         {
           return false;
         }
-        unsigned char* p = &pixbuf[0];
+        const std::uint8_t* p = lineBufferPtr;
         for(unsigned int j = 0; j < width; j++)
         {
           if(j & 0x1)
@@ -446,16 +451,18 @@ bool HandleBitsPerPixel(
 
     case 1:
     {
+      const std::uint32_t bytesPerWidth          = width / 8;
+      const std::uint32_t bytesRemainingPerWidth = width & 7;
       for(unsigned int i = 0; i < height; i++)
       {
-        pix = &surface[0] + ((height - 1 - i) * width);
-        if(!read_mem(&map[0], fsize, &position, &pixbuf[0], stride))
+        pix = outputBufferPtr + ((height - 1 - i) * width);
+        if(DALI_UNLIKELY(!read_mem(inputBufferPtr, fsize, &position, lineBufferPtr, stride)))
         {
           return false;
         }
-        unsigned char* p = &pixbuf[0];
 
-        for(unsigned int j = 0; j < width; j += 8)
+        const std::uint8_t* p = lineBufferPtr;
+        for(unsigned int j = 0; j < bytesPerWidth; ++j)
         {
           *pix++ = palette[*p >> 7];
           *pix++ = palette[*p >> 6 & 0x01];
@@ -466,7 +473,15 @@ bool HandleBitsPerPixel(
           *pix++ = palette[*p >> 1 & 0x01];
           *pix++ = palette[*p >> 0 & 0x01];
 
-          p++;
+          ++p;
+        }
+        if(bytesRemainingPerWidth > 0)
+        {
+          for(std::uint32_t j = 0; j < bytesRemainingPerWidth; ++j)
+          {
+            *pix++ = palette[(*p >> (7 - j)) & 0x01];
+          }
+          ++p;
         }
       }
       break;
@@ -484,31 +499,28 @@ bool HandleBitsPerPixel(
 
 /**
  * @brief Apply the mask if required
- * @param[in/out] map The map to use/set
+ * @param[in] inputBufferPtr The map to use
  * @param[in] fsize The file size
  * @param[in/out] position The position in the file
- * @param[in//out] maskbuf The mask buffer
  * @param[in] bitStride The stride
  * @param[in] width The width
  * @param[in] height The height
  * @param[in/out] pix A reference to the pointer to the pix buffer
- * @param[in/out] surface A reference to the surface buffer
+ * @param[in/out] outputBufferPtr A reference to the surface buffer
  */
 bool ApplyMask(
-  Dali::Vector<unsigned char>& map,
-  const unsigned int           fsize,
-  size_t&                      position,
-  Dali::Vector<unsigned char>& maskbuf,
-  const unsigned int           bitStride,
-  const unsigned int           width,
-  const unsigned int           height,
-  unsigned int*&               pix,
-  Dali::Vector<unsigned int>&  surface)
+  const std::uint8_t* const& inputBufferPtr,
+  const unsigned int         fsize,
+  size_t&                    position,
+  const unsigned int         bitStride,
+  const unsigned int         width,
+  const unsigned int         height,
+  unsigned int*&             pix,
+  std::uint32_t* const&      outputBufferPtr)
 {
-  if(!read_mem(&map[0], fsize, &position, &maskbuf[0], bitStride * height))
-  {
-    return false;
-  }
+  Dali::Vector<std::uint8_t> maskbuf;
+  maskbuf.ResizeUninitialized(bitStride);
+  std::uint8_t* lineBufferPtr = &maskbuf[0];
 
   // Apply mask.
   // Precalc to save time in the loops.
@@ -518,8 +530,12 @@ bool ApplyMask(
   // Loop for each line of the image.
   for(unsigned int i = 0; i < height; ++i)
   {
-    unsigned char* m = &maskbuf[0] + (bitStride * i);
-    pix              = &surface[0] + ((height - 1 - i) * width);
+    pix = outputBufferPtr + ((height - 1 - i) * width);
+    if(DALI_UNLIKELY(!read_mem(inputBufferPtr, fsize, &position, lineBufferPtr, bitStride)))
+    {
+      return false;
+    }
+    const std::uint8_t* m = lineBufferPtr;
 
     // Do chunks of 8 pixels first so mask operations can be unrolled.
     for(unsigned int j = 0; j < bytesPerWidth; ++j)
@@ -561,7 +577,7 @@ bool LoadIcoHeader(const Dali::ImageLoader::Input& input, unsigned int& width, u
   unsigned int                fsize;
   FILE* const                 fp = input.file;
 
-  if(false == LoadIcoHeaderHelper(fp, chosen, map, fsize))
+  if(DALI_UNLIKELY(false == LoadIcoHeaderHelper(fp, chosen, map, fsize)))
   {
     return false;
   }
@@ -579,17 +595,11 @@ bool LoadBitmapFromIco(const Dali::ImageLoader::Input& input, Dali::Devel::Pixel
   unsigned int                fsize;
   FILE* const                 fp = input.file;
 
-  if(false == LoadIcoHeaderHelper(fp, chosen, map, fsize))
+  if(DALI_UNLIKELY(false == LoadIcoHeaderHelper(fp, chosen, map, fsize)))
   {
     return false;
   }
 
-  Dali::Vector<unsigned int>  pal;
-  Dali::Vector<unsigned int>  surface;
-  Dali::Vector<unsigned char> maskbuf;
-  Dali::Vector<unsigned char> pixbuf;
-  pal.Resize(256 * 4);
-
   unsigned int   dword;
   unsigned short word;
 
@@ -602,12 +612,14 @@ bool LoadBitmapFromIco(const Dali::ImageLoader::Input& input, Dali::Devel::Pixel
   unsigned int h    = chosen.h;
   unsigned int cols = chosen.cols;
 
+  const std::uint8_t* const inputBufferPtr = &map[0];
+
   // read bmp header time... let's do some checking
-  if(!read_uint(&map[0], fsize, &position, &dword))
+  if(DALI_UNLIKELY(!read_uint(inputBufferPtr, fsize, &position, &dword)))
   {
     return false; // headersize - dont care
   }
-  if(!read_uint(&map[0], fsize, &position, &dword))
+  if(DALI_UNLIKELY(!read_uint(inputBufferPtr, fsize, &position, &dword)))
   {
     return false; // width
   }
@@ -619,7 +631,7 @@ bool LoadBitmapFromIco(const Dali::ImageLoader::Input& input, Dali::Devel::Pixel
       diff_size = 1;
     }
   }
-  if(!read_uint(&map[0], fsize, &position, &dword))
+  if(DALI_UNLIKELY(!read_uint(inputBufferPtr, fsize, &position, &dword)))
   {
     return false; // height
   }
@@ -636,95 +648,98 @@ bool LoadBitmapFromIco(const Dali::ImageLoader::Input& input, Dali::Devel::Pixel
     DALI_LOG_WARNING("Broken ICO file!\n");
   }
 
-  // Set up the surface as soon as we have the width and height, so we have a black image if there are any further errors.
-  surface.ResizeUninitialized(w * h * 4);
-  memset(&surface[0], 0, w * h * 4);
-
-  if(!read_ushort(&map[0], fsize, &position, &word))
+  if(DALI_UNLIKELY(!read_ushort(inputBufferPtr, fsize, &position, &word)))
   {
     return false; // planes
   }
   //planes2 = word;
-  if(!read_ushort(&map[0], fsize, &position, &word))
+  if(DALI_UNLIKELY(!read_ushort(inputBufferPtr, fsize, &position, &word)))
   {
     return false; // bitcount
   }
   unsigned int bitcount = word;
-  if(!read_uint(&map[0], fsize, &position, &dword))
+  if(DALI_UNLIKELY(!read_uint(inputBufferPtr, fsize, &position, &dword)))
   {
     return false; // compression
   }
   //compression = dword;
-  if(!read_uint(&map[0], fsize, &position, &dword))
+  if(DALI_UNLIKELY(!read_uint(inputBufferPtr, fsize, &position, &dword)))
   {
     return false; // imagesize
   }
   //imagesize = dword;
-  if(!read_uint(&map[0], fsize, &position, &dword))
+  if(DALI_UNLIKELY(!read_uint(inputBufferPtr, fsize, &position, &dword)))
   {
     return false; // z pixels per m
   }
-  if(!read_uint(&map[0], fsize, &position, &dword))
+  if(DALI_UNLIKELY(!read_uint(inputBufferPtr, fsize, &position, &dword)))
   {
     return false; // y pizels per m
   }
-  if(!read_uint(&map[0], fsize, &position, &dword))
+  if(DALI_UNLIKELY(!read_uint(inputBufferPtr, fsize, &position, &dword)))
   {
     return false; // colors used
   }
   //colorsused = dword;
-  if(!read_uint(&map[0], fsize, &position, &dword))
+  if(DALI_UNLIKELY(!read_uint(inputBufferPtr, fsize, &position, &dword)))
   {
     return false; // colors important
   }
 
+  Dali::Vector<unsigned int> pal;
+  pal.Resize(256 * 4);
   for(unsigned int i = 0; i < cols; i++)
   {
     unsigned char a, r, g, b;
 
-    if(!read_uchar(&map[0], fsize, &position, &b))
+    if(DALI_UNLIKELY(!read_uchar(inputBufferPtr, fsize, &position, &b)))
     {
       return false;
     }
-    if(!read_uchar(&map[0], fsize, &position, &g))
+    if(DALI_UNLIKELY(!read_uchar(inputBufferPtr, fsize, &position, &g)))
     {
       return false;
     }
-    if(!read_uchar(&map[0], fsize, &position, &r))
+    if(DALI_UNLIKELY(!read_uchar(inputBufferPtr, fsize, &position, &r)))
     {
       return false;
     }
-    if(!read_uchar(&map[0], fsize, &position, &a))
+    if(DALI_UNLIKELY(!read_uchar(inputBufferPtr, fsize, &position, &a)))
     {
       return false;
     }
     pal[i] = ARGB_JOIN(0xff, b, g, r);
   }
 
+  Dali::Vector<std::uint32_t> surface;
+
   // This is the reference way of calculating the total number of bytes necessary to store one row of pixels.
   unsigned int stride    = (((bitcount * w) + 31) / 32) * 4;
   unsigned int bitStride = ((w + 31) / 32) * 4;
+  // Set up the surface as soon as we have the width and height.
+  surface.ResizeUninitialized(w * h);
 
-  // Pixbuf only ever contains one scanline worth of data.
-  pixbuf.ResizeUninitialized(stride);
-  maskbuf.ResizeUninitialized(bitStride * h);
+  std::uint32_t* const outputBufferPtr = &surface[0];
 
   // Handle different bits-per-pixel.
-  if(!HandleBitsPerPixel(bitcount, map, pix, surface, w, h, fsize, position, pixbuf, stride, pal))
+  if(DALI_UNLIKELY(!HandleBitsPerPixel(bitcount, inputBufferPtr, pix, outputBufferPtr, w, h, fsize, position, stride, pal)))
   {
     return false;
   }
 
   // From the spec: If bpp is less than 32, there will be a 1bpp mask bitmap also.
-  if((bitcount < 32) && !ApplyMask(map, fsize, position, maskbuf, bitStride, w, h, pix, surface))
+  if(bitcount < 32)
   {
-    // Return false if not able to apply mask when the bpp is less than 32
-    return false;
+    if(DALI_UNLIKELY(!ApplyMask(inputBufferPtr, fsize, position, bitStride, w, h, pix, outputBufferPtr)))
+    {
+      // Return false if not able to apply mask when the bpp is less than 32
+      return false;
+    }
   }
 
   bitmap      = Dali::Devel::PixelBuffer::New(w, h, Pixel::Format::RGBA8888);
   auto pixels = bitmap.GetBuffer();
-  memcpy(pixels, &surface[0], w * h * 4);
+  memcpy(pixels, outputBufferPtr, w * h * 4);
 
   return true;
 }
index 7ed1d1c..dc39f24 100644 (file)
@@ -113,6 +113,22 @@ bool IsJpegErrorFatal(const std::string& errorMessage)
   return true;
 }
 
+bool IsJpegDecodingFailed()
+{
+  std::string errorString = tjGetErrorStr();
+
+  if(DALI_UNLIKELY(IsJpegErrorFatal(errorString)))
+  {
+    DALI_LOG_ERROR("%s\n", errorString.c_str());
+    return true;
+  }
+  else
+  {
+    DALI_LOG_WARNING("%s\n", errorString.c_str());
+    return false;
+  }
+}
+
 // helpers for safe exif memory handling
 using ExifHandle = std::unique_ptr<ExifData, decltype(exif_data_free)*>;
 
@@ -476,12 +492,202 @@ void Rotate270(PixelArray buffer, int width, int height)
   }
 }
 
+void GetJpegPixelFormat(int jpegColorspace, TJPF& pixelLibJpegType, Pixel::Format& pixelFormat)
+{
+  pixelLibJpegType = TJPF_RGB;
+  pixelFormat      = Pixel::RGB888;
+
+  switch(jpegColorspace)
+  {
+    case TJCS_RGB:
+    // YCbCr is not an absolute colorspace but rather a mathematical transformation of RGB designed solely for storage and transmission.
+    // YCbCr images must be converted to RGB before they can actually be displayed.
+    case TJCS_YCbCr:
+    {
+      pixelLibJpegType = TJPF_RGB;
+      pixelFormat      = Pixel::RGB888;
+      break;
+    }
+    case TJCS_GRAY:
+    {
+      pixelLibJpegType = TJPF_GRAY;
+      pixelFormat      = Pixel::L8;
+      break;
+    }
+    case TJCS_CMYK:
+    case TJCS_YCCK:
+    {
+      pixelLibJpegType = TJPF_CMYK;
+      pixelFormat      = Pixel::RGBA8888;
+      break;
+    }
+    default:
+    {
+      pixelLibJpegType = TJPF_RGB;
+      pixelFormat      = Pixel::RGB888;
+      break;
+    }
+  }
+}
+
+bool TransformBitmap(int scaledPreXformWidth, int scaledPreXformHeight, JpegTransform transform, uint8_t* bitmapPixelBuffer, Pixel::Format pixelFormat)
+{
+  const unsigned int bufferWidth  = Dali::TizenPlatform::GetTextureDimension(scaledPreXformWidth);
+  const unsigned int bufferHeight = Dali::TizenPlatform::GetTextureDimension(scaledPreXformHeight);
+
+  bool result = false;
+
+  switch(transform)
+  {
+    case JpegTransform::NONE:
+    {
+      result = true;
+      break;
+    }
+    // 3 orientation changes for a camera held perpendicular to the ground or upside-down:
+    case JpegTransform::ROTATE_180:
+    {
+      static auto rotate180Functions = TransformFunctionArray{
+        &Rotate180<1>,
+        &Rotate180<3>,
+        &Rotate180<4>,
+      };
+      result = Transform(rotate180Functions, bitmapPixelBuffer, bufferWidth, bufferHeight, pixelFormat);
+      break;
+    }
+    case JpegTransform::ROTATE_270:
+    {
+      static auto rotate270Functions = TransformFunctionArray{
+        &Rotate270<1>,
+        &Rotate270<3>,
+        &Rotate270<4>,
+      };
+      result = Transform(rotate270Functions, bitmapPixelBuffer, bufferWidth, bufferHeight, pixelFormat);
+      break;
+    }
+    case JpegTransform::ROTATE_90:
+    {
+      static auto rotate90Functions = TransformFunctionArray{
+        &Rotate90<1>,
+        &Rotate90<3>,
+        &Rotate90<4>,
+      };
+      result = Transform(rotate90Functions, bitmapPixelBuffer, bufferWidth, bufferHeight, pixelFormat);
+      break;
+    }
+    case JpegTransform::FLIP_VERTICAL:
+    {
+      static auto flipVerticalFunctions = TransformFunctionArray{
+        &FlipVertical<1>,
+        &FlipVertical<3>,
+        &FlipVertical<4>,
+      };
+      result = Transform(flipVerticalFunctions, bitmapPixelBuffer, bufferWidth, bufferHeight, pixelFormat);
+      break;
+    }
+    // Less-common orientation changes, since they don't correspond to a camera's physical orientation:
+    case JpegTransform::FLIP_HORIZONTAL:
+    {
+      static auto flipHorizontalFunctions = TransformFunctionArray{
+        &FlipHorizontal<1>,
+        &FlipHorizontal<3>,
+        &FlipHorizontal<4>,
+      };
+      result = Transform(flipHorizontalFunctions, bitmapPixelBuffer, bufferWidth, bufferHeight, pixelFormat);
+      break;
+    }
+    case JpegTransform::TRANSPOSE:
+    {
+      static auto transposeFunctions = TransformFunctionArray{
+        &Transpose<1>,
+        &Transpose<3>,
+        &Transpose<4>,
+      };
+      result = Transform(transposeFunctions, bitmapPixelBuffer, bufferWidth, bufferHeight, pixelFormat);
+      break;
+    }
+    case JpegTransform::TRANSVERSE:
+    {
+      static auto transverseFunctions = TransformFunctionArray{
+        &Transverse<1>,
+        &Transverse<3>,
+        &Transverse<4>,
+      };
+      result = Transform(transverseFunctions, bitmapPixelBuffer, bufferWidth, bufferHeight, pixelFormat);
+      break;
+    }
+    default:
+    {
+      DALI_LOG_ERROR("Unsupported JPEG Orientation transformation: %x.\n", transform);
+      break;
+    }
+  }
+  return result;
+}
+
+bool LoadJpegFile(const Dali::ImageLoader::Input& input, Vector<uint8_t>& jpegBuffer, unsigned int& jpegBufferSize)
+{
+  FILE* const fp = input.file;
+
+  if(DALI_UNLIKELY(fseek(fp, 0, SEEK_END)))
+  {
+    DALI_LOG_ERROR("Error seeking to end of file\n");
+    return false;
+  }
+
+  long positionIndicator = ftell(fp);
+  jpegBufferSize         = 0u;
+  if(positionIndicator > -1L)
+  {
+    jpegBufferSize = static_cast<unsigned int>(positionIndicator);
+  }
+
+  if(DALI_UNLIKELY(0u == jpegBufferSize))
+  {
+    DALI_LOG_ERROR("Jpeg buffer size error\n");
+    return false;
+  }
+
+  if(DALI_UNLIKELY(fseek(fp, 0, SEEK_SET)))
+  {
+    DALI_LOG_ERROR("Error seeking to start of file\n");
+    return false;
+  }
+
+  try
+  {
+    jpegBuffer.ResizeUninitialized(jpegBufferSize);
+  }
+  catch(...)
+  {
+    DALI_LOG_ERROR("Could not allocate temporary memory to hold JPEG file of size %uMB.\n", jpegBufferSize / 1048576U);
+    return false;
+  }
+  unsigned char* const jpegBufferPtr = jpegBuffer.Begin();
+
+  // Pull the compressed JPEG image bytes out of a file and into memory:
+  if(DALI_UNLIKELY(fread(jpegBufferPtr, 1, jpegBufferSize, fp) != jpegBufferSize))
+  {
+    DALI_LOG_ERROR("Error on image file read.\n");
+    return false;
+  }
+
+  if(DALI_UNLIKELY(fseek(fp, 0, SEEK_SET)))
+  {
+    DALI_LOG_ERROR("Error seeking to start of file\n");
+    return false;
+  }
+
+  return true;
+}
+
 } // namespace
 
 namespace Dali
 {
 namespace TizenPlatform
 {
+bool          DecodeJpeg(const Dali::ImageLoader::Input& input, std::vector<Dali::Devel::PixelBuffer>& pixelBuffers, bool decodeToYuv);
 JpegTransform ConvertExifOrientation(ExifData* exifData);
 bool          TransformSize(int requiredWidth, int requiredHeight, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, JpegTransform transform, int& preXformImageWidth, int& preXformImageHeight, int& postXformImageWidth, int& postXformImageHeight);
 
@@ -497,7 +703,7 @@ bool LoadJpegHeader(FILE* fp, unsigned int& width, unsigned int& height)
 
   // On error exit from the JPEG lib, control will pass via JpegErrorHandler
   // into this branch body for cleanup and error return:
-  if(setjmp(jerr.jumpBuffer))
+  if(DALI_UNLIKELY(setjmp(jerr.jumpBuffer)))
   {
     DALI_LOG_ERROR("setjmp failed\n");
     jpeg_destroy_decompress(&cinfo);
@@ -513,7 +719,7 @@ bool LoadJpegHeader(FILE* fp, unsigned int& width, unsigned int& height)
   jpeg_stdio_src(&cinfo, fp);
 
   // Check header to see if it is  JPEG file
-  if(jpeg_read_header(&cinfo, TRUE) != JPEG_HEADER_OK)
+  if(DALI_UNLIKELY(jpeg_read_header(&cinfo, TRUE) != JPEG_HEADER_OK))
   {
     DALI_LOG_ERROR("jpeg_read_header failed\n");
     width = height = 0;
@@ -530,67 +736,45 @@ bool LoadJpegHeader(FILE* fp, unsigned int& width, unsigned int& height)
 
 bool LoadBitmapFromJpeg(const Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& bitmap)
 {
-  const int   flags = 0;
-  FILE* const fp    = input.file;
+  std::vector<Dali::Devel::PixelBuffer> pixelBuffers;
 
-  if(fseek(fp, 0, SEEK_END))
+  bool result = DecodeJpeg(input, pixelBuffers, false);
+  if(!result && pixelBuffers.empty())
   {
-    DALI_LOG_ERROR("Error seeking to end of file\n");
-    return false;
+    bitmap.Reset();
   }
-
-  long         positionIndicator = ftell(fp);
-  unsigned int jpegBufferSize    = 0u;
-  if(positionIndicator > -1L)
-  {
-    jpegBufferSize = static_cast<unsigned int>(positionIndicator);
-  }
-
-  if(0u == jpegBufferSize)
+  else
   {
-    DALI_LOG_ERROR("Jpeg buffer size error\n");
-    return false;
+    bitmap = pixelBuffers[0];
   }
+  return result;
+}
 
-  if(fseek(fp, 0, SEEK_SET))
-  {
-    DALI_LOG_ERROR("Error seeking to start of file\n");
-    return false;
-  }
+bool LoadPlanesFromJpeg(const Dali::ImageLoader::Input& input, std::vector<Dali::Devel::PixelBuffer>& pixelBuffers)
+{
+  return DecodeJpeg(input, pixelBuffers, true);
+}
 
-  Vector<unsigned char> jpegBuffer;
-  try
-  {
-    jpegBuffer.ResizeUninitialized(jpegBufferSize);
-  }
-  catch(...)
-  {
-    DALI_LOG_ERROR("Could not allocate temporary memory to hold JPEG file of size %uMB.\n", jpegBufferSize / 1048576U);
-    return false;
-  }
-  unsigned char* const jpegBufferPtr = jpegBuffer.Begin();
+bool DecodeJpeg(const Dali::ImageLoader::Input& input, std::vector<Dali::Devel::PixelBuffer>& pixelBuffers, bool decodeToYuv)
+{
+  Vector<uint8_t> jpegBuffer;
+  unsigned int    jpegBufferSize = 0u;
 
-  // Pull the compressed JPEG image bytes out of a file and into memory:
-  if(fread(jpegBufferPtr, 1, jpegBufferSize, fp) != jpegBufferSize)
+  if(!LoadJpegFile(input, jpegBuffer, jpegBufferSize))
   {
-    DALI_LOG_ERROR("Error on image file read.\n");
+    DALI_LOG_ERROR("LoadJpegFile failed\n");
     return false;
   }
 
-  if(fseek(fp, 0, SEEK_SET))
-  {
-    DALI_LOG_ERROR("Error seeking to start of file\n");
-  }
-
   auto jpeg = MakeJpegDecompressor();
-
-  if(!jpeg)
+  if(DALI_UNLIKELY(!jpeg))
   {
     DALI_LOG_ERROR("%s\n", tjGetErrorStr());
     return false;
   }
 
-  auto transform = JpegTransform::NONE;
+  uint8_t* const jpegBufferPtr = jpegBuffer.Begin();
+  auto           transform     = JpegTransform::NONE;
 
   // extract exif data
   auto exifData = MakeExifDataFromData(jpegBufferPtr, jpegBufferSize);
@@ -600,45 +784,18 @@ bool LoadBitmapFromJpeg(const Dali::ImageLoader::Input& input, Dali::Devel::Pixe
     transform = ConvertExifOrientation(exifData.get());
   }
 
-  std::unique_ptr<Property::Map> exifMap;
-  exifMap.reset(new Property::Map());
-
-  for(auto k = 0u; k < EXIF_IFD_COUNT; ++k)
-  {
-    auto content = exifData->ifd[k];
-    for(auto i = 0u; i < content->count; ++i)
-    {
-      auto&&      tag       = content->entries[i];
-      const char* shortName = exif_tag_get_name_in_ifd(tag->tag, static_cast<ExifIfd>(k));
-      if(shortName)
-      {
-        AddExifFieldPropertyMap(*exifMap, *tag, static_cast<ExifIfd>(k));
-      }
-    }
-  }
-
   // Push jpeg data in memory buffer through TurboJPEG decoder to make a raw pixel array:
   int chrominanceSubsampling = -1;
   int preXformImageWidth = 0, preXformImageHeight = 0;
-
-  // In Ubuntu, the turbojpeg version is not correct. so build error occurs.
-  // Temporarily separate Ubuntu and other profiles.
-#ifndef DALI_PROFILE_UBUNTU
   int jpegColorspace = -1;
+
   if(tjDecompressHeader3(jpeg.get(), jpegBufferPtr, jpegBufferSize, &preXformImageWidth, &preXformImageHeight, &chrominanceSubsampling, &jpegColorspace) == -1)
   {
     DALI_LOG_ERROR("%s\n", tjGetErrorStr());
     // Do not set width and height to 0 or return early as this sometimes fails only on determining subsampling type.
   }
-#else
-  if(tjDecompressHeader2(jpeg.get(), jpegBufferPtr, jpegBufferSize, &preXformImageWidth, &preXformImageHeight, &chrominanceSubsampling) == -1)
-  {
-    DALI_LOG_ERROR("%s\n", tjGetErrorStr());
-    // Do not set width and height to 0 or return early as this sometimes fails only on determining subsampling type.
-  }
-#endif
 
-  if(preXformImageWidth == 0 || preXformImageHeight == 0)
+  if(DALI_UNLIKELY(preXformImageWidth == 0 || preXformImageHeight == 0))
   {
     DALI_LOG_ERROR("Invalid Image!\n");
     return false;
@@ -660,153 +817,108 @@ bool LoadBitmapFromJpeg(const Dali::ImageLoader::Input& input, Dali::Devel::Pixe
 
   TransformSize(requiredWidth, requiredHeight, input.scalingParameters.scalingMode, input.scalingParameters.samplingMode, transform, scaledPreXformWidth, scaledPreXformHeight, scaledPostXformWidth, scaledPostXformHeight);
 
-  // Colorspace conversion options
-  TJPF          pixelLibJpegType = TJPF_RGB;
-  Pixel::Format pixelFormat      = Pixel::RGB888;
-#ifndef DALI_PROFILE_UBUNTU
-  switch(jpegColorspace)
+  bool result = false;
+
+  // Now we support YUV420 only
+  if(decodeToYuv && chrominanceSubsampling == TJSAMP_420 && transform == JpegTransform::NONE)
   {
-    case TJCS_RGB:
-    // YCbCr is not an absolute colorspace but rather a mathematical transformation of RGB designed solely for storage and transmission.
-    // YCbCr images must be converted to RGB before they can actually be displayed.
-    case TJCS_YCbCr:
-    {
-      pixelLibJpegType = TJPF_RGB;
-      pixelFormat      = Pixel::RGB888;
-      break;
-    }
-    case TJCS_GRAY:
-    {
-      pixelLibJpegType = TJPF_GRAY;
-      pixelFormat      = Pixel::L8;
-      break;
-    }
-    case TJCS_CMYK:
-    case TJCS_YCCK:
-    {
-      pixelLibJpegType = TJPF_CMYK;
-      pixelFormat      = Pixel::RGBA8888;
-      break;
-    }
-    default:
+    unsigned char* planes[3];
+
+    // Allocate buffers for each plane and decompress the jpeg buffer into the buffers
+    for(int i = 0; i < 3; i++)
     {
-      pixelLibJpegType = TJPF_RGB;
-      pixelFormat      = Pixel::RGB888;
-      break;
-    }
-  }
-#endif
-  // Allocate a bitmap and decompress the jpeg buffer into its pixel buffer:
-  bitmap = Dali::Devel::PixelBuffer::New(scaledPostXformWidth, scaledPostXformHeight, pixelFormat);
+      auto planeSize = tjPlaneSizeYUV(i, scaledPostXformWidth, 0, scaledPostXformHeight, chrominanceSubsampling);
 
-  // set metadata
-  GetImplementation(bitmap).SetMetadata(std::move(exifMap));
+      unsigned char* buffer = static_cast<unsigned char*>(malloc(planeSize));
+      if(!buffer)
+      {
+        DALI_LOG_ERROR("Buffer allocation is failed [%d]\n", planeSize);
+        pixelBuffers.clear();
+        return false;
+      }
 
-  auto bitmapPixelBuffer = bitmap.GetBuffer();
+      int           width, height, planeWidth;
+      Pixel::Format pixelFormat = Pixel::RGB888;
 
-  if(tjDecompress2(jpeg.get(), jpegBufferPtr, jpegBufferSize, reinterpret_cast<unsigned char*>(bitmapPixelBuffer), scaledPreXformWidth, 0, scaledPreXformHeight, pixelLibJpegType, flags) == -1)
-  {
-    std::string errorString = tjGetErrorStr();
+      if(i == 0)
+      {
+        // luminance plane
+        width       = scaledPostXformWidth;
+        height      = scaledPostXformHeight;
+        planeWidth  = tjPlaneWidth(i, scaledPostXformWidth, chrominanceSubsampling);
+        pixelFormat = Pixel::L8;
+      }
+      else
+      {
+        // chrominance plane
+        width       = tjPlaneWidth(i, scaledPostXformWidth, chrominanceSubsampling);
+        height      = tjPlaneHeight(i, scaledPostXformHeight, chrominanceSubsampling);
+        planeWidth  = width;
+        pixelFormat = (i == 1 ? Pixel::CHROMINANCE_U : Pixel::CHROMINANCE_V);
+      }
 
-    if(IsJpegErrorFatal(errorString))
-    {
-      DALI_LOG_ERROR("%s\n", errorString.c_str());
-      return false;
+      Internal::Adaptor::PixelBufferPtr internal = Internal::Adaptor::PixelBuffer::New(buffer, planeSize, width, height, planeWidth, pixelFormat);
+      Dali::Devel::PixelBuffer          bitmap   = Devel::PixelBuffer(internal.Get());
+      planes[i]                                  = buffer;
+      pixelBuffers.push_back(bitmap);
     }
-    else
+
+    const int flags = 0;
+
+    int decodeResult = tjDecompressToYUVPlanes(jpeg.get(), jpegBufferPtr, jpegBufferSize, reinterpret_cast<unsigned char**>(&planes), scaledPostXformWidth, nullptr, scaledPostXformHeight, flags);
+    if(decodeResult == -1 && IsJpegDecodingFailed())
     {
-      DALI_LOG_WARNING("%s\n", errorString.c_str());
+      pixelBuffers.clear();
+      return false;
     }
+
+    result = true;
   }
+  else
+  {
+    // Colorspace conversion options
+    TJPF          pixelLibJpegType = TJPF_RGB;
+    Pixel::Format pixelFormat      = Pixel::RGB888;
 
-  const unsigned int bufferWidth  = GetTextureDimension(scaledPreXformWidth);
-  const unsigned int bufferHeight = GetTextureDimension(scaledPreXformHeight);
+    GetJpegPixelFormat(jpegColorspace, pixelLibJpegType, pixelFormat);
 
-  bool result = false;
-  switch(transform)
-  {
-    case JpegTransform::NONE:
-    {
-      result = true;
-      break;
-    }
-    // 3 orientation changes for a camera held perpendicular to the ground or upside-down:
-    case JpegTransform::ROTATE_180:
-    {
-      static auto rotate180Functions = TransformFunctionArray{
-        &Rotate180<1>,
-        &Rotate180<3>,
-        &Rotate180<4>,
-      };
-      result = Transform(rotate180Functions, bitmapPixelBuffer, bufferWidth, bufferHeight, pixelFormat);
-      break;
-    }
-    case JpegTransform::ROTATE_270:
-    {
-      static auto rotate270Functions = TransformFunctionArray{
-        &Rotate270<1>,
-        &Rotate270<3>,
-        &Rotate270<4>,
-      };
-      result = Transform(rotate270Functions, bitmapPixelBuffer, bufferWidth, bufferHeight, pixelFormat);
-      break;
-    }
-    case JpegTransform::ROTATE_90:
-    {
-      static auto rotate90Functions = TransformFunctionArray{
-        &Rotate90<1>,
-        &Rotate90<3>,
-        &Rotate90<4>,
-      };
-      result = Transform(rotate90Functions, bitmapPixelBuffer, bufferWidth, bufferHeight, pixelFormat);
-      break;
-    }
-    case JpegTransform::FLIP_VERTICAL:
-    {
-      static auto flipVerticalFunctions = TransformFunctionArray{
-        &FlipVertical<1>,
-        &FlipVertical<3>,
-        &FlipVertical<4>,
-      };
-      result = Transform(flipVerticalFunctions, bitmapPixelBuffer, bufferWidth, bufferHeight, pixelFormat);
-      break;
-    }
-    // Less-common orientation changes, since they don't correspond to a camera's physical orientation:
-    case JpegTransform::FLIP_HORIZONTAL:
-    {
-      static auto flipHorizontalFunctions = TransformFunctionArray{
-        &FlipHorizontal<1>,
-        &FlipHorizontal<3>,
-        &FlipHorizontal<4>,
-      };
-      result = Transform(flipHorizontalFunctions, bitmapPixelBuffer, bufferWidth, bufferHeight, pixelFormat);
-      break;
-    }
-    case JpegTransform::TRANSPOSE:
-    {
-      static auto transposeFunctions = TransformFunctionArray{
-        &Transpose<1>,
-        &Transpose<3>,
-        &Transpose<4>,
-      };
-      result = Transform(transposeFunctions, bitmapPixelBuffer, bufferWidth, bufferHeight, pixelFormat);
-      break;
-    }
-    case JpegTransform::TRANSVERSE:
+    // Allocate a bitmap and decompress the jpeg buffer into its pixel buffer:
+    Dali::Devel::PixelBuffer bitmap = Dali::Devel::PixelBuffer::New(scaledPostXformWidth, scaledPostXformHeight, pixelFormat);
+
+    // Set metadata
+    if(DALI_LIKELY(exifData))
     {
-      static auto transverseFunctions = TransformFunctionArray{
-        &Transverse<1>,
-        &Transverse<3>,
-        &Transverse<4>,
-      };
-      result = Transform(transverseFunctions, bitmapPixelBuffer, bufferWidth, bufferHeight, pixelFormat);
-      break;
+      std::unique_ptr<Property::Map> exifMap = std::make_unique<Property::Map>();
+
+      for(auto k = 0u; k < EXIF_IFD_COUNT; ++k)
+      {
+        auto content = exifData->ifd[k];
+        for(auto i = 0u; i < content->count; ++i)
+        {
+          auto&&      tag       = content->entries[i];
+          const char* shortName = exif_tag_get_name_in_ifd(tag->tag, static_cast<ExifIfd>(k));
+          if(shortName)
+          {
+            AddExifFieldPropertyMap(*exifMap, *tag, static_cast<ExifIfd>(k));
+          }
+        }
+      }
+
+      GetImplementation(bitmap).SetMetadata(std::move(exifMap));
     }
-    default:
+
+    auto      bitmapPixelBuffer = bitmap.GetBuffer();
+    const int flags             = 0;
+
+    int decodeResult = tjDecompress2(jpeg.get(), jpegBufferPtr, jpegBufferSize, reinterpret_cast<unsigned char*>(bitmapPixelBuffer), scaledPreXformWidth, 0, scaledPreXformHeight, pixelLibJpegType, flags);
+    if(decodeResult == -1 && IsJpegDecodingFailed())
     {
-      DALI_LOG_ERROR("Unsupported JPEG Orientation transformation: %x.\n", transform);
-      break;
+      return false;
     }
+    pixelBuffers.push_back(bitmap);
+
+    // Transform bitmap
+    result = TransformBitmap(scaledPreXformWidth, scaledPreXformHeight, transform, bitmapPixelBuffer, pixelFormat);
   }
 
   return result;
@@ -864,7 +976,7 @@ bool EncodeToJpeg(const unsigned char* const pixelBuffer, Vector<unsigned char>&
   // Initialise a JPEG codec:
   {
     auto jpeg = MakeJpegCompressor();
-    if(!jpeg)
+    if(DALI_UNLIKELY(!jpeg))
     {
       DALI_LOG_ERROR("JPEG Compressor init failed: %s\n", tjGetErrorStr());
       return false;
@@ -879,17 +991,17 @@ bool EncodeToJpeg(const unsigned char* const pixelBuffer, Vector<unsigned char>&
     unsigned long dstBufferSize = 0;
     const int     flags         = 0;
 
-    if(tjCompress2(jpeg.get(),
-                   const_cast<unsigned char*>(pixelBuffer),
-                   width,
-                   0,
-                   height,
-                   jpegPixelFormat,
-                   SetPointer(dstBuffer),
-                   &dstBufferSize,
-                   TJSAMP_444,
-                   quality,
-                   flags))
+    if(DALI_UNLIKELY(tjCompress2(jpeg.get(),
+                                 const_cast<unsigned char*>(pixelBuffer),
+                                 width,
+                                 0,
+                                 height,
+                                 jpegPixelFormat,
+                                 SetPointer(dstBuffer),
+                                 &dstBufferSize,
+                                 TJSAMP_444,
+                                 quality,
+                                 flags)))
     {
       DALI_LOG_ERROR("JPEG Compression failed: %s\n", tjGetErrorStr());
       return false;
@@ -982,7 +1094,7 @@ bool TransformSize(int requiredWidth, int requiredHeight, FittingMode::Type fitt
 
   int              numFactors = 0;
   tjscalingfactor* factors    = tjGetScalingFactors(&numFactors);
-  if(factors == NULL)
+  if(DALI_UNLIKELY(factors == NULL))
   {
     DALI_LOG_WARNING("TurboJpeg tjGetScalingFactors error!\n");
     success = false;
@@ -1077,7 +1189,7 @@ ExifHandle LoadExifData(FILE* fp)
   auto          exifData = MakeNullExifData();
   unsigned char dataBuffer[1024];
 
-  if(fseek(fp, 0, SEEK_SET))
+  if(DALI_UNLIKELY(fseek(fp, 0, SEEK_SET)))
   {
     DALI_LOG_ERROR("Error seeking to start of file\n");
   }
@@ -1117,7 +1229,7 @@ bool LoadJpegHeader(const Dali::ImageLoader::Input& input, unsigned int& width,
   unsigned int headerHeight;
 
   success = LoadJpegHeader(fp, headerWidth, headerHeight);
-  if(success)
+  if(DALI_LIKELY(success))
   {
     auto transform = JpegTransform::NONE;
 
index 45c99e4..41df859 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TIZEN_PLATFORM_LOADER_JPEG_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -51,6 +51,16 @@ const unsigned char MAGIC_BYTE_2 = 0xD8;
 bool LoadBitmapFromJpeg(const Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& bitmap);
 
 /**
+ * Loads the image planes from an JPEG file.  This function checks the header first
+ * and if it is not a JPEG file, then it returns straight away.
+ * @param[in]  input  Information about the input image (including file pointer)
+ * @param[out] pixelBuffers The buffer list where the each plane will be stored
+ * @return true if file decoded successfully, false otherwise
+ * @note If the image file doesn't support to load planes, this method returns one RGB bitmap image.
+ */
+bool LoadPlanesFromJpeg(const Dali::ImageLoader::Input& input, std::vector<Dali::Devel::PixelBuffer>& pixelBuffers);
+
+/**
  * Loads the header of a JPEG file and fills in the width and height appropriately.
  * If the width and height are set on entry, it will set the width and height
  * to the closest scaled size (exactly as will be loaded by LoadBitmapFromJpeg with the same
index 7600732..f4ab1e2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -187,7 +187,7 @@ inline bool ReadHeader(FILE* filePointer, KtxFileHeader& header)
   const unsigned int readLength = sizeof(KtxFileHeader);
 
   // Load the information directly into our structure
-  if(fread(&header, 1, readLength, filePointer) != readLength)
+  if(DALI_UNLIKELY(fread(&header, 1, readLength, filePointer) != readLength))
   {
     return false;
   }
@@ -457,14 +457,14 @@ bool ConvertPixelFormat(const uint32_t ktxPixelFormat, Dali::Pixel::Format& form
 bool LoadKtxHeader(FILE* const fp, unsigned int& width, unsigned int& height, KtxFileHeader& fileHeader)
 {
   // Pull the bytes of the file header in as a block:
-  if(!ReadHeader(fp, fileHeader))
+  if(DALI_UNLIKELY(!ReadHeader(fp, fileHeader)))
   {
     return false;
   }
   width  = fileHeader.pixelWidth;
   height = fileHeader.pixelHeight;
 
-  if(width > MAX_TEXTURE_DIMENSION || height > MAX_TEXTURE_DIMENSION)
+  if(DALI_UNLIKELY(width > MAX_TEXTURE_DIMENSION || height > MAX_TEXTURE_DIMENSION))
   {
     return false;
   }
@@ -531,7 +531,7 @@ bool LoadBitmapFromKtx(const Dali::ImageLoader::Input& input, Dali::Devel::Pixel
   static_assert(sizeof(uint32_t) == 4);
 
   FILE* const fp = input.file;
-  if(fp == NULL)
+  if(DALI_UNLIKELY(fp == NULL))
   {
     DALI_LOG_ERROR("Null file handle passed to KTX compressed bitmap file loader.\n");
     return false;
@@ -541,14 +541,14 @@ bool LoadBitmapFromKtx(const Dali::ImageLoader::Input& input, Dali::Devel::Pixel
   // Load the header info
   unsigned int width, height;
 
-  if(!LoadKtxHeader(fp, width, height, fileHeader))
+  if(DALI_UNLIKELY(!LoadKtxHeader(fp, width, height, fileHeader)))
   {
     return false;
   }
 
   // Skip the key-values:
   const long int imageSizeOffset = sizeof(KtxFileHeader) + fileHeader.bytesOfKeyValueData;
-  if(fseek(fp, imageSizeOffset, SEEK_SET))
+  if(DALI_UNLIKELY(fseek(fp, imageSizeOffset, SEEK_SET)))
   {
     DALI_LOG_ERROR("Seek past key/vals in KTX compressed bitmap file failed.\n");
     return false;
@@ -556,15 +556,15 @@ bool LoadBitmapFromKtx(const Dali::ImageLoader::Input& input, Dali::Devel::Pixel
 
   // Load the size of the image data:
   uint32_t imageByteCount = 0;
-  if(fread(&imageByteCount, 1, 4, fp) != 4)
+  if(DALI_UNLIKELY(fread(&imageByteCount, 1, 4, fp) != 4))
   {
     DALI_LOG_ERROR("Read of image size failed.\n");
     return false;
   }
   // Sanity-check the image size:
-  if(imageByteCount > MAX_IMAGE_DATA_SIZE ||
-     // A compressed texture should certainly be less than 2 bytes per texel:
-     imageByteCount > width * height * 2)
+  if(DALI_UNLIKELY(imageByteCount > MAX_IMAGE_DATA_SIZE ||
+                   // A compressed texture should certainly be less than 2 bytes per texel:
+                   imageByteCount > width * height * 2))
   {
     DALI_LOG_ERROR("KTX file with too-large image-data field.\n");
     return false;
@@ -572,7 +572,7 @@ bool LoadBitmapFromKtx(const Dali::ImageLoader::Input& input, Dali::Devel::Pixel
 
   Pixel::Format pixelFormat;
   const bool    pixelFormatKnown = ConvertPixelFormat(fileHeader.glInternalFormat, pixelFormat);
-  if(!pixelFormatKnown)
+  if(DALI_UNLIKELY(!pixelFormatKnown))
   {
     DALI_LOG_ERROR("No internal pixel format supported for KTX file pixel format.\n");
     return false;
@@ -591,14 +591,14 @@ bool LoadBitmapFromKtx(const Dali::ImageLoader::Input& input, Dali::Devel::Pixel
     pixels = bitmap.GetBuffer();
   }
 
-  if(!pixels)
+  if(DALI_UNLIKELY(!pixels))
   {
     DALI_LOG_ERROR("Unable to reserve a pixel buffer to load the requested bitmap into.\n");
     return false;
   }
 
   const size_t bytesRead = fread(pixels, 1, imageByteCount, fp);
-  if(bytesRead != imageByteCount)
+  if(DALI_UNLIKELY(bytesRead != imageByteCount))
   {
     DALI_LOG_ERROR("Read of image pixel data failed.\n");
     return false;
index 397b822..c9a5866 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -59,13 +59,13 @@ bool LoadPngHeader(FILE* fp, unsigned int& width, unsigned int& height, png_stru
 
   // Check header to see if it is a PNG file
   size_t size = fread(header, 1, 8, fp);
-  if(size != 8)
+  if(DALI_UNLIKELY(size != 8))
   {
     DALI_LOG_ERROR("fread failed\n");
     return false;
   }
 
-  if(png_sig_cmp(header, 0, 8))
+  if(DALI_UNLIKELY(png_sig_cmp(header, 0, 8)))
   {
     DALI_LOG_ERROR("png_sig_cmp failed\n");
     return false;
@@ -73,14 +73,14 @@ bool LoadPngHeader(FILE* fp, unsigned int& width, unsigned int& height, png_stru
 
   png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
 
-  if(!png)
+  if(DALI_UNLIKELY(!png))
   {
     DALI_LOG_ERROR("Can't create PNG read structure\n");
     return false;
   }
 
   info = png_create_info_struct(png);
-  if(!info)
+  if(DALI_UNLIKELY(!info))
   {
     DALI_LOG_ERROR("png_create_info_struct failed\n");
     return false;
@@ -88,7 +88,7 @@ bool LoadPngHeader(FILE* fp, unsigned int& width, unsigned int& height, png_stru
 
   png_set_expand(png);
 
-  if(setjmp(png_jmpbuf(png)))
+  if(DALI_UNLIKELY(setjmp(png_jmpbuf(png))))
   {
     DALI_LOG_ERROR("error during png_init_io\n");
     return false;
@@ -134,7 +134,7 @@ bool LoadBitmapFromPng(const Dali::ImageLoader::Input& input, Dali::Devel::Pixel
   bool         valid = false;
 
   // Load info from the header
-  if(!LoadPngHeader(input.file, width, height, png, info))
+  if(DALI_UNLIKELY(!LoadPngHeader(input.file, width, height, png, info)))
   {
     return false;
   }
@@ -259,7 +259,7 @@ bool LoadBitmapFromPng(const Dali::ImageLoader::Input& input, Dali::Devel::Pixel
     }
   }
 
-  if(!valid)
+  if(DALI_UNLIKELY(!valid))
   {
     DALI_LOG_ERROR("Unsupported png format\n");
     return false;
@@ -270,7 +270,7 @@ bool LoadBitmapFromPng(const Dali::ImageLoader::Input& input, Dali::Devel::Pixel
 
   png_read_update_info(png, info);
 
-  if(setjmp(png_jmpbuf(png)))
+  if(DALI_UNLIKELY(setjmp(png_jmpbuf(png))))
   {
     DALI_LOG_ERROR("error during png_read_image\n");
     return false;
@@ -300,18 +300,18 @@ bool LoadBitmapFromPng(const Dali::ImageLoader::Input& input, Dali::Devel::Pixel
         break;
     }
   }
-
-  // decode the whole image into bitmap buffer
-  auto pixels = (bitmap = Dali::Devel::PixelBuffer::New(bufferWidth, bufferHeight, pixelFormat)).GetBuffer();
-
-  DALI_ASSERT_DEBUG(pixels);
   rows = reinterpret_cast<png_bytep*>(malloc(sizeof(png_bytep) * height));
-  if(!rows)
+  if(DALI_UNLIKELY(!rows))
   {
     DALI_LOG_ERROR("malloc is failed\n");
     return false;
   }
 
+  // decode the whole image into bitmap buffer
+  auto pixels = (bitmap = Dali::Devel::PixelBuffer::New(bufferWidth, bufferHeight, pixelFormat)).GetBuffer();
+
+  DALI_ASSERT_DEBUG(pixels);
+
   for(y = 0; y < height; y++)
   {
     rows[y] = pixels + y * stride;
@@ -371,7 +371,7 @@ extern "C" void WriteData(png_structp png_ptr, png_bytep data, png_size_t length
     if(encoded_img)
     {
       const Vector<unsigned char>::SizeType bufferSize = encoded_img->Count();
-      encoded_img->Resize(bufferSize + length); //< Can throw OOM.
+      encoded_img->ResizeUninitialized(bufferSize + length); //< Can throw OOM.
       unsigned char* const bufferBack = encoded_img->Begin() + bufferSize;
       memcpy(bufferBack, data, length);
     }
index f20b5ce..40fe8f1 100644 (file)
@@ -37,6 +37,9 @@ namespace
 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_LOADER_WBMP");
 #endif
 
+// TODO : We need to determine it in dali-common.h or something else. Currently, we set this value in code level.
+#define DALI_BYTE_ORDER_BIG_ENDIAN 0
+
 #define IMG_MAX_SIZE 65536
 
 #define IMG_TOO_BIG(w, h)                                 \
@@ -44,7 +47,7 @@ Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_LOA
    ((1ULL << (29)) - 2048))
 
 //extract multiple bytes integer , and saved in *data
-int extractMultiByteInteger(unsigned int* data, void* map, size_t length, size_t* position)
+int extractMultiByteInteger(unsigned int* data, const std::uint8_t* const& map, size_t length, size_t* position)
 {
   // the header field contains an image type indentifier of multi-byte length(TypeField), an octet of general header info(FixHeaderField)
   //,  a multi-byte width field(Width) and a multi-byte height field(Height) and so on.
@@ -63,15 +66,15 @@ int extractMultiByteInteger(unsigned int* data, void* map, size_t length, size_t
     // for general width and height, if(buf & 0x80) == 0, then the next byte does not need to fetch again
     // first step, readBufCount = 1 , read int(4 bytes) to buf, if buf & 0x80 !=0, the buf need to continue to fetch
     // second step, readBufCount = 2, read next( 4 bytes) to buf, if buf & 0x80 == 0, then assigned the buf to target
-    if((readBufCount++) == 4)
+    if(DALI_UNLIKELY((readBufCount++) == 4))
     {
       return -1;
     }
-    if(*position > length)
+    if(DALI_UNLIKELY(*position > length))
     {
       return -1;
     }
-    buf                    = reinterpret_cast<unsigned char*>(map)[(*position)++];
+    buf                    = map[(*position)++];
     targetMultiByteInteger = (targetMultiByteInteger << 7) | (buf & 0x7f);
 
     if((buf & 0x80) == 0)
@@ -84,27 +87,53 @@ int extractMultiByteInteger(unsigned int* data, void* map, size_t length, size_t
   return 0;
 }
 
+// Calculate 4bit integer into 4byte integer
+constexpr std::uint32_t Calculate4BitTo4Byte(const std::uint8_t& input)
+{
+  std::uint32_t output = 0;
+#if DALI_BYTE_ORDER_BIG_ENDIAN
+  output |= static_cast<std::uint32_t>(input & 0x08) << 21;
+  output |= static_cast<std::uint32_t>(input & 0x04) << 14;
+  output |= static_cast<std::uint32_t>(input & 0x02) << 7;
+  output |= static_cast<std::uint32_t>(input & 0x01);
+#else
+  output |= static_cast<std::uint32_t>(input & 0x08) >> 3;
+  output |= static_cast<std::uint32_t>(input & 0x04) << 6;
+  output |= static_cast<std::uint32_t>(input & 0x02) << 15;
+  output |= static_cast<std::uint32_t>(input & 0x01) << 24;
+#endif
+  return output * 0xff;
+}
+
+/**
+ * @brief Calculation result bit-->byte table in compile.
+ * Required memory = 16 * 4byte = 64byte
+ */
+// clang-format off
+constexpr std::uint32_t cachedCalculation4BitTo4ByteTable[16] = {
+  Calculate4BitTo4Byte(0x00), Calculate4BitTo4Byte(0x01), Calculate4BitTo4Byte(0x02), Calculate4BitTo4Byte(0x03),
+  Calculate4BitTo4Byte(0x04), Calculate4BitTo4Byte(0x05), Calculate4BitTo4Byte(0x06), Calculate4BitTo4Byte(0x07),
+  Calculate4BitTo4Byte(0x08), Calculate4BitTo4Byte(0x09), Calculate4BitTo4Byte(0x0a), Calculate4BitTo4Byte(0x0b),
+  Calculate4BitTo4Byte(0x0c), Calculate4BitTo4Byte(0x0d), Calculate4BitTo4Byte(0x0e), Calculate4BitTo4Byte(0x0f)};
+// clang-format on
 } // end unnamed namespace
 
 bool LoadBitmapFromWbmp(const Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& bitmap)
 {
   FILE* const fp = input.file;
-  if(fp == NULL)
+  if(DALI_UNLIKELY(fp == NULL))
   {
     DALI_LOG_ERROR("Error loading bitmap\n");
     return false;
   }
   Dali::Vector<unsigned char> map;
-  Dali::Vector<unsigned char> surface; //unsigned int
   size_t                      position = 0;
 
-  unsigned int   w, h;
-  unsigned int   type;
-  unsigned int   line_length;
-  unsigned char* line = NULL;
-  unsigned int   cur  = 0, x, y;
+  std::uint32_t w, h;
+  std::uint32_t type;
+  std::uint32_t lineByteLength;
 
-  if(fseek(fp, 0, SEEK_END))
+  if(DALI_UNLIKELY(fseek(fp, 0, SEEK_END)))
   {
     DALI_LOG_ERROR("Error seeking WBMP data\n");
     return false;
@@ -117,91 +146,133 @@ bool LoadBitmapFromWbmp(const Dali::ImageLoader::Input& input, Dali::Devel::Pixe
     fsize = static_cast<unsigned int>(positionIndicator);
   }
 
-  if(0u == fsize)
+  if(DALI_UNLIKELY(0u == fsize))
   {
     DALI_LOG_ERROR("Error: filesize is 0!\n");
     return false;
   }
 
-  if(fseek(fp, 0, SEEK_SET))
+  if(DALI_UNLIKELY(fseek(fp, 0, SEEK_SET)))
   {
     DALI_LOG_ERROR("Error seeking WBMP data\n");
     return false;
   }
-  if(fsize <= 4)
+  if(DALI_UNLIKELY(fsize <= 4))
   {
     DALI_LOG_ERROR("Error: WBMP Raw Data Not Found!\n");
     return false;
   }
-  if(fsize > 4096 * 4096 * 4)
+  if(DALI_UNLIKELY(fsize > 4096 * 4096 * 4))
   {
     DALI_LOG_ERROR("Error: WBMP size is too large!\n");
     return false;
   }
   map.ResizeUninitialized(fsize);
 
-  if(fread(&map[0], 1, fsize, fp) != fsize)
+  if(DALI_UNLIKELY(fread(&map[0], 1, fsize, fp) != fsize))
   {
     DALI_LOG_WARNING("image file read opeation error!\n");
     return false;
   }
 
-  if(extractMultiByteInteger(&type, &map[0], fsize, &position) < 0)
+  const std::uint8_t* const inputBufferPtr = &map[0];
+
+  if(DALI_UNLIKELY(extractMultiByteInteger(&type, inputBufferPtr, fsize, &position) < 0))
   {
     return false;
   }
 
   position++; /* skipping one byte */
 
-  if(extractMultiByteInteger(&w, &map[0], fsize, &position) < 0)
+  if(DALI_UNLIKELY(extractMultiByteInteger(&w, inputBufferPtr, fsize, &position) < 0))
   {
     return false;
   }
-  if(extractMultiByteInteger(&h, &map[0], fsize, &position) < 0)
+  if(DALI_UNLIKELY(extractMultiByteInteger(&h, inputBufferPtr, fsize, &position) < 0))
   {
     return false;
   }
-  if(type != 0)
+  if(DALI_UNLIKELY(type != 0))
   {
     DALI_LOG_ERROR("Unknown Format!\n");
     return false;
   }
 
-  if((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE))
+  if(DALI_UNLIKELY((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE)))
   {
     return false;
   }
 
-  surface.ResizeUninitialized(w * h); //(w * h * 4);
-  memset(&surface[0], 0, w * h);      // w * h * 4
+  lineByteLength = (w + 7) >> 3;
+  // fsize was wrong! Load failed.
+  if(DALI_UNLIKELY(position + h * lineByteLength > fsize))
+  {
+    DALI_LOG_ERROR("Pixel infomation is bigger than file size! (%u + %u * %u > %u)\n", static_cast<std::uint32_t>(position), h, lineByteLength, fsize);
+    return false;
+  }
 
-  line_length = (w + 7) >> 3;
-  for(y = 0; y < h; y++)
+  // w >= 1 and h >= 1. So we can assume that outputPixels is not null.
+  auto outputPixels = (bitmap = Dali::Devel::PixelBuffer::New(w, h, Pixel::L8)).GetBuffer();
+
+  /**
+   * @code
+   * std::uint8_t* line = NULL;
+   * std::uint32_t cur  = 0, x, y;
+   * for(y = 0; y < h; y++)
+   * {
+   *   line = &map[0] + position;
+   *   position += lineByteLength;
+   *   for(x = 0; x < w; x++)
+   *   {
+   *     int idx    = x >> 3;
+   *     int offset = 1 << (0x07 - (x & 0x07));
+   *     if(line[idx] & offset)
+   *     {
+   *       outputPixels[cur] = 0xff; //0xffffffff;
+   *     }
+   *     else
+   *     {
+   *       outputPixels[cur] = 0x00; //0xff000000;
+   *     }
+   *     cur++;
+   *   }
+   * }
+   * @endcode
+   */
+
+  const std::uint8_t* inputPixels                 = inputBufferPtr + position;
+  const std::uint32_t lineBitLengthWithoutPadding = (w >> 3) << 3;
+
+  for(std::uint32_t y = 0; y < h; ++y)
   {
-    if(position + line_length > fsize)
-    {
-      return false;
-    }
-    line = &map[0] + position;
-    position += line_length;
-    for(x = 0; x < w; x++)
+    std::uint32_t x = 0;
+    if((reinterpret_cast<std::ptrdiff_t>(outputPixels) & (sizeof(std::uint32_t) - 1)) == 0)
     {
-      int idx    = x >> 3;
-      int offset = 1 << (0x07 - (x & 0x07));
-      if(line[idx] & offset)
+      for(; x < lineBitLengthWithoutPadding; x += 8)
       {
-        surface[cur] = 0xff; //0xffffffff;
+        // memset whole 8 bits
+        // outputPixels filled 4 bytes in one operation.
+        // cachedCalculation4BitTo4ByteTable calculated in compile-time.
+        *(reinterpret_cast<std::uint32_t*>(outputPixels + 0)) = cachedCalculation4BitTo4ByteTable[((*inputPixels) >> 4) & 0x0f];
+        *(reinterpret_cast<std::uint32_t*>(outputPixels + 4)) = cachedCalculation4BitTo4ByteTable[(*inputPixels) & 0x0f];
+        outputPixels += 8;
+        ++inputPixels;
       }
-      else
+    }
+    {
+      // memset linePadding bits naive.
+      for(; x < w; ++x)
       {
-        surface[cur] = 0x00; //0xff000000;
+        const std::uint8_t offset = (0x07 - (x & 0x07));
+        *outputPixels             = ((*inputPixels) >> offset) & 1 ? 0xff : 0x00;
+        ++outputPixels;
+        if(offset == 0)
+        {
+          ++inputPixels;
+        }
       }
-      cur++;
     }
   }
-  auto pixels = (bitmap = Dali::Devel::PixelBuffer::New(w, h, Pixel::L8)).GetBuffer();
-
-  memcpy(pixels, &surface[0], w * h); //w * h * 4
 
   return true;
 }
@@ -209,7 +280,7 @@ bool LoadBitmapFromWbmp(const Dali::ImageLoader::Input& input, Dali::Devel::Pixe
 bool LoadWbmpHeader(const Dali::ImageLoader::Input& input, unsigned int& width, unsigned int& height)
 {
   FILE* const fp = input.file;
-  if(fp == NULL)
+  if(DALI_UNLIKELY(fp == NULL))
   {
     DALI_LOG_ERROR("Error loading bitmap\n");
     return false;
@@ -219,7 +290,7 @@ bool LoadWbmpHeader(const Dali::ImageLoader::Input& input, unsigned int& width,
 
   unsigned int w, h;
   unsigned int type;
-  if(fseek(fp, 0, SEEK_END))
+  if(DALI_UNLIKELY(fseek(fp, 0, SEEK_END)))
   {
     DALI_LOG_ERROR("Error seeking WBMP data\n");
     return false;
@@ -232,17 +303,17 @@ bool LoadWbmpHeader(const Dali::ImageLoader::Input& input, unsigned int& width,
     fsize = static_cast<unsigned int>(positionIndicator);
   }
 
-  if(0u == fsize)
+  if(DALI_UNLIKELY(0u == fsize))
   {
     return false;
   }
 
-  if(fseek(fp, 0, SEEK_SET))
+  if(DALI_UNLIKELY(fseek(fp, 0, SEEK_SET)))
   {
     DALI_LOG_ERROR("Error seeking WBMP data\n");
     return false;
   }
-  if(fsize <= 4)
+  if(DALI_UNLIKELY(fsize <= 4))
   {
     DALI_LOG_ERROR("Error: WBMP Raw Data Not Found!\n");
     return false;
@@ -253,35 +324,37 @@ bool LoadWbmpHeader(const Dali::ImageLoader::Input& input, unsigned int& width,
   headerSize              = std::min(headerSize, fsize);
 
   map.ResizeUninitialized(headerSize);
-  if(fread(&map[0], 1, headerSize, fp) != headerSize)
+  if(DALI_UNLIKELY(fread(&map[0], 1, headerSize, fp) != headerSize))
   {
     DALI_LOG_WARNING("image file read opeation error!\n");
     return false;
   }
 
-  if(extractMultiByteInteger(&type, &map[0], headerSize, &position) < 0)
+  const std::uint8_t* const inputBufferPtr = &map[0];
+
+  if(DALI_UNLIKELY(extractMultiByteInteger(&type, inputBufferPtr, headerSize, &position) < 0))
   {
     DALI_LOG_ERROR("Error: unable to read type!\n");
     return false;
   }
   position++; /* skipping one byte */
-  if(type != 0)
+  if(DALI_UNLIKELY(type != 0))
   {
     DALI_LOG_ERROR("Error: unknown format!\n");
     return false;
   }
-  if(extractMultiByteInteger(&w, &map[0], headerSize, &position) < 0)
+  if(DALI_UNLIKELY(extractMultiByteInteger(&w, inputBufferPtr, headerSize, &position) < 0))
   {
     DALI_LOG_ERROR("Error: can not read width!\n");
     return false;
   }
-  if(extractMultiByteInteger(&h, &map[0], headerSize, &position) < 0)
+  if(DALI_UNLIKELY(extractMultiByteInteger(&h, inputBufferPtr, headerSize, &position) < 0))
   {
     DALI_LOG_ERROR("Error: can not read height!\n");
     return false;
   }
 
-  if((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE))
+  if(DALI_UNLIKELY((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE)))
   {
     DALI_LOG_ERROR("Error: file size is not supported!\n");
     return false;
index da82a89..25a24d6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  *
  */
 
+// HEADER
 #include <dali/internal/imaging/common/loader-webp.h>
 
-// EXTERNAL INCLUDES
-#ifdef DALI_WEBP_AVAILABLE
-#include <webp/decode.h>
-#include <webp/demux.h>
-
-#if WEBP_DEMUX_ABI_VERSION > 0x0101
-#define DALI_ANIMATED_WEBP_ENABLED 1
-#endif
-#endif
+// INTERNAL INCLUDES
 #include <dali/devel-api/adaptor-framework/pixel-buffer.h>
-#include <dali/integration-api/debug.h>
-#include <cstring>
-#include <memory>
-
-typedef unsigned char WebPByteType;
+#include <dali/internal/imaging/common/webp-loading.h>
 
 namespace Dali
 {
 namespace TizenPlatform
 {
-#ifdef DALI_ANIMATED_WEBP_ENABLED
-bool ReadWebPInformation(FILE* const fp, WebPData& webPData)
-{
-  if(fp == NULL)
-  {
-    return false;
-  }
-
-  if(fseek(fp, 0, SEEK_END) <= -1)
-  {
-    return false;
-  }
-  WebPDataInit(&webPData);
-  webPData.size = ftell(fp);
-
-  if((!fseek(fp, 0, SEEK_SET)))
-  {
-    unsigned char* WebPDataBuffer;
-    WebPDataBuffer = reinterpret_cast<WebPByteType*>(malloc(sizeof(WebPByteType) * webPData.size));
-    webPData.size  = fread(WebPDataBuffer, sizeof(WebPByteType), webPData.size, fp);
-    webPData.bytes = WebPDataBuffer;
-  }
-  else
-  {
-    return false;
-  }
-  return true;
-}
-
-void ReleaseResource(WebPData& webPData, WebPAnimDecoder* webPAnimDecoder)
+namespace
 {
-  free((void*)webPData.bytes);
-  webPData.bytes = nullptr;
-  WebPDataInit(&webPData);
-  if(webPAnimDecoder)
-  {
-    WebPAnimDecoderDelete(webPAnimDecoder);
-  }
+constexpr uint32_t FIRST_FRAME_INDEX = 0u;
 }
 
-#endif
-
 bool LoadWebpHeader(const Dali::ImageLoader::Input& input, unsigned int& width, unsigned int& height)
 {
-  FILE* const fp = input.file;
-  if(fp == NULL)
-  {
-    return false;
-  }
-
-  if(fseek(fp, 0, SEEK_END) <= -1)
-  {
-    return false;
-  }
-
-  // If the image is non-animated webp
-#ifdef DALI_WEBP_AVAILABLE
-  size_t webPSize = ftell(fp);
-  if((!fseek(fp, 0, SEEK_SET)))
-  {
-    std::vector<uint8_t> encodedImage;
-    encodedImage.resize(webPSize, 0);
-    size_t readCount = fread(&encodedImage[0], sizeof(uint8_t), encodedImage.size(), fp);
-    if(readCount != encodedImage.size())
-    {
-      return false;
-    }
-    int32_t imageWidth, imageHeight;
-    if(WebPGetInfo(&encodedImage[0], encodedImage.size(), &imageWidth, &imageHeight))
-    {
-      width  = static_cast<uint32_t>(imageWidth);
-      height = static_cast<uint32_t>(imageHeight);
-      return true;
-    }
-  }
-#endif
-
-  // If the image is animated webp
-#ifdef DALI_ANIMATED_WEBP_ENABLED
-  WebPData         webPData;
-  WebPAnimDecoder* webPAnimDecoder = nullptr;
-  WebPAnimInfo     webPAnimInfo;
-  if(ReadWebPInformation(fp, webPData))
+  FILE* const                fp          = input.file;
+  Dali::AnimatedImageLoading webPLoading = Dali::AnimatedImageLoading(Dali::Internal::Adaptor::WebPLoading::New(fp).Get());
+  if(webPLoading)
   {
-    WebPAnimDecoderOptions webPAnimDecoderOptions;
-    WebPAnimDecoderOptionsInit(&webPAnimDecoderOptions);
-    webPAnimDecoderOptions.color_mode = MODE_RGBA;
-    webPAnimDecoder                   = WebPAnimDecoderNew(&webPData, &webPAnimDecoderOptions);
-    if(webPAnimDecoder != nullptr)
+    ImageDimensions imageSize = webPLoading.GetImageSize();
+    if(webPLoading.HasLoadingSucceeded())
     {
-      WebPAnimDecoderGetInfo(webPAnimDecoder, &webPAnimInfo);
-      width  = webPAnimInfo.canvas_width;
-      height = webPAnimInfo.canvas_height;
-      ReleaseResource(webPData, webPAnimDecoder);
+      width  = imageSize.GetWidth();
+      height = imageSize.GetHeight();
       return true;
     }
   }
-  ReleaseResource(webPData, webPAnimDecoder);
-#endif
-  DALI_LOG_ERROR("WebP file open failed.\n");
   return false;
 }
 
 bool LoadBitmapFromWebp(const Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& bitmap)
 {
-  FILE* const fp = input.file;
-  if(fp == NULL)
-  {
-    return false;
-  }
-
-  if(fseek(fp, 0, SEEK_END) <= -1)
-  {
-    return false;
-  }
-
-  // If the image is non-animated webp
-#ifdef DALI_WEBP_AVAILABLE
-  size_t webPSize = ftell(fp);
-  if((!fseek(fp, 0, SEEK_SET)))
-  {
-    std::vector<uint8_t> encodedImage;
-    encodedImage.resize(webPSize, 0);
-    size_t readCount = fread(&encodedImage[0], sizeof(uint8_t), encodedImage.size(), fp);
-    if(readCount != encodedImage.size())
-    {
-      DALI_LOG_ERROR("WebP image loading failed.\n");
-      return false;
-    }
-
-    int32_t width, height;
-    if(!WebPGetInfo(&encodedImage[0], encodedImage.size(), &width, &height))
-    {
-      DALI_LOG_ERROR("Cannot retrieve WebP image size information.\n");
-      return false;
-    }
-
-    WebPBitstreamFeatures features;
-    if(VP8_STATUS_NOT_ENOUGH_DATA == WebPGetFeatures(&encodedImage[0], encodedImage.size(), &features))
-    {
-      DALI_LOG_ERROR("Cannot retrieve WebP image features.\n");
-      return false;
-    }
-
-    uint32_t      channelNumber = (features.has_alpha) ? 4 : 3;
-    Pixel::Format pixelFormat   = (channelNumber == 4) ? Pixel::RGBA8888 : Pixel::RGB888;
-    bitmap                      = Dali::Devel::PixelBuffer::New(width, height, pixelFormat);
-    uint8_t* frameBuffer        = nullptr;
-    if(channelNumber == 4)
-    {
-      frameBuffer = WebPDecodeRGBA(&encodedImage[0], encodedImage.size(), &width, &height);
-    }
-    else
-    {
-      frameBuffer = WebPDecodeRGB(&encodedImage[0], encodedImage.size(), &width, &height);
-    }
-
-    if(frameBuffer != nullptr)
-    {
-      const int32_t bufferSize = width * height * sizeof(uint8_t) * channelNumber;
-      memcpy(bitmap.GetBuffer(), frameBuffer, bufferSize);
-      free((void*)frameBuffer);
-      return true;
-    }
-  }
-#endif
-
-  // If the image is animated webp
-#ifdef DALI_ANIMATED_WEBP_ENABLED
-  WebPData         webPData;
-  WebPAnimDecoder* webPAnimDecoder = nullptr;
-  WebPAnimInfo     webPAnimInfo;
-  if(ReadWebPInformation(fp, webPData))
+  FILE* const                fp          = input.file;
+  Dali::AnimatedImageLoading webPLoading = Dali::AnimatedImageLoading(Dali::Internal::Adaptor::WebPLoading::New(fp).Get());
+  if(webPLoading)
   {
-    WebPAnimDecoderOptions webPAnimDecoderOptions;
-    WebPAnimDecoderOptionsInit(&webPAnimDecoderOptions);
-    webPAnimDecoderOptions.color_mode = MODE_RGBA;
-    webPAnimDecoder                   = WebPAnimDecoderNew(&webPData, &webPAnimDecoderOptions);
-    if(webPAnimDecoder != nullptr)
+    Dali::Devel::PixelBuffer pixelBuffer = webPLoading.LoadFrame(FIRST_FRAME_INDEX);
+    if(pixelBuffer)
     {
-      uint8_t* frameBuffer;
-      int      timestamp;
-      WebPAnimDecoderGetInfo(webPAnimDecoder, &webPAnimInfo);
-      WebPAnimDecoderReset(webPAnimDecoder);
-      WebPAnimDecoderGetNext(webPAnimDecoder, &frameBuffer, &timestamp);
-
-      bitmap                   = Dali::Devel::PixelBuffer::New(webPAnimInfo.canvas_width, webPAnimInfo.canvas_height, Dali::Pixel::RGBA8888);
-      const int32_t bufferSize = webPAnimInfo.canvas_width * webPAnimInfo.canvas_height * sizeof(uint32_t);
-      memcpy(bitmap.GetBuffer(), frameBuffer, bufferSize);
-      ReleaseResource(webPData, webPAnimDecoder);
+      bitmap = pixelBuffer;
       return true;
     }
   }
-  ReleaseResource(webPData, webPAnimDecoder);
-#endif
-
-  DALI_LOG_ERROR("WebP image loading failed.\n");
   return false;
 }
 
index 6ed2e31..533db68 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -47,12 +47,14 @@ PixelBuffer::PixelBuffer(unsigned char*      buffer,
                          unsigned int        bufferSize,
                          unsigned int        width,
                          unsigned int        height,
+                         unsigned int        stride,
                          Dali::Pixel::Format pixelFormat)
 : mMetadata(),
   mBuffer(buffer),
   mBufferSize(bufferSize),
   mWidth(width),
   mHeight(height),
+  mStride(stride ? stride : width),
   mPixelFormat(pixelFormat),
   mPreMultiplied(false)
 {
@@ -73,16 +75,17 @@ PixelBufferPtr PixelBuffer::New(unsigned int        width,
   {
     buffer = static_cast<unsigned char*>(malloc(bufferSize));
   }
-  return new PixelBuffer(buffer, bufferSize, width, height, pixelFormat);
+  return new PixelBuffer(buffer, bufferSize, width, height, width, pixelFormat);
 }
 
 PixelBufferPtr PixelBuffer::New(unsigned char*      buffer,
                                 unsigned int        bufferSize,
                                 unsigned int        width,
                                 unsigned int        height,
+                                unsigned int        stride,
                                 Dali::Pixel::Format pixelFormat)
 {
-  return new PixelBuffer(buffer, bufferSize, width, height, pixelFormat);
+  return new PixelBuffer(buffer, bufferSize, width, height, stride, pixelFormat);
 }
 
 Dali::PixelData PixelBuffer::Convert(PixelBuffer& pixelBuffer)
@@ -91,12 +94,14 @@ Dali::PixelData PixelBuffer::Convert(PixelBuffer& pixelBuffer)
                                                    pixelBuffer.mBufferSize,
                                                    pixelBuffer.mWidth,
                                                    pixelBuffer.mHeight,
+                                                   pixelBuffer.mStride,
                                                    pixelBuffer.mPixelFormat,
                                                    Dali::PixelData::FREE);
   pixelBuffer.mBuffer       = NULL;
   pixelBuffer.mWidth        = 0;
   pixelBuffer.mHeight       = 0;
   pixelBuffer.mBufferSize   = 0;
+  pixelBuffer.mStride       = 0;
 
   return pixelData;
 }
@@ -111,6 +116,11 @@ unsigned int PixelBuffer::GetHeight() const
   return mHeight;
 }
 
+uint32_t PixelBuffer::GetStride() const
+{
+  return mStride;
+}
+
 Dali::Pixel::Format PixelBuffer::GetPixelFormat() const
 {
   return mPixelFormat;
@@ -141,7 +151,7 @@ Dali::PixelData PixelBuffer::CreatePixelData() const
     memcpy(destBuffer, mBuffer, mBufferSize);
   }
 
-  Dali::PixelData pixelData = Dali::PixelData::New(destBuffer, mBufferSize, mWidth, mHeight, mPixelFormat, Dali::PixelData::FREE);
+  Dali::PixelData pixelData = Dali::PixelData::New(destBuffer, mBufferSize, mWidth, mHeight, mStride, mPixelFormat, Dali::PixelData::FREE);
   return pixelData;
 }
 
@@ -201,6 +211,7 @@ void PixelBuffer::TakeOwnershipOfBuffer(PixelBuffer& pixelBuffer)
   mBufferSize         = pixelBuffer.mBufferSize;
   mWidth              = pixelBuffer.mWidth;
   mHeight             = pixelBuffer.mHeight;
+  mStride             = pixelBuffer.mStride;
   mPixelFormat        = pixelBuffer.mPixelFormat;
 }
 
@@ -271,6 +282,7 @@ bool PixelBuffer::Rotate(Degree angle)
   Platform::RotateByShear(mBuffer,
                           mWidth,
                           mHeight,
+                          mStride,
                           pixelSize,
                           radians,
                           pixelsOut,
@@ -289,6 +301,7 @@ bool PixelBuffer::Rotate(Degree angle)
     mBuffer     = pixelsOut;
     pixelsOut   = nullptr;
     mBufferSize = mWidth * mHeight * pixelSize;
+    mStride     = mWidth; // The buffer is tightly packed.
   }
 
   return success;
@@ -327,8 +340,8 @@ PixelBufferPtr PixelBuffer::NewCrop(const PixelBuffer& inBuffer, uint16_t x, uin
 {
   PixelBufferPtr outBuffer     = PixelBuffer::New(cropDimensions.GetWidth(), cropDimensions.GetHeight(), inBuffer.GetPixelFormat());
   int            bytesPerPixel = Pixel::GetBytesPerPixel(inBuffer.mPixelFormat);
-  int            srcStride     = inBuffer.mWidth * bytesPerPixel;
-  int            destStride    = cropDimensions.GetWidth() * bytesPerPixel;
+  int            srcStride     = inBuffer.mStride * bytesPerPixel;
+  int            destStride    = cropDimensions.GetWidth() * bytesPerPixel; // The destination buffer is tightly packed
 
   // Clamp crop to right edge
   if(x + cropDimensions.GetWidth() > inBuffer.mWidth)
@@ -409,7 +422,7 @@ PixelBufferPtr PixelBuffer::NewResize(const PixelBuffer& inBuffer, ImageDimensio
      inBuffer.mPixelFormat == Pixel::RGBA8888 ||
      inBuffer.mPixelFormat == Pixel::BGRA8888)
   {
-    Dali::Internal::Platform::Resample(inBuffer.mBuffer, inDimensions, outBuffer->GetBuffer(), outDimensions, filterType, bytesPerPixel, hasAlpha);
+    Dali::Internal::Platform::Resample(inBuffer.mBuffer, inDimensions, inBuffer.mStride, outBuffer->GetBuffer(), outDimensions, filterType, bytesPerPixel, hasAlpha);
   }
   else
   {
@@ -443,26 +456,51 @@ void PixelBuffer::MultiplyColorByAlpha()
   // must be skipped in such case
   if(Pixel::GetBytesPerPixel(mPixelFormat) && Pixel::HasAlpha(mPixelFormat))
   {
-    unsigned char*     pixel      = mBuffer;
-    const unsigned int bufferSize = mWidth * mHeight;
+    unsigned char*     pixel       = mBuffer;
+    const unsigned int strideBytes = mStride * bytesPerPixel;
+    const unsigned int widthBytes  = mWidth * bytesPerPixel;
 
-    for(unsigned int i = 0; i < bufferSize; ++i)
+    // Collect all valid channel list before lookup whole buffer
+    std::vector<Channel> validChannelList;
+    for(const Channel& channel : {Adaptor::RED, Adaptor::GREEN, Adaptor::BLUE, Adaptor::LUMINANCE})
     {
-      unsigned int alpha = ReadChannel(pixel, mPixelFormat, Adaptor::ALPHA);
+      if(HasChannel(mPixelFormat, channel))
       {
-        auto red       = ReadChannel(pixel, mPixelFormat, Adaptor::RED);
-        auto green     = ReadChannel(pixel, mPixelFormat, Adaptor::GREEN);
-        auto blue      = ReadChannel(pixel, mPixelFormat, Adaptor::BLUE);
-        auto luminance = ReadChannel(pixel, mPixelFormat, Adaptor::LUMINANCE);
-        WriteChannel(pixel, mPixelFormat, Adaptor::RED, red * alpha / 255);
-        WriteChannel(pixel, mPixelFormat, Adaptor::GREEN, green * alpha / 255);
-        WriteChannel(pixel, mPixelFormat, Adaptor::BLUE, blue * alpha / 255);
-        WriteChannel(pixel, mPixelFormat, Adaptor::LUMINANCE, luminance * alpha / 255);
+        validChannelList.emplace_back(channel);
       }
-      pixel += bytesPerPixel;
     }
+
+    if(DALI_LIKELY(!validChannelList.empty()))
+    {
+      for(unsigned int y = 0; y < mHeight; y++)
+      {
+        for(unsigned int x = 0; x < widthBytes; x += bytesPerPixel)
+        {
+          unsigned int alpha = ReadChannel(&pixel[x], mPixelFormat, Adaptor::ALPHA);
+          if(alpha < 255)
+          {
+            // If alpha is 255, we don't need to change color. Skip current pixel
+            // But if alpha is not 255, we should change color.
+            if(alpha > 0)
+            {
+              for(const Channel& channel : validChannelList)
+              {
+                auto color = ReadChannel(&pixel[x], mPixelFormat, channel);
+                WriteChannel(&pixel[x], mPixelFormat, channel, Platform::MultiplyAndNormalizeColor(color, alpha));
+              }
+            }
+            else
+            {
+              // If alpha is 0, just set all pixel as zero.
+              memset(&pixel[x], 0, bytesPerPixel);
+            }
+          }
+        }
+        pixel += strideBytes;
+      }
+    }
+    mPreMultiplied = true;
   }
-  mPreMultiplied = true;
 }
 
 bool PixelBuffer::IsAlphaPreMultiplied() const
@@ -472,30 +510,33 @@ bool PixelBuffer::IsAlphaPreMultiplied() const
 
 uint32_t PixelBuffer::GetBrightness() const
 {
-  uint32_t brightness = 0;
-
+  uint32_t brightness    = 0;
   uint32_t bytesPerPixel = Pixel::GetBytesPerPixel(mPixelFormat);
-  if(bytesPerPixel)
+
+  if(bytesPerPixel && mWidth && mHeight)
   {
-    unsigned char* pixel      = mBuffer;
-    const uint32_t bufferSize = mWidth * mHeight;
+    unsigned char* pixel       = mBuffer;
+    const uint32_t strideBytes = mStride * bytesPerPixel;
+    const uint32_t widthBytes  = mWidth * bytesPerPixel;
+    const uint32_t bufferSize  = mWidth * mHeight;
 
-    if(bufferSize) // avoid division by zero to calculate brightness
-    {
-      uint64_t red   = 0;
-      uint64_t green = 0;
-      uint64_t blue  = 0;
+    uint64_t red   = 0;
+    uint64_t green = 0;
+    uint64_t blue  = 0;
 
-      for(uint32_t i = 0; i < bufferSize; ++i)
+    for(unsigned int y = 0; y < mHeight; y++)
+    {
+      for(unsigned int x = 0; x < widthBytes; x += bytesPerPixel)
       {
-        red += ReadChannel(pixel, mPixelFormat, Adaptor::RED);
-        green += ReadChannel(pixel, mPixelFormat, Adaptor::GREEN);
-        blue += ReadChannel(pixel, mPixelFormat, Adaptor::BLUE);
-        pixel += bytesPerPixel;
+        red += ReadChannel(&pixel[x], mPixelFormat, Adaptor::RED);
+        green += ReadChannel(&pixel[x], mPixelFormat, Adaptor::GREEN);
+        blue += ReadChannel(&pixel[x], mPixelFormat, Adaptor::BLUE);
       }
-      // http://www.w3.org/TR/AERT#color-contrast
-      brightness = (red * BRIGHTNESS_CONSTANT_R + green * BRIGHTNESS_CONSTANT_G + blue * BRIGHTNESS_CONSTANT_B) / (1000uLL * bufferSize);
+      pixel += strideBytes;
     }
+
+    // http://www.w3.org/TR/AERT#color-contrast
+    brightness = (red * BRIGHTNESS_CONSTANT_R + green * BRIGHTNESS_CONSTANT_G + blue * BRIGHTNESS_CONSTANT_B) / (1000uLL * bufferSize);
   }
 
   return brightness;
index da25097..6e02f3c 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_ADAPTOR_PIXEL_BUFFER_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -60,13 +60,14 @@ public:
    * @param [in] bufferSize       The size of the buffer in bytes
    * @param [in] width            Buffer width in pixels
    * @param [in] height           Buffer height in pixels
+   * @param [in] stride           Buffer stride in pixels, 0 means the buffer is tightly packed
    * @param [in] pixelFormat      The pixel format
-   * @param [in] releaseFunction  The function used to release the memory.
    */
   static PixelBufferPtr New(unsigned char* buffer,
                             unsigned int   bufferSize,
                             unsigned int   width,
                             unsigned int   height,
+                            unsigned int   stride,
                             Pixel::Format  pixelFormat);
 
   /**
@@ -85,12 +86,14 @@ public:
    * @param [in] bufferSize       The size of the buffer in bytes
    * @param [in] width            Buffer width in pixels
    * @param [in] height           Buffer height in pixels
+   * @param [in] stride           Buffer stride in pixels, 0 means the buffer is tightly packed
    * @param [in] pixelFormat      The pixel format
    */
   PixelBuffer(unsigned char* buffer,
               unsigned int   bufferSize,
               unsigned int   width,
               unsigned int   height,
+              unsigned int   stride,
               Pixel::Format  pixelFormat);
 
 protected:
@@ -115,6 +118,12 @@ public:
   unsigned int GetHeight() const;
 
   /**
+   * @brief Gets the stride of the buffer in pixels.
+   * @return The stride of the buffer in pixels. 0 means the buffer is tightly packed.
+   */
+  unsigned int GetStride() const;
+
+  /**
    * Get the pixel format
    * @return The pixel format
    */
@@ -281,10 +290,11 @@ private:
 
 private:
   std::unique_ptr<Property::Map> mMetadata;      ///< Metadata fields
-  unsigned char*                 mBuffer;        ///< The raw pixel data
-  unsigned int                   mBufferSize;    ///< Buffer sized in bytes
-  unsigned int                   mWidth;         ///< Buffer width in pixels
-  unsigned int                   mHeight;        ///< Buffer height in pixels
+  uint8_t*                       mBuffer;        ///< The raw pixel data
+  uint32_t                       mBufferSize;    ///< Buffer sized in bytes
+  uint32_t                       mWidth;         ///< Buffer width in pixels
+  uint32_t                       mHeight;        ///< Buffer height in pixels
+  uint32_t                       mStride;        ///< Buffer stride in bytes, 0 means the buffer is tightly packed
   Pixel::Format                  mPixelFormat;   ///< Pixel format
   bool                           mPreMultiplied; ///< PreMultiplied
 };
index e4c3fe0..357df28 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -29,13 +29,20 @@ namespace Adaptor
 {
 namespace
 {
-constexpr Channel ALPHA_CHANNEL_ONLY[]       = {ALPHA};
-constexpr Channel LUMINANCE_CHANNEL_ONLY[]   = {LUMINANCE};
-constexpr Channel LUMINANCE_ALPHA_CHANNELS[] = {LUMINANCE, ALPHA};
-constexpr Channel RGB_CHANNELS[]             = {RED, GREEN, BLUE};
-constexpr Channel BGR_CHANNELS[]             = {BLUE, GREEN, RED};
-constexpr Channel RGBA_CHANNELS[]            = {RED, GREEN, BLUE, ALPHA};
-constexpr Channel BGRA_CHANNELS[]            = {BLUE, GREEN, RED, ALPHA};
+// clang-format off
+/**
+ * @brief Pre-defined offset tables for each Channel.
+ * If invalid channel, return -1. else, return the offset bytes.
+ */
+//                                                                           | LUMINANCE | RED | GREEN | BLUE | ALPHA | DEPTH | STENCIL |
+constexpr std::int8_t ALPHA_ONLY_OFFSET_TABLE[MAX_NUMBER_OF_CHANNELS]      = {        -1 ,  -1 ,    -1 ,   -1 ,     0 ,    -1 ,      -1 };
+constexpr std::int8_t LUMINANCE_ONLY_OFFSET_TABLE[MAX_NUMBER_OF_CHANNELS]  = {         0 ,  -1 ,    -1 ,   -1 ,    -1 ,    -1 ,      -1 };
+constexpr std::int8_t LUMINANCE_ALPHA_OFFSET_TABLE[MAX_NUMBER_OF_CHANNELS] = {         0 ,  -1 ,    -1 ,   -1 ,     1 ,    -1 ,      -1 };
+constexpr std::int8_t RGB_OFFSET_TABLE[MAX_NUMBER_OF_CHANNELS]             = {        -1 ,   0 ,     1 ,    2 ,    -1 ,    -1 ,      -1 };
+constexpr std::int8_t BGR_OFFSET_TABLE[MAX_NUMBER_OF_CHANNELS]             = {        -1 ,   2 ,     1 ,    0 ,    -1 ,    -1 ,      -1 };
+constexpr std::int8_t RGBA_OFFSET_TABLE[MAX_NUMBER_OF_CHANNELS]            = {        -1 ,   0 ,     1 ,    2 ,     3 ,    -1 ,      -1 };
+constexpr std::int8_t BGRA_OFFSET_TABLE[MAX_NUMBER_OF_CHANNELS]            = {        -1 ,   2 ,     1 ,    0 ,     3 ,    -1 ,      -1 };
+// clang-format on
 
 /**
  * @brief Template to Read from a buffer with pixel formats that have one byte per channel.
@@ -43,22 +50,15 @@ constexpr Channel BGRA_CHANNELS[]            = {BLUE, GREEN, RED, ALPHA};
  * @tparam NumberOfChannels The number of channels to check
  * @param pixelData The pixel data to retrieve the value from
  * @param channel The channel we're after
- * @param channels The array of channels in the pixel format
+ * @param offsetTable The array of offset bytes for each channels in the pixel format
  * @return The value of the required channel
  */
-template<size_t NumberOfChannels>
-unsigned int ReadChannel(unsigned char* pixelData, Channel channel, const Channel (&channels)[NumberOfChannels])
+unsigned int ReadChannelTable(unsigned char* pixelData, Channel channel, const std::int8_t (&offsetTable)[MAX_NUMBER_OF_CHANNELS])
 {
-  auto num    = 0u;
   auto retVal = 0u;
-  for(auto current : channels)
+  if(offsetTable[channel] >= 0)
   {
-    if(channel == current)
-    {
-      retVal = static_cast<unsigned int>(*(pixelData + num));
-      break;
-    }
-    ++num;
+    retVal = static_cast<unsigned int>(*(pixelData + offsetTable[channel]));
   }
   return retVal;
 }
@@ -70,20 +70,13 @@ unsigned int ReadChannel(unsigned char* pixelData, Channel channel, const Channe
  * @param pixelData The pixel data to write the value to
  * @param channel The channel we're after
  * @param channelValue The value of the channel to set
- * @param channels The array of channels in the pixel format
+ * @param offsetTable The array of offset bytes for each channels in the pixel format
  */
-template<size_t NumberOfChannels>
-void WriteChannel(unsigned char* pixelData, Channel channel, unsigned int channelValue, const Channel (&channels)[NumberOfChannels])
+void WriteChannelTable(unsigned char* pixelData, Channel channel, unsigned int channelValue, const std::int8_t (&offsetTable)[MAX_NUMBER_OF_CHANNELS])
 {
-  auto num = 0u;
-  for(auto current : channels)
+  if(offsetTable[channel] >= 0)
   {
-    if(channel == current)
-    {
-      *(pixelData + num) = static_cast<unsigned char>(channelValue & 0xFF);
-      break;
-    }
-    ++num;
+    *(pixelData + offsetTable[channel]) = static_cast<unsigned char>(channelValue & 0xFF);
   }
 }
 
@@ -399,6 +392,13 @@ bool HasChannel(Dali::Pixel::Format pixelFormat, Channel channel)
       DALI_LOG_ERROR("Pixel formats for compressed images are not compatible with simple channels.\n");
       break;
     }
+
+    case Dali::Pixel::CHROMINANCE_U:
+    case Dali::Pixel::CHROMINANCE_V:
+    {
+      DALI_LOG_ERROR("Pixel formats for chrominance are not compatible with simple channels.\n");
+      break;
+    }
   }
 
   return false;
@@ -412,15 +412,15 @@ unsigned int ReadChannel(unsigned char*      pixelData,
   {
     case Dali::Pixel::A8:
     {
-      return ReadChannel(pixelData, channel, ALPHA_CHANNEL_ONLY);
+      return ReadChannelTable(pixelData, channel, ALPHA_ONLY_OFFSET_TABLE);
     }
     case Dali::Pixel::L8:
     {
-      return ReadChannel(pixelData, channel, LUMINANCE_CHANNEL_ONLY);
+      return ReadChannelTable(pixelData, channel, LUMINANCE_ONLY_OFFSET_TABLE);
     }
     case Dali::Pixel::LA88:
     {
-      return ReadChannel(pixelData, channel, LUMINANCE_ALPHA_CHANNELS);
+      return ReadChannelTable(pixelData, channel, LUMINANCE_ALPHA_OFFSET_TABLE);
     }
     case Dali::Pixel::RGB565:
     {
@@ -435,22 +435,22 @@ unsigned int ReadChannel(unsigned char*      pixelData,
     case Dali::Pixel::RGB888:
     case Dali::Pixel::RGB8888:
     {
-      return ReadChannel(pixelData, channel, RGB_CHANNELS);
+      return ReadChannelTable(pixelData, channel, RGB_OFFSET_TABLE);
     }
 
     case Dali::Pixel::BGR8888:
     {
-      return ReadChannel(pixelData, channel, BGR_CHANNELS);
+      return ReadChannelTable(pixelData, channel, BGR_OFFSET_TABLE);
     }
 
     case Dali::Pixel::RGBA8888:
     {
-      return ReadChannel(pixelData, channel, RGBA_CHANNELS);
+      return ReadChannelTable(pixelData, channel, RGBA_OFFSET_TABLE);
     }
 
     case Dali::Pixel::BGRA8888:
     {
-      return ReadChannel(pixelData, channel, BGRA_CHANNELS);
+      return ReadChannelTable(pixelData, channel, BGRA_OFFSET_TABLE);
     }
 
     case Dali::Pixel::RGBA4444:
@@ -496,17 +496,17 @@ void WriteChannel(unsigned char*      pixelData,
   {
     case Dali::Pixel::A8:
     {
-      WriteChannel(pixelData, channel, channelValue, ALPHA_CHANNEL_ONLY);
+      WriteChannelTable(pixelData, channel, channelValue, ALPHA_ONLY_OFFSET_TABLE);
       break;
     }
     case Dali::Pixel::L8:
     {
-      WriteChannel(pixelData, channel, channelValue, LUMINANCE_CHANNEL_ONLY);
+      WriteChannelTable(pixelData, channel, channelValue, LUMINANCE_ONLY_OFFSET_TABLE);
       break;
     }
     case Dali::Pixel::LA88:
     {
-      WriteChannel(pixelData, channel, channelValue, LUMINANCE_ALPHA_CHANNELS);
+      WriteChannelTable(pixelData, channel, channelValue, LUMINANCE_ALPHA_OFFSET_TABLE);
       break;
     }
     case Dali::Pixel::RGB565:
@@ -524,25 +524,25 @@ void WriteChannel(unsigned char*      pixelData,
     case Dali::Pixel::RGB888:
     case Dali::Pixel::RGB8888:
     {
-      WriteChannel(pixelData, channel, channelValue, RGB_CHANNELS);
+      WriteChannelTable(pixelData, channel, channelValue, RGB_OFFSET_TABLE);
       break;
     }
 
     case Dali::Pixel::BGR8888:
     {
-      WriteChannel(pixelData, channel, channelValue, BGR_CHANNELS);
+      WriteChannelTable(pixelData, channel, channelValue, BGR_OFFSET_TABLE);
       break;
     }
 
     case Dali::Pixel::RGBA8888:
     {
-      WriteChannel(pixelData, channel, channelValue, RGBA_CHANNELS);
+      WriteChannelTable(pixelData, channel, channelValue, RGBA_OFFSET_TABLE);
       break;
     }
 
     case Dali::Pixel::BGRA8888:
     {
-      WriteChannel(pixelData, channel, channelValue, BGRA_CHANNELS);
+      WriteChannelTable(pixelData, channel, channelValue, BGRA_OFFSET_TABLE);
       break;
     }
 
index 707821b..7790c66 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -42,8 +42,9 @@
 
 // INTERNAL INCLUDES
 #include <dali/devel-api/adaptor-framework/image-loading.h>
+#include <dali/internal/imaging/common/pixel-buffer-impl.h>
 
-typedef unsigned char WebPByteType;
+typedef uint8_t WebPByteType;
 
 namespace Dali
 {
@@ -57,7 +58,8 @@ namespace
 Debug::Filter* gWebPLoadingLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_GIF_LOADING");
 #endif
 
-constexpr size_t MAXIMUM_DOWNLOAD_IMAGE_SIZE = 50 * 1024 * 1024;
+static constexpr int32_t INITIAL_INDEX               = -1;
+static constexpr size_t  MAXIMUM_DOWNLOAD_IMAGE_SIZE = 50 * 1024 * 1024;
 
 } // namespace
 
@@ -65,41 +67,87 @@ struct WebPLoading::Impl
 {
 public:
   Impl(const std::string& url, bool isLocalResource)
-  : mUrl(url),
+  : mFile(nullptr),
+    mUrl(url),
     mFrameCount(1u),
     mMutex(),
     mBuffer(nullptr),
     mBufferSize(0u),
     mImageSize(),
-    mLoadSucceeded(true)
+    mLoadSucceeded(false),
+    mIsAnimatedImage(false),
+    mIsLocalResource(isLocalResource)
   {
+  }
+
+  Impl(FILE* const fp)
+  : mFile(fp),
+    mUrl(),
+    mFrameCount(1u),
+    mMutex(),
+    mBuffer(nullptr),
+    mBufferSize(0u),
+    mImageSize(),
+    mLoadSucceeded(false),
+    mIsAnimatedImage(false),
+    mIsLocalResource(true)
+  {
+  }
+
+  bool LoadWebPInformation()
+  {
+    // Block to do not load this file again.
+    Mutex::ScopedLock lock(mMutex);
+    if(DALI_UNLIKELY(mLoadSucceeded))
+    {
+      return mLoadSucceeded;
+    }
+
+#ifndef DALI_WEBP_AVAILABLE
+    // If the system doesn't support webp, loading will be failed.
+    mFrameCount    = 0u;
+    mLoadSucceeded = false;
+    return mLoadSucceeded;
+#endif
+
     // mFrameCount will be 1 if the input image is non-animated image or animated image with single frame.
-    if(ReadWebPInformation(isLocalResource))
+    if(DALI_LIKELY(ReadWebPInformation()))
     {
-#ifdef DALI_ANIMATED_WEBP_ENABLED
+#ifdef DALI_WEBP_AVAILABLE
       WebPDataInit(&mWebPData);
       mWebPData.size  = mBufferSize;
       mWebPData.bytes = mBuffer;
-      WebPAnimDecoderOptions webPAnimDecoderOptions;
-      WebPAnimDecoderOptionsInit(&webPAnimDecoderOptions);
-      webPAnimDecoderOptions.color_mode = MODE_RGBA;
-      mWebPAnimDecoder                  = WebPAnimDecoderNew(&mWebPData, &webPAnimDecoderOptions);
-      WebPAnimDecoderGetInfo(mWebPAnimDecoder, &mWebPAnimInfo);
-      mTimeStamp.assign(mWebPAnimInfo.frame_count, 0);
-      mFrameCount = mWebPAnimInfo.frame_count;
-      mImageSize  = ImageDimensions(mWebPAnimInfo.canvas_width, mWebPAnimInfo.canvas_height);
-#elif DALI_WEBP_AVAILABLE
-      int32_t imageWidth, imageHeight;
-      if(WebPGetInfo(mBuffer, mBufferSize, &imageWidth, &imageHeight))
+
+      WebPDemuxer* demuxer = WebPDemux(&mWebPData);
+      uint32_t     flags   = WebPDemuxGetI(demuxer, WEBP_FF_FORMAT_FLAGS);
+      if(flags & ANIMATION_FLAG)
       {
-        mImageSize = ImageDimensions(imageWidth, imageHeight);
+        mIsAnimatedImage = true;
+      }
+
+      if(!mIsAnimatedImage)
+      {
+        int32_t imageWidth, imageHeight;
+        if(WebPGetInfo(mBuffer, mBufferSize, &imageWidth, &imageHeight))
+        {
+          mImageSize = ImageDimensions(imageWidth, imageHeight);
+        }
       }
 #endif
-#ifndef DALI_WEBP_AVAILABLE
-      // If the system doesn't support webp, loading will be failed.
-      mFrameCount    = 0u;
-      mLoadSucceeded = false;
+#ifdef DALI_ANIMATED_WEBP_ENABLED
+      if(mIsAnimatedImage)
+      {
+        WebPAnimDecoderOptions webPAnimDecoderOptions;
+        WebPAnimDecoderOptionsInit(&webPAnimDecoderOptions);
+        webPAnimDecoderOptions.color_mode = MODE_RGBA;
+        mWebPAnimDecoder                  = WebPAnimDecoderNew(&mWebPData, &webPAnimDecoderOptions);
+        WebPAnimDecoderGetInfo(mWebPAnimDecoder, &mWebPAnimInfo);
+        mTimeStamp.assign(mWebPAnimInfo.frame_count, 0);
+        mFrameCount = mWebPAnimInfo.frame_count;
+        mImageSize  = ImageDimensions(mWebPAnimInfo.canvas_width, mWebPAnimInfo.canvas_height);
+      }
 #endif
+      mLoadSucceeded = true;
     }
     else
     {
@@ -107,59 +155,59 @@ public:
       mLoadSucceeded = false;
       DALI_LOG_ERROR("Image loading failed for: \"%s\".\n", mUrl.c_str());
     }
+
+    return mLoadSucceeded;
   }
 
-  bool ReadWebPInformation(bool isLocalResource)
+  bool ReadWebPInformation()
   {
-    FILE* fp = nullptr;
-    if(isLocalResource)
+    mBufferSize = 0;
+
+    FILE*                                           fp = mFile;
+    std::unique_ptr<Internal::Platform::FileReader> fileReader;
+    Dali::Vector<uint8_t>                           dataBuffer;
+    if(fp == nullptr)
     {
-      Internal::Platform::FileReader fileReader(mUrl);
-      fp = fileReader.GetFile();
-      if(fp == nullptr)
+      if(mIsLocalResource)
       {
-        return false;
+        fileReader = std::make_unique<Internal::Platform::FileReader>(mUrl);
       }
-
-      if(fseek(fp, 0, SEEK_END) <= -1)
+      else
       {
-        return false;
+        size_t dataSize;
+        if(DALI_LIKELY(TizenPlatform::Network::DownloadRemoteFileIntoMemory(mUrl, dataBuffer, dataSize, MAXIMUM_DOWNLOAD_IMAGE_SIZE)))
+        {
+          mBufferSize = dataBuffer.Size();
+          if(DALI_LIKELY(mBufferSize > 0U))
+          {
+            // Open a file handle on the memory buffer:
+            fileReader = std::make_unique<Internal::Platform::FileReader>(dataBuffer, mBufferSize);
+          }
+        }
       }
 
-      mBufferSize = ftell(fp);
-      if(!fseek(fp, 0, SEEK_SET))
+      if(fileReader)
       {
-        mBuffer     = reinterpret_cast<WebPByteType*>(malloc(sizeof(WebPByteType) * mBufferSize));
-        mBufferSize = fread(mBuffer, sizeof(WebPByteType), mBufferSize, fp);
-        return true;
+        fp = fileReader->GetFile();
       }
     }
-    else
-    {
-      // remote file
-      bool                  succeeded;
-      Dali::Vector<uint8_t> dataBuffer;
-      size_t                dataSize;
 
-      succeeded = TizenPlatform::Network::DownloadRemoteFileIntoMemory(mUrl, dataBuffer, dataSize, MAXIMUM_DOWNLOAD_IMAGE_SIZE);
-      if(succeeded)
+    if(DALI_LIKELY(fp != nullptr))
+    {
+      if(mBufferSize == 0)
       {
-        mBufferSize = dataBuffer.Size();
-        if(mBufferSize > 0U)
+        if(DALI_UNLIKELY(fseek(fp, 0, SEEK_END) <= -1))
         {
-          // Open a file handle on the memory buffer:
-          Internal::Platform::FileReader fileReader(dataBuffer, mBufferSize);
-          fp = fileReader.GetFile();
-          if(fp != nullptr)
-          {
-            if(!fseek(fp, 0, SEEK_SET))
-            {
-              mBuffer     = reinterpret_cast<WebPByteType*>(malloc(sizeof(WebPByteType) * mBufferSize));
-              mBufferSize = fread(mBuffer, sizeof(WebPByteType), mBufferSize, fp);
-              return true;
-            }
-          }
+          return false;
         }
+        mBufferSize = ftell(fp);
+      }
+
+      if(DALI_LIKELY(!fseek(fp, 0, SEEK_SET)))
+      {
+        mBuffer     = reinterpret_cast<WebPByteType*>(malloc(sizeof(WebPByteType) * mBufferSize));
+        mBufferSize = fread(mBuffer, sizeof(WebPByteType), mBufferSize, fp);
+        return true;
       }
     }
     return false;
@@ -167,16 +215,21 @@ public:
 
   void ReleaseResource()
   {
-#ifdef DALI_ANIMATED_WEBP_ENABLED
+#ifdef DALI_WEBP_AVAILABLE
     if(&mWebPData != nullptr)
     {
       mWebPData.bytes = nullptr;
       WebPDataInit(&mWebPData);
     }
-    if(mWebPAnimDecoder != nullptr)
+#endif
+#ifdef DALI_ANIMATED_WEBP_ENABLED
+    if(mIsAnimatedImage)
     {
-      WebPAnimDecoderDelete(mWebPAnimDecoder);
-      mWebPAnimDecoder = nullptr;
+      if(mWebPAnimDecoder != nullptr)
+      {
+        WebPAnimDecoderDelete(mWebPAnimDecoder);
+        mWebPAnimDecoder = nullptr;
+      }
     }
 #endif
     if(mBuffer != nullptr)
@@ -184,6 +237,8 @@ public:
       free((void*)mBuffer);
       mBuffer = nullptr;
     }
+
+    mLoadSucceeded = false;
   }
 
   // Moveable but not copyable
@@ -198,9 +253,10 @@ public:
     ReleaseResource();
   }
 
+  FILE*                 mFile;
   std::string           mUrl;
   std::vector<uint32_t> mTimeStamp;
-  uint32_t              mLoadingFrame{0};
+  int32_t               mLatestLoadedFrame{INITIAL_INDEX};
   uint32_t              mFrameCount;
   Mutex                 mMutex;
   // For the case the system doesn't support DALI_ANIMATED_WEBP_ENABLED
@@ -208,11 +264,17 @@ public:
   uint32_t        mBufferSize;
   ImageDimensions mImageSize;
   bool            mLoadSucceeded;
+  bool            mIsAnimatedImage;
+  bool            mIsLocalResource;
+
+#ifdef DALI_WEBP_AVAILABLE
+  WebPData mWebPData{0};
+#endif
 
 #ifdef DALI_ANIMATED_WEBP_ENABLED
-  WebPData         mWebPData{0};
-  WebPAnimDecoder* mWebPAnimDecoder{nullptr};
-  WebPAnimInfo     mWebPAnimInfo{0};
+  WebPAnimDecoder*         mWebPAnimDecoder{nullptr};
+  WebPAnimInfo             mWebPAnimInfo{0};
+  Dali::Devel::PixelBuffer mPreLoadedFrame{};
 #endif
 };
 
@@ -224,142 +286,194 @@ AnimatedImageLoadingPtr WebPLoading::New(const std::string& url, bool isLocalRes
   return AnimatedImageLoadingPtr(new WebPLoading(url, isLocalResource));
 }
 
+AnimatedImageLoadingPtr WebPLoading::New(FILE* const fp)
+{
+#ifndef DALI_ANIMATED_WEBP_ENABLED
+  DALI_LOG_ERROR("The system does not support Animated WebP format.\n");
+#endif
+  return AnimatedImageLoadingPtr(new WebPLoading(fp));
+}
+
 WebPLoading::WebPLoading(const std::string& url, bool isLocalResource)
 : mImpl(new WebPLoading::Impl(url, isLocalResource))
 {
 }
 
-WebPLoading::~WebPLoading()
+WebPLoading::WebPLoading(FILE* const fp)
+: mImpl(new WebPLoading::Impl(fp))
 {
-  delete mImpl;
 }
 
-bool WebPLoading::LoadNextNFrames(uint32_t frameStartIndex, int count, std::vector<Dali::PixelData>& pixelData)
+WebPLoading::~WebPLoading()
 {
-  for(int i = 0; i < count; ++i)
-  {
-    Dali::Devel::PixelBuffer pixelBuffer = LoadFrame((frameStartIndex + i) % mImpl->mFrameCount);
-    Dali::PixelData          imageData   = Devel::PixelBuffer::Convert(pixelBuffer);
-    pixelData.push_back(imageData);
-  }
-  if(pixelData.size() != static_cast<uint32_t>(count))
-  {
-    return false;
-  }
-  return true;
+  delete mImpl;
 }
 
 Dali::Devel::PixelBuffer WebPLoading::LoadFrame(uint32_t frameIndex)
 {
   Dali::Devel::PixelBuffer pixelBuffer;
 
+  // If WebP file is still not loaded, Load the information.
+  if(DALI_UNLIKELY(!mImpl->mLoadSucceeded))
+  {
+    if(DALI_UNLIKELY(!mImpl->LoadWebPInformation()))
+    {
+      mImpl->ReleaseResource();
+      return pixelBuffer;
+    }
+  }
+
   // WebPDecodeRGBA is faster than to use demux API for loading non-animated image.
   // If frame count is 1, use WebPDecodeRGBA api.
 #ifdef DALI_WEBP_AVAILABLE
-  if(mImpl->mFrameCount == 1)
+  if(!mImpl->mIsAnimatedImage)
   {
     int32_t width, height;
-    if(!WebPGetInfo(mImpl->mBuffer, mImpl->mBufferSize, &width, &height))
+    if(DALI_LIKELY(WebPGetInfo(mImpl->mBuffer, mImpl->mBufferSize, &width, &height)))
     {
-      return pixelBuffer;
-    }
+      WebPBitstreamFeatures features;
+      if(DALI_LIKELY(VP8_STATUS_NOT_ENOUGH_DATA != WebPGetFeatures(mImpl->mBuffer, mImpl->mBufferSize, &features)))
+      {
+        uint32_t channelNumber = (features.has_alpha) ? 4 : 3;
+        uint8_t* frameBuffer   = nullptr;
+        if(channelNumber == 4)
+        {
+          frameBuffer = WebPDecodeRGBA(mImpl->mBuffer, mImpl->mBufferSize, &width, &height);
+        }
+        else
+        {
+          frameBuffer = WebPDecodeRGB(mImpl->mBuffer, mImpl->mBufferSize, &width, &height);
+        }
 
-    WebPBitstreamFeatures features;
-    if(VP8_STATUS_NOT_ENOUGH_DATA == WebPGetFeatures(mImpl->mBuffer, mImpl->mBufferSize, &features))
-    {
-      return pixelBuffer;
+        if(frameBuffer != nullptr)
+        {
+          Pixel::Format                     pixelFormat = (channelNumber == 4) ? Pixel::RGBA8888 : Pixel::RGB888;
+          int32_t                           bufferSize  = width * height * Dali::Pixel::GetBytesPerPixel(pixelFormat);
+          Internal::Adaptor::PixelBufferPtr internal =
+            Internal::Adaptor::PixelBuffer::New(frameBuffer, bufferSize, width, height, width, pixelFormat);
+          pixelBuffer = Devel::PixelBuffer(internal.Get());
+        }
+      }
     }
+    // The single frame resource should be released after loading.
+    mImpl->ReleaseResource();
+  }
+#endif
 
-    uint32_t      channelNumber = (features.has_alpha) ? 4 : 3;
-    Pixel::Format pixelFormat   = (channelNumber == 4) ? Pixel::RGBA8888 : Pixel::RGB888;
-    pixelBuffer                 = Dali::Devel::PixelBuffer::New(width, height, pixelFormat);
-    uint8_t* frameBuffer        = nullptr;
-    if(channelNumber == 4)
+#ifdef DALI_ANIMATED_WEBP_ENABLED
+  if(mImpl->mIsAnimatedImage && mImpl->mBuffer != nullptr)
+  {
+    Mutex::ScopedLock lock(mImpl->mMutex);
+    if(DALI_LIKELY(frameIndex < mImpl->mWebPAnimInfo.frame_count && mImpl->mLoadSucceeded))
     {
-      frameBuffer = WebPDecodeRGBA(mImpl->mBuffer, mImpl->mBufferSize, &width, &height);
+      DALI_LOG_INFO(gWebPLoadingLogFilter, Debug::Concise, "LoadFrame( frameIndex:%d )\n", frameIndex);
+
+      if(mImpl->mPreLoadedFrame && mImpl->mLatestLoadedFrame == static_cast<int32_t>(frameIndex))
+      {
+        pixelBuffer = mImpl->mPreLoadedFrame;
+      }
+      else
+      {
+        pixelBuffer = DecodeFrame(frameIndex);
+      }
+      mImpl->mPreLoadedFrame.Reset();
+
+      // If time stamp of next frame is unknown, load a frame more to know it.
+      if(frameIndex + 1 < mImpl->mWebPAnimInfo.frame_count && mImpl->mTimeStamp[frameIndex + 1] == 0u)
+      {
+        mImpl->mPreLoadedFrame = DecodeFrame(frameIndex + 1);
+      }
     }
     else
     {
-      frameBuffer = WebPDecodeRGB(mImpl->mBuffer, mImpl->mBufferSize, &width, &height);
+      mImpl->ReleaseResource();
     }
-
-    if(frameBuffer != nullptr)
-    {
-      const int32_t imageBufferSize = width * height * sizeof(uint8_t) * channelNumber;
-      memcpy(pixelBuffer.GetBuffer(), frameBuffer, imageBufferSize);
-      free((void*)frameBuffer);
-    }
-    mImpl->ReleaseResource();
-    return pixelBuffer;
   }
 #endif
+  return pixelBuffer;
+}
 
+Dali::Devel::PixelBuffer WebPLoading::DecodeFrame(uint32_t frameIndex)
+{
+  Dali::Devel::PixelBuffer pixelBuffer;
 #ifdef DALI_ANIMATED_WEBP_ENABLED
-  Mutex::ScopedLock lock(mImpl->mMutex);
-  if(frameIndex >= mImpl->mWebPAnimInfo.frame_count || !mImpl->mLoadSucceeded)
-  {
-    return pixelBuffer;
-  }
-
-  DALI_LOG_INFO(gWebPLoadingLogFilter, Debug::Concise, "LoadFrame( frameIndex:%d )\n", frameIndex);
-
-  if(mImpl->mLoadingFrame > frameIndex)
+  if(mImpl->mLatestLoadedFrame >= static_cast<int32_t>(frameIndex))
   {
-    mImpl->mLoadingFrame = 0;
+    mImpl->mLatestLoadedFrame = INITIAL_INDEX;
     WebPAnimDecoderReset(mImpl->mWebPAnimDecoder);
   }
 
-  for(; mImpl->mLoadingFrame < frameIndex; ++mImpl->mLoadingFrame)
+  uint8_t* frameBuffer = nullptr;
+  int32_t  timestamp   = 0u;
+  for(; mImpl->mLatestLoadedFrame < static_cast<int32_t>(frameIndex);)
   {
-    uint8_t* frameBuffer;
-    int      timestamp;
     WebPAnimDecoderGetNext(mImpl->mWebPAnimDecoder, &frameBuffer, &timestamp);
-    mImpl->mTimeStamp[mImpl->mLoadingFrame] = timestamp;
+    mImpl->mTimeStamp[++mImpl->mLatestLoadedFrame] = timestamp;
   }
 
-  const int bufferSize = mImpl->mWebPAnimInfo.canvas_width * mImpl->mWebPAnimInfo.canvas_height * sizeof(uint32_t);
-  uint8_t*  frameBuffer;
-  int       timestamp;
-  WebPAnimDecoderGetNext(mImpl->mWebPAnimDecoder, &frameBuffer, &timestamp);
-
-  pixelBuffer = Dali::Devel::PixelBuffer::New(mImpl->mWebPAnimInfo.canvas_width, mImpl->mWebPAnimInfo.canvas_height, Dali::Pixel::RGBA8888);
-  memcpy(pixelBuffer.GetBuffer(), frameBuffer, bufferSize);
-  mImpl->mTimeStamp[mImpl->mLoadingFrame] = timestamp;
-
-  mImpl->mLoadingFrame++;
-  if(mImpl->mLoadingFrame >= mImpl->mWebPAnimInfo.frame_count)
+  if(frameBuffer != nullptr)
   {
-    mImpl->mLoadingFrame = 0;
-    WebPAnimDecoderReset(mImpl->mWebPAnimDecoder);
+    const int bufferSize = mImpl->mWebPAnimInfo.canvas_width * mImpl->mWebPAnimInfo.canvas_height * sizeof(uint32_t);
+    pixelBuffer          = Dali::Devel::PixelBuffer::New(mImpl->mWebPAnimInfo.canvas_width, mImpl->mWebPAnimInfo.canvas_height, Dali::Pixel::RGBA8888);
+    memcpy(pixelBuffer.GetBuffer(), frameBuffer, bufferSize);
   }
+
 #endif
   return pixelBuffer;
 }
 
 ImageDimensions WebPLoading::GetImageSize() const
 {
+  if(DALI_UNLIKELY(!mImpl->mLoadSucceeded))
+  {
+    mImpl->LoadWebPInformation();
+  }
   return mImpl->mImageSize;
 }
 
 uint32_t WebPLoading::GetImageCount() const
 {
+  if(DALI_UNLIKELY(!mImpl->mLoadSucceeded))
+  {
+    mImpl->LoadWebPInformation();
+  }
   return mImpl->mFrameCount;
 }
 
 uint32_t WebPLoading::GetFrameInterval(uint32_t frameIndex) const
 {
-  // If frameIndex is above the value of ImageCount or current frame is not loading yet, return 0u.
-  if(frameIndex >= GetImageCount() || (frameIndex > 0 && mImpl->mTimeStamp[frameIndex - 1] > mImpl->mTimeStamp[frameIndex]))
+  if(DALI_UNLIKELY(!mImpl->mLoadSucceeded))
+  {
+    DALI_LOG_ERROR("WebP file is still not loaded, this frame interval could not be correct value.\n");
+  }
+  if(frameIndex >= GetImageCount())
   {
+    DALI_LOG_ERROR("Input frameIndex exceeded frame count of the WebP.");
     return 0u;
   }
   else
   {
-    if(frameIndex > 0)
+    int32_t interval = 0u;
+    if(GetImageCount() == 1u)
+    {
+      return 0u;
+    }
+    else if(frameIndex + 1 == GetImageCount())
+    {
+      // For the interval between last frame and first frame, use last interval again.
+      interval = mImpl->mTimeStamp[frameIndex] - mImpl->mTimeStamp[frameIndex - 1];
+    }
+    else
+    {
+      interval = mImpl->mTimeStamp[frameIndex + 1] - mImpl->mTimeStamp[frameIndex];
+    }
+
+    if(DALI_UNLIKELY(interval < 0))
     {
-      return mImpl->mTimeStamp[frameIndex] - mImpl->mTimeStamp[frameIndex - 1];
+      DALI_LOG_ERROR("This interval value is not correct, because the frame still hasn't ever been decoded.");
+      return 0u;
     }
-    return mImpl->mTimeStamp[frameIndex];
+    return static_cast<uint32_t>(interval);
   }
 }
 
index ecf8bbb..5a232fb 100644 (file)
@@ -57,6 +57,13 @@ public:
   static AnimatedImageLoadingPtr New(const std::string& url, bool isLocalResource);
 
   /**
+   * Create a WebPLoading with the given url and resourceType.
+   * @param[in] fp The file pointer to be load.
+   * @return A newly created WebPLoading.
+   */
+  static AnimatedImageLoadingPtr New(FILE* const fp);
+
+  /**
    * @brief Constructor
    *
    * Construct a Loader with the given URL
@@ -66,21 +73,17 @@ public:
   WebPLoading(const std::string& url, bool isLocalResource);
 
   /**
-   * @brief Destructor
+   * @brief Constructor
+   *
+   * Construct a Loader with the given URL
+   * @param[in] fp The file pointer to be load.
    */
-  ~WebPLoading() override;
+  WebPLoading(FILE* const fp);
 
   /**
-   * @brief Load the next N Frames of the webp.
-   *
-   * @note This function will load the entire webp into memory if not already loaded.
-   * @param[in] frameStartIndex The frame counter to start from. Will usually be the next frame
-   * after the previous invocation of this method, or 0 to start.
-   * @param[in] count The number of frames to load
-   * @param[out] pixelData The vector in which to return the frame data
-   * @return True if the frame data was successfully loaded
+   * @brief Destructor
    */
-  bool LoadNextNFrames(uint32_t frameStartIndex, int count, std::vector<Dali::PixelData>& pixelData) override;
+  ~WebPLoading() override;
 
   /**
    * @brief Load the next Frame of the animated image.
@@ -89,7 +92,6 @@ public:
    * @param[in] frameIndex The frame counter to load. Will usually be the next frame.
    * @return Dali::Devel::PixelBuffer The loaded PixelBuffer. If loading is fail, return empty handle.
    */
-
   Dali::Devel::PixelBuffer LoadFrame(uint32_t frameIndex) override;
 
   /**
@@ -109,7 +111,7 @@ public:
    *
    * @note The frame is needed to be loaded before this function is called.
    *
-   * @return The time interval of the frame(microsecond).
+   * @return The time interval between frameIndex and frameIndex + 1(microsecond).
    */
   uint32_t GetFrameInterval(uint32_t frameIndex) const override;
 
@@ -128,6 +130,15 @@ public:
   bool HasLoadingSucceeded() const override;
 
 private:
+  /**
+   * @brief Decode Frame of the animated image.
+   *
+   * @param[in] frameIndex The frame counter to load. Will usually be the next frame.
+   * @return Dali::Devel::PixelBuffer The loaded PixelBuffer. If loading is fail, return empty handle.
+   */
+  Dali::Devel::PixelBuffer DecodeFrame(uint32_t frameIndex);
+
+private:
   struct Impl;
   Impl* mImpl;
 };
index 107f4cd..9cd7681 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -38,7 +38,7 @@ namespace
 {
 #define TBM_SURFACE_QUEUE_SIZE 3
 
-const char* SAMPLER_TYPE    = "samplerExternalOES";
+const char* SAMPLER_TYPE = "samplerExternalOES";
 
 // clang-format off
 int FORMATS_BLENDING_REQUIRED[] = {
@@ -124,19 +124,22 @@ void NativeImageSourceQueueTizen::Initialize(Dali::NativeImageSourceQueue::Color
 
     switch(colorFormat)
     {
-      case Dali::NativeImageSourceQueue::ColorFormat::RGBA8888:
+      case Dali::NativeImageSourceQueue::ColorFormat::RGBA8888: // TODO : Implement me after other codes fixed.
+      case Dali::NativeImageSourceQueue::ColorFormat::BGRA8888:
       {
         tbmFormat         = TBM_FORMAT_ARGB8888;
         mBlendingRequired = true;
         break;
       }
-      case Dali::NativeImageSourceQueue::ColorFormat::RGBX8888:
+      case Dali::NativeImageSourceQueue::ColorFormat::RGBX8888: // TODO : Implement me after other codes fixed.
+      case Dali::NativeImageSourceQueue::ColorFormat::BGRX8888:
       {
         tbmFormat         = TBM_FORMAT_XRGB8888;
         mBlendingRequired = false;
         break;
       }
-      case Dali::NativeImageSourceQueue::ColorFormat::RGB888:
+      case Dali::NativeImageSourceQueue::ColorFormat::RGB888: // TODO : Implement me after other codes fixed.
+      case Dali::NativeImageSourceQueue::ColorFormat::BGR888:
       {
         tbmFormat         = TBM_FORMAT_RGB888;
         mBlendingRequired = false;
index eba7424..6791e28 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_INPUT_COMMON_INPUT_METHOD_CONTEXT_IMPL_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -177,6 +177,13 @@ public:
   {
   }
 
+  /**
+   * @copydoc Dali::InputMethodContext::SendSelectionSet()
+   */
+  virtual void SendSelectionSet(void* data, ImfContext* imfContext, void* eventInfo)
+  {
+  }
+
   // Cursor related
   /**
    * @copydoc Dali::InputMethodContext::NotifyCursorPosition()
index 38003b8..91db602 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -146,6 +146,11 @@ void InputMethodContextGeneric::SendCommitContent(void* data, ImfContext* imfCon
   DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextGeneric::SendCommitContent\n");
 }
 
+void InputMethodContextGeneric::SendSelectionSet(void* data, ImfContext* imfContext, void* eventInfo)
+{
+  DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextGeneric::SendSelectionSet\n");
+}
+
 void InputMethodContextGeneric::NotifyCursorPosition()
 {
   DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextGeneric::NotifyCursorPosition\n");
index ff83e50..34f3039 100644 (file)
@@ -2,7 +2,7 @@
 #define __DALI_INTERNAL_INPUT_METHOD_CONTEXT_IMPL_GENERIC_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -134,6 +134,11 @@ public:
    */
   void SendCommitContent(void* data, ImfContext* imfContext, void* eventInfo) override;
 
+  /**
+   * @copydoc Dali::InputMethodContext::SendSelectionSet()
+   */
+  void SendSelectionSet(void* data, ImfContext* imfContext, void* eventInfo) override;
+
   // Cursor related
   /**
    * @copydoc Dali::InputMethodContext::NotifyCursorPosition()
index a651c08..978446d 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -136,6 +136,13 @@ public:
   {
   }
 
+  /**
+   * @copydoc Dali::InputMethodContext::SendSelectionSet()
+   */
+  void SendSelectionSet(void* data, ImfContext* imfContext, void* eventInfo) override
+  {
+  }
+
   // Cursor related
   /**
    * @copydoc Dali::InputMethodContext::NotifyCursorPosition()
index c15f14b..6945b15 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -272,6 +272,18 @@ void CommitContent(void* data, Ecore_IMF_Context* imfContext, void* eventInfo)
   }
 }
 
+/**
+ * Called when the input method sends a selection set.
+ */
+void SelectionSet(void* data, Ecore_IMF_Context* imfContext, void* eventInfo)
+{
+  if(data)
+  {
+    InputMethodContextEcoreWl* inputMethodContext = static_cast<InputMethodContextEcoreWl*>(data);
+    inputMethodContext->SendSelectionSet(data, imfContext, eventInfo);
+  }
+}
+
 int GetWindowIdFromActor(Dali::Actor actor)
 {
   int windowId = kUninitializedWindowId;
@@ -397,6 +409,7 @@ void InputMethodContextEcoreWl::ConnectCallbacks()
     ecore_imf_context_event_callback_add(mIMFContext, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, ImfDeleteSurrounding, this);
     ecore_imf_context_event_callback_add(mIMFContext, ECORE_IMF_CALLBACK_PRIVATE_COMMAND_SEND, PrivateCommand, this);
     ecore_imf_context_event_callback_add(mIMFContext, ECORE_IMF_CALLBACK_COMMIT_CONTENT, CommitContent, this);
+    ecore_imf_context_event_callback_add(mIMFContext, ECORE_IMF_CALLBACK_SELECTION_SET, SelectionSet, this);
 
     ecore_imf_context_input_panel_event_callback_add(mIMFContext, ECORE_IMF_INPUT_PANEL_STATE_EVENT, InputPanelStateChangeCallback, this);
     ecore_imf_context_input_panel_event_callback_add(mIMFContext, ECORE_IMF_INPUT_PANEL_LANGUAGE_EVENT, InputPanelLanguageChangeCallback, this);
@@ -418,6 +431,7 @@ void InputMethodContextEcoreWl::DisconnectCallbacks()
     ecore_imf_context_event_callback_del(mIMFContext, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, ImfDeleteSurrounding);
     ecore_imf_context_event_callback_del(mIMFContext, ECORE_IMF_CALLBACK_PRIVATE_COMMAND_SEND, PrivateCommand);
     ecore_imf_context_event_callback_del(mIMFContext, ECORE_IMF_CALLBACK_COMMIT_CONTENT, CommitContent);
+    ecore_imf_context_event_callback_del(mIMFContext, ECORE_IMF_CALLBACK_SELECTION_SET, SelectionSet);
 
     ecore_imf_context_input_panel_event_callback_del(mIMFContext, ECORE_IMF_INPUT_PANEL_STATE_EVENT, InputPanelStateChangeCallback);
     ecore_imf_context_input_panel_event_callback_del(mIMFContext, ECORE_IMF_INPUT_PANEL_LANGUAGE_EVENT, InputPanelLanguageChangeCallback);
@@ -743,6 +757,26 @@ void InputMethodContextEcoreWl::SendCommitContent(void* data, ImfContext* imfCon
   }
 }
 
+/**
+ * Called when the input method selection set.
+ */
+void InputMethodContextEcoreWl::SendSelectionSet(void* data, ImfContext* imfContext, void* eventInfo)
+{
+  DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextEcoreWl::SendCommitContent\n");
+
+  if(Dali::Adaptor::IsAvailable())
+  {
+    Ecore_IMF_Event_Selection* selection = static_cast<Ecore_IMF_Event_Selection*>(eventInfo);
+    if(selection)
+    {
+      DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextEcoreWl::SendSelectionSet selection start index : %d, end index : %d\n", selection->start, selection->end);
+      Dali::InputMethodContext::EventData imfData(Dali::InputMethodContext::SELECTION_SET, selection->start, selection->end);
+      Dali::InputMethodContext            handle(this);
+      mEventSignal.Emit(handle, imfData);
+    }
+  }
+}
+
 void InputMethodContextEcoreWl::NotifyCursorPosition()
 {
   DALI_LOG_INFO(gLogFilter, Debug::General, "InputMethodContextEcoreWl::NotifyCursorPosition\n");
index e133a42..0cdfcb7 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_INPUT_METHOD_CONTEXT_IMPL_ECORE_WL_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -131,6 +131,11 @@ public:
    */
   void SendCommitContent(void* data, ImfContext* imfContext, void* eventInfo) override;
 
+  /**
+   * @copydoc Dali::InputMethodContext::SendSelectionSet()
+   */
+  void SendSelectionSet(void* data, ImfContext* imfContext, void* eventInfo) override;
+
   // Cursor related
   /**
    * @copydoc Dali::InputMethodContext::NotifyCursorPosition()
index 8727249..4e028c2 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_INPUT_METHOD_CONTEXT_IMPL_X_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -140,6 +140,13 @@ public:
   {
   }
 
+  /**
+   * @copydoc Dali::InputMethodContext::SendSelectionSet()
+   */
+  void SendSelectionSet(void* data, ImfContext* imfContext, void* eventInfo) override
+  {
+  }
+
   // Cursor related
   /**
    * @copydoc Dali::InputMethodContext::NotifyCursorPosition()
index e89a502..a36d0bd 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_INPUT_METHOD_CONTEXT_IMPL_WIN_H\r
 \r
 /*\r
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.\r
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.\r
  *\r
  * Licensed under the Apache License, Version 2.0 (the "License");\r
  * you may not use this file except in compliance with the License.\r
@@ -138,6 +138,13 @@ public:
   {\r
   }\r
 \r
+  /**\r
+   * @copydoc Dali::InputMethodContext::SendSelectionSet()\r
+   */\r
+  void SendSelectionSet(void* data, ImfContext* imfContext, void* eventInfo) override\r
+  {\r
+  }\r
+\r
   // Cursor related\r
   /**\r
    * @copydoc Dali::InputMethodContext::NotifyCursorPosition()\r
index 2a5ba8f..ebe4467 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 // EXTERNAL INCLUDES
 #include <dali/integration-api/debug.h>
-#include <dali/internal/adaptor/common/adaptor-impl.h>
 #include <dali/public-api/dali-core.h>
 #include <stdio.h>
 #include <iomanip>
 #include <sstream>
 
+// INTERNAL INCLUDES
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+#include <dali/internal/network/common/network-service-impl.h>
+
 using Dali::Matrix;
 using Dali::Matrix3;
 using Dali::Property;
@@ -453,6 +456,18 @@ void DumpScene(unsigned int clientId, ClientSendDataInterface* sendData)
   sendData->SendData(json.c_str(), json.length(), clientId);
 }
 
+void SetCustomCommand(const std::string& message)
+{
+  if(Adaptor::IsAvailable())
+  {
+    Internal::Adaptor::NetworkServicePtr networkService = Internal::Adaptor::NetworkService::Get();
+    if(networkService)
+    {
+      networkService->EmitCustomCommandReceivedSignal(message);
+    }
+  }
+}
+
 } // namespace Automation
 
 } // namespace Adaptor
index c675001..44e0418 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_ADAPTOR_AUTOMATION_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -59,6 +59,15 @@ void SetProperty(const std::string& message);
  */
 void DumpScene(unsigned int clientId, ClientSendDataInterface* sendData);
 
+
+/**
+ * @brief Sets a custom command.
+ * No ClientSendDataInterface required, as no response is sent back
+ * @param[in] message custom message
+ */
+void SetCustomCommand(const std::string& message);
+
+
 } // namespace Automation
 
 } // namespace Adaptor
index 836f2ba..4a02097 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@
 
 // EXTERNAL INCLUDES
 #include <stdio.h>
+#include <iostream>
 #include <string>
 
 // INTERNAL INCLUDES
@@ -52,6 +53,7 @@ public:
   {
     UNKNOWN_COMMAND,
     SET_PROPERTY,
+    CUSTOM_COMMAND,
     DUMP_SCENE
   };
 
@@ -67,21 +69,28 @@ public:
 
   void AssignSetPropertyCommand(std::string setPropertyCommand)
   {
-    mCommandId       = SET_PROPERTY;
-    mPropertyCommand = setPropertyCommand;
+    mCommandId     = SET_PROPERTY;
+    mCommandString = setPropertyCommand;
   }
+
   void AssignDumpSceneCommand()
   {
     mCommandId = DUMP_SCENE;
   }
 
+  void AssignCustomCommand(std::string&& customCommand)
+  {
+    mCommandId     = CUSTOM_COMMAND;
+    mCommandString = std::move(customCommand);
+  }
+
   void RunCallback()
   {
     switch(mCommandId)
     {
       case SET_PROPERTY:
       {
-        Automation::SetProperty(mPropertyCommand);
+        Automation::SetProperty(mCommandString);
         break;
       }
       case DUMP_SCENE:
@@ -89,6 +98,11 @@ public:
         Automation::DumpScene(mClientId, &mSendDataInterface);
         break;
       }
+      case CUSTOM_COMMAND:
+      {
+        Automation::SetCustomCommand(mCommandString);
+        break;
+      }
       default:
       {
         DALI_ASSERT_DEBUG(0 && "Unknown command");
@@ -103,12 +117,29 @@ public:
   }
 
 private:
-  std::string              mPropertyCommand;   ///< property command
+  std::string              mCommandString;     ///< command string for property or custom command
   ClientSendDataInterface& mSendDataInterface; ///< Abstract client send data interface
   CommandId                mCommandId;         ///< command id
   const unsigned int       mClientId;          ///< client id
 };
 
+/**
+ * @brief Helper to ensure the AutomationCallback method we want is called in the main thread
+ */
+template<typename T>
+void TriggerOnMainThread(unsigned int clientId, ClientSendDataInterface& sendDataInterface, T&& lambda)
+{
+  // this needs to be run on the main thread, use the trigger event....
+  AutomationCallback* callback = new AutomationCallback(clientId, sendDataInterface);
+  lambda(callback);
+
+  // create a trigger event that automatically deletes itself after the callback has run in the main thread
+  TriggerEventInterface* interface = TriggerEventFactory::CreateTriggerEvent(callback, TriggerEventInterface::DELETE_AFTER_TRIGGER);
+
+  // asynchronous call, the call back will be run sometime later on the main thread
+  interface->Trigger();
+}
+
 } // unnamed namespace
 
 NetworkPerformanceClient::NetworkPerformanceClient(pthread_t*               thread,
@@ -217,29 +248,21 @@ void NetworkPerformanceClient::ProcessCommand(char* buffer, unsigned int bufferS
 
     case PerformanceProtocol::DUMP_SCENE_GRAPH:
     {
-      // this needs to be run on the main thread, use the trigger event....
-      AutomationCallback* callback = new AutomationCallback(mClientId, mSendDataInterface);
-      callback->AssignDumpSceneCommand();
-
-      // create a trigger event that automatically deletes itself after the callback has run in the main thread
-      TriggerEventInterface* interface = TriggerEventFactory::CreateTriggerEvent(callback, TriggerEventInterface::DELETE_AFTER_TRIGGER);
-
-      // asynchronous call, the call back will be run sometime later on the main thread
-      interface->Trigger();
+      TriggerOnMainThread(mClientId, mSendDataInterface, [&](AutomationCallback* callback){callback->AssignDumpSceneCommand();});
       break;
     }
 
     case PerformanceProtocol::SET_PROPERTIES:
     {
-      // this needs to be run on the main thread, use the trigger event....
-      AutomationCallback* callback = new AutomationCallback(mClientId, mSendDataInterface);
-      callback->AssignSetPropertyCommand(stringParam);
-
-      // create a trigger event that automatically deletes itself after the callback has run in the main thread
-      TriggerEventInterface* interface = TriggerEventFactory::CreateTriggerEvent(callback, TriggerEventInterface::DELETE_AFTER_TRIGGER);
+      TriggerOnMainThread(mClientId, mSendDataInterface, [&](AutomationCallback* callback){callback->AssignSetPropertyCommand(stringParam);});
+      response = "Completed";
+      break;
+    }
 
-      // asynchronous call, the call back will be run sometime later on the main thread
-      interface->Trigger();
+    case PerformanceProtocol::CUSTOM_COMMAND:
+    {
+      TriggerOnMainThread(mClientId, mSendDataInterface, [&](AutomationCallback* callback){callback->AssignCustomCommand(std::move(stringParam));});
+      response = "Completed";
       break;
     }
 
index 5c23e84..d921f58 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -64,6 +64,7 @@ CommandInfo CommandLookup[]=
   {ENABLE_TIME_MARKER_BIT_MASK, "set_marker",     UNSIGNED_INT},
   {DUMP_SCENE_GRAPH,            "dump_scene",     NO_PARAMS   },
   {SET_PROPERTIES,              "set_properties", STRING      },
+  {CUSTOM_COMMAND,              "custom_command", STRING      },
   {UNKNOWN_COMMAND,             "unknown",        NO_PARAMS   }
 };
 // clang-format on
@@ -96,6 +97,9 @@ const char* const helpMsg =
     GREEN " set_properties " PARAM "|ActorIndex;Property;Value|" NORMAL ", e.g: \n"
     GREEN " set_properties " PARAM "|178;Size;[ 144.0, 144.0, 144.0 ]|178;Color;[ 1.0, 1,0, 1.0 ]|\n"
     "\n"
+    GREEN " custom_command " NORMAL " - A custom command for an application. Format:\n\n"
+    GREEN " custom_command " PARAM "ANY_STRING" NORMAL "\n"
+    "\n"
     GREEN " dump_scene" NORMAL " - dump the current scene in json format\n";
 // clang-format off
 } // un-named namespace
index a5123b2..1313e96 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_ADAPTOR_NETWORK_PERFORMANCE_PROTOCOL_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -39,6 +39,7 @@ enum CommandId
   ENABLE_TIME_MARKER_BIT_MASK = 4, ///< bit mask of time markers to enable
   SET_PROPERTIES              = 5, ///< set property
   DUMP_SCENE_GRAPH            = 6, ///< dump the scene graph
+  CUSTOM_COMMAND              = 7, ///< custom command for the application
   UNKNOWN_COMMAND             = 4096
 };
 
diff --git a/dali/internal/network/common/network-service-impl.cpp b/dali/internal/network/common/network-service-impl.cpp
new file mode 100644 (file)
index 0000000..30dc19e
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/network/common/network-service-impl.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/common/singleton-service.h>
+
+namespace Dali::Internal::Adaptor
+{
+NetworkServicePtr NetworkService::Get()
+{
+  NetworkServicePtr networkService;
+
+  Dali::SingletonService service(SingletonService::Get());
+  if(service)
+  {
+    // Check whether the singleton is already created
+    Dali::BaseHandle handle = service.GetSingleton(typeid(NetworkService));
+    if(handle)
+    {
+      // If so, downcast the handle
+      networkService = NetworkServicePtr(dynamic_cast<NetworkService*>(handle.GetObjectPtr()));
+    }
+    else
+    {
+      // Create a singleon instance
+      networkService = NetworkServicePtr(new NetworkService());
+      service.Register(typeid(NetworkService), BaseHandle(networkService.Get()));
+    }
+  }
+
+  return networkService;
+}
+
+void NetworkService::EmitCustomCommandReceivedSignal(const std::string& message)
+{
+  if(!mCustomCommandReceivedSignal.Empty())
+  {
+    mCustomCommandReceivedSignal.Emit(message);
+  }
+}
+
+} // namespace Dali::Internal::Adaptor
diff --git a/dali/internal/network/common/network-service-impl.h b/dali/internal/network/common/network-service-impl.h
new file mode 100644 (file)
index 0000000..3b4b796
--- /dev/null
@@ -0,0 +1,81 @@
+#ifndef DALI_INTERNAL_NETWORK_SERVICE_H
+#define DALI_INTERNAL_NETWORK_SERVICE_H
+
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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/common/intrusive-ptr.h>
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/application-devel.h>
+
+namespace Dali
+{
+namespace Internal::Adaptor
+{
+
+class NetworkService;
+using NetworkServicePtr = IntrusivePtr<NetworkService>;
+
+/**
+ * Provides methods to interface with the network services offered by DALi.
+ *
+ * This is only available when the adaptor is built with with -DENABLE_NETWORK_LOGGING=ON
+ * and when running, DALI_NETWORK_CONTROL=1 must also be set.
+ */
+class NetworkService : public Dali::BaseObject
+{
+public:
+  NetworkService()                      = default;      ///< Constructor
+  ~NetworkService() override            = default;      ///< Default Destructor
+  NetworkService(const NetworkService&) = delete;       ///< Deleted copy constructor
+  NetworkService(NetworkService&&)      = delete;       ///< Deleted move constructor
+  NetworkService& operator=(NetworkService&) = delete;  ///< Deleted copy assignment operator
+  NetworkService& operator=(NetworkService&&) = delete; ///< Deleted move assignment operator
+
+  /**
+   * @brief Retrieve the NetworkService Singleton.
+   * @return An intrusive pointer to the NetworkService
+   */
+  static NetworkServicePtr Get();
+
+  /**
+   * @brief This signal will be triggered when a custom command is received.
+   * @return The signal when a custom command is received
+   */
+  DevelApplication::CustomCommandReceivedSignalType& CustomCommandReceivedSignal()
+  {
+    return mCustomCommandReceivedSignal;
+  }
+
+  /**
+   * @brief Emit the Custom Command Received Signal
+   */
+  void EmitCustomCommandReceivedSignal(const std::string& message);
+
+private:
+  DevelApplication::CustomCommandReceivedSignalType mCustomCommandReceivedSignal;
+
+}; // class NetworkService
+
+} // namespace Internal::Adaptor
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_NETWORK_SERVICE_H
index 0beeaaf..aaa421c 100644 (file)
@@ -1,7 +1,8 @@
 
 # module: network, backend: common
 SET( adaptor_network_common_src_files 
-    ${adaptor_network_dir}/common/socket-factory.cpp 
+    ${adaptor_network_dir}/common/network-service-impl.cpp
+    ${adaptor_network_dir}/common/socket-factory.cpp
     ${adaptor_network_dir}/common/socket-impl.cpp
 )
 
index 1f94e51..8f769af 100644 (file)
@@ -104,11 +104,14 @@ void TriggerEvent::Triggered(FileDescriptorMonitor::EventType eventBitMask, int
     DALI_LOG_WARNING("Unable to read to UpdateEvent File descriptor\n");
   }
 
+  // Save value to prevent duplicate deletion
+  TriggerEventInterface::Options options = mOptions;
+
   // Call the connected callback
   CallbackBase::Execute(*mCallback);
 
   //check if we should delete ourselves after the trigger
-  if(mOptions == TriggerEventInterface::DELETE_AFTER_TRIGGER)
+  if(options == TriggerEventInterface::DELETE_AFTER_TRIGGER)
   {
     delete this;
   }
index 99b8995..7353f9b 100644 (file)
@@ -40,6 +40,31 @@ public:
    * Set content information to widget framework
    */
   virtual void SetContentInfo(const std::string& contentInfo) = 0;
+
+  /**
+   * Check Widget is using key
+   */
+  virtual bool IsKeyEventUsing() const = 0;
+
+  /**
+   * Set the flag that widget is using keyEvent
+   */
+  virtual void SetUsingKeyEvent(bool flag) = 0;
+
+  /**
+   * Set the Information of widget
+   */
+  virtual void SetInformation(Dali::Window window, const std::string& widgetId) = 0;
+
+  /**
+   * Get the window
+   */
+  virtual Dali::Window GetWindow() const = 0;
+
+  /**
+   * Get the widget id
+   */
+  virtual std::string GetWidgetId() const = 0;
 };
 
 } // namespace Adaptor
index 227284a..2faa238 100644 (file)
@@ -24,6 +24,7 @@
 #include <dali/internal/system/tizen-wayland/widget-controller-tizen.h>
 #include <dali/public-api/adaptor-framework/widget-impl.h>
 #include <dali/public-api/adaptor-framework/widget.h>
+#include <dali/devel-api/events/key-event-devel.h>
 
 // EXTERNAL INCLUDES
 #include <bundle.h>
@@ -35,6 +36,45 @@ namespace Internal
 {
 namespace
 {
+/**
+ * This Api is called when widget viewer send keyEvent.
+ * In this API, widget framework create a new keyEvent, find the proper widget and send this event.
+ * Finally widget framework receive feedback from widget.
+ */
+#ifdef OVER_TIZEN_VERSION_7
+bool OnKeyEventCallback(const char *id, screen_connector_event_type_e eventType, int keyCode, const char *keyName, long long cls, long long subcls, const char* identifier, long long timestamp, void *userData)
+{
+  Dali::Internal::Adaptor::WidgetApplicationTizen* application = static_cast<Dali::Internal::Adaptor::WidgetApplicationTizen*>(userData);
+
+  // Create new key for widget
+  Dali::KeyEvent::State state = Dali::KeyEvent::DOWN;
+  if(eventType == SCREEN_CONNECTOR_EVENT_TYPE_KEY_DOWN)
+  {
+    state = Dali::KeyEvent::DOWN;
+  }
+  else if(eventType == SCREEN_CONNECTOR_EVENT_TYPE_KEY_UP)
+  {
+    state = Dali::KeyEvent::UP;
+  }
+
+  bool consumed = true;
+  std::string keyEventName = std::string(keyName);
+  Dali::KeyEvent event = Dali::DevelKeyEvent::New(keyEventName, "", "", keyCode, 0, timestamp, state, "", "", Device::Class::NONE, Device::Subclass::NONE);
+
+  if(application)
+  {
+    std::string widgetId = std::string(id);
+    widget_base_instance_h instanceHandle = application->GetWidgetInstanceFromWidgetId(widgetId);
+    if(instanceHandle)
+    {
+      consumed = application->FeedKeyEvent(instanceHandle, event);
+    }
+  }
+
+  return consumed;
+}
+#endif
+
 int OnInstanceInit(widget_base_instance_h instanceHandle, bundle* content, int w, int h, void* classData)
 {
   char* id;
@@ -79,11 +119,12 @@ int OnInstanceInit(widget_base_instance_h instanceHandle, bundle* content, int w
   Dali::WidgetApplication::CreateWidgetFunction                        createFunction = pair.second;
 
   Dali::Widget widgetInstance = createFunction(pair.first);
-  application->AddWidget(instanceHandle, widgetInstance, window);
 
   Dali::Internal::Adaptor::Widget::Impl* widgetImpl = new Dali::Internal::Adaptor::WidgetImplTizen(instanceHandle);
   Internal::Adaptor::GetImplementation(widgetInstance).SetImpl(widgetImpl);
 
+  application->AddWidget(instanceHandle, widgetInstance, window, std::string(id));
+
   std::string encodedContentString = "";
 
   if(bundle_get_count(content))
@@ -98,6 +139,11 @@ int OnInstanceInit(widget_base_instance_h instanceHandle, bundle* content, int w
 
   Internal::Adaptor::GetImplementation(widgetInstance).OnCreate(encodedContentString, window);
 
+  // connect keyEvent for widget
+#ifdef OVER_TIZEN_VERSION_7
+  application->ConnectKeyEvent(window);
+#endif
+
   return 0;
 }
 
@@ -172,7 +218,7 @@ int OnInstanceResize(widget_base_instance_h instanceHandle, int w, int h, void*
 
   // Get Dali::Widget instance.
   Dali::Widget widgetInstance = application->GetWidget(instanceHandle);
-  Dali::Window window         = application->GetWindowFromWidget(instanceHandle);
+  Dali::Window window         = application->GetWindowFromWidget(widgetInstance);
   window.SetSize(Dali::Window::WindowSize(w, h));
   Internal::Adaptor::GetImplementation(widgetInstance).OnResize(window);
 
@@ -225,7 +271,9 @@ WidgetApplicationPtr WidgetApplicationTizen::New(
 }
 
 WidgetApplicationTizen::WidgetApplicationTizen(int* argc, char** argv[], const std::string& stylesheet)
-: WidgetApplication(argc, argv, stylesheet)
+: WidgetApplication(argc, argv, stylesheet),
+  mConnectedKeyEvent(false),
+  mReceivedKeyEvent(false)
 {
 }
 
@@ -269,10 +317,10 @@ WidgetApplicationTizen::CreateWidgetFunctionPair WidgetApplicationTizen::GetWidg
   return CreateWidgetFunctionPair("", NULL);
 }
 
-void WidgetApplicationTizen::AddWidget(widget_base_instance_h widgetBaseInstance, Dali::Widget widget, Dali::Window window)
+void WidgetApplicationTizen::AddWidget(widget_base_instance_h widgetBaseInstance, Dali::Widget widget, Dali::Window window, const std::string& widgetId)
 {
   mWidgetInstanceContainer.push_back(WidgetInstancePair(widgetBaseInstance, widget));
-  mWindowInstanceContainer.push_back(WindowInstancePair(widgetBaseInstance, window));
+  Internal::Adaptor::GetImplementation(widget).SetInformation(window, widgetId);
 }
 
 Dali::Widget WidgetApplicationTizen::GetWidget(widget_base_instance_h widgetBaseInstance) const
@@ -298,29 +346,29 @@ void WidgetApplicationTizen::DeleteWidget(widget_base_instance_h widgetBaseInsta
   {
     mWidgetInstanceContainer.erase(widgetInstance);
   }
+}
 
-  // Delete WindowInstance
-  auto windowInstance = std::find_if(mWindowInstanceContainer.begin(),
-                                     mWindowInstanceContainer.end(),
-                                     [widgetBaseInstance](WindowInstancePair pair) { return (pair.first == widgetBaseInstance); });
-
-  if(windowInstance != mWindowInstanceContainer.end())
+Dali::Window WidgetApplicationTizen::GetWindowFromWidget(Dali::Widget widgetInstance) const
+{
+  if(widgetInstance)
   {
-    mWindowInstanceContainer.erase(windowInstance);
+    return Internal::Adaptor::GetImplementation(widgetInstance).GetWindow();
   }
+
+  return Dali::Window();
 }
 
-Dali::Window WidgetApplicationTizen::GetWindowFromWidget(widget_base_instance_h widgetBaseInstance) const
+widget_base_instance_h WidgetApplicationTizen::GetWidgetInstanceFromWidgetId(std::string& widgetId) const
 {
-  for(auto&& iter : mWindowInstanceContainer)
+  for(auto&& iter : mWidgetInstanceContainer)
   {
-    if((iter).first == widgetBaseInstance)
+    if(widgetId == Internal::Adaptor::GetImplementation((iter).second).GetWidgetId())
     {
-      Dali::Window ret = (iter).second;
-      return ret;
+      return (iter).first;
     }
   }
-  return Dali::Window();
+
+  return nullptr;
 }
 
 int WidgetApplicationTizen::GetWidgetCount()
@@ -328,6 +376,51 @@ int WidgetApplicationTizen::GetWidgetCount()
   return mWidgetInstanceContainer.size();
 }
 
+void WidgetApplicationTizen::ConnectKeyEvent(Dali::Window window)
+{
+  if(!mConnectedKeyEvent)
+  {
+#ifdef OVER_TIZEN_VERSION_7
+    screen_connector_provider_set_key_event_cb(OnKeyEventCallback, this);
+#endif
+    mConnectedKeyEvent = true;
+  }
+  window.KeyEventSignal().Connect(this, &WidgetApplicationTizen::OnWindowKeyEvent);
+}
+
+void WidgetApplicationTizen::OnWindowKeyEvent(const Dali::KeyEvent& event)
+{
+  //If Widget Application consume key event, this api is not called.
+  mReceivedKeyEvent = true;
+}
+
+bool WidgetApplicationTizen::FeedKeyEvent(widget_base_instance_h instanceHandle, const Dali::KeyEvent& keyEvent)
+{
+  bool consumed = true;
+
+  // Check if application consume key event
+  Dali::Widget widgetInstance = GetWidget(instanceHandle);
+  if(widgetInstance)
+  {
+    Dali::Window window = GetWindowFromWidget(widgetInstance);
+
+    // Reset the state of key received
+    mReceivedKeyEvent = false;
+
+    // Feed the keyEvent to widget window
+    DevelWindow::FeedKeyEvent(window, keyEvent);
+
+    // if the application is not using a key event, verify that the window in the widget has received a key event.
+    if(Internal::Adaptor::GetImplementation(widgetInstance).IsKeyEventUsing() == false)
+    {
+      // if the window has received a key event, widget need to consume its key event
+      consumed = (mReceivedKeyEvent) ? false : true;
+    }
+  }
+
+  return consumed;
+}
+
 void WidgetApplicationTizen::OnInit()
 {
   WidgetApplication::OnInit();
index f2462bd..80166bd 100644 (file)
@@ -20,6 +20,7 @@
 
 // EXTERNAL INCLUDES
 #include <widget_base.h>
+#include <screen_connector_provider.h>
 
 // INTERNAL INCLUDES
 #include <dali/devel-api/adaptor-framework/window-devel.h>
@@ -40,7 +41,7 @@ typedef IntrusivePtr<WidgetApplication> WidgetApplicationPtr;
 /**
  * Implementation of the WidgetApplication class.
  */
-class WidgetApplicationTizen : public WidgetApplication
+class WidgetApplicationTizen : public WidgetApplication, public ConnectionTracker
 {
 public:
   typedef std::pair<const std::string, Dali::WidgetApplication::CreateWidgetFunction> CreateWidgetFunctionPair;
@@ -78,7 +79,7 @@ public:
   /**
    * Add widget_base_instance_h - Widget instance pair to container.
    */
-  void AddWidget(widget_base_instance_h widgetBaseInstance, Dali::Widget widget, Dali::Window window);
+  void AddWidget(widget_base_instance_h widgetBaseInstance, Dali::Widget widget, Dali::Window window, const std::string& widgetId);
 
   /**
    * Find and get Widget instance in container by widget_base_instance_h.
@@ -93,13 +94,42 @@ public:
   /**
    * Find and get Window instance in container by widget_base_instance_h.
    */
-  Dali::Window GetWindowFromWidget(widget_base_instance_h widgetBaseInstance) const;
+  Dali::Window GetWindowFromWidget(Dali::Widget widget) const;
 
   /**
+   * Find and get widget_base_instance in container by widget id.
+   */
+  widget_base_instance_h GetWidgetInstanceFromWidgetId(std::string& widgetId) const;
+  /**
    * Get the number of created widget.
    */
   int32_t GetWidgetCount();
 
+  /**
+   * @brief connect the keyEvent for window
+   *
+   * @param[in] window window for connecting keyEvent
+   */
+  void ConnectKeyEvent(Dali::Window window);
+
+  /**
+   * @brief Callback for widget window
+   *
+   * If Widget Application consume key event, this api is not called.
+   *
+   * @param[in] event The key event.
+   */
+  void OnWindowKeyEvent(const Dali::KeyEvent& event);
+
+  /**
+   * @brief Feed keyEvent to Widget.
+   *
+   * @param[in] instanceHandle the handle of widget instance
+   * @param[in] keyEvent The key event for widget
+   * @return True if widget consume keyEvent, false otherwise.
+   */
+  bool FeedKeyEvent(widget_base_instance_h instanceHandle, const Dali::KeyEvent& keyEvent);
+
 protected:
   /**
    * Private Constructor
@@ -124,9 +154,8 @@ private:
   CreateWidgetFunctionContainer mCreateWidgetFunctionContainer;
   WidgetInstanceContainer       mWidgetInstanceContainer;
 
-  typedef std::pair<widget_base_instance_h, Dali::Window> WindowInstancePair;
-  typedef std::vector<WindowInstancePair>                 WindowInstanceContainer;
-  WindowInstanceContainer                                 mWindowInstanceContainer;
+  bool mConnectedKeyEvent; // Check if keyEvent is connected
+  bool mReceivedKeyEvent;  // Check if application receive keyEvent
 };
 
 } // namespace Adaptor
index d4c4498..efe9f16 100644 (file)
@@ -30,7 +30,10 @@ namespace Adaptor
 {
 WidgetImplTizen::WidgetImplTizen(widget_base_instance_h instanceHandle)
 : Widget::Impl(),
-  mInstanceHandle(instanceHandle)
+  mInstanceHandle(instanceHandle),
+  mWindow(),
+  mWidgetId(),
+  mUsingKeyEvent(false)
 {
 }
 
@@ -50,6 +53,32 @@ void WidgetImplTizen::SetContentInfo(const std::string& contentInfo)
   bundle_free(contentBundle);
 }
 
+bool WidgetImplTizen::IsKeyEventUsing() const
+{
+  return mUsingKeyEvent;
+}
+
+void WidgetImplTizen::SetUsingKeyEvent(bool flag)
+{
+  mUsingKeyEvent = flag;
+}
+
+void WidgetImplTizen::SetInformation(Dali::Window window, const std::string& widgetId)
+{
+  mWindow = window;
+  mWidgetId = widgetId;
+}
+
+Dali::Window WidgetImplTizen::GetWindow() const
+{
+  return mWindow;
+}
+
+std::string WidgetImplTizen::GetWidgetId() const
+{
+  return mWidgetId;
+}
+
 } // namespace Adaptor
 
 } // namespace Internal
index de6ae1d..5877f42 100644 (file)
@@ -54,8 +54,36 @@ public:
    */
   void SetContentInfo(const std::string& contentInfo) override;
 
+  /**
+   * Check Widget is using key
+   */
+  bool IsKeyEventUsing() const override;
+
+  /**
+   * Set the flag that widget is using keyEvent
+   */
+  void SetUsingKeyEvent(bool flag) override;
+
+  /**
+   * Set the Information of widget
+   */
+  void SetInformation(Dali::Window window, const std::string& widgetId) override;
+
+  /**
+   * Get the window
+   */
+  Dali::Window GetWindow() const override;
+
+  /**
+   * Get the widget id
+   */
+  std::string GetWidgetId() const override;
+
 private:
   widget_base_instance_h mInstanceHandle;
+  Dali::Window           mWindow;
+  std::string            mWidgetId;
+  bool                   mUsingKeyEvent;
 };
 
 } // namespace Adaptor
index dc40cdd..2596642 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -36,6 +36,29 @@ void WidgetImplUbuntu::SetContentInfo(const std::string& contentInfo)
 {
 }
 
+bool WidgetImplUbuntu::IsKeyEventUsing() const
+{
+  return false;
+}
+
+void WidgetImplUbuntu::SetUsingKeyEvent(bool flag)
+{
+}
+
+void WidgetImplUbuntu::SetInformation(Dali::Window window, const std::string& widgetId)
+{
+}
+
+Dali::Window WidgetImplUbuntu::GetWindow() const
+{
+  return Dali::Window();
+}
+
+std::string WidgetImplUbuntu::GetWidgetId() const
+{
+  return std::string();
+}
+
 } // namespace Adaptor
 
 } // namespace Internal
index 685e52a..798e066 100644 (file)
@@ -51,6 +51,31 @@ public:
    * Set content information to widget framework
    */
   void SetContentInfo(const std::string& contentInfo) override;
+
+  /**
+   * Check Widget is using key
+   */
+  bool IsKeyEventUsing() const override;
+
+  /**
+   * Set the flag that widget is using keyEvent
+   */
+  void SetUsingKeyEvent(bool flag) override;
+
+  /**
+   * Set the Information of widget
+   */
+  void SetInformation(Dali::Window window, const std::string& widgetId) override;
+
+  /**
+   * Get the window
+   */
+  Dali::Window GetWindow() const override;
+
+  /**
+   * Get the widget id
+   */
+  std::string GetWidgetId() const override;
 };
 
 } // namespace Adaptor
index 7dd6686..5c8022e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -36,6 +36,29 @@ void WidgetImplWin::SetContentInfo(const std::string& contentInfo)
 {
 }
 
+bool WidgetImplWin::IsKeyEventUsing() const
+{
+  return false;
+}
+
+void WidgetImplWin::SetUsingKeyEvent(bool flag)
+{
+}
+
+void WidgetImplWin::SetInformation(Dali::Window window, const std::string& widgetId)
+{
+}
+
+Dali::Window WidgetImplWin::GetWindow() const
+{
+  return Dali::Window();
+}
+
+std::string WidgetImplWin::GetWidgetId() const
+{
+  return std::string();
+}
+
 } // namespace Adaptor
 
 } // namespace Internal
index 63fe4e4..de1e896 100644 (file)
@@ -51,6 +51,31 @@ public:
    * Set content information to widget framework
    */
   void SetContentInfo(const std::string& contentInfo) override;
+
+  /**
+   * Check Widget is using key
+   */
+  bool IsKeyEventUsing() const override;
+
+  /**
+   * Set the flag that widget is using keyEvent
+   */
+  void SetUsingKeyEvent(bool flag) override;
+
+  /**
+   * Set the Information of widget
+   */
+  void SetInformation(Dali::Window window, const std::string& widgetId) override;
+
+  /**
+   * Get the window
+   */
+  Dali::Window GetWindow() const override;
+
+  /**
+   * Get the widget id
+   */
+  std::string GetWidgetId() const override;
 };
 
 } // namespace Adaptor
index 7f00ae6..867fb26 100644 (file)
@@ -13,4 +13,6 @@ SET( adaptor_text_common_src_files
     ${adaptor_text_dir}/text-abstraction/plugin/font-client-utils.cpp
     ${adaptor_text_dir}/text-abstraction/plugin/font-client-plugin-impl.cpp
     ${adaptor_text_dir}/text-abstraction/plugin/font-face-cache-item.cpp
+    ${adaptor_text_dir}/text-abstraction/plugin/font-face-glyph-cache-manager.cpp
+    ${adaptor_text_dir}/text-abstraction/plugin/harfbuzz-proxy-font.cpp
 )
index 0735798..d58c3f1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -854,7 +854,6 @@ Devel::PixelBuffer RenderTextCairo(const TextAbstraction::TextRenderer::Paramete
 
           // Retrieve the image
           TextAbstraction::FontClient::GlyphBufferData data;
-          std::unique_ptr<GlyphBuffer>                 glyphBufferPtr(new GlyphBuffer(data, GlyphBuffer::DELETE));
           if(isEmoji)
           {
             data.width  = parameters.glyphs[run.glyphIndex].width;
@@ -893,9 +892,28 @@ Devel::PixelBuffer RenderTextCairo(const TextAbstraction::TextRenderer::Paramete
             unsigned int       heightOut = data.height;
             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)
+            {
+              uint8_t* newBuffer = (uint8_t*)malloc(widthOut * heightOut * pixelSize);
+              if(DALI_LIKELY(newBuffer != nullptr))
+              {
+                TextAbstraction::FontClient::GlyphBufferData::Decompress(data, newBuffer);
+                if(data.isBufferOwned)
+                {
+                  // Release previous buffer
+                  free(data.buffer);
+                }
+                data.isBufferOwned   = true;
+                data.buffer          = newBuffer;
+                data.compressionType = TextAbstraction::FontClient::GlyphBufferData::CompressionType::NO_COMPRESSION;
+              }
+            }
+
             Dali::Internal::Platform::RotateByShear(data.buffer,
                                                     data.width,
                                                     data.height,
+                                                    data.width,
                                                     pixelSize,
                                                     radians,
                                                     pixelsOut,
@@ -903,11 +921,15 @@ Devel::PixelBuffer RenderTextCairo(const TextAbstraction::TextRenderer::Paramete
                                                     heightOut);
             if(nullptr != pixelsOut)
             {
-              delete[] data.buffer;
-              data.buffer                = pixelsOut;
-              glyphBufferPtr.get()->type = GlyphBuffer::FREE;
-              data.width                 = widthOut;
-              data.height                = heightOut;
+              if(data.isBufferOwned)
+              {
+                free(data.buffer);
+              }
+              data.isBufferOwned   = true;
+              data.compressionType = Dali::TextAbstraction::FontClient::GlyphBufferData::CompressionType::NO_COMPRESSION;
+              data.buffer          = pixelsOut;
+              data.width           = widthOut;
+              data.height          = heightOut;
             }
 
             glyphX = centerX - 0.5 * static_cast<double>(data.width);
index 2b5c40a..0656765 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -419,6 +419,13 @@ bool FontClient::AddCustomFontDirectory(const FontPath& path)
   return mPlugin->AddCustomFontDirectory(path);
 }
 
+HarfBuzzFontHandle FontClient::GetHarfBuzzFont(FontId fontId)
+{
+  CreatePlugin();
+
+  return mPlugin->GetHarfBuzzFont(fontId);
+}
+
 void FontClient::CreatePlugin()
 {
   if(!mPlugin)
index ffa070a..7b158ef 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_TEXT_ABSTRACTION_FONT_CLIENT_IMPL_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -32,6 +32,8 @@ namespace TextAbstraction
 {
 namespace Internal
 {
+using HarfBuzzFontHandle = void*; ///< @note We don't want to make other class include harfbuzz header. So we will keep harfbuzz font data as HarfBuzzFontHandle.
+
 /**
  * Implementation of the FontClient
  */
@@ -48,6 +50,7 @@ public:
    */
   ~FontClient();
 
+public: // API for Dali::TextAbstraction::FontClient used.
   /**
    * @copydoc Dali::TextAbstraction::FontClient::Get()
    */
@@ -259,6 +262,12 @@ public:
   uint32_t GetNumberOfPointsPerOneUnitOfPointSize() const;
 
   /**
+   * @copydoc Dali::TextAbstraction::FontClient::AddCustomFontDirectory()
+   */
+  bool AddCustomFontDirectory(const FontPath& path);
+
+public: // API for Dali::TextAbstraction::Internal::FontClient used.
+  /**
    * @brief Retrieves the pointer to the FreeType Font Face for the given @p fontId.
    *
    * @param[in] fontId The font id.
@@ -277,9 +286,12 @@ public:
   FontDescription::Type GetFontType(FontId fontId);
 
   /**
-   * @copydoc Dali::TextAbstraction::FontClient::AddCustomFontDirectory()
+   * @brief Get the harfbuzz font data of font.
+   *
+   * @param fontId The font id.
+   * @return The harfbuzz font data, or nullptr if failed.
    */
-  bool AddCustomFontDirectory(const FontPath& path);
+  HarfBuzzFontHandle GetHarfBuzzFont(FontId fontId);
 
 private:
   /**
index e7b5d43..972f323 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -67,14 +67,14 @@ void BitmapFontCacheItem::GetFontMetrics(FontMetrics& metrics, unsigned int dpiV
   metrics.underlineThickness = font.underlineThickness;
 }
 
-bool BitmapFontCacheItem::GetGlyphMetrics(GlyphInfo& glyph, unsigned int dpiVertical, bool horizontal) const
+bool BitmapFontCacheItem::GetGlyphMetrics(GlyphInfo& glyphInfo, unsigned int dpiVertical, bool horizontal) const
 {
   bool success(false);
 
   unsigned int index = 0u;
   for(auto& item : font.glyphs)
   {
-    if(item.utf32 == glyph.index)
+    if(item.utf32 == glyphInfo.index)
     {
       Devel::PixelBuffer& pixelBuffer = const_cast<Devel::PixelBuffer&>(pixelBuffers[index]);
       if(!pixelBuffer)
@@ -82,13 +82,13 @@ bool BitmapFontCacheItem::GetGlyphMetrics(GlyphInfo& glyph, unsigned int dpiVert
         pixelBuffer = LoadImageFromFile(item.url);
       }
 
-      glyph.width       = static_cast<float>(pixelBuffer.GetWidth());
-      glyph.height      = static_cast<float>(pixelBuffer.GetHeight());
-      glyph.xBearing    = 0.f;
-      glyph.yBearing    = glyph.height + item.descender;
-      glyph.advance     = glyph.width;
-      glyph.scaleFactor = 1.f;
-      success           = true;
+      glyphInfo.width       = static_cast<float>(pixelBuffer.GetWidth());
+      glyphInfo.height      = static_cast<float>(pixelBuffer.GetHeight());
+      glyphInfo.xBearing    = 0.f;
+      glyphInfo.yBearing    = glyphInfo.height + item.descender;
+      glyphInfo.advance     = glyphInfo.width;
+      glyphInfo.scaleFactor = 1.f;
+      success               = true;
       break;
     }
     ++index;
@@ -115,10 +115,7 @@ void BitmapFontCacheItem::CreateBitmap(
 
       data.isColorBitmap = font.isColorFont;
 
-      ConvertBitmap(data, data.width, data.height, pixelBuffer.GetBuffer());
-
-      // Sets the pixel format.
-      data.format = pixelBuffer.GetPixelFormat();
+      ConvertBitmap(data, data.width, data.height, pixelBuffer.GetBuffer(), pixelBuffer.GetPixelFormat());
       break;
     }
     ++index;
index 501f56e..1799eb2 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_TEXT_ABSTRACTION_BITMAP_FONT_CACHE_ITEM_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -42,6 +42,11 @@ struct BitmapFontCacheItem : public FontCacheItemInterface
   BitmapFontCacheItem(const BitmapFont& bitmapFont, FontId fontId);
 
   /**
+   * Destructor
+   */
+  ~BitmapFontCacheItem() = default;
+
+  /**
    * @copydoc FontCacheItemInterface::GetFontMetrics()
    */
   void GetFontMetrics(FontMetrics& metrics, unsigned int dpiVertical) const override;
@@ -49,7 +54,7 @@ struct BitmapFontCacheItem : public FontCacheItemInterface
   /**
    * @copydoc FontCacheItemInterface::GetGlyphMetrics()
    */
-  bool GetGlyphMetrics(GlyphInfo& glyph, unsigned int dpiVertical, bool horizontal) const override;
+  bool GetGlyphMetrics(GlyphInfo& glyphInfo, unsigned int dpiVertical, bool horizontal) const override;
 
   /**
    * @copydoc FontCacheItemInterface::CreateBitmap()
@@ -102,6 +107,14 @@ struct BitmapFontCacheItem : public FontCacheItemInterface
   }
 
   /**
+   * @copydoc FontCacheItemInterface::GetHarfBuzzFont()
+   */
+  HarfBuzzFontHandle GetHarfBuzzFont(const uint32_t& horizontalDpi, const uint32_t& verticalDpi) override
+  {
+    return nullptr;
+  }
+
+  /**
    * @copydoc FontCacheItemInterface::HasItalicStyle()
    */
   bool HasItalicStyle() const override
index cdec41f..c2486c1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -40,17 +40,17 @@ void EmbeddedItem::CreateBitmap(const std::vector<PixelBufferCacheItem>&
     Devel::PixelBuffer pixelBuffer = pixelBufferCache[pixelBufferId - 1u].pixelBuffer;
     if(pixelBuffer)
     {
-      ConvertBitmap(data, pixelBuffer.GetWidth(), pixelBuffer.GetHeight(), pixelBuffer.GetBuffer());
-
-      // Sets the pixel format.
-      data.format = pixelBuffer.GetPixelFormat();
+      ConvertBitmap(data, pixelBuffer.GetWidth(), pixelBuffer.GetHeight(), pixelBuffer.GetBuffer(), pixelBuffer.GetPixelFormat());
     }
   }
   else
   {
+    data.isBufferOwned   = true;
+    data.compressionType = Dali::TextAbstraction::FontClient::GlyphBufferData::CompressionType::NO_COMPRESSION;
+
     // Creates the output buffer
-    const unsigned int bufferSize = data.width * data.height * 4u;
-    data.buffer                   = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
+    const uint32_t bufferSize = data.width * data.height * 4u;
+    data.buffer               = (uint8_t*)malloc(bufferSize); // @note The caller is responsible for deallocating the bitmap data using free.
 
     memset(data.buffer, 0u, bufferSize);
 
index 09addd2..c5cce86 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TEST_ABSTRACTION_INTERNAL_FONT_CACHE_ITEM_INTERFACE_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * limitations under the License.
  */
 
+// INTERNAL INCLUDES
 #include <dali/devel-api/text-abstraction/font-client.h>
 #include <dali/devel-api/text-abstraction/font-metrics.h>
 #include <dali/devel-api/text-abstraction/glyph-info.h>
+#include <dali/internal/text/text-abstraction/font-client-impl.h> // for HarfBuzzFontHandle
 
+// EXTERNAL INCLUDES
 #include <ft2build.h>
 #include FT_FREETYPE_H
 
@@ -40,7 +43,7 @@ struct FontCacheItemInterface
    *
    * @param[in,out] glyph The glyph to fill
    */
-  virtual bool GetGlyphMetrics(GlyphInfo& glyph, unsigned int dpiVertical, bool horizontal) const = 0;
+  virtual bool GetGlyphMetrics(GlyphInfo& glyphInfo, unsigned int dpiVertical, bool horizontal) const = 0;
 
   /**
    * Create a bitmap for the given glyph
@@ -96,6 +99,15 @@ struct FontCacheItemInterface
   virtual FT_Face GetTypeface() const = 0;
 
   /**
+   * Get the harfbuzz font struct for this font.
+   *
+   * @param[in] horizontalDpi Horizontal DPI for this harfbuzz font.
+   * @param[in] verticalDpi Vertical DPI for this harfbuzz font.
+   * @return the harfbuzz font data, or nullptr if failed.
+   */
+  virtual HarfBuzzFontHandle GetHarfBuzzFont(const uint32_t& horizontalDpi, const uint32_t& verticalDpi) = 0;
+
+  /**
    * @return true if this font has an italic style
    */
   virtual bool HasItalicStyle() const = 0;
index 5668718..4ac6bd0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -248,12 +248,10 @@ FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem(FontDescr
 {
 }
 
-FontClient::Plugin::FontDescriptionSizeCacheItem::FontDescriptionSizeCacheItem(FontDescriptionId validatedFontId,
-                                                                               PointSize26Dot6   requestedPointSize,
-                                                                               FontId            fontId)
-: validatedFontId(validatedFontId),
-  requestedPointSize(requestedPointSize),
-  fontId(fontId)
+FontClient::Plugin::FontDescriptionSizeCacheKey::FontDescriptionSizeCacheKey(FontDescriptionId fontDescriptionId,
+                                                                             PointSize26Dot6   requestedPointSize)
+: fontDescriptionId(fontDescriptionId),
+  requestedPointSize(requestedPointSize)
 {
 }
 
@@ -274,6 +272,10 @@ FontClient::Plugin::Plugin(unsigned int horizontalDpi,
   mVectorFontCache(nullptr),
   mEllipsisCache(),
   mEmbeddedItemCache(),
+  mLatestFoundFontDescription(),
+  mLatestFoundFontDescriptionId(0u),
+  mLatestFoundCacheKey(0, 0),
+  mLatestFoundCacheIndex(0u),
   mDefaultFontDescriptionCached(false),
   mIsAtlasLimitationEnabled(TextAbstraction::FontClient::DEFAULT_ATLAS_LIMITATION_ENABLED),
   mCurrentMaximumBlockSizeFitInAtlas(TextAbstraction::FontClient::MAX_SIZE_FIT_IN_ATLAS)
@@ -299,6 +301,9 @@ FontClient::Plugin::~Plugin()
   DestroyCharacterSets(mCharacterSetCache);
   ClearCharacterSetFromFontFaceCache();
 
+  // Clear FontFaceCache here. Due to we sould deallocate FT_Faces before done freetype library
+  mFontFaceCache.clear();
+
 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
   delete mVectorFontCache;
 #endif
@@ -330,12 +335,16 @@ void FontClient::Plugin::ClearCache()
   mCharacterSetCache.Clear();
 
   mFontDescriptionSizeCache.clear();
+  mFontDescriptionSizeCache.rehash(0); // Note : unordered_map.clear() didn't deallocate memory
 
   mEllipsisCache.Clear();
   mPixelBufferCache.clear();
   mEmbeddedItemCache.Clear();
   mBitmapFontCache.clear();
 
+  mLatestFoundFontDescription.family.clear();
+  mLatestFoundCacheKey = FontDescriptionSizeCacheKey(0, 0);
+
   mDefaultFontDescriptionCached = false;
 }
 
@@ -478,8 +487,39 @@ void FontClient::Plugin::GetDefaultPlatformFontDescription(FontDescription& font
       FcDefaultSubstitute(matchPattern);
 
       FcCharSet* characterSet = nullptr;
-      MatchFontDescriptionToPattern(matchPattern, mDefaultFontDescription, &characterSet);
+      bool       matched      = MatchFontDescriptionToPattern(matchPattern, mDefaultFontDescription, &characterSet);
+
+      // Caching the default font description
+      if(matched)
+      {
+        // Copy default font description info.
+        // Due to the type changed, we need to make some temperal font description.
+        FontDescription tempFontDescription = mDefaultFontDescription;
+
+        // Add the path to the cache.
+        tempFontDescription.type = FontDescription::FACE_FONT;
+        mFontDescriptionCache.push_back(tempFontDescription);
+
+        // Set the index to the vector of paths to font file names.
+        const FontDescriptionId fontDescriptionId = mFontDescriptionCache.size();
+
+        FONT_LOG_DESCRIPTION(tempFontDescription, "default platform font");
+        DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  default font fontDescriptionId : %d\n", fontDescriptionId);
+
+        // Cache the index and the matched font's description.
+        FontDescriptionCacheItem item(tempFontDescription,
+                                      fontDescriptionId);
+
+        mValidatedFontCache.push_back(std::move(item));
+      }
+      else
+      {
+        DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  default font validation failed for font [%s]\n", mDefaultFontDescription.family.c_str());
+      }
+
       // Decrease the reference counter of the character set as it's not stored.
+      // Note. the cached default font description will increase reference counter by
+      // mFontDescriptionCache. So we can decrease reference counter here.
       FcCharSetDestroy(characterSet);
 
       // Destroys the pattern created.
@@ -555,9 +595,9 @@ void FontClient::Plugin::GetDescription(FontId           id,
       {
         for(const auto& item : mFontDescriptionSizeCache)
         {
-          if(item.fontId == fontIdCacheItem.id)
+          if(item.second == fontIdCacheItem.index)
           {
-            fontDescription = *(mFontDescriptionCache.begin() + item.validatedFontId - 1u);
+            fontDescription = *(mFontDescriptionCache.begin() + item.first.fontDescriptionId - 1u);
 
             FONT_LOG_DESCRIPTION(fontDescription, "");
             return;
@@ -568,7 +608,7 @@ void FontClient::Plugin::GetDescription(FontId           id,
       case FontDescription::BITMAP_FONT:
       {
         fontDescription.type   = FontDescription::BITMAP_FONT;
-        fontDescription.family = mBitmapFontCache[fontIdCacheItem.id].font.name;
+        fontDescription.family = mBitmapFontCache[fontIdCacheItem.index].font.name;
         break;
       }
       default:
@@ -618,7 +658,7 @@ bool FontClient::Plugin::IsCharacterSupportedByFont(FontId fontId, Character cha
 
 const FontCacheItemInterface* FontClient::Plugin::GetCachedFontItem(FontId id) const
 {
-  const FontId index = id - 1u;
+  const FontCacheIndex index = id - 1u;
   if((id > 0u) && (index < mFontIdCache.Count()))
   {
     const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
@@ -626,11 +666,11 @@ const FontCacheItemInterface* FontClient::Plugin::GetCachedFontItem(FontId id) c
     {
       case FontDescription::FACE_FONT:
       {
-        return &mFontFaceCache[fontIdCacheItem.id];
+        return &mFontFaceCache[fontIdCacheItem.index];
       }
       case FontDescription::BITMAP_FONT:
       {
-        return &mBitmapFontCache[fontIdCacheItem.id];
+        return &mBitmapFontCache[fontIdCacheItem.index];
       }
       default:
       {
@@ -684,7 +724,7 @@ FontId FontClient::Plugin::FindFontForCharacter(const FontList&         fontList
         if((fontId > 0) &&
            (fontId - 1u < mFontIdCache.Count()))
         {
-          const FontFaceCacheItem& item = mFontFaceCache[mFontIdCache[fontId - 1u].id];
+          const FontFaceCacheItem& item = mFontFaceCache[mFontIdCache[fontId - 1u].index];
 
           foundColor = item.mHasColorTables;
         }
@@ -832,6 +872,18 @@ FontId FontClient::Plugin::GetFontId(const FontDescription& fontDescription,
 {
   DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
   FONT_LOG_DESCRIPTION(fontDescription, "");
+
+  // Special case when font Description don't have family information.
+  // In this case, we just use default description family and path.
+  const FontDescription& realFontDescription = fontDescription.family.empty() ? FontDescription(mDefaultFontDescription.path,
+                                                                                                mDefaultFontDescription.family,
+                                                                                                fontDescription.width,
+                                                                                                fontDescription.weight,
+                                                                                                fontDescription.slant,
+                                                                                                fontDescription.type)
+                                                                              : fontDescription;
+
+  FONT_LOG_DESCRIPTION(realFontDescription, "");
   DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "   requestedPointSize : %d\n", requestedPointSize);
 
   // This method uses three vectors which caches:
@@ -856,28 +908,28 @@ FontId FontClient::Plugin::GetFontId(const FontDescription& fontDescription,
   FontId fontId = 0u;
 
   // Check first if the font description matches with a previously loaded bitmap font.
-  if(FindBitmapFont(fontDescription.family, fontId))
+  if(FindBitmapFont(realFontDescription.family, fontId))
   {
     return fontId;
   }
 
   // Check if the font's description have been validated before.
-  FontDescriptionId validatedFontId = 0u;
+  FontDescriptionId fontDescriptionId = 0u;
 
-  if(!FindValidatedFont(fontDescription,
-                        validatedFontId))
+  if(!FindValidatedFont(realFontDescription,
+                        fontDescriptionId))
   {
     // Use font config to validate the font's description.
-    ValidateFont(fontDescription,
-                 validatedFontId);
+    ValidateFont(realFontDescription,
+                 fontDescriptionId);
   }
 
-  FontId fontFaceId = 0u;
-  // Check if exists a pair 'validatedFontId, requestedPointSize' in the cache.
-  if(!FindFont(validatedFontId, requestedPointSize, fontFaceId))
+  FontCacheIndex fontCacheIndex = 0u;
+  // Check if exists a pair 'fontDescriptionId, requestedPointSize' in the cache.
+  if(!FindFont(fontDescriptionId, requestedPointSize, fontCacheIndex))
   {
     // Retrieve the font file name path.
-    const FontDescription& description = *(mFontDescriptionCache.begin() + validatedFontId - 1u);
+    const FontDescription& description = *(mFontDescriptionCache.begin() + fontDescriptionId - 1u);
 
     // Retrieve the font id. Do not cache the description as it has been already cached.
     fontId = GetFontId(description.path,
@@ -885,17 +937,15 @@ FontId FontClient::Plugin::GetFontId(const FontDescription& fontDescription,
                        faceIndex,
                        false);
 
-    fontFaceId                               = mFontIdCache[fontId - 1u].id;
-    mFontFaceCache[fontFaceId].mCharacterSet = FcCharSetCopy(mCharacterSetCache[validatedFontId - 1u]);
+    fontCacheIndex                               = mFontIdCache[fontId - 1u].index;
+    mFontFaceCache[fontCacheIndex].mCharacterSet = FcCharSetCopy(mCharacterSetCache[fontDescriptionId - 1u]);
 
-    // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
-    mFontDescriptionSizeCache.push_back(FontDescriptionSizeCacheItem(validatedFontId,
-                                                                     requestedPointSize,
-                                                                     fontFaceId));
+    // Cache the pair 'fontDescriptionId, requestedPointSize' to improve the following queries.
+    mFontDescriptionSizeCache.emplace(FontDescriptionSizeCacheKey(fontDescriptionId, requestedPointSize), fontCacheIndex);
   }
   else
   {
-    fontId = mFontFaceCache[fontFaceId].mFontId + 1u;
+    fontId = mFontFaceCache[fontCacheIndex].mFontId + 1u;
   }
 
   DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  font id : %d\n", fontId);
@@ -915,8 +965,8 @@ FontId FontClient::Plugin::GetFontId(const BitmapFont& bitmapFont)
   BitmapFontCacheItem bitmapFontCacheItem(bitmapFont, mFontIdCache.Count());
 
   FontIdCacheItem fontIdCacheItem;
-  fontIdCacheItem.type = FontDescription::BITMAP_FONT;
-  fontIdCacheItem.id   = mBitmapFontCache.size();
+  fontIdCacheItem.type  = FontDescription::BITMAP_FONT;
+  fontIdCacheItem.index = mBitmapFontCache.size();
 
   mBitmapFontCache.push_back(std::move(bitmapFontCacheItem));
   mFontIdCache.PushBack(fontIdCacheItem);
@@ -925,7 +975,7 @@ FontId FontClient::Plugin::GetFontId(const BitmapFont& bitmapFont)
 }
 
 void FontClient::Plugin::ValidateFont(const FontDescription& fontDescription,
-                                      FontDescriptionId&     validatedFontId)
+                                      FontDescriptionId&     fontDescriptionId)
 {
   DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
   FONT_LOG_DESCRIPTION(fontDescription, "");
@@ -946,17 +996,17 @@ void FontClient::Plugin::ValidateFont(const FontDescription& fontDescription,
     mFontDescriptionCache.push_back(description);
 
     // Set the index to the vector of paths to font file names.
-    validatedFontId = mFontDescriptionCache.size();
+    fontDescriptionId = mFontDescriptionCache.size();
 
     FONT_LOG_DESCRIPTION(description, "matched");
-    DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  validatedFontId : %d\n", validatedFontId);
+    DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  fontDescriptionId : %d\n", fontDescriptionId);
 
     // The reference counter of the character set has already been increased in MatchFontDescriptionToPattern.
     mCharacterSetCache.PushBack(characterSet);
 
     // Cache the index and the matched font's description.
     FontDescriptionCacheItem item(description,
-                                  validatedFontId);
+                                  fontDescriptionId);
 
     mValidatedFontCache.push_back(std::move(item));
 
@@ -967,7 +1017,7 @@ void FontClient::Plugin::ValidateFont(const FontDescription& fontDescription,
     {
       // Cache the given font's description if it's different than the matched.
       FontDescriptionCacheItem item(fontDescription,
-                                    validatedFontId);
+                                    fontDescriptionId);
 
       mValidatedFontCache.push_back(std::move(item));
     }
@@ -1066,7 +1116,7 @@ bool FontClient::Plugin::GetVectorMetrics(GlyphInfo* array,
     if((fontId > 0u) &&
        (fontId - 1u) < mFontIdCache.Count())
     {
-      FontFaceCacheItem& font = mFontFaceCache[mFontIdCache[fontId - 1u].id];
+      FontFaceCacheItem& font = mFontFaceCache[mFontIdCache[fontId - 1u].index];
 
       if(!font.mVectorFontId)
       {
@@ -1122,7 +1172,7 @@ PixelData FontClient::Plugin::CreateBitmap(FontId fontId, GlyphIndex glyphIndex,
                         data.width,
                         data.height,
                         data.format,
-                        PixelData::DELETE_ARRAY);
+                        PixelData::FREE);
 }
 
 void FontClient::Plugin::CreateVectorBlob(FontId fontId, GlyphIndex glyphIndex, VectorBlob*& blob, unsigned int& blobLength, unsigned int& nominalWidth, unsigned int& nominalHeight)
@@ -1134,8 +1184,8 @@ void FontClient::Plugin::CreateVectorBlob(FontId fontId, GlyphIndex glyphIndex,
   if((fontId > 0u) &&
      (fontId - 1u < mFontIdCache.Count()))
   {
-    const FontId       fontFaceId = mFontIdCache[fontId - 1u].id;
-    FontFaceCacheItem& font       = mFontFaceCache[fontFaceId];
+    const FontCacheIndex fontFaceId = mFontIdCache[fontId - 1u].index;
+    FontFaceCacheItem&   font       = mFontFaceCache[fontFaceId];
 
     if(!font.mVectorFontId)
     {
@@ -1176,7 +1226,7 @@ const GlyphInfo& FontClient::Plugin::GetEllipsisGlyph(PointSize26Dot6 requestedP
                                       false);
 
   // Set the character index to access the glyph inside the font.
-  item.glyph.index = FT_Get_Char_Index(mFontFaceCache[mFontIdCache[item.glyph.fontId - 1u].id].mFreeTypeFace,
+  item.glyph.index = FT_Get_Char_Index(mFontFaceCache[mFontIdCache[item.glyph.fontId - 1u].index].mFreeTypeFace,
                                        ELLIPSIS_CHARACTER);
 
   GetBitmapMetrics(&item.glyph, 1u, true);
@@ -1219,6 +1269,16 @@ bool FontClient::Plugin::AddCustomFontDirectory(const FontPath& path)
   return FcConfigAppFontAddDir(nullptr, reinterpret_cast<const FcChar8*>(path.c_str()));
 }
 
+HarfBuzzFontHandle FontClient::Plugin::GetHarfBuzzFont(FontId fontId)
+{
+  FontCacheItemInterface* fontCacheItem = const_cast<FontCacheItemInterface*>(GetCachedFontItem(fontId));
+  if(fontCacheItem != nullptr)
+  {
+    return fontCacheItem->GetHarfBuzzFont(mDpiHorizontal, mDpiVertical); // May cache
+  }
+  return nullptr;
+}
+
 GlyphIndex FontClient::Plugin::CreateEmbeddedItem(const TextAbstraction::FontClient::EmbeddedItemDescription& description, Pixel::Format& pixelFormat)
 {
   EmbeddedItem embeddedItem;
@@ -1589,11 +1649,11 @@ FontId FontClient::Plugin::CreateFont(const FontPath& path,
         fontIdCacheItem.type = FontDescription::FACE_FONT;
 
         // Set the index to the FreeType font face cache.
-        fontIdCacheItem.id = mFontFaceCache.size();
-        fontFaceId         = fontIdCacheItem.id + 1u;
+        fontIdCacheItem.index = mFontFaceCache.size();
+        fontFaceId            = fontIdCacheItem.index + 1u;
 
         // Cache the items.
-        mFontFaceCache.push_back(fontFaceCacheItem);
+        mFontFaceCache.emplace_back(std::move(fontFaceCacheItem));
         mFontIdCache.PushBack(fontIdCacheItem);
 
         // Set the font id to be returned.
@@ -1647,11 +1707,11 @@ FontId FontClient::Plugin::CreateFont(const FontPath& path,
         fontIdCacheItem.type = FontDescription::FACE_FONT;
 
         // Set the index to the FreeType font face cache.
-        fontIdCacheItem.id = mFontFaceCache.size();
-        fontFaceId         = fontIdCacheItem.id + 1u;
+        fontIdCacheItem.index = mFontFaceCache.size();
+        fontFaceId            = fontIdCacheItem.index + 1u;
 
         // Cache the items.
-        mFontFaceCache.push_back(fontFaceCacheItem);
+        mFontFaceCache.emplace_back(std::move(fontFaceCacheItem));
         mFontIdCache.PushBack(fontIdCacheItem);
 
         // Set the font id to be returned.
@@ -1709,30 +1769,51 @@ bool FontClient::Plugin::FindFont(const FontPath& path,
 }
 
 bool FontClient::Plugin::FindValidatedFont(const FontDescription& fontDescription,
-                                           FontDescriptionId&     validatedFontId)
+                                           FontDescriptionId&     fontDescriptionId)
 {
   DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
   FONT_LOG_DESCRIPTION(fontDescription, "");
   DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, "  number of validated fonts in the cache : %d\n", mValidatedFontCache.size());
 
-  validatedFontId = 0u;
+  fontDescriptionId = 0u;
+
+  // Fast cut if inputed family is empty.
+  if(DALI_UNLIKELY(fontDescription.family.empty()))
+  {
+    DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  validated font description not found / fontDescription.family is empty!\n");
+    return false;
+  }
+
+  // Heuristic optimize code : Compare with latest found item.
+  if((fontDescription.width == mLatestFoundFontDescription.width) &&
+     (fontDescription.weight == mLatestFoundFontDescription.weight) &&
+     (fontDescription.slant == mLatestFoundFontDescription.slant) &&
+     (fontDescription.family == mLatestFoundFontDescription.family))
+  {
+    fontDescriptionId = mLatestFoundFontDescriptionId;
+
+    DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  validated font description same as latest, id : %d\n", fontDescriptionId);
+    return true;
+  }
 
   for(const auto& item : mValidatedFontCache)
   {
-    if(!fontDescription.family.empty() &&
-       (fontDescription.family == item.fontDescription.family) &&
-       (fontDescription.width == item.fontDescription.width) &&
+    if((fontDescription.width == item.fontDescription.width) &&
        (fontDescription.weight == item.fontDescription.weight) &&
-       (fontDescription.slant == item.fontDescription.slant))
+       (fontDescription.slant == item.fontDescription.slant) &&
+       (fontDescription.family == item.fontDescription.family))
     {
-      validatedFontId = item.index;
+      fontDescriptionId = item.index;
+
+      mLatestFoundFontDescription   = fontDescription;
+      mLatestFoundFontDescriptionId = fontDescriptionId;
 
-      DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  validated font found, id : %d\n", validatedFontId);
+      DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  validated font description found, id : %d\n", fontDescriptionId);
       return true;
     }
   }
 
-  DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  validated font not found\n");
+  DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  validated font description not found\n");
   return false;
 }
 
@@ -1766,26 +1847,37 @@ bool FontClient::Plugin::FindFallbackFontList(const FontDescription& fontDescrip
   return false;
 }
 
-bool FontClient::Plugin::FindFont(FontDescriptionId validatedFontId,
+bool FontClient::Plugin::FindFont(FontDescriptionId fontDescriptionId,
                                   PointSize26Dot6   requestedPointSize,
-                                  FontId&           fontId)
+                                  FontCacheIndex&   fontCacheIndex)
 {
   DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
-  DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "    validatedFontId  : %d\n", validatedFontId);
+  DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "   fontDescriptionId : %d\n", fontDescriptionId);
   DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize);
 
-  fontId = 0u;
+  fontCacheIndex = 0u;
 
-  for(const auto& item : mFontDescriptionSizeCache)
+  const FontDescriptionSizeCacheKey key(fontDescriptionId, requestedPointSize);
+
+  // Heuristic optimize code : Compare with latest found item.
+  if(key == mLatestFoundCacheKey)
   {
-    if((validatedFontId == item.validatedFontId) &&
-       (requestedPointSize == item.requestedPointSize))
-    {
-      fontId = item.fontId;
+    fontCacheIndex = mLatestFoundCacheIndex;
 
-      DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  font found, id : %d\n", fontId);
-      return true;
-    }
+    DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  font same as latest, index of font cache : %d\n", fontCacheIndex);
+    return true;
+  }
+
+  const auto& iter = mFontDescriptionSizeCache.find(key);
+  if(iter != mFontDescriptionSizeCache.cend())
+  {
+    fontCacheIndex = iter->second;
+
+    mLatestFoundCacheKey   = key;
+    mLatestFoundCacheIndex = fontCacheIndex;
+
+    DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  font found, index of font cache : %d\n", fontCacheIndex);
+    return true;
   }
 
   DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  font not found.\n");
@@ -1941,9 +2033,9 @@ void FontClient::Plugin::CacheFontPath(FT_Face ftFace, FontId id, PointSize26Dot
     description.weight = FontWeight::BOLD;
   }
 
-  FontDescriptionId validatedFontId = 0u;
+  FontDescriptionId fontDescriptionId = 0u;
   if(!FindValidatedFont(description,
-                        validatedFontId))
+                        fontDescriptionId))
   {
     FcPattern* pattern = CreateFontFamilyPattern(description); // Creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
 
@@ -1965,19 +2057,17 @@ void FontClient::Plugin::CacheFontPath(FT_Face ftFace, FontId id, PointSize26Dot
     mFontDescriptionCache.push_back(description);
 
     // Set the index to the vector of paths to font file names.
-    validatedFontId = mFontDescriptionCache.size();
+    fontDescriptionId = mFontDescriptionCache.size();
 
     // Increase the reference counter and add the character set to the cache.
     mCharacterSetCache.PushBack(FcCharSetCopy(characterSet));
 
     // Cache the index and the font's description.
     mValidatedFontCache.push_back(std::move(FontDescriptionCacheItem(std::move(description),
-                                                                     validatedFontId)));
+                                                                     fontDescriptionId)));
 
-    // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
-    mFontDescriptionSizeCache.push_back(FontDescriptionSizeCacheItem(validatedFontId,
-                                                                     requestedPointSize,
-                                                                     fontFaceId));
+    // Cache the pair 'fontDescriptionId, requestedPointSize' to improve the following queries.
+    mFontDescriptionSizeCache.emplace(FontDescriptionSizeCacheKey(fontDescriptionId, requestedPointSize), fontFaceId);
   }
 }
 
index e6eb986..bef0f89 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_TEXT_ABSTRACTION_FONT_CLIENT_PLUGIN_IMPL_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -36,6 +36,8 @@ class VectorFontCache;
 #endif
 
 // EXTERNAL INCLUDES
+#include <unordered_map>
+
 #include <ft2build.h>
 #include FT_FREETYPE_H
 #include FT_GLYPH_H
@@ -68,10 +70,17 @@ typedef Vector<_FcCharSet*> CharacterSetList;
  */
 struct FontClient::Plugin
 {
+private:
+  /// Redefine FontId name to specifiy the value's usage
+  using FontCacheIndex = FontId;
+
+  /**
+   * @brief Index of FontCache container.
+   */
   struct FontIdCacheItem
   {
-    FontDescription::Type type; ///< The type of font.
-    FontId                id;   ///< Index to the cache of fonts for the specified type.
+    FontDescription::Type type;  ///< The type of font.
+    FontCacheIndex        index; ///< Index to the cache of fonts for the specified type. Face or Bitmap
   };
 
   /**
@@ -101,25 +110,45 @@ struct FontClient::Plugin
   };
 
   /**
-   * @brief Caches the font id of the pair font point size and the index to the vector of font descriptions of validated fonts.
+   * @brief Pair of FontDescriptionId and PointSize. It will be used to find cached validate font.
    */
-  struct FontDescriptionSizeCacheItem
+  struct FontDescriptionSizeCacheKey
   {
-    FontDescriptionSizeCacheItem(FontDescriptionId validatedFontId,
-                                 PointSize26Dot6   requestedPointSize,
-                                 FontId            fontId);
+    FontDescriptionSizeCacheKey(FontDescriptionId fontDescriptionId,
+                                PointSize26Dot6   requestedPointSize);
 
-    FontDescriptionId validatedFontId;    ///< Index to the vector with font descriptions.
+    FontDescriptionId fontDescriptionId;  ///< Index to the vector with font descriptions.
     PointSize26Dot6   requestedPointSize; ///< The font point size.
-    FontId            fontId;             ///< The font identifier.
+
+    bool operator==(FontDescriptionSizeCacheKey const& rhs) const noexcept
+    {
+      return fontDescriptionId == rhs.fontDescriptionId && requestedPointSize == rhs.requestedPointSize;
+    }
+  };
+
+  /**
+   * @brief Custom hash functions for FontDescriptionSizeCacheKey.
+   */
+  struct FontDescriptionSizeCacheKeyHash
+  {
+    std::size_t operator()(FontDescriptionSizeCacheKey const& key) const noexcept
+    {
+      return key.fontDescriptionId ^ key.requestedPointSize;
+    }
   };
 
+  /**
+   * @brief Caches the font id of the pair font point size and the index to the vector of font descriptions of validated fonts.
+   */
+  using FontDescriptionSizeCacheContainer = std::unordered_map<FontDescriptionSizeCacheKey, FontCacheIndex, FontDescriptionSizeCacheKeyHash>;
+
   struct EllipsisItem
   {
     PointSize26Dot6 requestedPointSize;
     GlyphInfo       glyph;
   };
 
+public:
   /**
    * Constructor.
    *
@@ -385,6 +414,11 @@ struct FontClient::Plugin
    */
   bool AddCustomFontDirectory(const FontPath& path);
 
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::GetHarfBuzzFont()
+   */
+  HarfBuzzFontHandle GetHarfBuzzFont(FontId fontId);
+
 private:
   /**
    * @brief Caches the fonts present in the platform.
@@ -489,17 +523,17 @@ private:
 
   /**
    * @brief Finds in the cache a pair 'validated font identifier and font point size'.
-   * If there is one it writes the font identifier in the param @p fontId.
+   * If there is one it writes the font identifier in the param @p fontCacheIndex.
    *
    * @param[in] validatedFontId Index to the vector with font descriptions.
    * @param[in] requestedPointSize The font point size.
-   * @param[out] fontId The font identifier.
+   * @param[out] fontCacheIndex The index of font cache identifier.
    *
    * @return @e true if the pair is found.
    */
   bool FindFont(FontDescriptionId validatedFontId,
                 PointSize26Dot6   requestedPointSize,
-                FontId&           fontId);
+                FontCacheIndex&   fontCacheIndex);
 
   /**
    * @brief Finds in the cache a bitmap font with the @p bitmapFont family name.
@@ -571,12 +605,13 @@ private:
 
   std::vector<FallbackCacheItem> mFallbackCache; ///< Cached fallback font lists.
 
-  Vector<FontIdCacheItem>                   mFontIdCache;
-  std::vector<FontFaceCacheItem>            mFontFaceCache;            ///< Caches the FreeType face and font metrics of the triplet 'path to the font file name, font point size and face index'.
-  std::vector<FontDescriptionCacheItem>     mValidatedFontCache;       ///< Caches indices to the vector of font descriptions for a given font.
-  FontList                                  mFontDescriptionCache;     ///< Caches font descriptions for the validated font.
-  CharacterSetList                          mCharacterSetCache;        ///< Caches character set lists for the validated font.
-  std::vector<FontDescriptionSizeCacheItem> mFontDescriptionSizeCache; ///< Caches font identifiers for the pairs of font point size and the index to the vector with font descriptions of the validated fonts.
+  Vector<FontIdCacheItem>               mFontIdCache;          ///< Caches from FontId to FontCacheIndex.
+  std::vector<FontFaceCacheItem>        mFontFaceCache;        ///< Caches the FreeType face and font metrics of the triplet 'path to the font file name, font point size and face index'.
+  std::vector<FontDescriptionCacheItem> mValidatedFontCache;   ///< Caches indices to the vector of font descriptions for a given font.
+  FontList                              mFontDescriptionCache; ///< Caches font descriptions for the validated font.
+  CharacterSetList                      mCharacterSetCache;    ///< Caches character set lists for the validated font.
+
+  FontDescriptionSizeCacheContainer mFontDescriptionSizeCache; ///< Caches font identifiers for the pairs of font point size and the index to the vector with font descriptions of the validated fonts.
 
   VectorFontCache* mVectorFontCache; ///< Separate cache for vector data blobs etc.
 
@@ -585,6 +620,12 @@ private:
   Vector<EmbeddedItem>              mEmbeddedItemCache; ///< Cache embedded items.
   std::vector<BitmapFontCacheItem>  mBitmapFontCache;   ///< Stores bitmap fonts.
 
+  FontDescription   mLatestFoundFontDescription; ///< Latest found font description and id in FindValidatedFont()
+  FontDescriptionId mLatestFoundFontDescriptionId;
+
+  FontDescriptionSizeCacheKey mLatestFoundCacheKey; ///< Latest found font description and id in FindFont()
+  FontCacheIndex              mLatestFoundCacheIndex;
+
   bool mDefaultFontDescriptionCached : 1; ///< Whether the default font is cached or not
 
   bool    mIsAtlasLimitationEnabled : 1;      ///< Whether the validation on maximum atlas block size, then reduce block size to fit into it is enabled or not.
index 3f9743f..fbe76aa 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -129,7 +129,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)
+void ConvertBitmap(TextAbstraction::FontClient::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);
@@ -141,21 +141,32 @@ void ConvertBitmap(TextAbstraction::FontClient::GlyphBufferData& data, unsigned
   data.height = (data.height == 0) ? srcHeight : data.height;
   const ImageDimensions desiredDimensions(data.width, data.height);
 
+  data.format = srcFormat;
+
+  // Note we don't compress here
+  data.compressionType = TextAbstraction::FontClient::GlyphBufferData::CompressionType::NO_COMPRESSION;
+
+  const uint32_t bytePerPixel = Dali::Pixel::GetBytesPerPixel(srcFormat);
+
   // Creates the output buffer
-  const unsigned int bufferSize = data.width * data.height * 4u;
-  data.buffer                   = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
+  const uint32_t bufferSize = data.width * data.height * bytePerPixel;
 
   if(inputDimensions == desiredDimensions)
   {
     // There isn't downscaling.
-    memcpy(data.buffer, srcBuffer, bufferSize);
+    data.isBufferOwned = false;
+    data.buffer        = const_cast<uint8_t*>(srcBuffer);
   }
   else
   {
-    Dali::Internal::Platform::LanczosSample4BPP(srcBuffer,
-                                                inputDimensions,
-                                                data.buffer,
-                                                desiredDimensions);
+    data.isBufferOwned = true;
+    data.buffer        = (uint8_t*)malloc(bufferSize); // @note The caller is responsible for deallocating the bitmap data using free.
+    Dali::Internal::Platform::LanczosSample(srcBuffer,
+                                            inputDimensions,
+                                            srcWidth,
+                                            srcFormat,
+                                            data.buffer,
+                                            desiredDimensions);
   }
 }
 
@@ -163,11 +174,14 @@ void ConvertBitmap(TextAbstraction::FontClient::GlyphBufferData& data, unsigned
  * @brief Copy the FreeType bitmap to the given buffer.
  *
  * @param[out] data The bitmap data.
- * @param[in] srcBitmap The FreeType bitmap.
+ * @param[in,out] srcBitmap The FreeType bitmap.
  * @param[in] isShearRequired Whether the bitmap needs a shear transform (for software italics).
+ * @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)
+void ConvertBitmap(TextAbstraction::FontClient::GlyphBufferData& data, FT_Bitmap& srcBitmap, bool isShearRequired, bool moveBuffer)
 {
+  data.buffer = nullptr;
   if(srcBitmap.width * srcBitmap.rows > 0)
   {
     switch(srcBitmap.pixel_mode)
@@ -180,7 +194,7 @@ void ConvertBitmap(TextAbstraction::FontClient::GlyphBufferData& data, FT_Bitmap
           unsigned int width    = srcBitmap.width;
           unsigned     height   = srcBitmap.rows;
 
-          std::unique_ptr<uint8_t, void (*)(void*)> pixelsOutPtr(nullptr, free);
+          uint8_t* releaseRequiredPixelPtr = nullptr;
 
           if(isShearRequired)
           {
@@ -224,24 +238,61 @@ void ConvertBitmap(TextAbstraction::FontClient::GlyphBufferData& data, FT_Bitmap
             Dali::Internal::Platform::HorizontalShear(pixelsIn,
                                                       width,
                                                       height,
+                                                      width,
                                                       1u,
                                                       -TextAbstraction::FontClient::DEFAULT_ITALIC_ANGLE,
                                                       pixelsOut,
                                                       widthOut,
                                                       heightOut);
 
-            width    = widthOut;
-            height   = heightOut;
-            pixelsIn = pixelsOut;
-            pixelsOutPtr.reset(pixelsOut);
+            if(DALI_LIKELY(pixelsOut))
+            {
+              width  = widthOut;
+              height = heightOut;
+
+              if(moveBuffer)
+              {
+                releaseRequiredPixelPtr = pixelsIn;
+              }
+              else
+              {
+                releaseRequiredPixelPtr = pixelsOut;
+              }
+
+              // Change input buffer ptr.
+              pixelsIn = pixelsOut;
+            }
+            else
+            {
+              DALI_LOG_ERROR("ERROR! software italic slant failed!\n");
+            }
           }
 
-          const unsigned int bufferSize = width * height;
-          data.buffer                   = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
-          data.width                    = width;
-          data.height                   = height;
-          data.format                   = Pixel::L8; // Sets the pixel format.
-          memcpy(data.buffer, pixelsIn, bufferSize);
+          data.width  = width;
+          data.height = height;
+          data.format = Pixel::L8; // Sets the pixel format.
+
+          // Note we don't compress here
+          data.compressionType = TextAbstraction::FontClient::GlyphBufferData::CompressionType::NO_COMPRESSION;
+
+          if(moveBuffer)
+          {
+            data.isBufferOwned = true;
+            data.buffer        = pixelsIn;
+
+            // Happy trick for copyless convert bitmap!
+            srcBitmap.buffer = nullptr;
+          }
+          else
+          {
+            data.isBufferOwned = false;
+            data.buffer        = pixelsIn;
+          }
+
+          if(releaseRequiredPixelPtr)
+          {
+            free(releaseRequiredPixelPtr);
+          }
         }
         break;
       }
@@ -251,10 +302,8 @@ void ConvertBitmap(TextAbstraction::FontClient::GlyphBufferData& data, FT_Bitmap
       {
         if(srcBitmap.pitch == static_cast<int>(srcBitmap.width << 2u))
         {
-          ConvertBitmap(data, srcBitmap.width, srcBitmap.rows, srcBitmap.buffer);
-
-          // Sets the pixel format.
-          data.format = Pixel::BGRA8888;
+          // Color glyph doesn't support copyless convert bitmap. Just memcpy
+          ConvertBitmap(data, srcBitmap.width, srcBitmap.rows, srcBitmap.buffer, Pixel::BGRA8888);
         }
         break;
       }
index f329193..c73e3da 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TEST_ABSTRACTION_INTERNAL_FONT_CLIENT_UTILS_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -35,11 +35,13 @@ namespace Dali::TextAbstraction::Internal
 void ConvertBitmap(TextAbstraction::FontClient::GlyphBufferData& data,
                    unsigned int                                  srcWidth,
                    unsigned int                                  srcHeight,
-                   const unsigned char* const                    srcBuffer);
+                   const unsigned char* const                    srcBuffer,
+                   const Pixel::Format                           srcFormat);
 
 void ConvertBitmap(TextAbstraction::FontClient::GlyphBufferData& data,
-                   FT_Bitmap                                     srcBitmap,
-                   bool                                          isShearRequired);
+                   FT_Bitmap&                                    srcBitmap,
+                   bool                                          isShearRequired,
+                   bool                                          moveBuffer = false);
 
 /**
  * @brief Creates a font family pattern used to match fonts.
index 92a1ff2..35a5c72 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * limitations under the License.
  */
 
+// EXTERNAL HEADERS
 #include <dali/integration-api/debug.h>
+
+// INTERNAL HEADERS
+#include <dali/devel-api/adaptor-framework/environment-variable.h>
 #include <dali/internal/text/text-abstraction/plugin/font-client-utils.h>
 #include <dali/internal/text/text-abstraction/plugin/font-face-cache-item.h>
 
@@ -24,9 +28,91 @@ extern Dali::Integration::Log::Filter* gFontClientLogFilter;
 
 namespace Dali::TextAbstraction::Internal
 {
+namespace
+{
 const float FROM_266        = 1.0f / 64.0f;
 const float POINTS_PER_INCH = 72.f;
 
+/**
+ * @brief Maximum rate of bitmap glyph resize.
+ * If scale factor is bigger than this value, we will not cache resized glyph.
+ * Else, resize bitmap glyph itself and cache it.
+ */
+constexpr float MAXIMUM_RATE_OF_BITMAP_GLYPH_CACHE_RESIZE = 1.5f;
+
+/**
+ * @brief Maximum size of glyph cache per each font face.
+ */
+constexpr std::size_t DEFAULT_GLYPH_CACHE_MAX         = 128;
+constexpr std::size_t MINIMUM_SIZE_OF_GLYPH_CACHE_MAX = 3u;
+
+constexpr auto MAX_NUMBER_OF_GLYPH_CACHE_ENV = "DALI_GLYPH_CACHE_MAX";
+
+/**
+ * @brief Get maximum size of glyph cache size from environment.
+ * If not settuped, default as 128.
+ * @note This value fixed when we call it first time.
+ * @return The max size of glyph cache.
+ */
+inline const size_t GetMaxNumberOfGlyphCache()
+{
+  using Dali::EnvironmentVariable::GetEnvironmentVariable;
+  static auto numberString = GetEnvironmentVariable(MAX_NUMBER_OF_GLYPH_CACHE_ENV);
+  static auto number       = numberString ? std::strtoul(numberString, nullptr, 10) : DEFAULT_GLYPH_CACHE_MAX;
+  return (number < MINIMUM_SIZE_OF_GLYPH_CACHE_MAX) ? MINIMUM_SIZE_OF_GLYPH_CACHE_MAX : number;
+}
+
+/**
+ * @brief Behavior about cache the rendered glyph cache.
+ */
+constexpr bool DEFAULT_ENABLE_CACHE_RENDERED_GLYPH = true;
+constexpr auto ENABLE_CACHE_RENDERED_GLYPH_ENV     = "DALI_ENABLE_CACHE_RENDERED_GLYPH";
+
+/**
+ * @brief Get whether we allow to cache rendered glyph from environment.
+ * If not settuped, default as true.
+ * @note This value fixed when we call it first time.
+ * @return True if we allow to cache rendered glyph.
+ */
+inline const bool EnableCacheRenderedGlyph()
+{
+  using Dali::EnvironmentVariable::GetEnvironmentVariable;
+  static auto numberString = GetEnvironmentVariable(ENABLE_CACHE_RENDERED_GLYPH_ENV);
+  static auto number       = numberString ? (std::strtoul(numberString, nullptr, 10) ? true : false) : DEFAULT_ENABLE_CACHE_RENDERED_GLYPH;
+  return number;
+}
+
+/**
+ * @brief Policy about compress the cached rendered glyph.
+ * It will be used only if CacheRenderedGlyph is enabled
+ */
+constexpr auto DEFAULT_RENDERED_GLYPH_COMPRESS_POLICY =
+#if !(defined(DALI_PROFILE_UBUNTU) || defined(ANDROID) || defined(WIN32) || defined(__APPLE__))
+  GlyphCacheManager::CompressionPolicyType::MEMORY; // If tizen target
+#else
+  GlyphCacheManager::CompressionPolicyType::SPEED; // If not tizen target
+#endif
+constexpr auto RENDERED_GLYPH_COMPRESS_POLICY_ENV = "DALI_RENDERED_GLYPH_COMPRESS_POLICY";
+
+/**
+ * @brief Get whether we allow to cache rendered glyph from environment.
+ * If not settuped, default value used, as defined above.
+ * @note This value fixed when we call it first time.
+ * @return SPEED if value start with 's' or 'S'. MEMORY if value start with 'm' or 'M'. otherwise, use default
+ */
+inline const 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
+                                    : DEFAULT_RENDERED_GLYPH_COMPRESS_POLICY;
+  return policy;
+}
+} // namespace
+
 FontFaceCacheItem::FontFaceCacheItem(FT_Library&        freeTypeLibrary,
                                      FT_Face            ftFace,
                                      const FontPath&    path,
@@ -35,6 +121,8 @@ FontFaceCacheItem::FontFaceCacheItem(FT_Library&        freeTypeLibrary,
                                      const FontMetrics& metrics)
 : mFreeTypeLibrary(freeTypeLibrary),
   mFreeTypeFace(ftFace),
+  mGlyphCacheManager(new GlyphCacheManager(mFreeTypeFace, GetMaxNumberOfGlyphCache())),
+  mHarfBuzzProxyFont(),
   mPath(path),
   mRequestedPointSize(requestedPointSize),
   mFaceIndex(face),
@@ -62,6 +150,8 @@ FontFaceCacheItem::FontFaceCacheItem(FT_Library&        freeTypeLibrary,
                                      bool               hasColorTables)
 : mFreeTypeLibrary(freeTypeLibrary),
   mFreeTypeFace(ftFace),
+  mGlyphCacheManager(new GlyphCacheManager(mFreeTypeFace, GetMaxNumberOfGlyphCache())),
+  mHarfBuzzProxyFont(),
   mPath(path),
   mRequestedPointSize(requestedPointSize),
   mFaceIndex(face),
@@ -77,6 +167,50 @@ FontFaceCacheItem::FontFaceCacheItem(FT_Library&        freeTypeLibrary,
 {
 }
 
+// Move constructor. font client plugin container may call this.
+// Note that we make nullptr of some reference sensitive values here.
+FontFaceCacheItem::FontFaceCacheItem(FontFaceCacheItem&& rhs)
+: mFreeTypeLibrary(rhs.mFreeTypeLibrary)
+{
+  mFreeTypeFace       = rhs.mFreeTypeFace;
+  mGlyphCacheManager  = std::move(rhs.mGlyphCacheManager);
+  mHarfBuzzProxyFont  = std::move(rhs.mHarfBuzzProxyFont);
+  mPath               = std::move(rhs.mPath);
+  mRequestedPointSize = rhs.mRequestedPointSize;
+  mFaceIndex          = rhs.mFaceIndex;
+  mMetrics            = rhs.mMetrics;
+  mCharacterSet       = rhs.mCharacterSet;
+  mFixedSizeIndex     = rhs.mFixedSizeIndex;
+  mFixedWidthPixels   = rhs.mFixedWidthPixels;
+  mFixedHeightPixels  = rhs.mFixedWidthPixels;
+  mVectorFontId       = rhs.mVectorFontId;
+  mFontId             = rhs.mFontId;
+  mIsFixedSizeBitmap  = rhs.mIsFixedSizeBitmap;
+  mHasColorTables     = rhs.mHasColorTables;
+
+  rhs.mFreeTypeFace = nullptr;
+}
+
+FontFaceCacheItem::~FontFaceCacheItem()
+{
+  // delete glyph cache manager before free face.
+  if(mGlyphCacheManager)
+  {
+    mGlyphCacheManager.reset();
+  }
+
+  if(mHarfBuzzProxyFont)
+  {
+    mHarfBuzzProxyFont.reset();
+  }
+
+  // Free face.
+  if(mFreeTypeFace)
+  {
+    FT_Done_Face(mFreeTypeFace);
+  }
+}
+
 void FontFaceCacheItem::GetFontMetrics(FontMetrics& metrics, unsigned int dpiVertical) const
 {
   metrics = mMetrics;
@@ -99,32 +233,36 @@ void FontFaceCacheItem::GetFontMetrics(FontMetrics& metrics, unsigned int dpiVer
   }
 }
 
-bool FontFaceCacheItem::GetGlyphMetrics(GlyphInfo& glyph, unsigned int dpiVertical, bool horizontal) const
+bool FontFaceCacheItem::GetGlyphMetrics(GlyphInfo& glyphInfo, unsigned int dpiVertical, bool horizontal) const
 {
   bool success(true);
 
-  FT_Face ftFace = mFreeTypeFace;
+  GlyphCacheManager::GlyphCacheData glyphData;
+  FT_Error                          error;
 
 #ifdef FREETYPE_BITMAP_SUPPORT
   // Check to see if we should be loading a Fixed Size bitmap?
   if(mIsFixedSizeBitmap)
   {
-    FT_Select_Size(ftFace, mFixedSizeIndex); ///< @todo: needs to be investigated why it's needed to select the size again.
-    int error = FT_Load_Glyph(ftFace, glyph.index, FT_LOAD_COLOR);
+    FT_Select_Size(mFreeTypeFace, mFixedSizeIndex); ///< @todo: needs to be investigated why it's needed to select the size again.
+    mGlyphCacheManager->GetGlyphCacheDataFromIndex(glyphInfo.index, FT_LOAD_COLOR, glyphInfo.isBoldRequired, glyphData, error);
+
     if(FT_Err_Ok == error)
     {
-      glyph.width    = mFixedWidthPixels;
-      glyph.height   = mFixedHeightPixels;
-      glyph.advance  = mFixedWidthPixels;
-      glyph.xBearing = 0.0f;
+      glyphInfo.width    = mFixedWidthPixels;
+      glyphInfo.height   = mFixedHeightPixels;
+      glyphInfo.advance  = mFixedWidthPixels;
+      glyphInfo.xBearing = 0.0f;
+
+      const auto& metrics = glyphData.mGlyphMetrics;
 
       if(horizontal)
       {
-        glyph.yBearing += static_cast<float>(ftFace->glyph->metrics.horiBearingY) * FROM_266;
+        glyphInfo.yBearing += static_cast<float>(metrics.horiBearingY) * FROM_266;
       }
       else
       {
-        glyph.yBearing += static_cast<float>(ftFace->glyph->metrics.vertBearingY) * FROM_266;
+        glyphInfo.yBearing += static_cast<float>(metrics.vertBearingY) * FROM_266;
       }
 
       // Adjust the metrics if the fixed-size font should be down-scaled
@@ -133,13 +271,24 @@ bool FontFaceCacheItem::GetGlyphMetrics(GlyphInfo& glyph, unsigned int dpiVertic
       if(desiredFixedSize > 0.f)
       {
         const float scaleFactor = desiredFixedSize / mFixedHeightPixels;
-        glyph.width             = round(glyph.width * scaleFactor);
-        glyph.height            = round(glyph.height * scaleFactor);
-        glyph.advance           = round(glyph.advance * scaleFactor);
-        glyph.xBearing          = round(glyph.xBearing * scaleFactor);
-        glyph.yBearing          = round(glyph.yBearing * scaleFactor);
+        glyphInfo.width         = round(glyphInfo.width * scaleFactor);
+        glyphInfo.height        = round(glyphInfo.height * scaleFactor);
+        glyphInfo.advance       = round(glyphInfo.advance * scaleFactor);
+        glyphInfo.xBearing      = round(glyphInfo.xBearing * scaleFactor);
+        glyphInfo.yBearing      = round(glyphInfo.yBearing * scaleFactor);
+
+        glyphInfo.scaleFactor = scaleFactor;
 
-        glyph.scaleFactor = scaleFactor;
+        if(scaleFactor < MAXIMUM_RATE_OF_BITMAP_GLYPH_CACHE_RESIZE)
+        {
+          // Resize bitmap glyph and cache it due to the performance issue.
+          // If scaleFactor is too big, cached bitmap may hold too big memory.
+          // So, we only hold small enough case.
+
+          // TODO : If dpiVertical value changed, this resize feature will be break down.
+          // Otherwise, this glyph will be resized only one times.
+          mGlyphCacheManager->ResizeBitmapGlyph(glyphInfo.index, FT_LOAD_COLOR, glyphInfo.isBoldRequired, static_cast<uint32_t>(glyphInfo.width), static_cast<uint32_t>(glyphInfo.height));
+        }
       }
     }
     else
@@ -154,60 +303,59 @@ bool FontFaceCacheItem::GetGlyphMetrics(GlyphInfo& glyph, unsigned int dpiVertic
     // 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?
-    int error = FT_Load_Glyph(ftFace, glyph.index, FT_LOAD_NO_AUTOHINT);
+    mGlyphCacheManager->GetGlyphCacheDataFromIndex(glyphInfo.index, FT_LOAD_NO_AUTOHINT, glyphInfo.isBoldRequired, glyphData, 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
     // advance as Harfbuzz doesn't apply any SW emboldening to calculate
     // the advance of the glyph.
-    const float width = static_cast<float>(ftFace->glyph->metrics.width) * FROM_266;
 
     if(FT_Err_Ok == error)
     {
-      const bool isEmboldeningRequired = glyph.isBoldRequired && !(ftFace->style_flags & FT_STYLE_FLAG_BOLD);
-      if(isEmboldeningRequired)
-      {
-        // Does the software bold.
-        FT_GlyphSlot_Embolden(ftFace->glyph);
-      }
+      const auto& metrics = glyphData.mGlyphMetrics;
 
-      glyph.width  = static_cast<float>(ftFace->glyph->metrics.width) * FROM_266;
-      glyph.height = static_cast<float>(ftFace->glyph->metrics.height) * FROM_266;
+      glyphInfo.width  = static_cast<float>(metrics.width) * FROM_266;
+      glyphInfo.height = static_cast<float>(metrics.height) * FROM_266;
       if(horizontal)
       {
-        glyph.xBearing += static_cast<float>(ftFace->glyph->metrics.horiBearingX) * FROM_266;
-        glyph.yBearing += static_cast<float>(ftFace->glyph->metrics.horiBearingY) * FROM_266;
+        glyphInfo.xBearing += static_cast<float>(metrics.horiBearingX) * FROM_266;
+        glyphInfo.yBearing += static_cast<float>(metrics.horiBearingY) * FROM_266;
       }
       else
       {
-        glyph.xBearing += static_cast<float>(ftFace->glyph->metrics.vertBearingX) * FROM_266;
-        glyph.yBearing += static_cast<float>(ftFace->glyph->metrics.vertBearingY) * FROM_266;
+        glyphInfo.xBearing += static_cast<float>(metrics.vertBearingX) * FROM_266;
+        glyphInfo.yBearing += static_cast<float>(metrics.vertBearingY) * FROM_266;
       }
 
-      if(isEmboldeningRequired && !Dali::EqualsZero(width))
+      const bool isEmboldeningRequired = glyphInfo.isBoldRequired && !(glyphData.mStyleFlags & FT_STYLE_FLAG_BOLD);
+      if(isEmboldeningRequired)
       {
-        // If the glyph is emboldened by software, the advance is multiplied by a
-        // scale factor to make it slightly bigger.
-        glyph.advance *= (glyph.width / width);
+        // Get dummy glyph data without embolden.
+        GlyphCacheManager::GlyphCacheData dummyData;
+        if(mGlyphCacheManager->GetGlyphCacheDataFromIndex(glyphInfo.index, FT_LOAD_NO_AUTOHINT, false, dummyData, 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;
+          if(!EqualsZero(width))
+          {
+            glyphInfo.advance *= (glyphInfo.width / width);
+          }
+        }
       }
 
       // Use the bounding box of the bitmap to correct the metrics.
       // For some fonts i.e the SNum-3R the metrics need to be corrected,
       // otherwise the glyphs 'dance' up and down depending on the
       // font's point size.
-
-      FT_Glyph ftGlyph;
-      error = FT_Get_Glyph(ftFace->glyph, &ftGlyph);
+      FT_Glyph glyph = glyphData.mGlyph;
 
       FT_BBox bbox;
-      FT_Glyph_Get_CBox(ftGlyph, FT_GLYPH_BBOX_GRIDFIT, &bbox);
+      FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_GRIDFIT, &bbox);
 
-      const float descender = glyph.height - glyph.yBearing;
-      glyph.height          = (bbox.yMax - bbox.yMin) * FROM_266;
-      glyph.yBearing        = glyph.height - round(descender);
-
-      // Created FT_Glyph object must be released with FT_Done_Glyph
-      FT_Done_Glyph(ftGlyph);
+      const float descender = glyphInfo.height - glyphInfo.yBearing;
+      glyphInfo.height      = (bbox.yMax - bbox.yMin) * FROM_266;
+      glyphInfo.yBearing    = glyphInfo.height - round(descender);
     }
     else
     {
@@ -221,16 +369,17 @@ bool FontFaceCacheItem::GetGlyphMetrics(GlyphInfo& glyph, unsigned int dpiVertic
  * @brief Create a bitmap representation of a glyph from a face font
  *
  * @param[in]  glyphIndex        The index of a glyph within the specified font.
- * @param[in]  isItalicRequired  Whether the glyph requires italic style.
- * @param[in]  isBoldRequired    Whether the glyph requires bold style.
  * @param[out] data              The bitmap data.
  * @param[in]  outlineWidth      The width of the glyph outline in pixels.
+ * @param[in]  isItalicRequired  Whether the glyph requires italic style.
+ * @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
 {
-  FT_Face  ftFace = mFreeTypeFace;
-  FT_Error error;
+  GlyphCacheManager::GlyphCacheData glyphData;
+  FT_Error                          error;
+  FT_Int32                          loadFlag;
   // For the software italics.
   bool isShearRequired = false;
 
@@ -238,7 +387,7 @@ void FontFaceCacheItem::CreateBitmap(
   // Check to see if this is fixed size bitmap
   if(mIsFixedSizeBitmap)
   {
-    error = FT_Load_Glyph(ftFace, glyphIndex, FT_LOAD_COLOR);
+    loadFlag = FT_LOAD_COLOR;
   }
   else
 #endif
@@ -246,83 +395,98 @@ void FontFaceCacheItem::CreateBitmap(
     // 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?
-    error = FT_Load_Glyph(ftFace, glyphIndex, FT_LOAD_NO_AUTOHINT);
+    loadFlag = FT_LOAD_NO_AUTOHINT;
   }
+  mGlyphCacheManager->GetGlyphCacheDataFromIndex(glyphIndex, loadFlag, isBoldRequired, glyphData, error);
+
   if(FT_Err_Ok == error)
   {
-    if(isBoldRequired && !(ftFace->style_flags & FT_STYLE_FLAG_BOLD))
-    {
-      // Does the software bold.
-      FT_GlyphSlot_Embolden(ftFace->glyph);
-    }
-
-    if(isItalicRequired && !(ftFace->style_flags & FT_STYLE_FLAG_ITALIC))
+    if(isItalicRequired && !(glyphData.mStyleFlags & FT_STYLE_FLAG_ITALIC))
     {
       // Will do the software italic.
       isShearRequired = true;
     }
 
-    FT_Glyph glyph;
-    error = FT_Get_Glyph(ftFace->glyph, &glyph);
-
-    // Convert to bitmap if necessary
-    if(FT_Err_Ok == error)
+    if(!glyphData.mIsBitmap)
     {
-      if(glyph->format != FT_GLYPH_FORMAT_BITMAP)
-      {
-        int  offsetX = 0, offsetY = 0;
-        bool isOutlineGlyph = (glyph->format == FT_GLYPH_FORMAT_OUTLINE && outlineWidth > 0);
+      // Convert to bitmap if necessary
+      FT_Glyph glyph = glyphData.mGlyph;
+
+      DALI_ASSERT_ALWAYS(glyph->format != FT_GLYPH_FORMAT_BITMAP && "Something wrong with cashing. Some bitmap glyph cached failed.");
 
-        // Create a bitmap for the outline
-        if(isOutlineGlyph)
+      int  offsetX = 0, offsetY = 0;
+      bool isOutlineGlyph       = (glyph->format == FT_GLYPH_FORMAT_OUTLINE && outlineWidth > 0);
+      bool isStrokeGlyphSuccess = false;
+
+      // Create a bitmap for the outline
+      if(isOutlineGlyph)
+      {
+        // Retrieve the horizontal and vertical distance from the current pen position to the
+        // left and top border of the glyph bitmap for a normal glyph before applying the outline.
+        if(FT_Err_Ok == error)
         {
-          // Retrieve the horizontal and vertical distance from the current pen position to the
-          // left and top border of the glyph bitmap for a normal glyph before applying the outline.
+          // Copy new glyph, and keep original cached glyph.
+          error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 0);
           if(FT_Err_Ok == error)
           {
-            FT_Glyph normalGlyph;
-            error = FT_Get_Glyph(ftFace->glyph, &normalGlyph);
-
-            error = FT_Glyph_To_Bitmap(&normalGlyph, FT_RENDER_MODE_NORMAL, 0, 1);
-            if(FT_Err_Ok == error)
-            {
-              FT_BitmapGlyph bitmapGlyph = reinterpret_cast<FT_BitmapGlyph>(normalGlyph);
+            FT_BitmapGlyph bitmapGlyph = reinterpret_cast<FT_BitmapGlyph>(glyph);
 
-              offsetX = bitmapGlyph->left;
-              offsetY = bitmapGlyph->top;
-            }
+            offsetX = bitmapGlyph->left;
+            offsetY = bitmapGlyph->top;
 
-            // Created FT_Glyph object must be released with FT_Done_Glyph
-            FT_Done_Glyph(normalGlyph);
+            // Copied FT_Glyph object must be released with FT_Done_Glyph
+            FT_Done_Glyph(glyph);
           }
 
-          // Now apply the outline
+          // Replace as original glyph
+          glyph = glyphData.mGlyph;
+        }
+
+        // Now apply the outline
 
-          // Set up a stroker
-          FT_Stroker stroker;
-          error = FT_Stroker_New(mFreeTypeLibrary, &stroker);
+        // Set up a stroker
+        FT_Stroker stroker;
+        error = FT_Stroker_New(mFreeTypeLibrary, &stroker);
+
+        if(FT_Err_Ok == error)
+        {
+          // Copy glyph pointer for release memory.
+          FT_Stroker_Set(stroker, outlineWidth * 64, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);
+          error = FT_Glyph_StrokeBorder(&glyph, stroker, 0, 0);
 
           if(FT_Err_Ok == error)
           {
-            FT_Stroker_Set(stroker, outlineWidth * 64, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);
-            error = FT_Glyph_StrokeBorder(&glyph, stroker, 0, 1);
-
-            if(FT_Err_Ok == error)
-            {
-              FT_Stroker_Done(stroker);
-            }
-            else
-            {
-              DALI_LOG_ERROR("FT_Glyph_StrokeBorder Failed with error: %d\n", error);
-            }
+            FT_Stroker_Done(stroker);
+            isStrokeGlyphSuccess = true;
           }
           else
           {
-            DALI_LOG_ERROR("FT_Stroker_New Failed with error: %d\n", error);
+            DALI_LOG_ERROR("FT_Glyph_StrokeBorder Failed with error: %d\n", error);
           }
         }
+        else
+        {
+          DALI_LOG_ERROR("FT_Stroker_New Failed with error: %d\n", error);
+        }
+      }
+
+      const bool ableUseCachedRenderedGlyph = EnableCacheRenderedGlyph() && !isOutlineGlyph && !isShearRequired;
 
-        error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1);
+      // If we cache rendered glyph, and if we can use it, use cached thing first.
+      if(ableUseCachedRenderedGlyph && glyphData.mRenderedBuffer)
+      {
+        data.buffer          = glyphData.mRenderedBuffer->buffer;
+        data.width           = glyphData.mRenderedBuffer->width;
+        data.height          = glyphData.mRenderedBuffer->height;
+        data.format          = glyphData.mRenderedBuffer->format;
+        data.compressionType = glyphData.mRenderedBuffer->compressionType;
+        data.isBufferOwned   = false;
+      }
+      else
+      {
+        // Copy new glyph, and keep original cached glyph.
+        // If we already copy new glyph by stroke, just re-use that.
+        error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, isStrokeGlyphSuccess);
         if(FT_Err_Ok == error)
         {
           FT_BitmapGlyph bitmapGlyph = reinterpret_cast<FT_BitmapGlyph>(glyph);
@@ -334,23 +498,52 @@ void FontFaceCacheItem::CreateBitmap(
             data.outlineOffsetY = bitmapGlyph->top - offsetY - outlineWidth;
           }
 
-          ConvertBitmap(data, bitmapGlyph->bitmap, isShearRequired);
+          // If we can cache this bitmapGlyph, store it.
+          // Note : We will call this API once per each glyph.
+          if(ableUseCachedRenderedGlyph)
+          {
+            mGlyphCacheManager->CacheRenderedGlyphBuffer(glyphIndex, loadFlag, isBoldRequired, bitmapGlyph->bitmap, GetRenderedGlyphCompressPolicy());
+
+            GlyphCacheManager::GlyphCacheData dummyData;
+            mGlyphCacheManager->GetGlyphCacheDataFromIndex(glyphIndex, loadFlag, isBoldRequired, dummyData, error);
+
+            if(DALI_LIKELY(FT_Err_Ok == error && dummyData.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.isBufferOwned   = false;
+            }
+            else
+            {
+              // Something problem during cache or get rendered glyph buffer.
+              // Move bitmap buffer into data.buffer
+              ConvertBitmap(data, bitmapGlyph->bitmap, isShearRequired, true);
+            }
+          }
+          else
+          {
+            // Move bitmap buffer into data.buffer
+            ConvertBitmap(data, bitmapGlyph->bitmap, isShearRequired, true);
+          }
+
+          // Copied FT_Glyph object must be released with FT_Done_Glyph
+          FT_Done_Glyph(glyph);
         }
         else
         {
           DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "FontClient::Plugin::CreateBitmap. FT_Get_Glyph Failed with error: %d\n", error);
         }
       }
-      else
-      {
-        ConvertBitmap(data, ftFace->glyph->bitmap, isShearRequired);
-      }
-
-      data.isColorEmoji = mIsFixedSizeBitmap;
-
-      // Created FT_Glyph object must be released with FT_Done_Glyph
-      FT_Done_Glyph(glyph);
     }
+    else
+    {
+      ConvertBitmap(data, *glyphData.mBitmap, isShearRequired);
+    }
+
+    data.isColorEmoji = mIsFixedSizeBitmap;
   }
   else
   {
@@ -366,7 +559,8 @@ bool FontFaceCacheItem::IsColorGlyph(GlyphIndex glyphIndex) const
   // Check to see if this is fixed size bitmap
   if(mHasColorTables)
   {
-    error = FT_Load_Glyph(mFreeTypeFace, glyphIndex, FT_LOAD_COLOR);
+    GlyphCacheManager::GlyphCacheData dummyData;
+    mGlyphCacheManager->GetGlyphCacheDataFromIndex(glyphIndex, FT_LOAD_COLOR, false, dummyData, error);
   }
 #endif
   return FT_Err_Ok == error;
@@ -416,4 +610,14 @@ GlyphIndex FontFaceCacheItem::GetGlyphIndex(Character character, Character varia
   return FT_Face_GetCharVariantIndex(mFreeTypeFace, character, variantSelector);
 }
 
+HarfBuzzFontHandle FontFaceCacheItem::GetHarfBuzzFont(const uint32_t& horizontalDpi, const uint32_t& verticalDpi)
+{
+  // Create new harfbuzz font only first time or DPI changed.
+  if(DALI_UNLIKELY(!mHarfBuzzProxyFont || mHarfBuzzProxyFont->mHorizontalDpi != horizontalDpi || mHarfBuzzProxyFont->mVerticalDpi != verticalDpi))
+  {
+    mHarfBuzzProxyFont.reset(new HarfBuzzProxyFont(mFreeTypeFace, mRequestedPointSize, horizontalDpi, verticalDpi, mGlyphCacheManager.get()));
+  }
+  return mHarfBuzzProxyFont->GetHarfBuzzFont();
+}
+
 } // namespace Dali::TextAbstraction::Internal
index cf75b27..08baff7 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TEST_ABSTRACTION_INTERNAL_FONT_FACE_CACHE_ITEM_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  */
 
 // INTERNAL INCLUDES
-
 #include <dali/internal/text/text-abstraction/plugin/font-cache-item-interface.h>
+#include <dali/internal/text/text-abstraction/plugin/font-face-glyph-cache-manager.h>
+#include <dali/internal/text/text-abstraction/plugin/harfbuzz-proxy-font.h>
 
 // EXTERNAL INCLUDES
 #include <fontconfig/fontconfig.h>
+#include <memory> // for std::unique_ptr
 
 // EXTERNAL INCLUDES
 #include <ft2build.h>
@@ -57,6 +59,11 @@ struct FontFaceCacheItem : public FontCacheItemInterface
                     float              fixedHeight,
                     bool               hasColorTables);
 
+  FontFaceCacheItem(const FontFaceCacheItem& rhs) = delete; // Do not use copy construct
+  FontFaceCacheItem(FontFaceCacheItem&& rhs);
+
+  ~FontFaceCacheItem();
+
   /**
    * @copydoc FontCacheItemInterface::GetFontMetrics()
    */
@@ -65,7 +72,7 @@ struct FontFaceCacheItem : public FontCacheItemInterface
   /**
    * @copydoc FontCacheItemInterface::GetGlyphMetrics()
    */
-  bool GetGlyphMetrics(GlyphInfo& glyph, unsigned int dpiVertical, bool horizontal) const override;
+  bool GetGlyphMetrics(GlyphInfo& glyphInfo, unsigned int dpiVertical, bool horizontal) const override;
 
   /**
    * @copydoc FontCacheItemInterface::CreateBitmap()
@@ -109,6 +116,11 @@ struct FontFaceCacheItem : public FontCacheItemInterface
   }
 
   /**
+   * @copydoc FontCacheItemInterface::GetHarfBuzzFont()
+   */
+  HarfBuzzFontHandle GetHarfBuzzFont(const uint32_t& horizontalDpi, const uint32_t& verticalDpi) override;
+
+  /**
    * @copydoc FontCacheItemInterface::HasItalicStyle()
    */
   bool HasItalicStyle() const override
@@ -116,8 +128,13 @@ struct FontFaceCacheItem : public FontCacheItemInterface
     return (0u != (mFreeTypeFace->style_flags & FT_STYLE_FLAG_ITALIC));
   }
 
-  FT_Library&     mFreeTypeLibrary;       ///< A handle to a FreeType library instance.
-  FT_Face         mFreeTypeFace;          ///< The FreeType face.
+public:
+  FT_Library& mFreeTypeLibrary; ///< A handle to a FreeType library instance.
+  FT_Face     mFreeTypeFace;    ///< The FreeType face.
+
+  std::unique_ptr<GlyphCacheManager> mGlyphCacheManager; ///< The glyph cache manager. It will cache this face's glyphs.
+  std::unique_ptr<HarfBuzzProxyFont> mHarfBuzzProxyFont; ///< The harfbuzz font. It will store harfbuzz relate data.
+
   FontPath        mPath;                  ///< The path to the font file name.
   PointSize26Dot6 mRequestedPointSize;    ///< The font point size.
   FaceIndex       mFaceIndex;             ///< The face index.
diff --git a/dali/internal/text/text-abstraction/plugin/font-face-glyph-cache-manager.cpp b/dali/internal/text/text-abstraction/plugin/font-face-glyph-cache-manager.cpp
new file mode 100644 (file)
index 0000000..1ced0b5
--- /dev/null
@@ -0,0 +1,425 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// CLASS HEADER
+#include <dali/internal/text/text-abstraction/plugin/font-face-glyph-cache-manager.h>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/internal/imaging/common/image-operations.h>
+#include <dali/internal/text/text-abstraction/plugin/font-client-utils.h>
+
+// EXTERNAL INCLUDES
+#include FT_BITMAP_H
+
+#if defined(DEBUG_ENABLED)
+extern Dali::Integration::Log::Filter* gFontClientLogFilter;
+#endif
+
+namespace Dali::TextAbstraction::Internal
+{
+namespace
+{
+constexpr uint32_t THRESHOLD_WIDTH_FOR_RLE4_COMPRESSION = 8; // The smallest width of glyph that we use RLE4 method.
+} // namespace
+
+GlyphCacheManager::GlyphCacheManager(FT_Face ftFace, std::size_t maxNumberOfGlyphCache)
+: mFreeTypeFace(ftFace),
+  mGlyphCacheMaxSize(maxNumberOfGlyphCache),
+  mLRUGlyphCache(mGlyphCacheMaxSize)
+{
+  DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, "FontClient::Plugin::GlyphCacheManager Create with maximum size : %d\n", static_cast<int>(mGlyphCacheMaxSize));
+}
+
+GlyphCacheManager::~GlyphCacheManager()
+{
+  while(!mLRUGlyphCache.IsEmpty())
+  {
+    auto removedData = mLRUGlyphCache.Pop();
+
+    // Release Glyph data resource
+    removedData.ReleaseGlyphData();
+  }
+  mLRUGlyphCache.Clear();
+}
+
+bool GlyphCacheManager::GetGlyphCacheDataFromIndex(
+  const GlyphIndex index,
+  const FT_Int32   flag,
+  const bool       isBoldRequired,
+  GlyphCacheData&  glyphData,
+  FT_Error&        error)
+{
+  // Append some error value here instead of FT_Err_Ok.
+  error = static_cast<FT_Error>(-1);
+
+  const GlyphCacheKey key  = GlyphCacheKey(index, flag, isBoldRequired);
+  auto                iter = mLRUGlyphCache.Find(key);
+
+  if(iter == mLRUGlyphCache.End())
+  {
+    // If cache size is full, remove oldest glyph.
+    if(mLRUGlyphCache.IsFull())
+    {
+      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();
+    }
+
+    const bool loadSuccess = LoadGlyphDataFromIndex(index, flag, isBoldRequired, glyphData, error);
+    if(loadSuccess)
+    {
+      // Copy and cached data.
+      mLRUGlyphCache.Push(key, glyphData);
+
+      DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, "FontClient::Plugin::GlyphCacheManager::GetGlyphCacheDataFromIndex. Create cache for index : %u flag : %d isBold : %d isBitmap : %d, glyph : %p\n", index, static_cast<int>(flag), isBoldRequired, glyphData.mIsBitmap, glyphData.mGlyph);
+    }
+
+    return loadSuccess;
+  }
+  else
+  {
+    error = FT_Err_Ok;
+
+    // We already notify that we use this glyph. And now, copy cached data.
+    glyphData = iter->element;
+
+    DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, "FontClient::Plugin::GlyphCacheManager::GetGlyphCacheDataFromIndex. Find cache for index : %u flag : %d isBold : %d isBitmap : %d, glyph : %p\n", index, static_cast<int>(flag), isBoldRequired, glyphData.mIsBitmap, glyphData.mGlyph);
+    return true;
+  }
+}
+
+bool GlyphCacheManager::LoadGlyphDataFromIndex(
+  const GlyphIndex index,
+  const FT_Int32   flag,
+  const bool       isBoldRequired,
+  GlyphCacheData&  glyphData,
+  FT_Error&        error)
+{
+  error = FT_Load_Glyph(mFreeTypeFace, index, flag);
+  if(FT_Err_Ok == error)
+  {
+    glyphData.mStyleFlags = mFreeTypeFace->style_flags;
+
+    const bool isEmboldeningRequired = isBoldRequired && !(glyphData.mStyleFlags & FT_STYLE_FLAG_BOLD);
+    if(isEmboldeningRequired)
+    {
+      // Does the software bold.
+      FT_GlyphSlot_Embolden(mFreeTypeFace->glyph);
+    }
+
+    glyphData.mGlyphMetrics = mFreeTypeFace->glyph->metrics;
+    glyphData.mIsBitmap     = false;
+    // Load glyph
+    error = FT_Get_Glyph(mFreeTypeFace->glyph, &glyphData.mGlyph);
+
+    if(glyphData.mGlyph->format == FT_GLYPH_FORMAT_BITMAP)
+    {
+      // Copy original glyph infomation. Due to we use union, we should keep original handle.
+      FT_Glyph bitmapGlyph = glyphData.mGlyph;
+
+      // Copy rendered bitmap
+      // TODO : Is there any way to keep bitmap buffer without copy?
+      glyphData.mBitmap  = new FT_Bitmap();
+      *glyphData.mBitmap = mFreeTypeFace->glyph->bitmap;
+
+      // New allocate buffer
+      size_t bufferSize = 0;
+      switch(glyphData.mBitmap->pixel_mode)
+      {
+        case FT_PIXEL_MODE_GRAY:
+        {
+          if(glyphData.mBitmap->pitch == static_cast<int>(glyphData.mBitmap->width))
+          {
+            bufferSize = static_cast<size_t>(glyphData.mBitmap->width) * static_cast<size_t>(glyphData.mBitmap->rows);
+          }
+          break;
+        }
+#ifdef FREETYPE_BITMAP_SUPPORT
+        case FT_PIXEL_MODE_BGRA:
+        {
+          if(glyphData.mBitmap->pitch == static_cast<int>(glyphData.mBitmap->width << 2u))
+          {
+            bufferSize = (static_cast<size_t>(glyphData.mBitmap->width) * static_cast<size_t>(glyphData.mBitmap->rows)) << 2u;
+          }
+          break;
+        }
+#endif
+        default:
+        {
+          DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "FontClient::Plugin::GlyphCacheManager::LoadGlyphDataFromIndex. FontClient Unable to create Bitmap of this PixelType\n");
+          break;
+        }
+      }
+
+      if(bufferSize > 0)
+      {
+        glyphData.mIsBitmap       = true;
+        glyphData.mBitmap->buffer = (uint8_t*)malloc(bufferSize * sizeof(uint8_t)); // @note The caller is responsible for deallocating the bitmap data using free.
+        memcpy(glyphData.mBitmap->buffer, mFreeTypeFace->glyph->bitmap.buffer, bufferSize);
+      }
+      else
+      {
+        DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "FontClient::Plugin::GlyphCacheManager::LoadGlyphDataFromIndex. Bitmap glyph buffer size is zero\n");
+        delete glyphData.mBitmap;
+        glyphData.mBitmap = nullptr;
+        error             = static_cast<FT_Error>(-1);
+      }
+
+      // Release glyph data.
+      FT_Done_Glyph(bitmapGlyph);
+    }
+
+    if(FT_Err_Ok == error)
+    {
+      return true;
+    }
+  }
+  return false;
+}
+
+void GlyphCacheManager::ResizeBitmapGlyph(
+  const GlyphIndex index,
+  const FT_Int32   flag,
+  const bool       isBoldRequired,
+  const uint32_t   desiredWidth,
+  const uint32_t   desiredHeight)
+{
+  if(desiredWidth * desiredHeight <= 0)
+  {
+    // Skip this API if desired size is zero
+    return;
+  }
+  FT_Error       error;
+  GlyphCacheData originGlyphData;
+  if(GetGlyphCacheDataFromIndex(index, flag, isBoldRequired, originGlyphData, error))
+  {
+    if(DALI_LIKELY(originGlyphData.mIsBitmap && originGlyphData.mBitmap))
+    {
+      const bool requiredResize = (originGlyphData.mBitmap->rows != desiredHeight) || (originGlyphData.mBitmap->width != desiredWidth);
+      if(requiredResize)
+      {
+        // originalGlyphData is copy data. For change cached information, we should access as iterator.
+        const GlyphCacheKey key  = GlyphCacheKey(index, flag, isBoldRequired);
+        auto                iter = mLRUGlyphCache.Find(key);
+
+        GlyphCacheData& destinationGlpyhData = iter->element;
+
+        const ImageDimensions inputDimensions(destinationGlpyhData.mBitmap->width, destinationGlpyhData.mBitmap->rows);
+        const ImageDimensions desiredDimensions(desiredWidth, desiredHeight);
+
+        uint8_t* desiredBuffer = nullptr;
+
+        switch(destinationGlpyhData.mBitmap->pixel_mode)
+        {
+          case FT_PIXEL_MODE_GRAY:
+          {
+            if(destinationGlpyhData.mBitmap->pitch == static_cast<int>(destinationGlpyhData.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,
+                                                          inputDimensions,
+                                                          destinationGlpyhData.mBitmap->width,
+                                                          desiredBuffer,
+                                                          desiredDimensions);
+            }
+            break;
+          }
+#ifdef FREETYPE_BITMAP_SUPPORT
+          case FT_PIXEL_MODE_BGRA:
+          {
+            if(destinationGlpyhData.mBitmap->pitch == static_cast<int>(destinationGlpyhData.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,
+                                                          inputDimensions,
+                                                          destinationGlpyhData.mBitmap->width,
+                                                          desiredBuffer,
+                                                          desiredDimensions);
+            }
+            break;
+          }
+#endif
+          default:
+          {
+            DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "FontClient::Plugin::GlyphCacheManager::ResizeBitmapGlyph. FontClient Unable to create Bitmap of this PixelType\n");
+            break;
+          }
+        }
+
+        if(desiredBuffer)
+        {
+          // Success to resize bitmap glyph.
+          // Release origin bitmap buffer.
+          free(destinationGlpyhData.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)
+          {
+            case FT_PIXEL_MODE_GRAY:
+            {
+              destinationGlpyhData.mBitmap->pitch = desiredWidth;
+              break;
+            }
+#ifdef FREETYPE_BITMAP_SUPPORT
+            case FT_PIXEL_MODE_BGRA:
+            {
+              destinationGlpyhData.mBitmap->pitch = desiredWidth << 2u;
+              break;
+            }
+#endif
+          }
+        }
+      }
+    }
+  }
+}
+
+void GlyphCacheManager::CacheRenderedGlyphBuffer(
+  const GlyphIndex            index,
+  const FT_Int32              flag,
+  const bool                  isBoldRequired,
+  const FT_Bitmap&            srcBitmap,
+  const CompressionPolicyType policy)
+{
+  if(srcBitmap.width * srcBitmap.rows <= 0)
+  {
+    // Skip this API if rendered bitmap size is zero
+    return;
+  }
+  FT_Error       error;
+  GlyphCacheData originGlyphData;
+  if(GetGlyphCacheDataFromIndex(index, flag, isBoldRequired, originGlyphData, error))
+  {
+    if(DALI_LIKELY(!originGlyphData.mIsBitmap && originGlyphData.mRenderedBuffer == nullptr))
+    {
+      // originalGlyphData is copy data. For change cached information, we should access as iterator.
+      const GlyphCacheKey key  = GlyphCacheKey(index, flag, isBoldRequired);
+      auto                iter = mLRUGlyphCache.Find(key);
+
+      GlyphCacheData& destinationGlpyhData = iter->element;
+
+      destinationGlpyhData.mRenderedBuffer = new TextAbstraction::FontClient::GlyphBufferData();
+      if(DALI_UNLIKELY(!destinationGlpyhData.mRenderedBuffer))
+      {
+        DALI_LOG_ERROR("Allocate GlyphBufferData failed\n");
+        return;
+      }
+
+      TextAbstraction::FontClient::GlyphBufferData& renderBuffer = *destinationGlpyhData.mRenderedBuffer;
+
+      // Set basic informations.
+      renderBuffer.width  = srcBitmap.width;
+      renderBuffer.height = srcBitmap.rows;
+
+      switch(srcBitmap.pixel_mode)
+      {
+        case FT_PIXEL_MODE_GRAY:
+        {
+          renderBuffer.format = Pixel::L8;
+
+          if(policy == CompressionPolicyType::SPEED)
+          {
+            // If policy is SPEED, we will not compress bitmap.
+            renderBuffer.compressionType = TextAbstraction::FontClient::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;
+            }
+            else
+            {
+              renderBuffer.compressionType = TextAbstraction::FontClient::GlyphBufferData::CompressionType::RLE_4;
+            }
+          }
+
+          const auto compressedBufferSize = TextAbstraction::FontClient::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;
+            return;
+          }
+          break;
+        }
+#ifdef FREETYPE_BITMAP_SUPPORT
+        case FT_PIXEL_MODE_BGRA:
+        {
+          // Copy buffer without compress
+          renderBuffer.compressionType = TextAbstraction::FontClient::GlyphBufferData::CompressionType::NO_COMPRESSION;
+          renderBuffer.format          = Pixel::BGRA8888;
+
+          const auto compressedBufferSize = TextAbstraction::FontClient::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;
+            return;
+          }
+          break;
+        }
+#endif
+        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;
+          break;
+        }
+      }
+    }
+  }
+}
+
+void GlyphCacheManager::GlyphCacheData::ReleaseGlyphData()
+{
+  if(mIsBitmap && mBitmap)
+  {
+    // Created FT_Bitmap object must be released with FT_Bitmap_Done
+    free(mBitmap->buffer); // This buffer created by malloc
+
+    delete mBitmap;
+    mBitmap = nullptr;
+  }
+  else if(mGlyph)
+  {
+    // Created FT_Glyph object must be released with FT_Done_Glyph
+    FT_Done_Glyph(mGlyph);
+    mGlyph = nullptr;
+  }
+
+  if(mRenderedBuffer)
+  {
+    delete mRenderedBuffer;
+  }
+}
+
+} // namespace Dali::TextAbstraction::Internal
diff --git a/dali/internal/text/text-abstraction/plugin/font-face-glyph-cache-manager.h b/dali/internal/text/text-abstraction/plugin/font-face-glyph-cache-manager.h
new file mode 100644 (file)
index 0000000..fd0eb05
--- /dev/null
@@ -0,0 +1,211 @@
+#ifndef DALI_TEST_ABSTRACTION_INTERNAL_FONT_FACE_GLYPH_CACHE_MANAGER_H
+#define DALI_TEST_ABSTRACTION_INTERNAL_FONT_FACE_GLYPH_CACHE_MANAGER_H
+
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/font-client.h> // For GlyphBufferData
+#include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
+#include <dali/internal/text/text-abstraction/plugin/lru-cache-container.h>
+
+// EXTERNAL INCLUDES
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_GLYPH_H
+
+namespace Dali::TextAbstraction::Internal
+{
+/**
+ * @brief Helper class to load and cache some glyphs of FT_Face.
+ */
+class GlyphCacheManager
+{
+public:
+  // Constructor
+  GlyphCacheManager(FT_Face ftFace, std::size_t maxNumberOfGlyphCache);
+
+  // Destructor
+  ~GlyphCacheManager();
+
+  GlyphCacheManager(const GlyphCacheManager& rhs) = delete; // Do not use copy construct
+  GlyphCacheManager(GlyphCacheManager&& rhs)      = delete; // Do not use move construct
+
+public:
+  // Public struct area.
+
+  /**
+   * @brief Result informations of glyph. It can be whether FT_Glyph or FT_Bitmap type.
+   * @note FontFaceCacheItem could use this.
+   */
+  struct GlyphCacheData
+  {
+    GlyphCacheData()
+    : mGlyph{nullptr}
+    {
+    }
+
+    union
+    {
+      FT_Glyph   mGlyph;
+      FT_Bitmap* mBitmap;
+    };
+    FT_Glyph_Metrics_ mGlyphMetrics{}; // Get from FT_GlyphSlot
+    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
+
+    /**
+     * @brief Release the memory of loaded mGlyph / mBitmap.
+     */
+    void ReleaseGlyphData();
+  };
+
+  // Compression priority of rendered glyph buffer.
+  enum class CompressionPolicyType
+  {
+    SPEED  = 0,
+    MEMORY = 1,
+  };
+
+public:
+  // Public API area.
+
+  /**
+   * @brief Load GlyphCacheData from face. The result will be cached.
+   *
+   * @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] error Error code during load glyph.
+   * @return True if load successfully. False if something error occured.
+   */
+  bool GetGlyphCacheDataFromIndex(
+    const GlyphIndex index,
+    const FT_Int32   flag,
+    const bool       isBoldRequired,
+    GlyphCacheData&  data,
+    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] 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] error Error code during load glyph.
+   * @return True if load successfully. False if something error occured.
+   */
+  bool LoadGlyphDataFromIndex(
+    const GlyphIndex index,
+    const FT_Int32   flag,
+    const bool       isBoldRequired,
+    GlyphCacheData&  data,
+    FT_Error&        error);
+
+  /**
+   * @brief Resize bitmap glyph. The result will change cached glyph bitmap information.
+   * If glyph is not bitmap glyph, nothing happened.
+   *
+   * @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[in] desiredWidth Desired width of bitmap.
+   * @param[in] desiredHeight Desired height of bitmap.
+   */
+  void ResizeBitmapGlyph(
+    const GlyphIndex index,
+    const FT_Int32   flag,
+    const bool       isBoldRequired,
+    const uint32_t   desiredWidth,
+    const uint32_t   desiredHeight);
+
+  /**
+   * @brief Cache rendered glyph bitmap. The result will change cached glyph information.
+   * If glyph is not single color glyph, or we already cached buffer before, nothing happened.
+   *
+   * @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[in] srcBitmap Rendered glyph bitmap.
+   * @param[in] policy Compress behavior policy.
+   */
+  void CacheRenderedGlyphBuffer(
+    const GlyphIndex            index,
+    const FT_Int32              flag,
+    const bool                  isBoldRequired,
+    const FT_Bitmap&            srcBitmap,
+    const CompressionPolicyType policy);
+
+private:
+  // Private struct area.
+  /**
+   * @brief Key of cached glyph.
+   */
+  struct GlyphCacheKey
+  {
+    GlyphCacheKey()
+    : mIndex(0u),
+      mFlag(0),
+      mIsBoldRequired(false)
+    {
+    }
+
+    GlyphCacheKey(const GlyphIndex index, const FT_Int32 flag, const bool boldRequired)
+    : mIndex(index),
+      mFlag(flag),
+      mIsBoldRequired(boldRequired)
+    {
+    }
+    GlyphIndex mIndex;
+    FT_Int32   mFlag;
+    bool       mIsBoldRequired : 1;
+
+    bool operator==(GlyphCacheKey const& rhs) const noexcept
+    {
+      return mIndex == rhs.mIndex && mFlag == rhs.mFlag && mIsBoldRequired == rhs.mIsBoldRequired;
+    }
+  };
+
+  /**
+   * @brief Hash function of GlyphCacheKey.
+   */
+  struct GlyphCacheKeyHash
+  {
+    std::size_t operator()(GlyphCacheKey const& key) const noexcept
+    {
+      return static_cast<std::size_t>(key.mIndex) ^ static_cast<std::size_t>(key.mFlag) ^ (static_cast<std::size_t>(key.mIsBoldRequired) << 29);
+    }
+  };
+
+private:
+  // Private member value area.
+  FT_Face mFreeTypeFace; ///< The FreeType face. Owned from font-face-cache-item
+
+  std::size_t mGlyphCacheMaxSize; ///< The maximum capacity of glyph cache.
+
+  using CacheContainer = LRUCacheContainer<GlyphCacheKey, GlyphCacheData, GlyphCacheKeyHash>;
+
+  CacheContainer mLRUGlyphCache; ///< LRU Cache container of glyph
+};
+
+} // namespace Dali::TextAbstraction::Internal
+
+#endif //DALI_TEST_ABSTRACTION_INTERNAL_FONT_FACE_GLYPH_CACHE_MANAGER_H
diff --git a/dali/internal/text/text-abstraction/plugin/harfbuzz-proxy-font.cpp b/dali/internal/text/text-abstraction/plugin/harfbuzz-proxy-font.cpp
new file mode 100644 (file)
index 0000000..5d62a95
--- /dev/null
@@ -0,0 +1,441 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/internal/text/text-abstraction/plugin/harfbuzz-proxy-font.h>
+
+// EXTERNAL INCLUDES
+#include FT_GLYPH_H
+#include <harfbuzz/hb-ft.h>
+#include <harfbuzz/hb.h>
+
+#if defined(DEBUG_ENABLED)
+extern Dali::Integration::Log::Filter* gFontClientLogFilter;
+#endif
+
+namespace Dali::TextAbstraction::Internal
+{
+/**
+ * @brief Helper class to create and destroy harfbuzz font, and hold data in harfbuzz callback
+ * It also cache informations what harfbuzz font need to be created.
+ */
+struct HarfBuzzProxyFont::Impl
+{
+  /**
+   * @brief Constructor.
+   *
+   * @param[in] freeTypeFace The FreeType face.
+   * @param[in] glyphCacheManager Glyph caching system for this harfbuzz font. It will be used as harfbuzz callback data.
+   */
+  Impl(FT_Face freeTypeFace, GlyphCacheManager* glyphCacheManager)
+  : mFreeTypeFace(freeTypeFace),
+    mGlyphCacheManager(glyphCacheManager),
+    mHarfBuzzFont(nullptr)
+  {
+  }
+
+  // Destructor
+  ~Impl()
+  {
+    if(mHarfBuzzFont)
+    {
+      // It will reduce reference of freetype face automatically.
+      hb_font_destroy(mHarfBuzzFont);
+    }
+  }
+
+public:
+  /**
+   * @brief Create new harfbuzz font.
+   *
+   * @param[in] requestedPointSize The requiested point size of font.
+   * @param[in] horizontalDpi Horizontal DPI.
+   * @param[in] verticalDpi Vertical DPI.
+   */
+  void CreateHarfBuzzFont(const PointSize26Dot6& requestedPointSize, const uint32_t& horizontalDpi, const uint32_t& verticalDpi);
+
+private:
+  /**
+   * @brief Register harfbuzz callback functions into current harfbuzz font.
+   */
+  void SetHarfBuzzFunctions();
+
+public:
+  FT_Face            mFreeTypeFace;      ///< The FreeType face. Owned from font-face-cache-item.
+  GlyphCacheManager* mGlyphCacheManager; ///< Glyph caching system for this harfbuzz font. Owned from font-face-cache-item.
+
+  hb_font_t* mHarfBuzzFont; ///< Harfbuzz font handle integrated with FT_Face.
+};
+
+HarfBuzzProxyFont::HarfBuzzProxyFont(FT_Face freeTypeFace, const PointSize26Dot6& requestedPointSize, const uint32_t& horizontalDpi, const uint32_t& verticalDpi, GlyphCacheManager* glyphCacheManager)
+: mHorizontalDpi(horizontalDpi),
+  mVerticalDpi(verticalDpi),
+  mImpl(new Impl(freeTypeFace, glyphCacheManager))
+{
+  mImpl->CreateHarfBuzzFont(requestedPointSize, mHorizontalDpi, mVerticalDpi);
+}
+
+HarfBuzzProxyFont::~HarfBuzzProxyFont()
+{
+  if(mImpl)
+  {
+    delete mImpl;
+  }
+}
+
+HarfBuzzFontHandle HarfBuzzProxyFont::GetHarfBuzzFont() const
+{
+  if(mImpl)
+  {
+    return static_cast<HarfBuzzFontHandle>(mImpl->mHarfBuzzFont);
+  }
+  return nullptr;
+}
+
+// Collection of harfbuzz custom callback functions.
+// Reference : https://github.com/harfbuzz/harfbuzz/blob/main/src/hb-ft.cc
+namespace
+{
+/**
+ * @brief Get glyph informations by dali glyph cache system.
+ *
+ * @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.
+ * @return True if we success to get some glyph data. False otherwise.
+ */
+static bool GetGlyphCacheData(void* font_data, const GlyphIndex& glyphIndex, GlyphCacheManager::GlyphCacheData& glyphData)
+{
+  HarfBuzzProxyFont::Impl* impl = reinterpret_cast<HarfBuzzProxyFont::Impl*>(font_data);
+
+  // Note : HarfBuzz used only FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING internally.
+  if(DALI_LIKELY(impl && impl->mGlyphCacheManager))
+  {
+    FT_Error error;
+    return impl->mGlyphCacheManager->GetGlyphCacheDataFromIndex(glyphIndex, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING, false, glyphData, error);
+  }
+  return false;
+}
+
+/**
+ * @brief Calculate font extents value both in vertical and horizontal.
+ *
+ * @param[in] font Current harfbuzz font data.
+ * @param[in] font_data HarfBuzzProxyFont::Impl pointer that register this callback as void* type.
+ * @param[out] extents Extents value of font. (scale as 26.6)
+ * @param[in] user_data Registered user data.
+ * @return True if we success to get font extents. False otherwise.
+ */
+static hb_bool_t FontExtentsFunc(hb_font_t* font, void* font_data, hb_font_extents_t* extents, void* user_data)
+{
+  HarfBuzzProxyFont::Impl* impl = reinterpret_cast<HarfBuzzProxyFont::Impl*>(font_data);
+
+  if(DALI_LIKELY(impl && impl->mFreeTypeFace))
+  {
+    FT_Size_Metrics& ftMetrics = impl->mFreeTypeFace->size->metrics;
+
+    extents->ascender  = ftMetrics.ascender;
+    extents->descender = ftMetrics.descender;
+    extents->line_gap  = ftMetrics.height - (extents->ascender - extents->descender);
+
+    return true;
+  }
+  return false;
+}
+
+/**
+ * @brief Convert from character into index of glyph.
+ *
+ * @param[in] font Current harfbuzz font data.
+ * @param[in] font_data HarfBuzzProxyFont::Impl pointer that register this callback as void* type.
+ * @param[in] character The value of character what we want to get index.
+ * @param[out] glyphIndex Index of glyph that current font face used.
+ * @param[in] user_data Registered user data.
+ * @return True if we success to convert.
+ */
+static hb_bool_t GlyphNormalIndexConvertFunc(hb_font_t* font, void* font_data, hb_codepoint_t character, hb_codepoint_t* glyphIndex, void* user_data)
+{
+  HarfBuzzProxyFont::Impl* impl = reinterpret_cast<HarfBuzzProxyFont::Impl*>(font_data);
+
+  if(DALI_LIKELY(impl && impl->mFreeTypeFace))
+  {
+    *glyphIndex = FT_Get_Char_Index(impl->mFreeTypeFace, character);
+    return *glyphIndex != 0;
+  }
+  return false;
+}
+
+/**
+ * @brief Convert from character and variant selector into index of glyph.
+ *
+ * @param[in] font Current harfbuzz font data.
+ * @param[in] font_data HarfBuzzProxyFont::Impl pointer that register this callback as void* type.
+ * @param[in] character The value of character what we want to get index.
+ * @param[in] variantSelector Variant selector.
+ * @param[out] glyphIndex Index of glyph that current font face used.
+ * @param[in] user_data Registered user data.
+ * @return True if we success to convert.
+ */
+static hb_bool_t GlyphVariantIndexConvertFunc(hb_font_t* font, void* font_data, hb_codepoint_t character, hb_codepoint_t variantSelector, hb_codepoint_t* glyphIndex, void* user_data)
+{
+  HarfBuzzProxyFont::Impl* impl = reinterpret_cast<HarfBuzzProxyFont::Impl*>(font_data);
+
+  if(DALI_LIKELY(impl && impl->mFreeTypeFace))
+  {
+    *glyphIndex = FT_Face_GetCharVariantIndex(impl->mFreeTypeFace, character, variantSelector);
+    return *glyphIndex != 0;
+  }
+  return false;
+}
+
+/**
+ * @brief Calculate glyph advance value in horizontal.
+ *
+ * @param[in] font Current harfbuzz font data.
+ * @param[in] font_data HarfBuzzProxyFont::Impl pointer that register this callback as void* type.
+ * @param[in] glyphIndex Index of glyph.
+ * @param[in] user_data Registered user data.
+ * @return Horizontal advance value of glyphIndex. (scale as 26.6)
+ */
+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))
+  {
+    // 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.
+    return static_cast<hb_position_t>(glyphData.mGlyphMetrics.horiAdvance);
+  }
+  return 0;
+}
+/**
+ * @brief Calculate glyph advance value in vertical.
+ *
+ * @param[in] font Current harfbuzz font data.
+ * @param[in] font_data HarfBuzzProxyFont::Impl pointer that register this callback as void* type.
+ * @param[in] glyphIndex Index of glyph.
+ * @param[in] user_data Registered user data.
+ * @return Vertical advance value of glyphIndex. (scale as 26.6)
+ */
+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))
+  {
+    // 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.
+    return static_cast<hb_position_t>(glyphData.mGlyphMetrics.vertAdvance);
+  }
+  return 0;
+}
+
+/**
+ * @brief Calculate glyph origin position value in horizontal.
+ *
+ * @param[in] font Current harfbuzz font data.
+ * @param[in] font_data HarfBuzzProxyFont::Impl that register this callback as void* type.
+ * @param[in] glyphIndex Index of glyph.
+ * @param[out] x Origin position x (scale as 26.6)
+ * @param[out] y Origin position y (scale as 26.6)
+ * @param[in] user_data Registered user data.
+ * @return True if we get data successfully. False if some error occured.
+ */
+static hb_bool_t GlyphHorizontalOriginFunc(hb_font_t* font, void* font_data, hb_codepoint_t glyphIndex, hb_position_t* x, hb_position_t* y, void* user_data)
+{
+  // Nothing to do
+  return true;
+}
+/**
+ * @brief Calculate glyph origin position value in vertical.
+ *
+ * @param[in] font Current harfbuzz font data.
+ * @param[in] font_data HarfBuzzProxyFont::Impl pointer that register this callback as void* type.
+ * @param[in] glyphIndex Index of glyph.
+ * @param[out] x Origin position x (scale as 26.6)
+ * @param[out] y Origin position y (scale as 26.6)
+ * @param[in] user_data Registered user data.
+ * @return True if we get data successfully. False if some error occured.
+ */
+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))
+  {
+    *x = glyphData.mGlyphMetrics.horiBearingX - glyphData.mGlyphMetrics.vertBearingX;
+    *y = glyphData.mGlyphMetrics.horiBearingY + glyphData.mGlyphMetrics.vertBearingY;
+    return true;
+  }
+  return false;
+}
+
+/**
+ * @brief Calculate glyph kerning value in horizontal.
+ *
+ * @param[in] font Current harfbuzz font data.
+ * @param[in] font_data HarfBuzzProxyFont::Impl pointer that register this callback as void* type.
+ * @param[in] glyphIndex1 First index of glyph to get kerning.
+ * @param[in] glyphIndex2 Second index of glyph to get kerning.
+ * @param[in] user_data Registered user data.
+ * @return Horizontal kerning position. (scale as 26.6)
+ */
+static hb_position_t GlyphHorizontalKerningFunc(hb_font_t* font, void* font_data, hb_codepoint_t glyphIndex1, hb_codepoint_t glyphIndex2, void* user_data)
+{
+  HarfBuzzProxyFont::Impl* impl = reinterpret_cast<HarfBuzzProxyFont::Impl*>(font_data);
+
+  if(DALI_LIKELY(impl && impl->mFreeTypeFace))
+  {
+    FT_Error  error;
+    FT_Vector kerning;
+
+    error = FT_Get_Kerning(impl->mFreeTypeFace, glyphIndex1, glyphIndex2, FT_KERNING_UNSCALED, &kerning);
+    if(error == FT_Err_Ok)
+    {
+      return kerning.x;
+    }
+  }
+  return 0;
+}
+/**
+ * @brief Calculate glyph kerning value in vertical.
+ *
+ * @param[in] font Current harfbuzz font data.
+ * @param[in] font_data HarfBuzzProxyFont::Impl pointer that register this callback as void* type.
+ * @param[in] glyphIndex1 First index of glyph to get kerning.
+ * @param[in] glyphIndex2 Second index of glyph to get kerning.
+ * @param[in] user_data Registered user data.
+ * @return Vertical kerning position. (scale as 26.6)
+ */
+static hb_position_t GlyphVerticalKerningFunc(hb_font_t* font, void* font_data, hb_codepoint_t glyphIndex1, hb_codepoint_t glyphIndex2, void* user_data)
+{
+  // FreeType doesn't support vertical kerning
+  return 0;
+}
+
+/**
+ * @brief Calculate glyph extents.
+ *
+ * @param[in] font Current harfbuzz font data.
+ * @param[in] font_data HarfBuzzProxyFont::Impl pointer that register this callback as void* type.
+ * @param[in] glyphIndex Index of glyph.
+ * @param[out] extents Extents value of glyph. (scale as 26.6)
+ * @param[in] user_data Registered user data.
+ * @return True if we get data successfully. False if some error occured.
+ */
+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))
+  {
+    extents->x_bearing = glyphData.mGlyphMetrics.horiBearingX;
+    extents->y_bearing = glyphData.mGlyphMetrics.horiBearingY;
+    extents->width     = glyphData.mGlyphMetrics.width;
+    extents->height    = glyphData.mGlyphMetrics.height;
+    return true;
+  }
+  return false;
+}
+
+} // namespace
+
+void HarfBuzzProxyFont::Impl::CreateHarfBuzzFont(const PointSize26Dot6& requestedPointSize, const uint32_t& horizontalDpi, const uint32_t& verticalDpi)
+{
+  // Destroy previous hb_font_t if exist.
+  if(mHarfBuzzFont)
+  {
+    // It will reduce reference of freetype face automatically.
+    hb_font_destroy(mHarfBuzzFont);
+    mHarfBuzzFont = nullptr;
+  }
+
+  if(mFreeTypeFace)
+  {
+    // Before create hb_font_t, we must set FT_Char_Size
+    FT_Set_Char_Size(mFreeTypeFace,
+                     0u,
+                     requestedPointSize,
+                     horizontalDpi,
+                     verticalDpi);
+
+    // Create font face with increase font face's reference.
+    mHarfBuzzFont = hb_ft_font_create_referenced(mFreeTypeFace);
+
+    SetHarfBuzzFunctions();
+
+    if(mHarfBuzzFont)
+    {
+      DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "FontClient::Plugin::HarfBuzzManager::GetHarfBuzzFont. Create new harfbuzz font : %p freetype face : %p. Requested point size : %u, dpi : horizon %u vertial %u\n", mHarfBuzzFont, mFreeTypeFace, requestedPointSize, horizontalDpi, verticalDpi);
+    }
+    else
+    {
+      DALI_LOG_ERROR("ERROR! failed to create harfbuzz font.");
+    }
+  }
+  else
+  {
+    DALI_LOG_ERROR("ERROR! freetype face is null! something unknown problem occured.");
+  }
+}
+
+void HarfBuzzProxyFont::Impl::SetHarfBuzzFunctions()
+{
+  if(mHarfBuzzFont)
+  {
+    hb_font_funcs_t* customFunctions = hb_font_funcs_create();
+
+    if(customFunctions)
+    {
+      // Bind custom functions here
+      hb_font_funcs_set_font_h_extents_func(customFunctions, FontExtentsFunc, 0, 0);
+      hb_font_funcs_set_font_v_extents_func(customFunctions, FontExtentsFunc, 0, 0);
+
+      hb_font_funcs_set_nominal_glyph_func(customFunctions, GlyphNormalIndexConvertFunc, 0, 0);
+      hb_font_funcs_set_variation_glyph_func(customFunctions, GlyphVariantIndexConvertFunc, 0, 0);
+
+      hb_font_funcs_set_glyph_h_advance_func(customFunctions, GlyphHorizontalAdvanceFunc, 0, 0);
+      hb_font_funcs_set_glyph_v_advance_func(customFunctions, GlyphVerticalAdvanceFunc, 0, 0);
+      hb_font_funcs_set_glyph_extents_func(customFunctions, GlyphExtentsFunc, 0, 0);
+
+      hb_font_funcs_set_glyph_h_origin_func(customFunctions, GlyphHorizontalOriginFunc, 0, 0);
+      hb_font_funcs_set_glyph_v_origin_func(customFunctions, GlyphVerticalOriginFunc, 0, 0);
+      hb_font_funcs_set_glyph_h_kerning_func(customFunctions, GlyphHorizontalKerningFunc, 0, 0);
+      hb_font_funcs_set_glyph_v_kerning_func(customFunctions, GlyphVerticalKerningFunc, 0, 0);
+
+      // Set custom functions into our own harfbuzz font
+      hb_font_set_funcs(mHarfBuzzFont, customFunctions, this, 0);
+
+      // We must release functions type what we create.
+      hb_font_funcs_destroy(customFunctions);
+    }
+    else
+    {
+      DALI_LOG_ERROR("ERROR! Fail to create custom harfbuzz functions.");
+
+      // Something wrong while create harfbuzz font. Destory it.
+      // It will reduce reference of freetype face automatically.
+      hb_font_destroy(mHarfBuzzFont);
+      mHarfBuzzFont = nullptr;
+    }
+  }
+}
+
+} // namespace Dali::TextAbstraction::Internal
diff --git a/dali/internal/text/text-abstraction/plugin/harfbuzz-proxy-font.h b/dali/internal/text/text-abstraction/plugin/harfbuzz-proxy-font.h
new file mode 100644 (file)
index 0000000..a14f2f7
--- /dev/null
@@ -0,0 +1,79 @@
+#ifndef DALI_TEXT_ABSTRACTION_INTERNAL_HARFBUZZ_PROXY_FONT_H
+#define DALI_TEXT_ABSTRACTION_INTERNAL_HARFBUZZ_PROXY_FONT_H
+
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
+#include <dali/internal/text/text-abstraction/font-client-impl.h> // for HarfBuzzFontHandle
+#include <dali/internal/text/text-abstraction/plugin/font-face-glyph-cache-manager.h>
+
+// EXTERNAL INCLUDES
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+namespace Dali::TextAbstraction::Internal
+{
+/**
+ * @brief Helper class to shape of FT_Face by harfbuzz library.
+ * @note Current class only be used for font face cache item.
+ */
+class HarfBuzzProxyFont
+{
+public:
+  /**
+   * @brief Constructor harfbuzz font data integrated with FreeType face and our font face cache item.
+   *
+   * @param[in] freeTypeFace The FreeType face.
+   * @param[in] requestedPointSize The requiested point size of font.
+   * @param[in] horizontalDpi Horizontal DPI.
+   * @param[in] verticalDpi Vertical DPI.
+   * @param[in] glyphCacheManager Glyph caching system for this harfbuzz font. It will be used as harfbuzz callback data.
+   */
+  HarfBuzzProxyFont(FT_Face freeTypeFace, const PointSize26Dot6& requestedPointSize, const uint32_t& horizontalDpi, const uint32_t& verticalDpi, GlyphCacheManager* glyphCacheManager);
+
+  // Destructor
+  ~HarfBuzzProxyFont();
+
+public:
+  // Public API area.
+
+  /**
+   * @brief Get the created harfbuzz font data integrated with FreeType face and our font face cache item.
+   *
+   * @return Created harfbuzz font data. or nullptr if there is something error.
+   */
+  HarfBuzzFontHandle GetHarfBuzzFont() const;
+
+private:
+  // Private API area.
+  HarfBuzzProxyFont()                             = delete; // Do not use default construct
+  HarfBuzzProxyFont(const HarfBuzzProxyFont& rhs) = delete; // Do not use copy construct
+  HarfBuzzProxyFont(HarfBuzzProxyFont&& rhs)      = delete; // Do not use move construct
+public:
+  struct Impl;             // Harfbuzz callback can access this struct.
+  uint32_t mHorizontalDpi; ///< Horizontal DPI.
+  uint32_t mVerticalDpi;   ///< VerticalDPI.
+
+private:
+  // Private member value area.
+  Impl* mImpl;
+};
+
+} // namespace Dali::TextAbstraction::Internal
+
+#endif //DALI_TEXT_ABSTRACTION_INTERNAL_HARFBUZZ_PROXY_FONT_H
diff --git a/dali/internal/text/text-abstraction/plugin/lru-cache-container.h b/dali/internal/text/text-abstraction/plugin/lru-cache-container.h
new file mode 100644 (file)
index 0000000..5c84f67
--- /dev/null
@@ -0,0 +1,433 @@
+#ifndef DALI_TEXT_ABSTRACTION_INTERNAL_LRU_CACHE_CONTAINER_H
+#define DALI_TEXT_ABSTRACTION_INTERNAL_LRU_CACHE_CONTAINER_H
+
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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/common/dali-common.h>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <limits> // for std::numeric_limits
+#include <unordered_map>
+
+namespace Dali::TextAbstraction::Internal
+{
+/**
+ * @brief Helper class to cache as LRU algirhtm.
+ * It implement as double-linked-list with header and footer.
+ *
+ * HEADER <-> n(LatestId) <-> n <-> ... <-> n(OldestId) <-> FOOTER <-> n(FreeId) <-> n <-> .. <-> n <-> HEADER
+ *
+ * @note This container cannot control the KeyType and ElementType construct and destruct timming.
+ *
+ * @todo Could we make "iteration" system here?
+ * @todo Could we move it into dali-core/devel-api?
+ *
+ * @tparam KeyType The type of the key that pairwise with element.
+ * @tparam ElementType The type of the data that the container holds
+ * @tparam KeyHash The custom hash funcion of KeyType. Default is std::hash
+ * @tparam KeyEqual The custom equal function of KeyType. Default is std::equal_to
+ */
+template<class KeyType, class ElementType, class KeyHash = std::hash<KeyType>, class KeyEqual = std::equal_to<KeyType>>
+class LRUCacheContainer
+{
+public:
+  // Constructor
+  LRUCacheContainer(std::size_t maxNumberOfCache = std::numeric_limits<std::size_t>::max())
+  : mCacheMaxSize(maxNumberOfCache)
+  {
+  }
+
+  // Destructor
+  ~LRUCacheContainer() = default;
+
+  LRUCacheContainer(const LRUCacheContainer& rhs) = default;
+  LRUCacheContainer(LRUCacheContainer&& rhs)      = default;
+
+public:
+  // Public struct area.
+  using CacheId          = std::size_t; ///< The id of cached element. It can be used until element poped out.
+  using CacheIdContainer = std::unordered_map<KeyType, CacheId, KeyHash, KeyEqual>;
+
+  /**
+   * @brief Special CacheId for header.
+   */
+  static constexpr CacheId CACHE_HEADER_ID = std::numeric_limits<std::size_t>::max();
+  /**
+   * @brief Special CacheId for footer.
+   */
+  static constexpr CacheId CACHE_FOOTER_ID = std::numeric_limits<std::size_t>::max() - 1u;
+
+  /**
+   * @brief Double linked CacheNode that this container used.
+   */
+  struct CacheNode
+  {
+    CacheNode()  = default;
+    ~CacheNode() = default;
+
+    CacheId     prev{CACHE_FOOTER_ID};
+    CacheId     next{CACHE_HEADER_ID};
+    ElementType element;
+
+    using CacheIdIterator = typename CacheIdContainer::iterator;
+
+    CacheIdIterator cacheIdIterator; ///< Note : It only validate until mCacheId rehashing.
+  };
+
+  using iterator = typename std::vector<CacheNode>::iterator;
+
+public:
+  // Public API area.
+
+  /**
+   * @brief Push an element into the cache. It will be marked as recent
+   * If it is already existed key, it will replace element.
+   *
+   * @param[in] key The key to push
+   * @param[in] element The element to push
+   * @warning This method pop oldest elements if the user attempts to push
+   * more elements than the maximum size specified in the constructor
+   */
+  void Push(const KeyType& key, const ElementType& element)
+  {
+    const auto iter = mCacheId.find(key);
+
+    // If already exist key, just replace element, and return.
+    if(iter != mCacheId.end())
+    {
+      const CacheId id = iter->second;
+
+      // Mark as recently used.
+      InternalPop(id);
+      InternalInsertAfterHeader(id);
+
+      mData[id].element = element;
+      return;
+    }
+
+    if(DALI_UNLIKELY(IsFull()))
+    {
+      // Pop latest element automatically.
+      Pop();
+    }
+
+    if(DALI_UNLIKELY(mNumberOfElements == mData.size()))
+    {
+      InternalReserve(mNumberOfElements == 0 ? 1 : (mNumberOfElements << 1));
+    }
+
+    ++mNumberOfElements;
+
+    const CacheId id = mFreeId;
+
+    // Mark as recently used.
+    InternalPop(id);
+    InternalInsertAfterHeader(id);
+
+    // Copy element
+    mData[id].element = element;
+
+    // Store cache iterator.
+    mData[id].cacheIdIterator = mCacheId.emplace(key, id).first;
+  }
+
+  /**
+   * @brief Pops an element off the oldest used element.
+   * After pop, CacheId relative with this element cannot be used.
+   * Access by poped element's CacheId is Undefined Behavior.
+   *
+   * @return A copy of the element
+   * @warning This method asserts if the container is empty
+   */
+  ElementType Pop()
+  {
+    DALI_ASSERT_ALWAYS(!IsEmpty() && "Reading from empty container");
+
+    const CacheId id = mOldestId;
+    InternalPop(id);
+    InternalInsertAfterFooter(id);
+
+    --mNumberOfElements;
+
+    // Erase cache id.
+    mCacheId.erase(mData[id].cacheIdIterator);
+
+    return mData[id].element;
+  }
+
+  /**
+   * @brief Get an element by the key. It will be marked as recent
+   *
+   * @param[in] key The key of element
+   * @return A reference of the element
+   * @warning This method asserts if invalid key inputed
+   */
+  ElementType& Get(const KeyType& key)
+  {
+    const auto iter = mCacheId.find(key);
+    DALI_ASSERT_ALWAYS((iter != mCacheId.end()) && "Try to get invalid key");
+
+    const auto id = iter->second;
+
+    // Mark as recently used.
+    InternalPop(id);
+    InternalInsertAfterHeader(id);
+
+    return mData[id].element;
+  }
+
+  /**
+   * @brief Find an element by the key. It will be marked as recent
+   *
+   * @param[in] key The key of element
+   * @return A iterator of cache node. If key not exist, return End()
+   */
+  iterator Find(const KeyType& key)
+  {
+    if(mCacheId.find(key) == mCacheId.end())
+    {
+      return End();
+    }
+
+    const auto id = mCacheId[key];
+
+    // Mark as recently used.
+    InternalPop(id);
+    InternalInsertAfterHeader(id);
+
+    return Begin() + id;
+  }
+
+  /**
+   * @brief Clear all data
+   */
+  void Clear()
+  {
+    mCacheId.clear();
+    mCacheId.rehash(0);
+    mData.clear();
+    mData.shrink_to_fit();
+
+    mNumberOfElements = 0;
+    mLatestId         = CACHE_FOOTER_ID;
+    mOldestId         = CACHE_HEADER_ID;
+    mFreeId           = CACHE_HEADER_ID;
+  }
+
+  /**
+   * @brief Predicate to determine if the container is empty
+   *
+   * @return true if the container is empty
+   */
+  bool IsEmpty() const
+  {
+    return mNumberOfElements == 0;
+  }
+
+  /**
+   * @brief Predicate to determine if the container is full
+   *
+   * @return true if the container is full
+   */
+  bool IsFull() const
+  {
+    return (mNumberOfElements == mCacheMaxSize);
+  }
+
+  iterator Begin()
+  {
+    return mData.begin();
+  }
+
+  iterator End()
+  {
+    return mData.end();
+  }
+
+  /**
+   * @brief Get a count of the elements in the container
+   *
+   * @return the number of elements in the container.
+   */
+  std::size_t Count() const
+  {
+    return mNumberOfElements;
+  }
+
+private:
+  // Private struct area.
+
+private:
+  // Private API area.
+
+  /**
+   * @brief Allocate cache memory as reserveSize.
+   * @note We assume that mFreeId is header.
+   *
+   * @param reserveSize Reserved size of cache.
+   */
+  void InternalReserve(std::size_t reserveSize) noexcept
+  {
+    // Increase mData capacity
+    if(reserveSize > mCacheMaxSize)
+    {
+      reserveSize = mCacheMaxSize;
+    }
+
+    CacheId newCreatedIdBegin = mData.size();
+    CacheId newCreatedIdEnd   = reserveSize - 1;
+
+    // Make temporary array for re-validate iterator.
+    std::vector<KeyType> keyList(mData.size());
+    for(auto i = static_cast<std::size_t>(0); i < newCreatedIdBegin; ++i)
+    {
+      keyList[i] = mData[i].cacheIdIterator->first;
+    }
+
+    // Reserve data and cacheid capacity.
+    mData.resize(reserveSize);
+    mCacheId.rehash(reserveSize);
+
+    // Revalidate each iterator.
+    for(auto i = static_cast<std::size_t>(0); i < newCreatedIdBegin; ++i)
+    {
+      mData[i].cacheIdIterator = mCacheId.find(keyList[i]);
+    }
+
+    // Setup new created CacheNode's prev and next id.
+    for(auto i = newCreatedIdBegin;; ++i)
+    {
+      mData[i].prev = DALI_UNLIKELY(i == newCreatedIdBegin) ? CACHE_FOOTER_ID : i - 1;
+      mData[i].next = DALI_UNLIKELY(i == newCreatedIdEnd) ? CACHE_HEADER_ID : i + 1;
+      if(DALI_UNLIKELY(i == newCreatedIdEnd))
+      {
+        break;
+      }
+    }
+    mFreeId = newCreatedIdBegin;
+  }
+
+  /**
+   * @brief Temperary pop of node. After call this, we should call
+   * InternalInsertAfterHeader or InternalInsertAfterFooter
+   *
+   * @param id CacheId that removed temperary.
+   */
+  void InternalPop(const CacheId& id) noexcept
+  {
+    const CacheId prev = mData[id].prev;
+    const CacheId next = mData[id].next;
+
+    // Disconnect prev -> id. and connect prev -> next
+    if(prev == CACHE_HEADER_ID)
+    {
+      mLatestId = next;
+    }
+    else if(prev == CACHE_FOOTER_ID)
+    {
+      mFreeId = next;
+    }
+    else
+    {
+      mData[prev].next = next;
+    }
+
+    // Disconnect id <- next. and connect prev <- next
+    if(next == CACHE_HEADER_ID)
+    {
+      // Do nothing.
+    }
+    else if(next == CACHE_FOOTER_ID)
+    {
+      mOldestId = prev;
+    }
+    else
+    {
+      mData[next].prev = prev;
+    }
+  }
+
+  /**
+   * @brief Insert the node after the header. That mean, this id recently used.
+   *
+   * @param id CacheId that insert after header.
+   */
+  void InternalInsertAfterHeader(const CacheId& id) noexcept
+  {
+    const CacheId next = mLatestId;
+
+    // Connect Header -> id.
+    mLatestId = id;
+
+    // Connect id <- next
+    if(next == CACHE_FOOTER_ID)
+    {
+      mOldestId = id;
+    }
+    else
+    {
+      mData[next].prev = id;
+    }
+
+    // Connect Header <- id -> next
+    mData[id].prev = CACHE_HEADER_ID;
+    mData[id].next = next;
+  }
+
+  /**
+   * @brief Insert the node after the footer. That mean, this id become free.
+   *
+   * @param id CacheId that insert after footer.
+   */
+  void InternalInsertAfterFooter(const CacheId& id) noexcept
+  {
+    const CacheId next = mFreeId;
+
+    // Connect Footer -> id.
+    mFreeId = id;
+
+    // Connect id <- next
+    if(next == CACHE_HEADER_ID)
+    {
+      // Do nothing.
+    }
+    else
+    {
+      mData[next].prev = id;
+    }
+
+    // Connect Footer <- id -> next
+    mData[id].prev = CACHE_FOOTER_ID;
+    mData[id].next = next;
+  }
+
+private:
+  // Private member value area.
+  std::size_t mCacheMaxSize{0};     ///< The maximum capacity of cache.
+  std::size_t mNumberOfElements{0}; ///< The number of elements.
+
+  CacheId mLatestId{CACHE_FOOTER_ID}; ///< The recently used element id
+  CacheId mOldestId{CACHE_HEADER_ID}; ///< The oldest used element id
+  CacheId mFreeId{CACHE_HEADER_ID};   ///< The free element id that can be allocated.
+
+  std::unordered_map<KeyType, CacheId, KeyHash, KeyEqual> mCacheId{}; ///< LRU Cache id container
+  std::vector<CacheNode>                                  mData{};    ///< The real data container.
+};
+
+} // namespace Dali::TextAbstraction::Internal
+
+#endif //DALI_TEXT_ABSTRACTION_INTERNAL_LRU_CACHE_CONTAINER_H
index 89d6498..f966fd6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -151,6 +151,14 @@ struct Shaping::Plugin
     {
       case FontDescription::FACE_FONT:
       {
+        // Get our harfbuzz font struct
+        hb_font_t* harfBuzzFont = reinterpret_cast<hb_font_t*>(fontClientImpl.GetHarfBuzzFont(fontId));
+        if(nullptr == harfBuzzFont)
+        {
+          // Nothing to do if the harfBuzzFont is null.
+          return 0u;
+        }
+
         // Reserve some space to avoid reallocations.
         const Length numberOfGlyphs = static_cast<Length>(1.3f * static_cast<float>(numberOfCharacters));
         mIndices.Reserve(numberOfGlyphs);
@@ -158,28 +166,6 @@ struct Shaping::Plugin
         mCharacterMap.Reserve(numberOfGlyphs);
         mOffset.Reserve(2u * numberOfGlyphs);
 
-        // Retrieve a FreeType font's face.
-        FT_Face face = fontClientImpl.GetFreetypeFace(fontId);
-        if(nullptr == face)
-        {
-          // Nothing to do if the face is null.
-          return 0u;
-        }
-
-        unsigned int horizontalDpi = 0u;
-        unsigned int verticalDpi   = 0u;
-        fontClient.GetDpi(horizontalDpi, verticalDpi);
-
-        FT_Set_Char_Size(face,
-                         0u,
-                         fontClient.GetPointSize(fontId),
-                         horizontalDpi,
-                         verticalDpi);
-
-        /* Get our harfbuzz font struct */
-        hb_font_t* harfBuzzFont;
-        harfBuzzFont = hb_ft_font_create(face, NULL);
-
         /* Create a buffer for harfbuzz to use */
         hb_buffer_t* harfBuzzBuffer = hb_buffer_create();
 
@@ -276,7 +262,6 @@ struct Shaping::Plugin
 
         /* Cleanup */
         hb_buffer_destroy(harfBuzzBuffer);
-        hb_font_destroy(harfBuzzFont);
         break;
       }
       case FontDescription::BITMAP_FONT:
index ddad644..665a37c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -42,15 +42,18 @@ Dali::Integration::Trace::LogContextFunction TraceManagerAndroid::GetLogContextF
 
 void TraceManagerAndroid::LogContext(bool start, const char* tag)
 {
-  if(start)
+  if(traceManagerAndroid && traceManagerAndroid->mPerformanceInterface)
   {
-    unsigned short contextId = traceManagerAndroid->mPerformanceInterface->AddContext(tag);
-    traceManagerAndroid->mPerformanceInterface->AddMarker(PerformanceInterface::START, contextId);
-  }
-  else
-  {
-    unsigned short contextId = traceManagerAndroid->mPerformanceInterface->AddContext(tag);
-    traceManagerAndroid->mPerformanceInterface->AddMarker(PerformanceInterface::END, contextId);
+    if(start)
+    {
+      unsigned short contextId = traceManagerAndroid->mPerformanceInterface->AddContext(tag);
+      traceManagerAndroid->mPerformanceInterface->AddMarker(PerformanceInterface::START, contextId);
+    }
+    else
+    {
+      unsigned short contextId = traceManagerAndroid->mPerformanceInterface->AddContext(tag);
+      traceManagerAndroid->mPerformanceInterface->AddMarker(PerformanceInterface::END, contextId);
+    }
   }
 }
 
index 92ada6e..bf9c696 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -42,15 +42,18 @@ Dali::Integration::Trace::LogContextFunction TraceManagerGeneric::GetLogContextF
 
 void TraceManagerGeneric::LogContext(bool start, const char* tag)
 {
-  if(start)
+  if(traceManagerGeneric && traceManagerGeneric->mPerformanceInterface)
   {
-    unsigned short contextId = traceManagerGeneric->mPerformanceInterface->AddContext(tag);
-    traceManagerGeneric->mPerformanceInterface->AddMarker(PerformanceInterface::START, contextId);
-  }
-  else
-  {
-    unsigned short contextId = traceManagerGeneric->mPerformanceInterface->AddContext(tag);
-    traceManagerGeneric->mPerformanceInterface->AddMarker(PerformanceInterface::END, contextId);
+    if(start)
+    {
+      unsigned short contextId = traceManagerGeneric->mPerformanceInterface->AddContext(tag);
+      traceManagerGeneric->mPerformanceInterface->AddMarker(PerformanceInterface::START, contextId);
+    }
+    else
+    {
+      unsigned short contextId = traceManagerGeneric->mPerformanceInterface->AddContext(tag);
+      traceManagerGeneric->mPerformanceInterface->AddMarker(PerformanceInterface::END, contextId);
+    }
   }
 }
 
index f8ecca5..feb8b5a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -46,6 +46,10 @@ Dali::BaseHandle Create()
 
 Dali::TypeRegistration type(typeid(Dali::VectorImageRenderer), typeid(Dali::BaseHandle), Create);
 
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gVectorImageLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_VECTOR_IMAGE");
+#endif
+
 } // unnamed namespace
 
 VectorImageRendererPtr VectorImageRenderer::New()
@@ -60,9 +64,7 @@ VectorImageRendererPtr VectorImageRenderer::New()
 
 VectorImageRenderer::VectorImageRenderer()
 #ifdef THORVG_SUPPORT
-: mPicture(nullptr),
-  mDefaultWidth(0),
-  mDefaultHeight(0)
+: mPicture(nullptr)
 #else
 : mParsedImage(nullptr),
   mRasterizer(nullptr)
@@ -106,7 +108,7 @@ void VectorImageRenderer::Initialize()
 
   mSwCanvas = tvg::SwCanvas::gen();
   mSwCanvas->mempool(tvg::SwCanvas::MempoolPolicy::Individual);
-  mSwCanvas->reserve(1);  //has one picture
+  mSwCanvas->reserve(1); //has one picture
 #else
   mRasterizer = nsvgCreateRasterizer();
 #endif
@@ -130,12 +132,16 @@ bool VectorImageRenderer::Load(const Vector<uint8_t>& data, float dpi)
       return false;
     }
   }
+  else
+  {
+    return true;
+  }
 
-  tvg::Result ret = mPicture->load(reinterpret_cast<char*>(data.Begin()), data.Size(), false);
+  tvg::Result ret = mPicture->load(reinterpret_cast<char*>(data.Begin()), data.Size(), true);
 
   if(ret != tvg::Result::Success)
   {
-    switch (ret)
+    switch(ret)
     {
       case tvg::Result::InvalidArguments:
       {
@@ -163,45 +169,88 @@ bool VectorImageRenderer::Load(const Vector<uint8_t>& data, float dpi)
 
   float w, h;
   mPicture->size(&w, &h);
-  mDefaultWidth = static_cast<uint32_t>(w);
+  mDefaultWidth  = static_cast<uint32_t>(w);
   mDefaultHeight = static_cast<uint32_t>(h);
 
   return true;
 #else
+  if(mParsedImage)
+  {
+    return true;
+  }
+
   mParsedImage = nsvgParse(reinterpret_cast<char*>(data.Begin()), UNITS, dpi);
   if(!mParsedImage || !mParsedImage->shapes)
   {
     DALI_LOG_ERROR("VectorImageRenderer::Load: nsvgParse failed\n");
     return false;
   }
+
+  mDefaultWidth  = mParsedImage->width;
+  mDefaultHeight = mParsedImage->height;
+
   return true;
 #endif
 }
 
-bool VectorImageRenderer::Rasterize(Dali::Devel::PixelBuffer& buffer, float scale)
+bool VectorImageRenderer::IsLoaded() const
 {
 #ifdef THORVG_SUPPORT
+  return mPicture ? true : false;
+#else
+  return mParsedImage ? true : false;
+#endif
+}
+
+Dali::Devel::PixelBuffer VectorImageRenderer::Rasterize(uint32_t width, uint32_t height)
+{
+  if(width == 0)
+  {
+    if(mDefaultWidth == 0)
+    {
+      DALI_LOG_ERROR("Invalid size [%d, %d]\n", width, height);
+      return Devel::PixelBuffer();
+    }
+    else
+    {
+      width = mDefaultWidth;
+    }
+  }
+
+  if(height == 0)
+  {
+    if(mDefaultHeight == 0)
+    {
+      DALI_LOG_ERROR("Invalid size [%d, %d]\n", width, height);
+      return Devel::PixelBuffer();
+    }
+    else
+    {
+      height = mDefaultHeight;
+    }
+  }
+
+#ifdef THORVG_SUPPORT
   if(!mSwCanvas || !mPicture)
   {
     DALI_LOG_ERROR("VectorImageRenderer::Rasterize: either Canvas[%p] or Picture[%p] is invalid [%p]\n", mSwCanvas.get(), mPicture, this);
-    return false;
+    return Devel::PixelBuffer();
   }
 
+  Devel::PixelBuffer pixelBuffer = Devel::PixelBuffer::New(width, height, Dali::Pixel::RGBA8888);
+
   mSwCanvas->clear(false);
 
-  auto pBuffer = buffer.GetBuffer();
+  auto pBuffer = pixelBuffer.GetBuffer();
   if(!pBuffer)
   {
     DALI_LOG_ERROR("VectorImageRenderer::Rasterize: pixel buffer is null [%p]\n", this);
-    return false;
+    return Devel::PixelBuffer();
   }
 
-  auto width = buffer.GetWidth();
-  auto height = buffer.GetHeight();
-
   mSwCanvas->target(reinterpret_cast<uint32_t*>(pBuffer), width, width, height, tvg::SwCanvas::ABGR8888);
 
-  DALI_LOG_RELEASE_INFO("VectorImageRenderer::Rasterize: Buffer[%p] size[%d x %d]! [%p]\n", pBuffer, width, height, this);
+  DALI_LOG_INFO(gVectorImageLogFilter, Debug::Verbose, "Buffer[%p] size[%d x %d]! [%p]\n", pBuffer, width, height, this);
 
   mPicture->size(width, height);
 
@@ -209,41 +258,40 @@ bool VectorImageRenderer::Rasterize(Dali::Devel::PixelBuffer& buffer, float scal
   if(mSwCanvas->push(std::unique_ptr<tvg::Picture>(mPicture)) != tvg::Result::Success)
   {
     DALI_LOG_ERROR("VectorImageRenderer::Rasterize: Picture push fail [%p]\n", this);
-    return false;
+    return Devel::PixelBuffer();
   }
 
-  if(mSwCanvas->draw() != tvg::Result::Success)
+  auto ret = mSwCanvas->draw();
+  if(ret != tvg::Result::Success)
   {
-    DALI_LOG_ERROR("VectorImageRenderer::Rasterize: Draw fail [%p]\n", this);
-    return false;
+    DALI_LOG_ERROR("VectorImageRenderer::Rasterize: Draw fail %d [%p]\n", static_cast<int>(ret), this);
+    return Devel::PixelBuffer();
   }
 
   mSwCanvas->sync();
 
-  return true;
+  return pixelBuffer;
 #else
   if(mParsedImage != nullptr)
   {
-    int stride = buffer.GetWidth() * Pixel::GetBytesPerPixel(buffer.GetPixelFormat());
-    nsvgRasterize(mRasterizer, mParsedImage, 0.0f, 0.0f, scale, buffer.GetBuffer(), buffer.GetWidth(), buffer.GetHeight(), stride);
-    return true;
+    Devel::PixelBuffer pixelBuffer = Devel::PixelBuffer::New(width, height, Dali::Pixel::RGBA8888);
+
+    float scaleX = static_cast<float>(width) / (mDefaultWidth > 0 ? static_cast<float>(mDefaultWidth) : 1.0f);
+    float scaleY = static_cast<float>(height) / (mDefaultHeight > 0 ? static_cast<float>(mDefaultHeight) : 1.0f);
+    float scale  = scaleX < scaleY ? scaleX : scaleY;
+    int   stride = pixelBuffer.GetWidth() * Pixel::GetBytesPerPixel(Dali::Pixel::RGBA8888);
+
+    nsvgRasterize(mRasterizer, mParsedImage, 0.0f, 0.0f, scale, pixelBuffer.GetBuffer(), width, height, stride);
+    return pixelBuffer;
   }
-  return false;
+  return Devel::PixelBuffer();
 #endif
 }
 
 void VectorImageRenderer::GetDefaultSize(uint32_t& width, uint32_t& height) const
 {
-#ifdef THORVG_SUPPORT
-  width = mDefaultWidth;
+  width  = mDefaultWidth;
   height = mDefaultHeight;
-#else
-  if(mParsedImage)
-  {
-    width  = mParsedImage->width;
-    height = mParsedImage->height;
-  }
-#endif
 }
 
 } // namespace Adaptor
index f2cce44..19ae0c1 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_VECTOR_IMAGE_RENDERER_IMPL_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -62,9 +62,14 @@ public:
   bool Load(const Vector<uint8_t>& data, float dpi);
 
   /**
+   * @copydoc Dali::VectorImageRenderer::IsLoaded()
+   */
+  bool IsLoaded() const;
+
+  /**
    * @copydoc Dali::VectorImageRenderer::Rasterize()
    */
-  bool Rasterize(Dali::Devel::PixelBuffer& buffer, float scale);
+  Dali::Devel::PixelBuffer Rasterize(uint32_t width, uint32_t height);
 
   /**
    * @copydoc Dali::VectorImageRenderer::GetDefaultSize()
@@ -94,14 +99,14 @@ private:
 
 private:
 #ifdef THORVG_SUPPORT
-  std::unique_ptr< tvg::SwCanvas >       mSwCanvas;
-  tvg::Picture*                          mPicture;        ///< The pointer to the picture
-  uint32_t                               mDefaultWidth;   ///< The width of the surface
-  uint32_t                               mDefaultHeight;  ///< The height of the surface
+  std::unique_ptr<tvg::SwCanvas> mSwCanvas{nullptr};
+  tvg::Picture*                  mPicture{nullptr}; ///< The pointer to the picture
 #else
-  NSVGimage*                     mParsedImage;
-  NSVGrasterizer*                mRasterizer;
+  NSVGimage*      mParsedImage{nullptr};
+  NSVGrasterizer* mRasterizer{nullptr};
 #endif
+  uint32_t mDefaultWidth{0};  ///< The default width of the file
+  uint32_t mDefaultHeight{0}; ///< The default height of the file
 };
 
 } // namespace Adaptor
index 75fe93f..808e9c9 100755 (executable)
@@ -515,6 +515,11 @@ void WebEngine::ActivateAccessibility(bool activated)
   mPlugin->ActivateAccessibility(activated);
 }
 
+Accessibility::Address WebEngine::GetAccessibilityAddress()
+{
+  return mPlugin->GetAccessibilityAddress();
+}
+
 bool WebEngine::SetVisibility(bool visible)
 {
   return mPlugin->SetVisibility(visible);
index d68f3a4..0423b6b 100755 (executable)
@@ -22,6 +22,7 @@
 #include <dali/public-api/object/base-object.h>
 
 // INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/accessibility.h>
 #include <dali/devel-api/adaptor-framework/web-engine-plugin.h>
 #include <dali/devel-api/adaptor-framework/web-engine.h>
 
@@ -400,6 +401,11 @@ public:
   void ActivateAccessibility(bool activated);
 
   /**
+   * @copydoc Dali::WebEngine::GetAccessibilityAddress()
+   */
+  Accessibility::Address GetAccessibilityAddress();
+
+  /**
    * @copydoc Dali::WebEngine::SetVisibility()
    */
   bool SetVisibility(bool visible);
index 842bcb1..004af89 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -125,6 +125,11 @@ int WindowBaseAndroid::GetNativeWindowId()
   return 0;
 }
 
+std::string WindowBaseAndroid::GetNativeWindowResourceId()
+{
+  return std::string();
+}
+
 EGLNativeWindowType WindowBaseAndroid::CreateEglWindow(int width, int height)
 {
   // from eglplatform.h header
@@ -196,6 +201,10 @@ bool WindowBaseAndroid::IsMaximized() const
   return false;
 }
 
+void WindowBaseAndroid::SetMaximumSize(Dali::Window::WindowSize size)
+{
+}
+
 void WindowBaseAndroid::Minimize(bool minimize)
 {
 }
@@ -205,6 +214,10 @@ bool WindowBaseAndroid::IsMinimized() const
   return false;
 }
 
+void WindowBaseAndroid::SetMimimumSize(Dali::Window::WindowSize size)
+{
+}
+
 void WindowBaseAndroid::SetAvailableAnlges(const std::vector<int>& angles)
 {
 }
index abfe727..9f1b797 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_WINDOWSYSTEM_ANDROID_WINDOW_BASE_ANDROID_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -124,6 +124,11 @@ public:
   int GetNativeWindowId() override;
 
   /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetNativeWindowResourceId()
+   */
+  std::string GetNativeWindowResourceId() override;
+
+  /**
    * @copydoc Dali::Internal::Adaptor::WindowBase::CreateEglWindow()
    */
   EGLNativeWindowType CreateEglWindow(int width, int height) override;
@@ -204,6 +209,11 @@ public:
   bool IsMaximized() const override;
 
   /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetMaximumSize()
+   */
+  void SetMaximumSize(Dali::Window::WindowSize size) override;
+
+  /**
    * @copydoc Dali::Internal::Adaptor::WindowBase::Minimize()
    */
   void Minimize(bool minimize) override;
@@ -214,6 +224,11 @@ public:
   bool IsMinimized() const override;
 
   /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetMimimumSize()
+   */
+  void SetMimimumSize(Dali::Window::WindowSize size) override;
+
+  /**
    * @copydoc Dali::Internal::Adaptor::WindowBase::SetAvailableAnlges()
    */
   void SetAvailableAnlges(const std::vector<int>& angles) override;
index 3ad8de5..4179fd7 100644 (file)
@@ -30,6 +30,8 @@ struct RotationEvent
 {
   int angle;     ///< one of 0, 90, 180, 270
   int winResize; ///< true if the window should be resized
+  int x;         ///< converted x coordinate
+  int y;         ///< converted y coordinate
   int width;     ///< new window width
   int height;    ///< new window height
 };
index e2b8707..155ca50 100644 (file)
@@ -37,7 +37,6 @@ WindowBase::WindowBase()
   mSelectionDataSendSignal(),
   mSelectionDataReceivedSignal(),
   mStyleChangedSignal(),
-  mAccessibilitySignal(),
   mTransitionEffectEventSignal(),
   mKeyboardRepeatSettingsChangedSignal(),
   mUpdatePositionSizeSignal(),
@@ -109,11 +108,6 @@ WindowBase::StyleSignalType& WindowBase::StyleChangedSignal()
   return mStyleChangedSignal;
 }
 
-WindowBase::AccessibilitySignalType& WindowBase::AccessibilitySignal()
-{
-  return mAccessibilitySignal;
-}
-
 WindowBase::TransitionEffectEventSignalType& WindowBase::TransitionEffectEventSignal()
 {
   return mTransitionEffectEventSignal;
index d84e528..0e0091a 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_WINDOWSYSTEM_COMMON_WINDOW_BASE_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -85,7 +85,6 @@ public:
 
   // Accessibility
   typedef Signal<void(StyleChange::Type)>        StyleSignalType;
-  typedef Signal<void(const AccessibilityInfo&)> AccessibilitySignalType;
 
   /**
    * @brief Default constructor
@@ -111,6 +110,12 @@ public:
   virtual int GetNativeWindowId() = 0;
 
   /**
+   * @brief Get the native window resource id assinged by window manager
+   * @return The native window resource id
+   */
+  virtual std::string GetNativeWindowResourceId() = 0;
+
+  /**
    * @brief Create the egl window
    */
   virtual EGLNativeWindowType CreateEglWindow(int width, int height) = 0;
@@ -191,6 +196,11 @@ public:
   virtual bool IsMaximized() const = 0;
 
   /**
+   * @copydoc Dali::DevelWindow::SetMaximumSize()
+   */
+  virtual void SetMaximumSize(Dali::Window::WindowSize size) = 0;
+
+  /**
    * @copydoc Dali::DevelWindow::Minimize()
    */
   virtual void Minimize(bool minimize) = 0;
@@ -201,6 +211,11 @@ public:
   virtual bool IsMinimized() const = 0;
 
   /**
+   * @copydoc Dali::DevelWindow::SetMimimumSize()
+   */
+  virtual void SetMimimumSize(Dali::Window::WindowSize size) = 0;
+
+  /**
    * @copydoc Dali::Window::SetAvailableOrientations()
    */
   virtual void SetAvailableAnlges(const std::vector<int>& angles) = 0;
@@ -502,11 +517,6 @@ public:
   StyleSignalType& StyleChangedSignal();
 
   /**
-   * @brief This signal is emitted when an accessibility event is received.
-   */
-  AccessibilitySignalType& AccessibilitySignal();
-
-  /**
    * @brief This signal is emitted when window's transition animation is started or ended.
    */
   TransitionEffectEventSignalType& TransitionEffectEventSignal();
@@ -551,7 +561,6 @@ protected:
   SelectionSignalType                     mSelectionDataSendSignal;
   SelectionSignalType                     mSelectionDataReceivedSignal;
   StyleSignalType                         mStyleChangedSignal;
-  AccessibilitySignalType                 mAccessibilitySignal;
   TransitionEffectEventSignalType         mTransitionEffectEventSignal;
   KeyboardRepeatSettingsChangedSignalType mKeyboardRepeatSettingsChangedSignal;
   WindowRedrawRequestSignalType           mWindowRedrawRequestSignal;
index fff3338..fa8c7c1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 // EXTERNAL HEADERS
 #include <dali/devel-api/adaptor-framework/orientation.h>
+#include <dali/devel-api/events/key-event-devel.h>
 #include <dali/integration-api/core.h>
 #include <dali/integration-api/events/touch-event-integ.h>
+#include <dali/integration-api/events/touch-integ.h>
 #include <dali/public-api/actors/actor.h>
 #include <dali/public-api/actors/camera-actor.h>
 #include <dali/public-api/actors/layer.h>
@@ -76,34 +78,42 @@ Window* Window::New(Any surface, const PositionSize& positionSize, const std::st
 Window::Window()
 : mWindowSurface(nullptr),
   mWindowBase(),
-  mIsTransparent(false),
-  mIsFocusAcceptable(true),
-  mIconified(false),
-  mOpaqueState(false),
-  mWindowRotationAcknowledgement(false),
   mParentWindow(NULL),
   mPreferredAngle(static_cast<int>(WindowOrientation::NO_ORIENTATION_PREFERENCE)),
   mRotationAngle(0),
   mWindowWidth(0),
   mWindowHeight(0),
-  mOrientationMode(Internal::Adaptor::Window::OrientationMode::PORTRAIT),
   mNativeWindowId(-1),
+  mOrientationMode(Internal::Adaptor::Window::OrientationMode::PORTRAIT),
   mDeleteRequestSignal(),
   mFocusChangeSignal(),
   mResizeSignal(),
   mVisibilityChangedSignal(),
   mTransitionEffectEventSignal(),
   mKeyboardRepeatSettingsChangedSignal(),
-  mAuxiliaryMessageSignal()
+  mAuxiliaryMessageSignal(),
+  mLastKeyEvent(),
+  mLastTouchEvent(),
+  mIsTransparent(false),
+  mIsFocusAcceptable(true),
+  mIconified(false),
+  mOpaqueState(false),
+  mWindowRotationAcknowledgement(false),
+  mFocused(false)
 {
 }
 
 Window::~Window()
 {
-  auto bridge     = Accessibility::Bridge::GetCurrentBridge();
-  auto rootLayer  = mScene.GetRootLayer();
-  auto accessible = Accessibility::Accessible::Get(rootLayer, true);
-  bridge->RemoveTopLevelWindow(accessible);
+  if(mScene)
+  {
+    auto bridge     = Accessibility::Bridge::GetCurrentBridge();
+    auto rootLayer  = mScene.GetRootLayer();
+    auto accessible = Accessibility::Accessible::Get(rootLayer);
+    bridge->RemoveTopLevelWindow(accessible);
+    // Related to multi-window case. This is called for default window and non-default window, but it is effective for non-default window.
+    bridge->Emit(accessible, Accessibility::WindowEvent::DESTROY);
+  }
 
   if(mAdaptor)
   {
@@ -175,10 +185,13 @@ void Window::OnAdaptorSet(Dali::Adaptor& adaptor)
   mEventHandler->AddObserver(*this);
 
   // Add Window to bridge for ATSPI
-  auto bridge     = Accessibility::Bridge::GetCurrentBridge();
-  auto rootLayer  = mScene.GetRootLayer();
-  auto accessible = Accessibility::Accessible::Get(rootLayer, true);
-  bridge->AddTopLevelWindow(accessible);
+  auto bridge = Accessibility::Bridge::GetCurrentBridge();
+  if(bridge->IsUp())
+  {
+    auto rootLayer  = mScene.GetRootLayer();
+    auto accessible = Accessibility::Accessible::Get(rootLayer);
+    bridge->AddTopLevelWindow(accessible);
+  }
 
   bridge->EnabledSignal().Connect(this, &Window::OnAccessibilityEnabled);
   bridge->DisabledSignal().Connect(this, &Window::OnAccessibilityDisabled);
@@ -244,6 +257,11 @@ bool Window::IsMaximized() const
   return mWindowBase->IsMaximized();
 }
 
+void Window::SetMaximumSize(Dali::Window::WindowSize size)
+{
+  mWindowBase->SetMaximumSize(size);
+}
+
 void Window::Minimize(bool minimize)
 {
   mWindowBase->Minimize(minimize);
@@ -256,6 +274,11 @@ bool Window::IsMinimized() const
   return mWindowBase->IsMinimized();
 }
 
+void Window::SetMimimumSize(Dali::Window::WindowSize size)
+{
+  mWindowBase->SetMimimumSize(size);
+}
+
 uint32_t Window::GetLayerCount() const
 {
   return mScene.GetLayerCount();
@@ -271,6 +294,11 @@ Dali::RenderTaskList Window::GetRenderTaskList() const
   return mScene.GetRenderTaskList();
 }
 
+std::string Window::GetNativeResourceId() const
+{
+  return mWindowBase->GetNativeWindowResourceId();
+}
+
 void Window::AddAvailableOrientation(WindowOrientation orientation)
 {
   if(IsOrientationAvailable(orientation) == false)
@@ -345,6 +373,12 @@ void Window::SetPositionSizeWithOrientation(PositionSize positionSize, WindowOri
   mWindowBase->SetPositionSizeWithAngle(positionSize, angle);
 }
 
+void Window::EmitAccessibilityHighlightSignal(bool highlight)
+{
+  Dali::Window handle(this);
+  mAccessibilityHighlightSignal.Emit(handle, highlight);
+}
+
 void Window::SetAvailableAnlges(const std::vector<int>& angles)
 {
   if(angles.size() > 4)
@@ -467,6 +501,7 @@ void Window::Show()
   {
     Dali::Window handle(this);
     mVisibilityChangedSignal.Emit(handle, true);
+    Dali::Accessibility::Bridge::GetCurrentBridge()->WindowShown(handle);
 
     WindowVisibilityObserver* observer(mAdaptor);
     observer->OnWindowShown();
@@ -487,6 +522,7 @@ void Window::Hide()
   {
     Dali::Window handle(this);
     mVisibilityChangedSignal.Emit(handle, false);
+    Dali::Accessibility::Bridge::GetCurrentBridge()->WindowHidden(handle);
 
     WindowVisibilityObserver* observer(mAdaptor);
     observer->OnWindowHidden();
@@ -632,11 +668,14 @@ void Window::SetSize(Dali::Window::WindowSize size)
   {
     Uint16Pair newSize(newRect.width, newRect.height);
 
+    mWindowWidth  = newRect.width;
+    mWindowHeight = newRect.height;
+
     SurfaceResized();
 
     mAdaptor->SurfaceResizePrepare(mSurface.get(), newSize);
 
-    DALI_LOG_RELEASE_INFO("Window (%p), WinId (%d), SetSize(): resize signal [%d x %d]\n", this, mNativeWindowId, newRect.width, newRect.height);
+    DALI_LOG_RELEASE_INFO("Window (%p), WinId (%d), current angle (%d), SetSize(): resize signal [%d x %d]\n", this, mNativeWindowId, mRotationAngle, newRect.width, newRect.height);
 
     Dali::Window handle(this);
     mResizeSignal.Emit(handle, newSize);
@@ -646,7 +685,7 @@ void Window::SetSize(Dali::Window::WindowSize size)
 
   mSurface->SetFullSwapNextFrame();
 
-  Dali::Accessibility::Accessible::Get(mScene.GetRootLayer(), true)->EmitBoundsChanged(Dali::Rect<>(oldRect.x, oldRect.y, size.GetWidth(), size.GetHeight()));
+  Dali::Accessibility::Accessible::Get(mScene.GetRootLayer())->EmitBoundsChanged(Dali::Rect<>(oldRect.x, oldRect.y, size.GetWidth(), size.GetHeight()));
 }
 
 Dali::Window::WindowSize Window::GetSize() const
@@ -664,7 +703,7 @@ void Window::SetPosition(Dali::Window::WindowPosition position)
 
   mSurface->SetFullSwapNextFrame();
 
-  Dali::Accessibility::Accessible::Get(mScene.GetRootLayer(), true)->EmitBoundsChanged(Dali::Rect<>(position.GetX(), position.GetY(), oldRect.width, oldRect.height));
+  Dali::Accessibility::Accessible::Get(mScene.GetRootLayer())->EmitBoundsChanged(Dali::Rect<>(position.GetX(), position.GetY(), oldRect.width, oldRect.height));
 }
 
 Dali::Window::WindowPosition Window::GetPosition() const
@@ -692,11 +731,14 @@ void Window::SetPositionSize(PositionSize positionSize)
   {
     Uint16Pair newSize(newRect.width, newRect.height);
 
+    mWindowWidth  = newRect.width;
+    mWindowHeight = newRect.height;
+
     SurfaceResized();
 
     mAdaptor->SurfaceResizePrepare(mSurface.get(), newSize);
 
-    DALI_LOG_RELEASE_INFO("Window (%p), WinId (%d), SetPositionSize():resize signal [%d x %d]\n", this, mNativeWindowId, newRect.width, newRect.height);
+    DALI_LOG_RELEASE_INFO("Window (%p), WinId (%d), current angle (%d), SetPositionSize():resize signal [%d x %d]\n", this, mNativeWindowId, mRotationAngle, newRect.width, newRect.height);
     Dali::Window handle(this);
     mResizeSignal.Emit(handle, newSize);
     mAdaptor->SurfaceResizeComplete(mSurface.get(), newSize);
@@ -704,7 +746,7 @@ void Window::SetPositionSize(PositionSize positionSize)
 
   mSurface->SetFullSwapNextFrame();
 
-  Dali::Accessibility::Accessible::Get(mScene.GetRootLayer(), true)->EmitBoundsChanged(Dali::Rect<>(positionSize.x, positionSize.y, positionSize.width, positionSize.height));
+  Dali::Accessibility::Accessible::Get(mScene.GetRootLayer())->EmitBoundsChanged(Dali::Rect<>(positionSize.x, positionSize.y, positionSize.width, positionSize.height));
 }
 
 Dali::Layer Window::GetRootLayer() const
@@ -747,6 +789,7 @@ void Window::OnIconifyChanged(bool iconified)
     {
       Dali::Window handle(this);
       mVisibilityChangedSignal.Emit(handle, false);
+      Dali::Accessibility::Bridge::GetCurrentBridge()->WindowHidden(handle);
 
       WindowVisibilityObserver* observer(mAdaptor);
       observer->OnWindowHidden();
@@ -762,6 +805,7 @@ void Window::OnIconifyChanged(bool iconified)
     {
       Dali::Window handle(this);
       mVisibilityChangedSignal.Emit(handle, true);
+      Dali::Accessibility::Bridge::GetCurrentBridge()->WindowShown(handle);
 
       WindowVisibilityObserver* observer(mAdaptor);
       observer->OnWindowShown();
@@ -791,6 +835,7 @@ void Window::OnFocusChanged(bool focusIn)
       bridge->WindowUnfocused(handle);
     }
   }
+  mFocused = focusIn;
 }
 
 void Window::OnOutputTransformed()
@@ -851,11 +896,12 @@ void Window::OnUpdatePositionSize(Dali::PositionSize& positionSize)
 
   mSurface->SetFullSwapNextFrame();
 
-  Dali::Accessibility::Accessible::Get(mScene.GetRootLayer(), true)->EmitBoundsChanged(Dali::Rect<>(positionSize.x, positionSize.y, positionSize.width, positionSize.height));
+  Dali::Accessibility::Accessible::Get(mScene.GetRootLayer())->EmitBoundsChanged(Dali::Rect<>(positionSize.x, positionSize.y, positionSize.width, positionSize.height));
 }
 
 void Window::OnTouchPoint(Dali::Integration::Point& point, int timeStamp)
 {
+  mLastTouchEvent = Dali::Integration::NewTouchEvent(timeStamp, point);
   FeedTouchPoint(point, timeStamp);
 }
 
@@ -866,11 +912,14 @@ void Window::OnWheelEvent(Dali::Integration::WheelEvent& wheelEvent)
 
 void Window::OnKeyEvent(Dali::Integration::KeyEvent& keyEvent)
 {
+  mLastKeyEvent = Dali::DevelKeyEvent::New(keyEvent.keyName, keyEvent.logicalKey, keyEvent.keyString, keyEvent.keyCode, keyEvent.keyModifier, keyEvent.time, static_cast<Dali::KeyEvent::State>(keyEvent.state), keyEvent.compose, keyEvent.deviceName, keyEvent.deviceClass, keyEvent.deviceSubclass);
   FeedKeyEvent(keyEvent);
 }
 
 void Window::OnRotation(const RotationEvent& rotation)
 {
+  PositionSize newPositionSize(rotation.x, rotation.y, rotation.width, rotation.height);
+
   mRotationAngle = rotation.angle;
   mWindowWidth   = rotation.width;
   mWindowHeight  = rotation.height;
@@ -878,14 +927,14 @@ void Window::OnRotation(const RotationEvent& rotation)
   // Notify that the orientation is changed
   mOrientation->OnOrientationChange(rotation);
 
-  mWindowSurface->RequestRotation(mRotationAngle, mWindowWidth, mWindowHeight);
+  mWindowSurface->RequestRotation(mRotationAngle, newPositionSize);
 
   int orientation = (mRotationAngle + mWindowBase->GetScreenRotationAngle()) % 360;
   SurfaceRotated(mWindowWidth, mWindowHeight, orientation);
 
   mAdaptor->SurfaceResizePrepare(mSurface.get(), Adaptor::SurfaceSize(mWindowWidth, mWindowHeight));
 
-  DALI_LOG_RELEASE_INFO("Window (%p), WinId (%d), OnRotation(): resize signal emit [%d x %d]\n", this, mNativeWindowId, mWindowWidth, mWindowHeight);
+  DALI_LOG_RELEASE_INFO("Window (%p), WinId (%d), OnRotation(): x[%d], y[%d], resize signal emit [%d x %d]\n", this, mNativeWindowId, newPositionSize.x, newPositionSize.y, mWindowWidth, mWindowHeight);
   // Emit signal
   Dali::Window handle(this);
   mResizeSignal.Emit(handle, Dali::Window::WindowSize(mWindowWidth, mWindowHeight));
@@ -920,15 +969,28 @@ void Window::OnAccessibilityEnabled()
 {
   auto bridge     = Accessibility::Bridge::GetCurrentBridge();
   auto rootLayer  = mScene.GetRootLayer();
-  auto accessible = Accessibility::Accessible::Get(rootLayer, true);
+  auto accessible = Accessibility::Accessible::Get(rootLayer);
   bridge->AddTopLevelWindow(accessible);
+
+  if(!mVisible || mIconified)
+  {
+    return;
+  }
+
+  Dali::Window handle(this);
+  bridge->WindowShown(handle);
+
+  if(mFocused)
+  {
+    bridge->WindowFocused(handle);
+  }
 }
 
 void Window::OnAccessibilityDisabled()
 {
   auto bridge     = Accessibility::Bridge::GetCurrentBridge();
   auto rootLayer  = mScene.GetRootLayer();
-  auto accessible = Accessibility::Accessible::Get(rootLayer, true);
+  auto accessible = Accessibility::Accessible::Get(rootLayer);
   bridge->RemoveTopLevelWindow(accessible);
 }
 
@@ -1091,7 +1153,7 @@ void Window::EnableFloatingMode(bool enable)
 Rect<int> Window::RecalculateRect(const Rect<int>& rect)
 {
   Rect<int> newRect;
-  int screenWidth, screenHeight;
+  int       screenWidth, screenHeight;
 
   WindowSystem::GetScreenSize(screenWidth, screenHeight);
 
@@ -1158,6 +1220,21 @@ void Window::SendRotationCompletedAcknowledgement()
   }
 }
 
+bool Window::IsWindowRotating() const
+{
+  return mWindowSurface->IsWindowRotating();
+}
+
+const Dali::KeyEvent& Window::GetLastKeyEvent() const
+{
+  return mLastKeyEvent;
+}
+
+const Dali::TouchEvent& Window::GetLastTouchEvent() const
+{
+  return mLastTouchEvent;
+}
+
 } // namespace Adaptor
 
 } // namespace Internal
index dff9c28..fe61dfe 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_WINDOWSYSTEM_COMMON_WINDOW_IMPL_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
 // EXTERNAL INCLUDES
 #include <dali/public-api/actors/layer.h>
 #include <dali/public-api/adaptor-framework/window-enumerations.h>
+#include <dali/public-api/events/touch-event.h>
 #include <dali/public-api/object/base-object.h>
 #include <dali/public-api/object/property-array.h>
 #include <dali/public-api/object/ref-object.h>
@@ -65,6 +66,7 @@ public:
   typedef Dali::DevelWindow::TransitionEffectEventSignalType         TransitionEffectEventSignalType;
   typedef Dali::DevelWindow::KeyboardRepeatSettingsChangedSignalType KeyboardRepeatSettingsChangedSignalType;
   typedef Dali::DevelWindow::AuxiliaryMessageSignalType              AuxiliaryMessageSignalType;
+  typedef Dali::DevelWindow::AccessibilityHighlightSignalType        AccessibilityHighlightSignalType;
   typedef Signal<void()>                                             SignalType;
 
   /**
@@ -88,7 +90,7 @@ public:
    * @param[in] isTransparent Whether window is transparent
    * @return A newly allocated Window
    */
-  static Window* New(Any surface, const PositionSize& positionSize, const std::string& name, const std::string& className,  Dali::WindowType type, bool isTransparent = false);
+  static Window* New(Any surface, const PositionSize& positionSize, const std::string& name, const std::string& className, Dali::WindowType type, bool isTransparent = false);
 
   /**
    * @copydoc Dali::Window::SetClass()
@@ -127,6 +129,11 @@ public:
   bool IsMaximized() const;
 
   /**
+   * @copydoc Dali::DevelWindow::SetMaximumSize()
+   */
+  void SetMaximumSize(Dali::Window::WindowSize size);
+
+  /**
    * @copydoc Dali::DevelWindow::Minimize()
    */
   void Minimize(bool minimize);
@@ -137,6 +144,11 @@ public:
   bool IsMinimized() const;
 
   /**
+   * @copydoc Dali::DevelWindow::SetMimimumSize()
+   */
+  void SetMimimumSize(Dali::Window::WindowSize size);
+
+  /**
    * @copydoc Dali::Window::GetLayerCount()
    */
   uint32_t GetLayerCount() const;
@@ -152,6 +164,12 @@ public:
   Dali::RenderTaskList GetRenderTaskList() const;
 
   /**
+   * @brief Get window resource ID assigned by window manager
+   * @return The resource ID of the window
+   */
+  std::string GetNativeResourceId() const;
+
+  /**
    * @copydoc Dali::Window::AddAvailableOrientation()
    */
   void AddAvailableOrientation(WindowOrientation orientation);
@@ -386,6 +404,16 @@ public:
    */
   void SetPositionSizeWithOrientation(PositionSize positionSize, WindowOrientation orientation);
 
+  /**
+   * @brief Emit the accessibility highlight signal.
+   * The highlight indicates that it is an object to interact with the user regardless of focus.
+   * After setting the highlight on the object, you can do things that the object can do, such as
+   * giving or losing focus.
+   *
+   * @param[in] highlight If window needs to grab or clear highlight.
+   */
+  void EmitAccessibilityHighlightSignal(bool highlight);
+
 public: // Dali::Internal::Adaptor::SceneHolder
   /**
    * @copydoc Dali::Internal::Adaptor::SceneHolder::GetNativeHandle
@@ -437,6 +465,21 @@ public: // Dali::Internal::Adaptor::SceneHolder
    */
   void SendRotationCompletedAcknowledgement();
 
+  /**
+   * @copydoc Dali::DevelWindow::IsWindowRotating()
+   */
+  bool IsWindowRotating() const;
+
+  /**
+   * @copydoc Dali::DevelWindow::GetLastKeyEvent()
+   */
+  const Dali::KeyEvent& GetLastKeyEvent() const;
+
+  /**
+   * @copydoc Dali::DevelWindow::GetLastTouchEvent()
+   */
+  const Dali::TouchEvent& GetLastTouchEvent() const;
+
 private:
   /**
    * @brief Enumeration for orietation mode.
@@ -677,31 +720,32 @@ public: // Signals
     return mAuxiliaryMessageSignal;
   }
 
+  /**
+   * @copydoc Dali::DevelWindow::AccessibilityHighlightSignal()
+   */
+  AccessibilityHighlightSignalType& AccessibilityHighlightSignal()
+  {
+    return mAccessibilityHighlightSignal;
+  }
+
 private:
   WindowRenderSurface* mWindowSurface; ///< The window rendering surface
   WindowBase*          mWindowBase;
   std::string          mName;
   std::string          mClassName;
-  bool                 mIsTransparent : 1;
-  bool                 mIsFocusAcceptable : 1;
-  bool                 mIconified : 1;
-  bool                 mOpaqueState : 1;
-  bool                 mWindowRotationAcknowledgement : 1;
   Dali::Window         mParentWindow;
 
   OrientationPtr   mOrientation;
   std::vector<int> mAvailableAngles;
   int              mPreferredAngle;
 
-  int mRotationAngle;                    ///< The angle of the rotation
-  int mWindowWidth;                      ///< The width of the window
-  int mWindowHeight;                     ///< The height of the window
-
-  EventHandlerPtr mEventHandler;         ///< The window events handler
+  int mRotationAngle;  ///< The angle of the rotation
+  int mWindowWidth;    ///< The width of the window
+  int mWindowHeight;   ///< The height of the window
+  int mNativeWindowId; ///< The Native Window Id
 
-  OrientationMode mOrientationMode;      ///< The physical screen mode is portrait or landscape
-
-  int mNativeWindowId;                   ///< The Native Window Id
+  EventHandlerPtr mEventHandler;    ///< The window events handler
+  OrientationMode mOrientationMode; ///< The physical screen mode is portrait or landscape
 
   // Signals
   SignalType                              mDeleteRequestSignal;
@@ -711,6 +755,17 @@ private:
   TransitionEffectEventSignalType         mTransitionEffectEventSignal;
   KeyboardRepeatSettingsChangedSignalType mKeyboardRepeatSettingsChangedSignal;
   AuxiliaryMessageSignalType              mAuxiliaryMessageSignal;
+  AccessibilityHighlightSignalType        mAccessibilityHighlightSignal;
+
+  Dali::KeyEvent   mLastKeyEvent;
+  Dali::TouchEvent mLastTouchEvent;
+
+  bool mIsTransparent : 1;
+  bool mIsFocusAcceptable : 1;
+  bool mIconified : 1;
+  bool mOpaqueState : 1;
+  bool mWindowRotationAcknowledgement : 1;
+  bool mFocused : 1;
 };
 
 } // namespace Adaptor
index 7d53976..c6cee4a 100644 (file)
@@ -211,7 +211,7 @@ void WindowRenderSurface::SetTransparency(bool transparent)
   mWindowBase->SetTransparency(transparent);
 }
 
-void WindowRenderSurface::RequestRotation(int angle, int width, int height)
+void WindowRenderSurface::RequestRotation(int angle, PositionSize positionSize)
 {
   if(!mPostRenderTrigger)
   {
@@ -219,8 +219,7 @@ void WindowRenderSurface::RequestRotation(int angle, int width, int height)
                                                                                                       TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER));
   }
 
-  mPositionSize.width  = width;
-  mPositionSize.height = height;
+  mPositionSize = positionSize;
 
   mWindowRotationAngle    = angle;
   mWindowRotationFinished = false;
@@ -228,7 +227,7 @@ void WindowRenderSurface::RequestRotation(int angle, int width, int height)
 
   mWindowBase->SetWindowRotationAngle(mWindowRotationAngle);
 
-  DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: angle = %d screen rotation = %d\n", mWindowRotationAngle, mScreenRotationAngle);
+  DALI_LOG_RELEASE_INFO("angle = %d screen rotation = %d, flag = %d\n", mWindowRotationAngle, mScreenRotationAngle, mWindowRotationFinished);
 }
 
 WindowBase* WindowRenderSurface::GetWindowBase()
@@ -582,7 +581,7 @@ bool WindowRenderSurface::PreRender(bool resizingSurface, const std::vector<Rect
       mWindowBase->ResizeEglWindow(positionSize);
       mResizeFinished = true;
 
-      DALI_LOG_RELEASE_INFO("WindowRenderSurface::PreRender: Set resize, x: %d, y: %d, w: %d, h:%d\n", positionSize.x, positionSize.y, positionSize.width, positionSize.height);
+      DALI_LOG_RELEASE_INFO("WindowRenderSurface::PreRender: Set resize, totalAngle: %d, x: %d, y: %d, w: %d, h:%d\n", totalAngle, positionSize.x, positionSize.y, positionSize.width, positionSize.height);
     }
 
     SetFullSwapNextFrame();
@@ -748,13 +747,18 @@ void WindowRenderSurface::OutputTransformed()
   }
 }
 
+bool WindowRenderSurface::IsWindowRotating() const
+{
+  return !(mWindowRotationFinished);
+}
+
 void WindowRenderSurface::ProcessPostRender()
 {
   if(!mWindowRotationFinished)
   {
     mWindowBase->WindowRotationCompleted(mWindowRotationAngle, mPositionSize.width, mPositionSize.height);
-    DALI_LOG_RELEASE_INFO("WindowRenderSurface::ProcessPostRender: Rotation Done\n");
     mWindowRotationFinished = true;
+    DALI_LOG_RELEASE_INFO("WindowRenderSurface::ProcessPostRender: Rotation Done, flag = %d\n", mWindowRotationFinished);
   }
 
   if(mIsImeWindowSurface)
index 2c81fe8..5e58893 100644 (file)
@@ -97,10 +97,9 @@ public: // API
   /**
    * Request surface rotation
    * @param[in] angle A new angle of the surface
-   * @param[in] width A new width of the surface
-   * @param[in] height A new height of the surface
+   * @param[in] positionSize A new position and size of the surface
    */
-  void RequestRotation(int angle, int width, int height);
+  void RequestRotation(int angle, PositionSize positionSize);
 
   /**
    * @brief Gets the window base object
@@ -139,6 +138,13 @@ public: // API
   void UpdatePositionSize(Dali::PositionSize positionSize);
 
   /**
+   * @brief Query whether window is rotating or not.
+   *
+   * @return true if window is rotating, false otherwise.
+   */
+  bool IsWindowRotating() const;
+
+  /**
    * @brief This signal is emitted when the output is transformed.
    */
   OutputSignalType& OutputTransformedSignal();
index eef4f6e..a1d6e2d 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -53,6 +53,11 @@ public:
   int GetNativeWindowId() override;
 
   /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetNativeWindowResourceId()
+   */
+  std::string GetNativeWindowResourceId() override;
+
+  /**
   * @copydoc Dali::Internal::Adaptor::WindowBase::CreateEglWindow()
    */
   EGLNativeWindowType CreateEglWindow(int width, int height) override;
@@ -133,6 +138,11 @@ public:
   bool IsMaximized() const override;
 
   /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetMaximumSize()
+   */
+  void SetMaximumSize(Dali::Window::WindowSize size) override;
+
+  /**
    * @copydoc Dali::Internal::Adaptor::WindowBase::Minimize()
    */
   void Minimize(bool minimize) override;
@@ -143,6 +153,11 @@ public:
   bool IsMinimized() const override;
 
   /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetMimimumSize()
+   */
+  void SetMimimumSize(Dali::Window::WindowSize size) override;
+
+  /**
    * @copydoc Dali::Internal::Adaptor::WindowBase::SetAvailableAnlges()
    */
   void SetAvailableAnlges(const std::vector<int>& angles) override;
index 6ca0681..7c1de56 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -376,6 +376,11 @@ int WindowBaseCocoa::GetNativeWindowId()
   return mImpl->mWindow.windowNumber;
 }
 
+std::string WindowBaseCocoa::GetNativeWindowResourceId()
+{
+  return std::string();
+}
+
 EGLNativeWindowType WindowBaseCocoa::CreateEglWindow(int width, int height)
 {
   // XXX: this method is called from a secondary thread, but
@@ -479,6 +484,10 @@ bool WindowBaseCocoa::IsMaximized() const
   return false;
 }
 
+void WindowBaseCocoa::SetMaximumSize(Dali::Window::WindowSize size)
+{
+}
+
 void WindowBaseCocoa::Minimize(bool minimize)
 {
 }
@@ -488,6 +497,10 @@ bool WindowBaseCocoa::IsMinimized() const
   return false;
 }
 
+void WindowBaseCocoa::SetMimimumSize(Dali::Window::WindowSize size)
+{
+}
+
 void WindowBaseCocoa::SetAvailableAnlges( const std::vector< int >& angles )
 {
 }
index 3c2e234..136f20a 100644 (file)
@@ -45,7 +45,8 @@ DisplayConnection* DisplayConnectionEcoreWl::New()
 DisplayConnectionEcoreWl::DisplayConnectionEcoreWl()
 : mDisplay(NULL),
   mSurfaceType(RenderSurfaceInterface::WINDOW_RENDER_SURFACE),
-  mGraphics(nullptr)
+  mGraphics(nullptr),
+  mBufMgr(nullptr)
 {
 }
 
@@ -106,6 +107,12 @@ void DisplayConnectionEcoreWl::SetGraphicsInterface(GraphicsInterface& graphics)
 
 EGLNativeDisplayType DisplayConnectionEcoreWl::GetNativeDisplay()
 {
+  mBufMgr = tbm_bufmgr_init(-1);  // -1 is meaningless. The parameter in this function is deprecated.
+  if(mBufMgr == nullptr)
+  {
+    DALI_LOG_ERROR("Fail to init tbm buf mgr\n");
+    return nullptr;
+  }
   return reinterpret_cast<EGLNativeDisplayType>(tbm_dummy_display_create());
 }
 
@@ -115,6 +122,11 @@ void DisplayConnectionEcoreWl::ReleaseNativeDisplay()
   {
     tbm_dummy_display_destroy(reinterpret_cast<tbm_dummy_display*>(mDisplay));
   }
+
+  if(mBufMgr != nullptr)
+  {
+    tbm_bufmgr_deinit(mBufMgr);
+  }
 }
 
 } // namespace Adaptor
index 191a9ee..06a3dad 100644 (file)
@@ -18,6 +18,9 @@
  *
  */
 
+// EXTERNAL INCLUDES
+#include <tbm_bufmgr.h>
+
 // INTERNAL INCLUDES
 #include <dali/internal/window-system/common/display-connection-impl.h>
 
@@ -102,6 +105,7 @@ private:
   EGLNativeDisplayType               mDisplay;     ///< Wayland-display for rendering
   Dali::RenderSurfaceInterface::Type mSurfaceType; ///< The surface type
   GraphicsInterface*                 mGraphics;    ///< The graphics interface
+  tbm_bufmgr                         mBufMgr;      ///< For creating tbm_dummy_display
 };
 
 } // namespace Adaptor
index 6be7165..ccef811 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -441,22 +441,6 @@ static void VconfNotifyFontSizeChanged(keynode_t* node, void* data)
   }
 }
 
-/////////////////////////////////////////////////////////////////////////////////////////////////
-// ElDBus Accessibility Callbacks
-/////////////////////////////////////////////////////////////////////////////////////////////////
-
-#ifdef DALI_ELDBUS_AVAILABLE
-// Callback for Ecore ElDBus accessibility events.
-static void EcoreElDBusAccessibilityNotification(void* context, const Eldbus_Message* message)
-{
-  WindowBaseEcoreWl* windowBase = static_cast<WindowBaseEcoreWl*>(context);
-  if(windowBase)
-  {
-    windowBase->OnEcoreElDBusAccessibilityNotification(context, message);
-  }
-}
-#endif // DALI_ELDBUS_AVAILABLE
-
 static void RegistryGlobalCallback(void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t version)
 {
   WindowBaseEcoreWl* windowBase = static_cast<WindowBaseEcoreWl*>(data);
@@ -582,24 +566,12 @@ WindowBaseEcoreWl::WindowBaseEcoreWl(Dali::PositionSize positionSize, Any surfac
   mWindowRotationAngle(0),
   mScreenRotationAngle(0),
   mSupportedPreProtation(0)
-#ifdef DALI_ELDBUS_AVAILABLE
-  ,
-  mSystemConnection(NULL)
-#endif
 {
   Initialize(positionSize, surface, isTransparent);
 }
 
 WindowBaseEcoreWl::~WindowBaseEcoreWl()
 {
-#ifdef DALI_ELDBUS_AVAILABLE
-  // Close down ElDBus connections.
-  if(mSystemConnection)
-  {
-    eldbus_connection_unref(mSystemConnection);
-  }
-#endif // DALI_ELDBUS_AVAILABLE
-
   vconf_ignore_key_changed(VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_SIZE, VconfNotifyFontSizeChanged);
   vconf_ignore_key_changed(DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_NAME, VconfNotifyFontNameChanged);
 
@@ -686,8 +658,6 @@ void WindowBaseEcoreWl::Initialize(PositionSize positionSize, Any surface, bool
   vconf_notify_key_changed(DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_NAME, VconfNotifyFontNameChanged, this);
   vconf_notify_key_changed(VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_SIZE, VconfNotifyFontSizeChanged, this);
 
-  InitializeEcoreElDBus();
-
   mDisplay = ecore_wl_display_get();
 
   if(mDisplay)
@@ -1098,21 +1068,6 @@ void WindowBaseEcoreWl::OnFontSizeChanged()
   mStyleChangedSignal.Emit(StyleChange::DEFAULT_FONT_SIZE_CHANGE);
 }
 
-void WindowBaseEcoreWl::OnEcoreElDBusAccessibilityNotification(void* context, const Eldbus_Message* message)
-{
-#ifdef DALI_ELDBUS_AVAILABLE
-  AccessibilityInfo info;
-
-  // The string defines the arg-list's respective types.
-  if(!eldbus_message_arguments_get(message, "iiiiiiu", &info.gestureValue, &info.startX, &info.startY, &info.endX, &info.endY, &info.state, &info.eventTime))
-  {
-    DALI_LOG_ERROR("OnEcoreElDBusAccessibilityNotification: Error getting arguments\n");
-  }
-
-  mAccessibilitySignal.Emit(info);
-#endif
-}
-
 void WindowBaseEcoreWl::RegistryGlobalCallback(void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t version)
 {
   if(strcmp(interface, tizen_policy_interface.name) == 0)
@@ -1188,6 +1143,11 @@ int WindowBaseEcoreWl::GetNativeWindowId()
   return ecore_wl_window_id_get(mEcoreWindow);
 }
 
+std::string WindowBaseEcoreWl::GetNativeWindowResourceId()
+{
+  return std::string();
+}
+
 EGLNativeWindowType WindowBaseEcoreWl::CreateEglWindow(int width, int height)
 {
   mEglWindow = wl_egl_window_create(mWlSurface, width, height);
@@ -1377,6 +1337,10 @@ bool WindowBaseEcoreWl::IsMaximized() const
   return false;
 }
 
+void WindowBaseEcoreWl::SetMaximumSize(Dali::Window::WindowSize size)
+{
+}
+
 void WindowBaseEcoreWl::Minimize(bool minimize)
 {
 }
@@ -1386,6 +1350,10 @@ bool WindowBaseEcoreWl::IsMinimized() const
   return false;
 }
 
+void WindowBaseEcoreWl::SetMimimumSize(Dali::Window::WindowSize size)
+{
+}
+
 void WindowBaseEcoreWl::SetAvailableAnlges(const std::vector<int>& angles)
 {
   int rotations[4] = {0};
@@ -2135,38 +2103,6 @@ void WindowBaseEcoreWl::SetTransparency(bool transparent)
   ecore_wl_window_alpha_set(mEcoreWindow, transparent);
 }
 
-void WindowBaseEcoreWl::InitializeEcoreElDBus()
-{
-#ifdef DALI_ELDBUS_AVAILABLE
-  Eldbus_Object* object;
-  Eldbus_Proxy*  manager;
-
-  if(!(mSystemConnection = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SYSTEM)))
-  {
-    DALI_LOG_ERROR("Unable to get system bus\n");
-  }
-
-  object = eldbus_object_get(mSystemConnection, BUS, PATH);
-  if(!object)
-  {
-    DALI_LOG_ERROR("Getting object failed\n");
-    return;
-  }
-
-  manager = eldbus_proxy_get(object, INTERFACE);
-  if(!manager)
-  {
-    DALI_LOG_ERROR("Getting proxy failed\n");
-    return;
-  }
-
-  if(!eldbus_proxy_signal_handler_add(manager, "GestureDetected", EcoreElDBusAccessibilityNotification, this))
-  {
-    DALI_LOG_ERROR("No signal handler returned\n");
-  }
-#endif
-}
-
 void WindowBaseEcoreWl::CreateWindow(PositionSize positionSize)
 {
   mEcoreWindow = ecore_wl_window_new(0, positionSize.x, positionSize.y, positionSize.width, positionSize.height, ECORE_WL_WINDOW_BUFFER_TYPE_EGL_WINDOW);
index 6bdbd10..741224d 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_WINDOWSYSTEM_TIZENWAYLAND_WINDOW_BASE_ECORE_WL_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #include <tizen-extension-client-protocol.h>
 #include <wayland-egl.h>
 
-#ifdef DALI_ELDBUS_AVAILABLE
-#include <Eldbus.h>
-#endif
-
 namespace Dali
 {
 namespace Internal
@@ -147,13 +143,6 @@ public:
    */
   void OnFontSizeChanged();
 
-#ifdef DALI_ELDBUS_AVAILABLE
-  /**
-   * @brief Called when Ecore ElDBus accessibility event is received.
-   */
-  void OnEcoreElDBusAccessibilityNotification(void* context, const Eldbus_Message* message);
-#endif
-
   /**
    * @brief RegistryGlobalCallback
    */
@@ -191,6 +180,11 @@ public:
   int GetNativeWindowId() override;
 
   /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetNativeWindowResourceId()
+   */
+  std::string GetNativeWindowResourceId() override;
+
+  /**
    * @copydoc Dali::Internal::Adaptor::WindowBase::CreateEglWindow()
    */
   EGLNativeWindowType CreateEglWindow(int width, int height) override;
@@ -271,6 +265,11 @@ public:
   bool IsMaximized() const override;
 
   /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetMaximumSize()
+   */
+  void SetMaximumSize(Dali::Window::WindowSize size) override;
+
+  /**
    * @copydoc Dali::Internal::Adaptor::WindowBase::Minimize()
    */
   void Minimize(bool minimize) override;
@@ -281,6 +280,11 @@ public:
   bool IsMinimized() const override;
 
   /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetMimimumSize()
+   */
+  void SetMimimumSize(Dali::Window::WindowSize size) override;
+
+  /**
    * @copydoc Dali::Internal::Adaptor::WindowBase::SetAvailableAnlges()
    */
   void SetAvailableAnlges(const std::vector<int>& angles) override;
@@ -507,11 +511,6 @@ private:
   void Initialize(PositionSize positionSize, Any surface, bool isTransparent);
 
   /**
-   * Initialize Ecore ElDBus
-   */
-  void InitializeEcoreElDBus();
-
-  /**
    * @brief Create window
    */
   void CreateWindow(PositionSize positionSize);
@@ -556,9 +555,6 @@ private:
   int mWindowRotationAngle;
   int mScreenRotationAngle;
   int mSupportedPreProtation;
-#ifdef DALI_ELDBUS_AVAILABLE
-  Eldbus_Connection* mSystemConnection;
-#endif // DALI_ELDBUS_AVAILABLE
 };
 
 } // namespace Adaptor
index dd15ec4..6c15aad 100644 (file)
@@ -55,13 +55,6 @@ const unsigned int PRIMARY_TOUCH_BUTTON_ID  = 1;
 
 const char* DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_NAME = "db/setting/accessibility/font_name"; // It will be update at vconf-key.h and replaced.
 
-#ifdef DALI_ELDBUS_AVAILABLE
-// DBUS accessibility
-const char* BUS       = "org.enlightenment.wm-screen-reader";
-const char* INTERFACE = "org.tizen.GestureNavigation";
-const char* PATH      = "/org/tizen/GestureNavigation";
-#endif // DALI_ELDBUS_AVAILABLE
-
 struct KeyCodeMap
 {
   xkb_keysym_t  keySym;
@@ -449,9 +442,9 @@ static Eina_Bool EcoreEventDataSend(void* data, int type, void* event)
 }
 
 /**
-* Called when the source window sends us about the selected content.
-* For example, when item is selected in the clipboard.
-*/
+ * Called when the source window sends us about the selected content.
+ * For example, when item is selected in the clipboard.
+ */
 static Eina_Bool EcoreEventDataReceive(void* data, int type, void* event)
 {
   WindowBaseEcoreWl2* windowBase = static_cast<WindowBaseEcoreWl2*>(data);
@@ -508,9 +501,8 @@ static Eina_Bool EcoreEventEffectEnd(void* data, int type, void* event)
 
 static Eina_Bool EcoreEventSeatKeyboardRepeatChanged(void* data, int type, void* event)
 {
-  Ecore_Wl2_Event_Seat_Keyboard_Repeat_Changed* keyboardRepeat = static_cast<Ecore_Wl2_Event_Seat_Keyboard_Repeat_Changed*>(event);
-  WindowBaseEcoreWl2*                           windowBase     = static_cast<WindowBaseEcoreWl2*>(data);
-  DALI_LOG_INFO(gWindowBaseLogFilter, Debug::General, "WindowBaseEcoreWl2::EcoreEventSeatKeyboardRepeatChanged, id[ %d ]\n", keyboardRepeat->id);
+  WindowBaseEcoreWl2* windowBase = static_cast<WindowBaseEcoreWl2*>(data);
+  DALI_LOG_INFO(gWindowBaseLogFilter, Debug::General, "WindowBaseEcoreWl2::EcoreEventSeatKeyboardRepeatChanged, id[ %d ]\n", static_cast<Ecore_Wl2_Event_Seat_Keyboard_Repeat_Changed*>(event)->id);
   if(windowBase)
   {
     windowBase->OnKeyboardRepeatSettingsChanged();
@@ -568,9 +560,8 @@ static void VconfNotifyFontSizeChanged(keynode_t* node, void* data)
 
 static Eina_Bool EcoreEventWindowRedrawRequest(void* data, int type, void* event)
 {
-  Ecore_Wl2_Event_Window_Redraw_Request* windowRedrawRequest = static_cast<Ecore_Wl2_Event_Window_Redraw_Request*>(event);
-  WindowBaseEcoreWl2*                    windowBase          = static_cast<WindowBaseEcoreWl2*>(data);
-  DALI_LOG_INFO(gWindowBaseLogFilter, Debug::General, "WindowBaseEcoreWl2::EcoreEventWindowRedrawRequest, window[ %d ]\n", windowRedrawRequest->win);
+  WindowBaseEcoreWl2* windowBase = static_cast<WindowBaseEcoreWl2*>(data);
+  DALI_LOG_INFO(gWindowBaseLogFilter, Debug::General, "WindowBaseEcoreWl2::EcoreEventWindowRedrawRequest, window[ %d ]\n", static_cast<Ecore_Wl2_Event_Window_Redraw_Request*>(event)->win);
   if(windowBase)
   {
     windowBase->OnEcoreEventWindowRedrawRequest();
@@ -592,22 +583,6 @@ static Eina_Bool EcoreEventWindowAuxiliaryMessage(void* data, int type, void* ev
   return ECORE_CALLBACK_RENEW;
 }
 
-/////////////////////////////////////////////////////////////////////////////////////////////////
-// ElDBus Accessibility Callbacks
-/////////////////////////////////////////////////////////////////////////////////////////////////
-
-#ifdef DALI_ELDBUS_AVAILABLE
-// Callback for Ecore ElDBus accessibility events.
-static void EcoreElDBusAccessibilityNotification(void* context, const Eldbus_Message* message)
-{
-  WindowBaseEcoreWl2* windowBase = static_cast<WindowBaseEcoreWl2*>(context);
-  if(windowBase)
-  {
-    windowBase->OnEcoreElDBusAccessibilityNotification(context, message);
-  }
-}
-#endif // DALI_ELDBUS_AVAILABLE
-
 static void RegistryGlobalCallback(void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t version)
 {
   WindowBaseEcoreWl2* windowBase = static_cast<WindowBaseEcoreWl2*>(data);
@@ -732,6 +707,8 @@ WindowBaseEcoreWl2::WindowBaseEcoreWl2(Dali::PositionSize positionSize, Any surf
   mWindowRotationAngle(0),
   mScreenRotationAngle(0),
   mSupportedPreProtation(0),
+  mScreenWidth(0),
+  mScreenHeight(0),
   mNotificationChangeState(0),
   mScreenOffModeChangeState(0),
   mBrightnessChangeState(0),
@@ -742,24 +719,12 @@ WindowBaseEcoreWl2::WindowBaseEcoreWl2(Dali::PositionSize positionSize, Any surf
   mVisible(true),
   mOwnSurface(false),
   mBrightnessChangeDone(true)
-#ifdef DALI_ELDBUS_AVAILABLE
-  ,
-  mSystemConnection(NULL)
-#endif
 {
   Initialize(positionSize, surface, isTransparent);
 }
 
 WindowBaseEcoreWl2::~WindowBaseEcoreWl2()
 {
-#ifdef DALI_ELDBUS_AVAILABLE
-  // Close down ElDBus connections.
-  if(mSystemConnection)
-  {
-    eldbus_connection_unref(mSystemConnection);
-  }
-#endif // DALI_ELDBUS_AVAILABLE
-
   vconf_ignore_key_changed(VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_SIZE, VconfNotifyFontSizeChanged);
   vconf_ignore_key_changed(DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_NAME, VconfNotifyFontNameChanged);
 
@@ -862,8 +827,6 @@ void WindowBaseEcoreWl2::Initialize(PositionSize positionSize, Any surface, bool
   vconf_notify_key_changed(DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_NAME, VconfNotifyFontNameChanged, this);
   vconf_notify_key_changed(VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_SIZE, VconfNotifyFontSizeChanged, this);
 
-  InitializeEcoreElDBus();
-
   Ecore_Wl2_Display* display = ecore_wl2_connected_display_get(NULL);
   mDisplay                   = ecore_wl2_display_get(display);
 
@@ -1005,34 +968,23 @@ void WindowBaseEcoreWl2::OnRotation(void* data, int type, void* event)
 
     if(ev->w == 0 || ev->h == 0)
     {
-      // Use previous client side window's size.
-      if(mWindowRotationAngle == 90 || mWindowRotationAngle == 270)
-      {
-        ev->w = mWindowPositionSize.height;
-        ev->h = mWindowPositionSize.width;
-      }
-      else
-      {
-        ev->w = mWindowPositionSize.width;
-        ev->h = mWindowPositionSize.height;
-      }
+      // When rotation event does not have the window width or height,
+      // previous DALi side window's size are used.
+      ev->w = mWindowPositionSize.width;
+      ev->h = mWindowPositionSize.height;
     }
 
     mWindowRotationAngle = ev->angle;
 
-    if(ev->angle == 0 || ev->angle == 180)
-    {
-      rotationEvent.width  = ev->w;
-      rotationEvent.height = ev->h;
-    }
-    else
-    {
-      rotationEvent.width  = ev->h;
-      rotationEvent.height = ev->w;
-    }
+    mWindowPositionSize.width  = ev->w;
+    mWindowPositionSize.height = ev->h;
 
-    mWindowPositionSize.width  = rotationEvent.width;
-    mWindowPositionSize.height = rotationEvent.height;
+    PositionSize newPositionSize = RecalculatePositionSizeToCurrentOrientation(mWindowPositionSize);
+
+    rotationEvent.x      = newPositionSize.x;
+    rotationEvent.y      = newPositionSize.y;
+    rotationEvent.width  = newPositionSize.width;
+    rotationEvent.height = newPositionSize.height;
 
     mRotationSignal.Emit(rotationEvent);
   }
@@ -1072,9 +1024,16 @@ void WindowBaseEcoreWl2::OnConfiguration(void* data, int type, void* event)
 
     if(windowMoved || windowResized)
     {
-      Dali::PositionSize newPositionSize(ev->x, ev->y, newWidth, newHeight);
-      mWindowPositionSize = newPositionSize;
-      DALI_LOG_RELEASE_INFO("Update position & resize signal by server, x[%d] y[%d] w[%d] h[%d]\n", newPositionSize.x, newPositionSize.y, newPositionSize.width, newPositionSize.height);
+      mWindowPositionSize.x      = ev->x;
+      mWindowPositionSize.y      = ev->y;
+      mWindowPositionSize.width  = newWidth;
+      mWindowPositionSize.height = newHeight;
+      DALI_LOG_RELEASE_INFO("Update position & resize signal by server, current angle [%d] x[%d] y[%d] w[%d] h[%d]\n", mWindowRotationAngle, mWindowPositionSize.x, mWindowPositionSize.y, mWindowPositionSize.width, mWindowPositionSize.height);
+
+      ecore_wl2_window_geometry_set(mEcoreWindow, mWindowPositionSize.x, mWindowPositionSize.y, mWindowPositionSize.width, mWindowPositionSize.height);
+
+      Dali::PositionSize newPositionSize = RecalculatePositionSizeToCurrentOrientation(mWindowPositionSize);
+      DALI_LOG_RELEASE_INFO("emit signal to update window's position and size, x[%d] y[%d] w[%d] h[%d]\n", newPositionSize.x, newPositionSize.y, newPositionSize.width, newPositionSize.height);
       mUpdatePositionSizeSignal.Emit(newPositionSize);
     }
 
@@ -1372,21 +1331,6 @@ void WindowBaseEcoreWl2::OnFontSizeChanged()
   mStyleChangedSignal.Emit(StyleChange::DEFAULT_FONT_SIZE_CHANGE);
 }
 
-#ifdef DALI_ELDBUS_AVAILABLE
-void WindowBaseEcoreWl2::OnEcoreElDBusAccessibilityNotification(void* context, const Eldbus_Message* message)
-{
-  AccessibilityInfo info;
-
-  // The string defines the arg-list's respective types.
-  if(!eldbus_message_arguments_get(message, "iiiiiiu", &info.gestureValue, &info.startX, &info.startY, &info.endX, &info.endY, &info.state, &info.eventTime))
-  {
-    DALI_LOG_ERROR("OnEcoreElDBusAccessibilityNotification: Error getting arguments\n");
-  }
-
-  mAccessibilitySignal.Emit(info);
-}
-#endif // DALI_ELDBUS_AVAILABLE
-
 void WindowBaseEcoreWl2::OnTransitionEffectEvent(WindowEffectState state, WindowEffectType type)
 {
   mTransitionEffectEventSignal.Emit(state, type);
@@ -1407,7 +1351,7 @@ void WindowBaseEcoreWl2::OnEcoreEventWindowAuxiliaryMessage(void* event)
   Ecore_Wl2_Event_Aux_Message* message = static_cast<Ecore_Wl2_Event_Aux_Message*>(event);
   if(message)
   {
-    DALI_LOG_RELEASE_INFO("WindowBaseEcoreWl2::OnEcoreEventWindowAuxiliaryMessage, key:%s, value:%s \n", message->key, message->val);
+    DALI_LOG_INFO(gWindowBaseLogFilter, Debug::General, "WindowBaseEcoreWl2::OnEcoreEventWindowAuxiliaryMessage, key:%s, value:%s \n", message->key, message->val);
     std::string           key(message->key);
     std::string           value(message->val);
     Dali::Property::Array options;
@@ -1418,7 +1362,7 @@ void WindowBaseEcoreWl2::OnEcoreEventWindowAuxiliaryMessage(void* event)
       void*      data;
       EINA_LIST_FOREACH(message->options, l, data)
       {
-        DALI_LOG_RELEASE_INFO("WindowBaseEcoreWl2::OnEcoreEventWindowAuxiliaryMessage, option: %s\n", (char*)data);
+        DALI_LOG_INFO(gWindowBaseLogFilter, Debug::General, "WindowBaseEcoreWl2::OnEcoreEventWindowAuxiliaryMessage, option: %s\n", (char*)data);
         std::string option(static_cast<char*>(data));
         options.Add(option);
       }
@@ -1532,6 +1476,15 @@ int WindowBaseEcoreWl2::GetNativeWindowId()
   return ecore_wl2_window_id_get(mEcoreWindow);
 }
 
+std::string WindowBaseEcoreWl2::GetNativeWindowResourceId()
+{
+#ifdef OVER_TIZEN_VERSION_7
+  return std::to_string(ecore_wl2_window_resource_id_get(mEcoreWindow));
+#else
+  return std::string();
+#endif
+}
+
 EGLNativeWindowType WindowBaseEcoreWl2::CreateEglWindow(int width, int height)
 {
   int totalAngle = (mWindowRotationAngle + mScreenRotationAngle) % 360;
@@ -1689,22 +1642,109 @@ bool WindowBaseEcoreWl2::IsEglWindowRotationSupported()
   return false;
 }
 
+PositionSize WindowBaseEcoreWl2::RecalculatePositionSizeToSystem(PositionSize positionSize)
+{
+  PositionSize newPositionSize;
+
+  if(mWindowRotationAngle == 90)
+  {
+    newPositionSize.x      = positionSize.y;
+    newPositionSize.y      = mScreenHeight - (positionSize.x + positionSize.width);
+    newPositionSize.width  = positionSize.height;
+    newPositionSize.height = positionSize.width;
+  }
+  else if(mWindowRotationAngle == 180)
+  {
+    newPositionSize.x      = mScreenWidth - (positionSize.x + positionSize.width);
+    newPositionSize.y      = mScreenHeight - (positionSize.y + positionSize.height);
+    newPositionSize.width  = positionSize.width;
+    newPositionSize.height = positionSize.height;
+  }
+  else if(mWindowRotationAngle == 270)
+  {
+    newPositionSize.x      = mScreenWidth - (positionSize.y + positionSize.height);
+    newPositionSize.y      = positionSize.x;
+    newPositionSize.width  = positionSize.height;
+    newPositionSize.height = positionSize.width;
+  }
+  else
+  {
+    newPositionSize.x      = positionSize.x;
+    newPositionSize.y      = positionSize.y;
+    newPositionSize.width  = positionSize.width;
+    newPositionSize.height = positionSize.height;
+  }
+
+  DALI_LOG_RELEASE_INFO("input coord x[%d], y[%d], w{%d], h[%d], screen w[%d], h[%d]\n", positionSize.x, positionSize.y, positionSize.width, positionSize.height, mScreenWidth, mScreenHeight);
+  DALI_LOG_RELEASE_INFO("recalc coord x[%d], y[%d], w{%d], h[%d]\n", newPositionSize.x, newPositionSize.y, newPositionSize.width, newPositionSize.height);
+
+  return newPositionSize;
+}
+
+PositionSize WindowBaseEcoreWl2::RecalculatePositionSizeToCurrentOrientation(PositionSize positionSize)
+{
+  PositionSize newPositionSize;
+
+  if(mWindowRotationAngle == 90)
+  {
+    newPositionSize.x      = mScreenHeight - (positionSize.y + positionSize.height);
+    newPositionSize.y      = positionSize.x;
+    newPositionSize.width  = positionSize.height;
+    newPositionSize.height = positionSize.width;
+  }
+  else if(mWindowRotationAngle == 180)
+  {
+    newPositionSize.x      = mScreenWidth - (positionSize.x + positionSize.width);
+    newPositionSize.y      = mScreenHeight - (positionSize.y + positionSize.height);
+    newPositionSize.width  = positionSize.width;
+    newPositionSize.height = positionSize.height;
+  }
+  else if(mWindowRotationAngle == 270)
+  {
+    newPositionSize.x      = positionSize.y;
+    newPositionSize.y      = mScreenWidth - (positionSize.x + positionSize.width);
+    newPositionSize.width  = positionSize.height;
+    newPositionSize.height = positionSize.width;
+  }
+  else
+  {
+    newPositionSize.x      = positionSize.x;
+    newPositionSize.y      = positionSize.y;
+    newPositionSize.width  = positionSize.width;
+    newPositionSize.height = positionSize.height;
+  }
+
+  DALI_LOG_RELEASE_INFO("input coord x[%d], y[%d], w{%d], h[%d], screen w[%d], h[%d]\n", positionSize.x, positionSize.y, positionSize.width, positionSize.height, mScreenWidth, mScreenHeight);
+  DALI_LOG_RELEASE_INFO("recalc by current orientation coord x[%d], y[%d], w{%d], h[%d]\n", newPositionSize.x, newPositionSize.y, newPositionSize.width, newPositionSize.height);
+
+  return newPositionSize;
+}
+
 void WindowBaseEcoreWl2::Move(PositionSize positionSize)
 {
-  mWindowPositionSize = positionSize;
-  ecore_wl2_window_position_set(mEcoreWindow, positionSize.x, positionSize.y);
+  PositionSize newPositionSize = RecalculatePositionSizeToSystem(positionSize);
+
+  mWindowPositionSize = newPositionSize;
+  DALI_LOG_RELEASE_INFO("ecore_wl2_window_position_set x[%d], y[%d]\n", newPositionSize.x, newPositionSize.y);
+  ecore_wl2_window_position_set(mEcoreWindow, newPositionSize.x, newPositionSize.y);
 }
 
 void WindowBaseEcoreWl2::Resize(PositionSize positionSize)
 {
-  mWindowPositionSize = positionSize;
-  ecore_wl2_window_geometry_set(mEcoreWindow, positionSize.x, positionSize.y, positionSize.width, positionSize.height);
+  PositionSize newPositionSize = RecalculatePositionSizeToSystem(positionSize);
+
+  mWindowPositionSize = newPositionSize;
+  DALI_LOG_RELEASE_INFO("ecore_wl2_window_sync_geometry_set, x[%d], y[%d], w{%d], h[%d]\n", newPositionSize.x, newPositionSize.y, newPositionSize.width, newPositionSize.height);
+  ecore_wl2_window_sync_geometry_set(mEcoreWindow, ++mMoveResizeSerial, newPositionSize.x, newPositionSize.y, newPositionSize.width, newPositionSize.height);
 }
 
 void WindowBaseEcoreWl2::MoveResize(PositionSize positionSize)
 {
-  mWindowPositionSize = positionSize;
-  ecore_wl2_window_sync_geometry_set(mEcoreWindow, ++mMoveResizeSerial, positionSize.x, positionSize.y, positionSize.width, positionSize.height);
+  PositionSize newPositionSize = RecalculatePositionSizeToSystem(positionSize);
+
+  mWindowPositionSize = newPositionSize;
+  DALI_LOG_RELEASE_INFO("ecore_wl2_window_sync_geometry_set, x[%d], y[%d], w{%d], h[%d]\n", newPositionSize.x, newPositionSize.y, newPositionSize.width, newPositionSize.height);
+  ecore_wl2_window_sync_geometry_set(mEcoreWindow, ++mMoveResizeSerial, newPositionSize.x, newPositionSize.y, newPositionSize.width, newPositionSize.height);
 }
 
 void WindowBaseEcoreWl2::SetClass(const std::string& name, const std::string& className)
@@ -1739,6 +1779,12 @@ bool WindowBaseEcoreWl2::IsMaximized() const
   return ecore_wl2_window_maximized_get(mEcoreWindow);
 }
 
+void WindowBaseEcoreWl2::SetMaximumSize(Dali::Window::WindowSize size)
+{
+  DALI_LOG_RELEASE_INFO("ecore_wl2_window_maximum_size_set, width: %d, height: %d\n", size.GetWidth(), size.GetHeight());
+  ecore_wl2_window_maximum_size_set(mEcoreWindow, size.GetWidth(), size.GetHeight());
+}
+
 void WindowBaseEcoreWl2::Minimize(bool minimize)
 {
   ecore_wl2_window_iconified_set(mEcoreWindow, minimize);
@@ -1749,6 +1795,12 @@ bool WindowBaseEcoreWl2::IsMinimized() const
   return ecore_wl2_window_iconified_get(mEcoreWindow);
 }
 
+void WindowBaseEcoreWl2::SetMimimumSize(Dali::Window::WindowSize size)
+{
+  DALI_LOG_RELEASE_INFO("ecore_wl2_window_minimum_size_set, width: %d, height: %d\n", size.GetWidth(), size.GetHeight());
+  ecore_wl2_window_minimum_size_set(mEcoreWindow, size.GetWidth(), size.GetHeight());
+}
+
 void WindowBaseEcoreWl2::SetAvailableAnlges(const std::vector<int>& angles)
 {
   int rotations[4] = {0};
@@ -1756,7 +1808,7 @@ void WindowBaseEcoreWl2::SetAvailableAnlges(const std::vector<int>& angles)
   for(std::size_t i = 0; i < angles.size(); ++i)
   {
     rotations[i] = static_cast<int>(angles[i]);
-    DALI_LOG_RELEASE_INFO("%d ", rotations[i]);
+    DALI_LOG_INFO(gWindowBaseLogFilter, Debug::General, "%d ", rotations[i]);
   }
   ecore_wl2_window_available_rotations_set(mEcoreWindow, rotations, angles.size());
 }
@@ -1776,17 +1828,7 @@ void WindowBaseEcoreWl2::Show()
 {
   if(!mVisible)
   {
-    // Ecore-wl2 has the original window size
-    // and he always sends the window rotation event with the swapped size.
-    // So, to restore, dali should set the reswapped size(original window size) to ecore-wl2 for restoring.
-    if(mWindowRotationAngle == 0 || mWindowRotationAngle == 180)
-    {
-      ecore_wl2_window_geometry_set(mEcoreWindow, mWindowPositionSize.x, mWindowPositionSize.y, mWindowPositionSize.width, mWindowPositionSize.height);
-    }
-    else
-    {
-      ecore_wl2_window_geometry_set(mEcoreWindow, mWindowPositionSize.x, mWindowPositionSize.y, mWindowPositionSize.height, mWindowPositionSize.width);
-    }
+    ecore_wl2_window_geometry_set(mEcoreWindow, mWindowPositionSize.x, mWindowPositionSize.y, mWindowPositionSize.width, mWindowPositionSize.height);
   }
   mVisible = true;
 
@@ -2525,38 +2567,6 @@ void WindowBaseEcoreWl2::SetTransparency(bool transparent)
   ecore_wl2_window_alpha_set(mEcoreWindow, transparent);
 }
 
-void WindowBaseEcoreWl2::InitializeEcoreElDBus()
-{
-#ifdef DALI_ELDBUS_AVAILABLE
-  Eldbus_Object* object;
-  Eldbus_Proxy*  manager;
-
-  if(!(mSystemConnection = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SYSTEM)))
-  {
-    DALI_LOG_ERROR("Unable to get system bus\n");
-  }
-
-  object = eldbus_object_get(mSystemConnection, BUS, PATH);
-  if(!object)
-  {
-    DALI_LOG_ERROR("Getting object failed\n");
-    return;
-  }
-
-  manager = eldbus_proxy_get(object, INTERFACE);
-  if(!manager)
-  {
-    DALI_LOG_ERROR("Getting proxy failed\n");
-    return;
-  }
-
-  if(!eldbus_proxy_signal_handler_add(manager, "GestureDetected", EcoreElDBusAccessibilityNotification, this))
-  {
-    DALI_LOG_ERROR("No signal handler returned\n");
-  }
-#endif
-}
-
 void WindowBaseEcoreWl2::CreateWindow(PositionSize positionSize)
 {
   Ecore_Wl2_Display* display = ecore_wl2_display_connect(NULL);
@@ -2576,6 +2586,9 @@ void WindowBaseEcoreWl2::CreateWindow(PositionSize positionSize)
 
   // Set default type
   ecore_wl2_window_type_set(mEcoreWindow, ECORE_WL2_WINDOW_TYPE_TOPLEVEL);
+
+  // Get Screen width, height
+  ecore_wl2_display_screen_size_get(display, &mScreenWidth, &mScreenHeight);
 }
 
 void WindowBaseEcoreWl2::SetParent(WindowBase* parentWinBase, bool belowParent)
index bf43ea3..78e2e8b 100644 (file)
 #include <wayland-egl.h>
 #include <xkbcommon/xkbcommon.h>
 
-#ifdef DALI_ELDBUS_AVAILABLE
-#include <Eldbus.h>
-#endif
-
 namespace Dali
 {
 namespace Internal
@@ -176,13 +172,6 @@ public:
    */
   void OnEcoreEventWindowAuxiliaryMessage(void* event);
 
-#ifdef DALI_ELDBUS_AVAILABLE
-  /**
-   * @brief Called when Ecore ElDBus accessibility event is received.
-   */
-  void OnEcoreElDBusAccessibilityNotification(void* context, const Eldbus_Message* message);
-#endif
-
   /**
    * @brief Called when a keymap is changed.
    */
@@ -230,6 +219,11 @@ public:
   int GetNativeWindowId() override;
 
   /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetNativeWindowResourceId()
+   */
+  std::string GetNativeWindowResourceId() override;
+
+  /**
    * @copydoc Dali::Internal::Adaptor::WindowBase::CreateEglWindow()
    */
   EGLNativeWindowType CreateEglWindow(int width, int height) override;
@@ -310,6 +304,11 @@ public:
   bool IsMaximized() const override;
 
   /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetMaximumSize()
+   */
+  void SetMaximumSize(Dali::Window::WindowSize size) override;
+
+  /**
    * @copydoc Dali::Internal::Adaptor::WindowBase::Minimize()
    */
   void Minimize(bool minimize) override;
@@ -320,6 +319,11 @@ public:
   bool IsMinimized() const override;
 
   /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetMimimumSize()
+   */
+  void SetMimimumSize(Dali::Window::WindowSize size) override;
+
+  /**
    * @copydoc Dali::Internal::Adaptor::WindowBase::SetAvailableAnlges()
    */
   void SetAvailableAnlges(const std::vector<int>& angles) override;
@@ -546,14 +550,27 @@ private:
   void Initialize(PositionSize positionSize, Any surface, bool isTransparent);
 
   /**
-   * Initialize Ecore ElDBus
+   * @brief Create window
    */
-  void InitializeEcoreElDBus();
+  void CreateWindow(PositionSize positionSize);
 
   /**
-   * @brief Create window
+   * @brief Return the window's position and size to recalulate with the default system coordinates.
+   * It is used when window is moved or resized for native ecore wayland window system.
+   *
+   * @param[in] positionSize the window's current position and size with current oriented window's coordinates.
+   * @return the re-calculated window's position and size on the default system coordinates.
    */
-  void CreateWindow(PositionSize positionSize);
+  PositionSize RecalculatePositionSizeToSystem(PositionSize positionSize);
+
+  /**
+   * @brief Return the window's position and size to recalulate with current oriented window's coordinates.
+   * It is used when window is moved or resized for dali and uppler layer framework.
+   *
+   * @param[in] positionSize the window's current position and size with the default system coordinates.
+   * @return the re-calculated window's position and size on current oriented window's coordinates.
+   */
+  PositionSize RecalculatePositionSizeToCurrentOrientation(PositionSize positionSize);
 
 protected:
   // Undefined
@@ -571,7 +588,7 @@ private:
 #ifdef OVER_TIZEN_VERSION_7
   zwp_input_panel_v1* mWlInputPanel;
 #else
-  wl_input_panel* mWlInputPanel;
+  wl_input_panel*         mWlInputPanel;
 #endif
   wl_output* mWlOutput;
 #ifdef OVER_TIZEN_VERSION_7
@@ -589,8 +606,10 @@ private:
 
   std::vector<std::string> mSupportedAuxiliaryHints;
 
+  // It is based on the default system coordinates.
   Dali::PositionSize mWindowPositionSize;
-  AuxiliaryHints     mAuxiliaryHints;
+
+  AuxiliaryHints mAuxiliaryHints;
 
   WindowType mType;
   int        mNotificationLevel;
@@ -599,6 +618,8 @@ private:
   int        mWindowRotationAngle;
   int        mScreenRotationAngle;
   int        mSupportedPreProtation;
+  int        mScreenWidth;
+  int        mScreenHeight;
 
   uint32_t          mNotificationChangeState;
   uint32_t          mScreenOffModeChangeState;
@@ -611,10 +632,6 @@ private:
   bool mVisible : 1;
   bool mOwnSurface;
   bool mBrightnessChangeDone;
-
-#ifdef DALI_ELDBUS_AVAILABLE
-  Eldbus_Connection* mSystemConnection;
-#endif // DALI_ELDBUS_AVAILABLE
 };
 
 } // namespace Adaptor
index 3e00080..3afc70e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -634,6 +634,11 @@ int WindowBaseEcoreX::GetNativeWindowId()
   return mEcoreWindow;
 }
 
+std::string WindowBaseEcoreX::GetNativeWindowResourceId()
+{
+  return std::string();
+}
+
 EGLNativeWindowType WindowBaseEcoreX::CreateEglWindow(int width, int height)
 {
   // need to create X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
@@ -712,6 +717,10 @@ bool WindowBaseEcoreX::IsMaximized() const
   return false;
 }
 
+void WindowBaseEcoreX::SetMaximumSize(Dali::Window::WindowSize size)
+{
+}
+
 void WindowBaseEcoreX::Minimize(bool minimize)
 {
 }
@@ -721,6 +730,10 @@ bool WindowBaseEcoreX::IsMinimized() const
   return false;
 }
 
+void WindowBaseEcoreX::SetMimimumSize(Dali::Window::WindowSize size)
+{
+}
+
 void WindowBaseEcoreX::SetAvailableAnlges(const std::vector<int>& angles)
 {
 }
index 1e0e569..5739c19 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_WINDOWSYSTEM_ECOREX_WINDOW_BASE_ECORE_X_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -125,6 +125,11 @@ public:
   int GetNativeWindowId() override;
 
   /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetNativeWindowResourceId()
+   */
+  std::string GetNativeWindowResourceId() override;
+
+  /**
    * @copydoc Dali::Internal::Adaptor::WindowBase::CreateEglWindow()
    */
   EGLNativeWindowType CreateEglWindow(int width, int height) override;
@@ -205,6 +210,11 @@ public:
   bool IsMaximized() const override;
 
   /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetMaximumSize()
+   */
+  void SetMaximumSize(Dali::Window::WindowSize size) override;
+
+  /**
    * @copydoc Dali::Internal::Adaptor::WindowBase::Minimize()
    */
   void Minimize(bool minimize) override;
@@ -215,6 +225,11 @@ public:
   bool IsMinimized() const override;
 
   /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetMimimumSize()
+   */
+  void SetMimimumSize(Dali::Window::WindowSize size) override;
+
+  /**
    * @copydoc Dali::Internal::Adaptor::WindowBase::SetAvailableAnlges()
    */
   void SetAvailableAnlges(const std::vector<int>& angles) override;
index 3bac5a4..0a66241 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -250,6 +250,11 @@ int WindowBaseWin::GetNativeWindowId()
   return mWin32Window;
 }
 
+std::string WindowBaseWin::GetNativeWindowResourceId()
+{
+  return std::string();
+}
+
 EGLNativeWindowType WindowBaseWin::CreateEglWindow(int width, int height)
 {
   return reinterpret_cast<EGLNativeWindowType>(mWin32Window);
@@ -318,6 +323,10 @@ bool WindowBaseWin::IsMaximized() const
   return false;
 }
 
+void WindowBaseWin::SetMaximumSize(Dali::Window::WindowSize size)
+{
+}
+
 void WindowBaseWin::Minimize(bool minimize)
 {
 }
@@ -327,6 +336,10 @@ bool WindowBaseWin::IsMinimized() const
   return false;
 }
 
+void WindowBaseWin::SetMimimumSize(Dali::Window::WindowSize size)
+{
+}
+
 void WindowBaseWin::SetAvailableAnlges(const std::vector<int>& angles)
 {
 }
index ae3a8c2..1a8404a 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_WINDOWSYSTEM_WINDOW_BASE_WIN_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -112,6 +112,11 @@ public:
   int GetNativeWindowId() override;
 
   /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetNativeWindowResourceId()
+   */
+  std:string GetNativeWindowResourceId() override;
+
+  /**
    * @copydoc Dali::Internal::Adaptor::WindowBase::CreateEglWindow()
    */
   EGLNativeWindowType CreateEglWindow(int width, int height) override;
@@ -192,6 +197,11 @@ public:
   bool IsMaximized() const override;
 
   /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetMaximumSize()
+   */
+  void SetMaximumSize(Dali::Window::WindowSize size) override;
+
+  /**
    * @copydoc Dali::Internal::Adaptor::WindowBase::Minimize()
    */
   void Minimize(bool minimize) override;
@@ -202,6 +212,11 @@ public:
   bool IsMinimized() const override;
 
   /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetMimimumSize()
+   */
+  void SetMimimumSize(Dali::Window::WindowSize size) override;
+
+  /**
    * @copydoc Dali::Internal::Adaptor::WindowBase::SetAvailableAnlges()
    */
   void SetAvailableAnlges(const std::vector<int>& angles) override;
index ddad181..4b34148 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -46,6 +46,11 @@ const EncodedImageBuffer::RawBufferType& EncodedImageBuffer::GetRawBuffer() cons
   return GetImplementation(*this).GetRawBuffer();
 }
 
+const std::size_t EncodedImageBuffer::GetHash() const
+{
+  return GetImplementation(*this).GetHash();
+}
+
 EncodedImageBuffer& EncodedImageBuffer::operator=(const EncodedImageBuffer& handle)
 {
   BaseHandle::operator=(handle);
index 6ab6b4d..3e1f65c 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef DALI_ENCODED_IMAGE_BUFFER_H
 #define DALI_ENCODED_IMAGE_BUFFER_H
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,8 +18,8 @@
  */
 
 // EXTERNAL INCLUDES
-#include <dali/public-api/object/base-handle.h>
 #include <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/object/base-handle.h>
 
 // INTERNAL INCLUDES
 #include <dali/public-api/dali-adaptor-common.h>
@@ -84,6 +84,13 @@ public:
    */
   const RawBufferType& GetRawBuffer() const;
 
+  /**
+   * @brief Get the hash value of raw buffer
+   *
+   * @return A hash value of raw buffer.
+   */
+  const std::size_t GetHash() const;
+
 public: // Not intended for developer use
   explicit DALI_INTERNAL EncodedImageBuffer(Internal::EncodedImageBuffer* impl);
 };
index 05444c0..d7bc085 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -25,6 +25,13 @@ namespace Dali
 {
 WidgetApplication WidgetApplication::New(int* argc, char** argv[], const std::string& stylesheet)
 {
+  Internal::Adaptor::ApplicationPtr preInitializedApplication = Internal::Adaptor::Application::GetPreInitializedApplication();
+  if(preInitializedApplication)
+  {
+    // WidgetApplication can't use pre-initialized application. So reset it.
+    preInitializedApplication.Reset();
+  }
+
   Internal::Adaptor::WidgetApplicationPtr internal = Internal::Adaptor::WidgetApplication::New(argc, argv, stylesheet);
   return WidgetApplication(internal.Get());
 }
index 6df39a0..8ac4d30 100644 (file)
@@ -87,11 +87,59 @@ void Widget::SetContentInfo(const std::string& contentInfo)
   }
 }
 
+bool Widget::IsKeyEventUsing() const
+{
+  if(mImpl != nullptr)
+  {
+    return mImpl->IsKeyEventUsing();
+  }
+
+  //if mImpl is null, return default value
+  return false;
+}
+
+void Widget::SetUsingKeyEvent(bool flag)
+{
+  if(mImpl != nullptr)
+  {
+    mImpl->SetUsingKeyEvent(flag);
+  }
+}
+
 void Widget::SetImpl(Impl* impl)
 {
   mImpl = impl;
 }
 
+
+void Widget::SetInformation(Dali::Window window, const std::string& widgetId)
+{
+  if(mImpl != nullptr)
+  {
+    mImpl->SetInformation(window, widgetId);
+  }
+}
+
+Dali::Window Widget::GetWindow() const
+{
+  if(mImpl != nullptr)
+  {
+    return mImpl->GetWindow();
+  }
+
+  return Dali::Window();
+}
+
+std::string Widget::GetWidgetId() const
+{
+  if(mImpl != nullptr)
+  {
+    return mImpl->GetWidgetId();
+  }
+
+  return std::string();
+}
+
 Internal::Adaptor::Widget& GetImplementation(Dali::Widget& widget)
 {
   DALI_ASSERT_ALWAYS(widget && "widget handle is empty");
index 3e7e87a..06e990f 100644 (file)
@@ -131,6 +131,22 @@ public:
    */
   void SetContentInfo(const std::string& contentInfo);
 
+  /**
+   * @brief Check Widget is using key
+   *
+   * widget can set flag to SetUsingKeyEvent
+   *
+   * @return True if Widget is using key
+   */
+  bool IsKeyEventUsing() const;
+
+  /**
+   * @brief Set the flag that widget is using keyEvent
+   *
+   * @param[in] flag The flag to set.
+   */
+  void SetUsingKeyEvent(bool flag);
+
 protected:
   /**
    * @brief WidgetImpl constructor
@@ -152,6 +168,28 @@ public:
    */
   void SetImpl(Impl* impl);
 
+  /**
+   * @brief Set the Information of widget
+   *
+   * @param window The window to set the information of widget
+   * @param widgetId The Id of widget
+   */
+  void SetInformation(Dali::Window window, const std::string& widgetId);
+
+  /**
+   * @brief Get the Window of widget
+   *
+   * @return the window of widget
+   */
+  Dali::Window GetWindow() const;
+
+  /**
+   * @brief Get the id of widget
+   *
+   * @return the id of widget
+   */
+  std::string GetWidgetId() const;
+
 private:
   Impl* mImpl;
 
index b9d47a1..ccf2eee 100644 (file)
@@ -27,7 +27,7 @@ namespace Dali
 {
 const unsigned int ADAPTOR_MAJOR_VERSION = 2;
 const unsigned int ADAPTOR_MINOR_VERSION = 1;
-const unsigned int ADAPTOR_MICRO_VERSION = 10;
+const unsigned int ADAPTOR_MICRO_VERSION = 29;
 const char* const  ADAPTOR_BUILD_DATE    = __DATE__ " " __TIME__;
 
 #ifdef DEBUG_ENABLED
index d0103a1..9f9648e 100644 (file)
@@ -17,7 +17,7 @@
 
 Name:       dali2-adaptor
 Summary:    The DALi Tizen Adaptor
-Version:    2.1.10
+Version:    2.1.29
 Release:    1
 Group:      System/Libraries
 License:    Apache-2.0 and BSD-3-Clause and MIT
@@ -36,9 +36,9 @@ BuildRequires:  pkgconfig(libtzplatform-config)
 %if "%{?profile}" != "mobile" && "%{?profile}" != "tv" && "%{?profile}" != "ivi" && "%{?profile}" != "common"
 BuildRequires:  pkgconfig(capi-appfw-watch-application)
 BuildRequires:  pkgconfig(appcore-watch)
-BuildRequires:  pkgconfig(screen_connector_provider)
 %endif
 
+BuildRequires:  pkgconfig(screen_connector_provider)
 BuildRequires:  pkgconfig(gles20)
 BuildRequires:  pkgconfig(glesv2)
 BuildRequires:  pkgconfig(ttrace)
@@ -95,7 +95,7 @@ BuildRequires:  pkgconfig(ecore-wayland)
 BuildRequires:  pkgconfig(libtbm)
 
 # for the adaptor
-BuildRequires:  pkgconfig(appcore-ui)
+BuildRequires:  pkgconfig(app-core-ui-cpp)
 BuildRequires:  pkgconfig(appcore-widget-base)
 BuildRequires:  pkgconfig(bundle)
 BuildRequires:  pkgconfig(capi-appfw-app-common)
@@ -270,7 +270,7 @@ CXXFLAGS+=" -D_ARCH_ARM_ -lgcc"
 
 CFLAGS+=" -DWAYLAND"
 CXXFLAGS+=" -DWAYLAND"
-cmake_flags=" -DENABLE_WAYLAND=ON -DENABLE_ATSPI=ON"
+cmake_flags=" -DENABLE_WAYLAND=ON -DENABLE_ATSPI=ON -DENABLE_TRACE=ON"
 
 # Use this conditional when Tizen version is 5.x or greater
 %if 0%{?tizen_version_major} >= 5
@@ -291,10 +291,6 @@ CXXFLAGS+=" -DOVER_TIZEN_VERSION_7"
 cmake_flags+=" -DCMAKE_BUILD_TYPE=Debug"
 %endif
 
-%if 0%{?enable_trace}
-cmake_flags+=" -DENABLE_TRACE=ON"
-%endif
-
 %if 0%{?enable_logging}
 cmake_flags+=" -DENABLE_NETWORK_LOGGING=ON"
 %endif