Merge branch 'devel/master' into tizen submit/tizen/20220420.085640
authorJaehyun Cho <jae_hyun.cho@samsung.com>
Wed, 20 Apr 2022 07:19:27 +0000 (16:19 +0900)
committerJaehyun Cho <jae_hyun.cho@samsung.com>
Wed, 20 Apr 2022 07:19:27 +0000 (16:19 +0900)
Change-Id: I26106c714f6d2d55437294930d6b1eaee5facfbf

79 files changed:
automated-tests/resources/lake_front.jpg [new file with mode: 0644]
automated-tests/src/dali-adaptor-internal/utc-Dali-ImageOperations.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-reflection.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
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/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/pixel-buffer.cpp
dali/devel-api/adaptor-framework/pixel-buffer.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/text-abstraction/font-list.h
dali/internal/accessibility/bridge/bridge-base.cpp
dali/internal/accessibility/bridge/bridge-base.h
dali/internal/accessibility/bridge/bridge-impl.cpp
dali/internal/accessibility/bridge/bridge-object.cpp
dali/internal/drag-and-drop/tizen-wayland/drag-and-drop-impl-ecore-wl2.cpp
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-graphics-reflection.cpp
dali/internal/imaging/common/alpha-mask.cpp
dali/internal/imaging/common/animated-image-loading-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/text/text-abstraction/cairo-renderer.cpp
dali/internal/text/text-abstraction/plugin/font-client-plugin-impl.cpp
dali/internal/text/text-abstraction/plugin/font-client-utils.cpp
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/window-base.h
dali/internal/window-system/common/window-impl.cpp
dali/internal/window-system/common/window-impl.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/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/dali-adaptor-version.cpp
packaging/dali-adaptor.spec

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 e7414ff..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];
@@ -1298,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
@@ -1367,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];
@@ -1400,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;
 
@@ -1452,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;
index cc7fac4..a1f8405 100644 (file)
@@ -997,10 +997,17 @@ public:
       {
         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 << "]";
+          nss << name << "[" << i << "]" << suffix;
           GetUniformLocation(program, nss.str().c_str()); // Generate a GL loc per element
         }
       }
index 5b3da8c..6cb90ba 100644 (file)
@@ -147,8 +147,6 @@ TestGraphicsReflection::TestGraphicsReflection(TestGlAbstraction& gl, uint32_t p
   for(const auto& data : mCustomUniforms)
   {
     fprintf(stderr, "\ncustom uniforms: %s\n", data.name.c_str());
-    mDefaultUniformBlock.members.emplace_back();
-    auto& item = mDefaultUniformBlock.members.back();
 
     auto iter        = data.name.find("[", 0);
     int  numElements = 1;
@@ -161,26 +159,60 @@ TestGraphicsReflection::TestGraphicsReflection(TestGlAbstraction& gl, uint32_t p
       {
         numElements = 1;
       }
-
-      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)
+      iter = data.name.find("]");
+      std::string suffix;
+      if(iter != std::string::npos && iter + 1 != data.name.length())
       {
-        std::stringstream elementNameStream;
-        elementNameStream << baseName << "[" << i << "]";
+        suffix = data.name.substr(iter + 1); // If there is a suffix, it means it is an element of an array of struct
+      }
 
-        item.locations.push_back(gl.GetUniformLocation(programId, elementNameStream.str().c_str()));
-        item.offsets.push_back(offset);
-        offset += GetSizeForType(data.type);
+      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);
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 2a2088b..ddc4f20 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.
@@ -43,6 +43,7 @@
 #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;
@@ -354,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
@@ -391,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
index 1142576..f3576c6 100644 (file)
@@ -466,10 +466,42 @@ enum class AtspiInterface
   MAX_COUNT\r
 };\r
 \r
-using AtspiInterfaces  = EnumBitSet<AtspiInterface, AtspiInterface::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
+ * @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
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 455465a..1337047 100644 (file)
@@ -103,7 +103,7 @@ public:
     {
       this->data = data;
     }
-    char* GetData()
+    char* GetData() const
     {
       return data;
     }
@@ -128,18 +128,18 @@ public:
      {
        return mimeType;
      }
-     void SetData(char* data)
+     void SetData(const char* data)
      {
        this->data = data;
      }
-     char* GetData() const
+     const char* GetData() const
      {
        return data;
      }
 
   private:
      const char* mimeType{nullptr}; ///<The mime type of drag data.
-     char*       data{nullptr};     ///<The drag data.
+     const char* data{nullptr};     ///<The drag data.
   };
 
   using DragAndDropFunction = std::function<void(const DragEvent&)>;
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 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 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..34b609a 100644 (file)
@@ -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);
index a4779f7..8f51d27 100644 (file)
@@ -53,6 +53,8 @@ typedef Signal<void()> KeyboardRepeatSettingsChangedSignalType; ///< Keyboard re
 
 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
+
 /**
  * @brief Creates an initialized handle to a new Window.
  *
@@ -163,6 +165,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.
index c41f6bf..b42ad35 100644 (file)
@@ -375,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;
@@ -484,6 +504,7 @@ private:
 
   mutable std::weak_ptr<Bridge::Data> mBridgeData;
   mutable AtspiInterfaces             mInterfaces;
+  AtspiEvents                         mSuppressedEvents;
   bool                                mIsOnRootLevel = false;
 
 }; // Accessible class
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 983bbe3..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)
@@ -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)
index 5e1ffca..bf2a22c 100644 (file)
@@ -40,7 +40,6 @@ 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 GetName() const override
index 817b445..0cf7d17 100644 (file)
@@ -235,7 +235,6 @@ public:
     mDirectReadingClient  = {};
     mDirectReadingCallbacks.clear();
     mApplication.mChildren.clear();
-    mApplication.mWindows.clear();
     ClearTimer();
   }
 
@@ -360,13 +359,6 @@ public:
 
     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;
   }
 
index 3efe6cb..6490166 100644 (file)
@@ -48,7 +48,7 @@ void BridgeObject::RegisterInterfaces()
 
 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;
   }
@@ -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;
   }
@@ -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;
   }
@@ -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;
   }
@@ -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;
   }
@@ -239,7 +239,7 @@ 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;
   }
@@ -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;
   }
@@ -285,7 +285,7 @@ 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;
   }
@@ -303,7 +303,7 @@ void BridgeObject::EmitMovedOutOfScreen(Accessible* obj, ScreenRelativeMoveType
 
 void BridgeObject::EmitSocketAvailable(Accessible* obj)
 {
-  if(!IsUp() || obj->IsHidden())
+  if(!IsUp() || obj->IsHidden()) //TODO Suppress SocketAvailable event
   {
     return;
   }
index 492210c..dd020c0 100644 (file)
@@ -125,7 +125,7 @@ bool DragAndDropEcoreWl::StartDragAndDrop(Dali::Actor source, Dali::Actor shadow
 
   // Set Drag Source Data
   mMimeType = data.GetMimeType();
-  mData = data.GetData();
+  mData     = data.GetData();
 
   // Apply Shadow Property
   shadow.SetProperty(Dali::Actor::Property::SIZE, Vector2(150, 150));
@@ -152,7 +152,6 @@ bool DragAndDropEcoreWl::StartDragAndDrop(Dali::Actor source, Dali::Actor shadow
   mimeTypes[0] = mMimeType.c_str();
   mimeTypes[1] = NULL;
 
-
   // Set mime type
   ecore_wl2_dnd_drag_types_set(input, (const char**)mimeTypes);
 
@@ -212,7 +211,7 @@ void DragAndDropEcoreWl::SendData(void* event)
      (mMimeType.find("markup") != std::string::npos) ||
      (mMimeType.find("image") != std::string::npos))
   {
-     bufferSize += 1;
+    bufferSize += 1;
   }
 
   char* buffer = new char[bufferSize];
@@ -224,7 +223,12 @@ void DragAndDropEcoreWl::SendData(void* event)
   memcpy(buffer, mData.c_str(), dataLength);
   buffer[dataLength] = '\0';
 
-  write(ev->fd, buffer, bufferSize);
+  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));
+  }
+
   close(ev->fd);
 
   if(mDragWindow)
@@ -232,7 +236,7 @@ void DragAndDropEcoreWl::SendData(void* event)
     mDragWindow.Hide();
   }
 
-  delete [] buffer;
+  delete[] buffer;
 }
 
 void DragAndDropEcoreWl::ReceiveData(void* event)
@@ -255,7 +259,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);
@@ -297,7 +301,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);
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 56c5f2d..0a22d9c 100644 (file)
@@ -663,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)
@@ -774,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 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 5205da5..9abdfec 100644 (file)
@@ -51,9 +51,8 @@ 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;
+  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())
@@ -71,6 +70,9 @@ 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)
         {
           auto srcAlpha = srcBuffer[srcOffset + srcAlphaByteOffset] & srcAlphaMask;
@@ -96,6 +98,8 @@ void ApplyMaskToAlphaChannel(PixelBuffer& buffer, const PixelBuffer& mask)
           srcOffset += srcBytesPerPixel;
           destOffset += destBytesPerPixel;
         }
+        srcBuffer += srcStrideBytes;
+        destBuffer += destStrideBytes;
       }
     }
   }
@@ -103,6 +107,9 @@ 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 srcAlpha  = srcBuffer[srcOffset + srcAlphaByteOffset] & srcAlphaMask;
@@ -116,6 +123,8 @@ void ApplyMaskToAlphaChannel(PixelBuffer& buffer, const PixelBuffer& mask)
         srcOffset += srcBytesPerPixel;
         destOffset += destBytesPerPixel;
       }
+      srcBuffer += srcStrideBytes;
+      destBuffer += destStrideBytes;
     }
   }
 }
@@ -136,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;
@@ -150,19 +161,20 @@ 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());
 
   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 srcAlpha = srcBuffer[srcAlphaOffset + srcAlphaByteOffset] & srcAlphaMask;
@@ -186,6 +198,9 @@ PixelBufferPtr CreateNewMaskedBuffer(const PixelBuffer& buffer, const PixelBuffe
       srcAlphaOffset += srcBytesPerPixel;
       destOffset += destBytesPerPixel;
     }
+    oldBuffer += srcColorStrideBytes;
+    srcBuffer += srcStrideBytes;
+    destBuffer += destStrideBytes;
   }
 
   return newPixelBuffer;
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 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 cfb055e..4ca7dd4 100644 (file)
@@ -61,7 +61,7 @@ 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 = 16; ///< Generate color map optimize only if colorCount * threshold < width * height, So we don't loop if image is small
+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 */
@@ -140,7 +140,6 @@ struct GifCachedColorData
   // precalculated colormap table
   std::vector<std::uint32_t> globalCachedColor{};
   std::vector<std::uint32_t> localCachedColor{};
-  ColorMapObject*            localCachedColorMap{nullptr}; // Weak-pointer of ColorMapObject. should be nullptr if image changed
 };
 
 // Forward declaration
@@ -260,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
     }
@@ -294,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);
@@ -330,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);
@@ -366,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
@@ -401,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++)
+  // Boost time if stride == width and x == 0. We can assume that all pointer is continuous.
+  if(x == 0 && stride == width)
   {
-    pixelPosition = data + ((y + yAxis) * row) + x;
-    for(xAxis = 0; xAxis < width; xAxis++)
+    pixelPosition = data + (y * stride);
+    // Clear as white or transparent
+    // Special case. we can use memset.
+    if(val == 0x00 || val == 0xffffffffu)
     {
-      *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)
-  {
-    ColorMapObject* colorMap;
-    int             backGroundColor;
-
-    // work out color to use from colorMap
-    if(gif->Image.ColorMap)
-    {
-      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;
+      }
+    }
   }
 }
 
@@ -630,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, GifCachedColorData& gifCachedColor, 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};
@@ -650,7 +665,7 @@ bool DecodeImage(GifFileType* gif, GifCachedColorData& gifCachedColor, uint32_t*
   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");
@@ -660,7 +675,7 @@ bool DecodeImage(GifFileType* gif, GifCachedColorData& gifCachedColor, uint32_t*
   // 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;
   }
@@ -678,7 +693,7 @@ bool DecodeImage(GifFileType* gif, GifCachedColorData& gifCachedColor, uint32_t*
     {
       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;
         }
@@ -690,7 +705,7 @@ bool DecodeImage(GifFileType* gif, GifCachedColorData& gifCachedColor, uint32_t*
   {
     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;
       }
@@ -701,20 +716,14 @@ bool DecodeImage(GifFileType* gif, GifCachedColorData& gifCachedColor, uint32_t*
   if(gif->Image.ColorMap)
   {
     colorMap = gif->Image.ColorMap;
-    // use local cached color map without re-calculate cache.
-    if(gifCachedColor.localCachedColorMap == colorMap)
-    {
-      cachedColorPtr = gifCachedColor.localCachedColor.data();
-    }
-    // else if w * h is big enough, generate local cached color.
-    else if(colorMap->ColorCount * LOCAL_CACHED_COLOR_GENERATE_THRESHOLD < w * h)
+    // 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);
       }
-      gifCachedColor.localCachedColorMap = colorMap;
 
       cachedColorPtr = gifCachedColor.localCachedColor.data();
     }
@@ -747,7 +756,7 @@ bool DecodeImage(GifFileType* gif, GifCachedColorData& gifCachedColor, uint32_t*
             }
             else
             {
-              *p = 0;
+              *p = fillColor;
             }
             p++;
           }
@@ -768,7 +777,7 @@ bool DecodeImage(GifFileType* gif, GifCachedColorData& gifCachedColor, uint32_t*
             }
             else
             {
-              *p = 0;
+              *p = fillColor;
             }
             p++;
           }
@@ -862,12 +871,10 @@ 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;
   GifCachedColorData&   cachedColor = loaderInfo.cachedColor;
@@ -884,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");
@@ -903,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))
         {
@@ -945,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");
@@ -975,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");
@@ -1007,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");
@@ -1068,10 +1075,6 @@ bool ReadHeader(LoaderInfo&      loaderInfo,
               cachedColor.globalCachedColor[i] = PixelLookup(colorMap, i);
             }
           }
-          cachedColor.localCachedColorMap = nullptr;
-
-          // no errors in header scan etc. so set err and return value
-          *error = 0;
         }
       }
     }
@@ -1104,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;
@@ -1112,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;
@@ -1137,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;
@@ -1158,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;
@@ -1186,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;
@@ -1204,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
@@ -1234,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
             {
@@ -1243,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;
@@ -1260,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, loaderInfo.cachedColor, 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;
@@ -1282,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, loaderInfo.cachedColor, 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;
@@ -1300,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;
@@ -1352,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;
+  }
+
+  bool LoadGifInformation()
+  {
+    // Block to do not load this file again.
+    Mutex::ScopedLock lock(mMutex);
+    if(DALI_LIKELY(mLoadSucceeded))
+    {
+      return mLoadSucceeded;
+    }
 
-    mLoadSucceeded = ReadHeader(loaderInfo, imageProperties, &error);
+    mLoadSucceeded = ReadHeader(loaderInfo, imageProperties);
+    return mLoadSucceeded;
   }
 
   // Moveable but not copyable
@@ -1391,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);
@@ -1451,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 772d26f..360c9ad 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
@@ -1511,15 +1532,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)
   {
@@ -1532,28 +1556,28 @@ void DownscaleInPlacePow2(unsigned char* const pixels,
       {
         case Pixel::RGBA8888:
         {
-          Internal::Platform::DownscaleInPlacePow2RGBA8888(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight);
+          Internal::Platform::DownscaleInPlacePow2RGBA8888(pixels, inputWidth, inputHeight, inputStride, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight, outStride);
           break;
         }
         case Pixel::RGB888:
         {
-          Internal::Platform::DownscaleInPlacePow2RGB888(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight);
+          Internal::Platform::DownscaleInPlacePow2RGB888(pixels, inputWidth, inputHeight, inputStride, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight, outStride);
           break;
         }
         case Pixel::RGB565:
         {
-          Internal::Platform::DownscaleInPlacePow2RGB565(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight);
+          Internal::Platform::DownscaleInPlacePow2RGB565(pixels, inputWidth, inputHeight, inputStride, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight, outStride);
           break;
         }
         case Pixel::LA88:
         {
-          Internal::Platform::DownscaleInPlacePow2ComponentPair(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight);
+          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, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight);
+          Internal::Platform::DownscaleInPlacePow2SingleBytePerPixel(pixels, inputWidth, inputHeight, inputStride, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight, outStride);
           break;
         }
         default:
@@ -1572,38 +1596,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);
 }
 
 /**
@@ -1614,25 +1644,29 @@ 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
@@ -1650,12 +1684,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, ...).");
@@ -1674,11 +1709,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;
@@ -1701,33 +1736,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
@@ -1736,6 +1774,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)
@@ -1757,7 +1796,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.
 
@@ -1790,6 +1829,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,
@@ -1802,24 +1842,24 @@ void PointSample(const unsigned char* inPixels,
     {
       case Pixel::RGB888:
       {
-        PointSample3BPP(inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight);
+        PointSample3BPP(inPixels, inputWidth, inputHeight, inputStride, outPixels, desiredWidth, desiredHeight);
         break;
       }
       case Pixel::RGBA8888:
       {
-        PointSample4BPP(inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight);
+        PointSample4BPP(inPixels, inputWidth, inputHeight, inputStride, outPixels, desiredWidth, desiredHeight);
         break;
       }
       case Pixel::RGB565:
       case Pixel::LA88:
       {
-        PointSample2BPP(inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight);
+        PointSample2BPP(inPixels, inputWidth, inputHeight, inputStride, outPixels, desiredWidth, desiredHeight);
         break;
       }
       case Pixel::L8:
       case Pixel::A8:
       {
-        PointSample1BPP(inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight);
+        PointSample1BPP(inPixels, inputWidth, inputHeight, inputStride, outPixels, desiredWidth, desiredHeight);
         break;
       }
       default:
@@ -1894,6 +1934,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)
 {
@@ -1902,7 +1943,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)
@@ -1933,8 +1974,8 @@ inline void LinearSampleGeneric(const unsigned char* __restrict__ inPixels,
     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)
@@ -1966,46 +2007,52 @@ 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);
 }
 
 void Resample(const unsigned char* __restrict__ inPixels,
               ImageDimensions inputDimensions,
+              unsigned int    inputStride,
               unsigned char* __restrict__ outPixels,
               ImageDimensions   desiredDimensions,
               Resampler::Filter filterType,
@@ -2089,7 +2136,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;
 
@@ -2185,24 +2232,27 @@ 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,
+                  unsigned int    inStride,
                   Pixel::Format   pixelFormat,
                   unsigned char* __restrict__ outPixels,
                   ImageDimensions outDimensions)
@@ -2214,28 +2264,28 @@ void LinearSample(const unsigned char* __restrict__ inPixels,
     {
       case Pixel::RGB888:
       {
-        LinearSample3BPP(inPixels, inDimensions, outPixels, outDimensions);
+        LinearSample3BPP(inPixels, inDimensions, inStride, outPixels, outDimensions);
         break;
       }
       case Pixel::RGBA8888:
       {
-        LinearSample4BPP(inPixels, inDimensions, outPixels, outDimensions);
+        LinearSample4BPP(inPixels, inDimensions, inStride, outPixels, outDimensions);
         break;
       }
       case Pixel::L8:
       case Pixel::A8:
       {
-        LinearSample1BPP(inPixels, inDimensions, outPixels, outDimensions);
+        LinearSample1BPP(inPixels, inDimensions, inStride, outPixels, outDimensions);
         break;
       }
       case Pixel::LA88:
       {
-        LinearSample2BPP(inPixels, inDimensions, outPixels, outDimensions);
+        LinearSample2BPP(inPixels, inDimensions, inStride, outPixels, outDimensions);
         break;
       }
       case Pixel::RGB565:
       {
-        LinearSampleRGB565(inPixels, inDimensions, outPixels, outDimensions);
+        LinearSampleRGB565(inPixels, inDimensions, inStride, outPixels, outDimensions);
         break;
       }
       default:
@@ -2253,6 +2303,7 @@ void LinearSample(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,
@@ -2273,6 +2324,7 @@ void RotateByShear(const uint8_t* const pixelsIn,
     fastRotationPerformed = Rotate90(pixelsIn,
                                      widthIn,
                                      heightIn,
+                                     strideIn,
                                      pixelSize,
                                      pixelsOut,
                                      widthOut,
@@ -2297,6 +2349,7 @@ void RotateByShear(const uint8_t* const pixelsIn,
     fastRotationPerformed = Rotate180(pixelsIn,
                                       widthIn,
                                       heightIn,
+                                      strideIn,
                                       pixelSize,
                                       pixelsOut);
 
@@ -2321,6 +2374,7 @@ void RotateByShear(const uint8_t* const pixelsIn,
     fastRotationPerformed = Rotate270(pixelsIn,
                                       widthIn,
                                       heightIn,
+                                      strideIn,
                                       pixelSize,
                                       pixelsOut,
                                       widthOut,
@@ -2348,6 +2402,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;
@@ -2386,7 +2442,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'.
@@ -2425,7 +2481,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
@@ -2460,7 +2516,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'.
@@ -2470,6 +2526,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,
@@ -2510,7 +2567,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 d1105ad..fd330a0 100644 (file)
@@ -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,6 +352,7 @@ 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);
 
@@ -337,11 +364,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 +382,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 +400,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 +424,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 +434,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 +453,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 +463,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,
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 80c455d..05d0518 100644 (file)
@@ -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,12 +136,12 @@ 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;
@@ -158,7 +158,7 @@ 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;
@@ -173,7 +173,7 @@ bool DecodeRGB24V5(FILE*          fp,
     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,12 +203,12 @@ 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;
@@ -225,7 +225,7 @@ 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;
@@ -239,7 +239,7 @@ bool DecodeBF32V4(FILE*          fp,
     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,12 +269,12 @@ 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;
@@ -294,7 +294,7 @@ 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;
@@ -309,7 +309,7 @@ bool DecodeBF32(FILE*          fp,
     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,12 +335,12 @@ 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;
@@ -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;
@@ -410,7 +410,7 @@ bool DecodeBF555(FILE*          fp,
   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;
     }
@@ -458,12 +458,12 @@ 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;
@@ -478,7 +478,7 @@ bool DecodeRGB555(FILE*          fp,
   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;
     }
@@ -524,12 +524,12 @@ 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;
@@ -541,14 +541,14 @@ bool DecodeRGB1(FILE*          fp,
   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(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;
     }
@@ -616,12 +616,12 @@ 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;
@@ -633,14 +633,14 @@ bool DecodeRGB4(FILE*          fp,
   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(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;
     }
@@ -692,12 +692,12 @@ 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;
@@ -708,11 +708,11 @@ bool DecodeRGB8(FILE*          fp,
   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;
   }
-  if(fread(&colorIndex[0], 1, width * height, fp) != width * height)
+  if(DALI_UNLIKELY(fread(&colorIndex[0], 1, width * height, fp) != width * height))
   {
     return false;
   }
@@ -758,7 +758,7 @@ 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;
@@ -779,13 +779,13 @@ bool DecodeRLE4(FILE*          fp,
 
   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;
   }
@@ -796,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;
     }
@@ -812,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;
@@ -831,7 +831,7 @@ bool DecodeRLE4(FILE*          fp,
           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;
@@ -926,7 +926,7 @@ 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;
@@ -941,13 +941,13 @@ bool DecodeRLE8(FILE*          fp,
   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;
   }
@@ -960,11 +960,11 @@ bool DecodeRLE8(FILE*          fp,
   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;
     }
@@ -981,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;
@@ -998,7 +998,7 @@ 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;
@@ -1049,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;
@@ -1061,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;
   }
@@ -1127,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;
         }
@@ -1322,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;
@@ -1342,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");
             }
@@ -1354,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 83ce109..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,48 +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());
-
-  if(DALI_LIKELY(exifData))
-  {
-    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;
@@ -663,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;
@@ -867,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;
@@ -882,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;
@@ -985,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;
@@ -1080,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");
   }
@@ -1120,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..ae63822 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;
index aee8621..0fd3773 100644 (file)
@@ -47,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.
@@ -66,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)
@@ -121,7 +121,7 @@ constexpr std::uint32_t cachedCalculation4BitTo4ByteTable[16] = {
 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;
@@ -133,7 +133,7 @@ bool LoadBitmapFromWbmp(const Dali::ImageLoader::Input& input, Dali::Devel::Pixe
   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;
@@ -146,57 +146,59 @@ 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;
   }
@@ -211,6 +213,7 @@ bool LoadBitmapFromWbmp(const Dali::ImageLoader::Input& input, Dali::Devel::Pixe
 
   // 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;
@@ -237,13 +240,13 @@ bool LoadBitmapFromWbmp(const Dali::ImageLoader::Input& input, Dali::Devel::Pixe
    * @endcode
    */
 
-  const std::uint8_t* inputPixels                  = &map[0] + position;
+  const std::uint8_t* inputPixels                  = inputBufferPtr + position;
   const std::uint32_t lineByteLengthWithoutPadding = w >> 3;
   const std::uint8_t  linePadding                  = w & 0x07;
 
-  for(std::uint32_t y = 0; y < h; y++)
+  for(std::uint32_t y = 0; y < h; ++y)
   {
-    for(std::uint32_t x = 0; x < lineByteLengthWithoutPadding; x++)
+    for(std::uint32_t x = 0; x < lineByteLengthWithoutPadding; ++x)
     {
       // memset whole 8 bits
       // outputPixels filled 4 bytes in one operation.
@@ -272,7 +275,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;
@@ -282,7 +285,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;
@@ -295,17 +298,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;
@@ -316,35 +319,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..3749127 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 && webPLoading.HasLoadingSucceeded())
     {
-      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 4ff2250..f2594ac 100644 (file)
@@ -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,8 +456,9 @@ 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;
 
     // Collect all valid channel list before lookup whole buffer
     std::vector<Channel> validChannelList;
@@ -458,32 +472,35 @@ void PixelBuffer::MultiplyColorByAlpha()
 
     if(DALI_LIKELY(!validChannelList.empty()))
     {
-      for(unsigned int i = 0; i < bufferSize; ++i)
+      for(unsigned int y = 0; y < mHeight; y++)
       {
-        unsigned int alpha = ReadChannel(pixel, mPixelFormat, Adaptor::ALPHA);
-        if(alpha < 255)
+        for(unsigned int x = 0; x < widthBytes; x += bytesPerPixel)
         {
-          // 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)
+          unsigned int alpha = ReadChannel(&pixel[x], mPixelFormat, Adaptor::ALPHA);
+          if(alpha < 255)
           {
-            for(const Channel& channel : validChannelList)
+            // 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)
             {
-              auto color = ReadChannel(pixel, mPixelFormat, channel);
-              WriteChannel(pixel, mPixelFormat, channel, color * alpha / 255);
+              for(const Channel& channel : validChannelList)
+              {
+                auto color = ReadChannel(&pixel[x], mPixelFormat, channel);
+                WriteChannel(&pixel[x], mPixelFormat, channel, color * alpha / 255);
+              }
+            }
+            else
+            {
+              // If alpha is 0, just set all pixel as zero.
+              memset(&pixel[x], 0, bytesPerPixel);
             }
-          }
-          else
-          {
-            // If alpha is 0, just set all pixel as zero.
-            memset(pixel, 0, bytesPerPixel);
           }
         }
-        pixel += bytesPerPixel;
+        pixel += strideBytes;
       }
     }
+    mPreMultiplied = true;
   }
-  mPreMultiplied = true;
 }
 
 bool PixelBuffer::IsAlphaPreMultiplied() const
@@ -493,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 93418d3..357df28 100644 (file)
@@ -392,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;
index 707821b..0cb8932 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,79 @@ 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
-      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))
+      if(mIsAnimatedImage)
       {
-        mImageSize = ImageDimensions(imageWidth, imageHeight);
+        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);
       }
 #endif
-#ifndef DALI_WEBP_AVAILABLE
-      // If the system doesn't support webp, loading will be failed.
-      mFrameCount    = 0u;
-      mLoadSucceeded = false;
+#ifdef DALI_WEBP_AVAILABLE
+      if(!mIsAnimatedImage)
+      {
+        int32_t imageWidth, imageHeight;
+        if(WebPGetInfo(mBuffer, mBufferSize, &imageWidth, &imageHeight))
+        {
+          mImageSize = ImageDimensions(imageWidth, imageHeight);
+        }
+      }
 #endif
+      mLoadSucceeded = true;
     }
     else
     {
@@ -107,59 +147,77 @@ 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))
-      {
-        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(DALI_LIKELY(!fseek(fp, 12, SEEK_SET)))
       {
-        mBufferSize = dataBuffer.Size();
-        if(mBufferSize > 0U)
+        uint8_t mHeaderBuffer[5];
+        fread(mHeaderBuffer, sizeof(WebPByteType), 5, fp);
+        unsigned char VP8X[4]    = {'V', 'P', '8', 'X'};
+        bool          isExtended = true;
+        for(uint32_t i = 0; i < 4; ++i)
         {
-          // Open a file handle on the memory buffer:
-          Internal::Platform::FileReader fileReader(dataBuffer, mBufferSize);
-          fp = fileReader.GetFile();
-          if(fp != nullptr)
+          if(mHeaderBuffer[i] != VP8X[i])
           {
-            if(!fseek(fp, 0, SEEK_SET))
-            {
-              mBuffer     = reinterpret_cast<WebPByteType*>(malloc(sizeof(WebPByteType) * mBufferSize));
-              mBufferSize = fread(mBuffer, sizeof(WebPByteType), mBufferSize, fp);
-              return true;
-            }
+            isExtended = false;
+            break;
           }
         }
+        if(isExtended)
+        {
+          unsigned char extension = mHeaderBuffer[4];
+          mIsAnimatedImage        = ((extension >> 1) & 1) ? true : false;
+        }
+      }
+
+      if(mBufferSize == 0)
+      {
+        if(DALI_UNLIKELY(fseek(fp, 0, SEEK_END) <= -1))
+        {
+          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;
@@ -168,15 +226,18 @@ public:
   void ReleaseResource()
   {
 #ifdef DALI_ANIMATED_WEBP_ENABLED
-    if(&mWebPData != nullptr)
+    if(mIsAnimatedImage)
     {
-      mWebPData.bytes = nullptr;
-      WebPDataInit(&mWebPData);
-    }
-    if(mWebPAnimDecoder != nullptr)
-    {
-      WebPAnimDecoderDelete(mWebPAnimDecoder);
-      mWebPAnimDecoder = nullptr;
+      if(&mWebPData != nullptr)
+      {
+        mWebPData.bytes = nullptr;
+        WebPDataInit(&mWebPData);
+      }
+      if(mWebPAnimDecoder != nullptr)
+      {
+        WebPAnimDecoderDelete(mWebPAnimDecoder);
+        mWebPAnimDecoder = nullptr;
+      }
     }
 #endif
     if(mBuffer != nullptr)
@@ -198,9 +259,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 +270,14 @@ public:
   uint32_t        mBufferSize;
   ImageDimensions mImageSize;
   bool            mLoadSucceeded;
+  bool            mIsAnimatedImage;
+  bool            mIsLocalResource;
 
 #ifdef DALI_ANIMATED_WEBP_ENABLED
-  WebPData         mWebPData{0};
-  WebPAnimDecoder* mWebPAnimDecoder{nullptr};
-  WebPAnimInfo     mWebPAnimInfo{0};
+  WebPData                 mWebPData{0};
+  WebPAnimDecoder*         mWebPAnimDecoder{nullptr};
+  WebPAnimInfo             mWebPAnimInfo{0};
+  Dali::Devel::PixelBuffer mPreLoadedFrame{};
 #endif
 };
 
@@ -224,142 +289,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 0735798..dd11c76 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.
@@ -896,6 +896,7 @@ Devel::PixelBuffer RenderTextCairo(const TextAbstraction::TextRenderer::Paramete
             Dali::Internal::Platform::RotateByShear(data.buffer,
                                                     data.width,
                                                     data.height,
+                                                    data.width,
                                                     pixelSize,
                                                     radians,
                                                     pixelsOut,
index 5668718..57ea4fb 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.
@@ -478,8 +478,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 validatedFontId = mFontDescriptionCache.size();
+
+        FONT_LOG_DESCRIPTION(tempFontDescription, "default platform font");
+        DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  default font validatedFontId : %d\n", validatedFontId);
+
+        // Cache the index and the matched font's description.
+        FontDescriptionCacheItem item(tempFontDescription,
+                                      validatedFontId);
+
+        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.
@@ -832,6 +863,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,7 +899,7 @@ 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;
   }
@@ -864,11 +907,11 @@ FontId FontClient::Plugin::GetFontId(const FontDescription& fontDescription,
   // Check if the font's description have been validated before.
   FontDescriptionId validatedFontId = 0u;
 
-  if(!FindValidatedFont(fontDescription,
+  if(!FindValidatedFont(realFontDescription,
                         validatedFontId))
   {
     // Use font config to validate the font's description.
-    ValidateFont(fontDescription,
+    ValidateFont(realFontDescription,
                  validatedFontId);
   }
 
index 3f9743f..869609c 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.
@@ -154,6 +154,7 @@ void ConvertBitmap(TextAbstraction::FontClient::GlyphBufferData& data, unsigned
   {
     Dali::Internal::Platform::LanczosSample4BPP(srcBuffer,
                                                 inputDimensions,
+                                                srcWidth,
                                                 data.buffer,
                                                 desiredDimensions);
   }
@@ -224,6 +225,7 @@ void ConvertBitmap(TextAbstraction::FontClient::GlyphBufferData& data, FT_Bitmap
             Dali::Internal::Platform::HorizontalShear(pixelsIn,
                                                       width,
                                                       height,
+                                                      width,
                                                       1u,
                                                       -TextAbstraction::FontClient::DEFAULT_ITALIC_ANGLE,
                                                       pixelsOut,
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..1693b34 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
index abfe727..cb80b83 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;
index d84e528..8003802 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.
@@ -111,6 +111,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;
index fff3338..1c99009 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.
@@ -81,6 +81,7 @@ Window::Window()
   mIconified(false),
   mOpaqueState(false),
   mWindowRotationAcknowledgement(false),
+  mFocused(false),
   mParentWindow(NULL),
   mPreferredAngle(static_cast<int>(WindowOrientation::NO_ORIENTATION_PREFERENCE)),
   mRotationAngle(0),
@@ -100,10 +101,13 @@ Window::Window()
 
 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, true);
+    bridge->RemoveTopLevelWindow(accessible);
+  }
 
   if(mAdaptor)
   {
@@ -175,10 +179,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, true);
+    bridge->AddTopLevelWindow(accessible);
+  }
 
   bridge->EnabledSignal().Connect(this, &Window::OnAccessibilityEnabled);
   bridge->DisabledSignal().Connect(this, &Window::OnAccessibilityDisabled);
@@ -271,6 +278,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 +357,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 +485,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 +506,7 @@ void Window::Hide()
   {
     Dali::Window handle(this);
     mVisibilityChangedSignal.Emit(handle, false);
+    Dali::Accessibility::Bridge::GetCurrentBridge()->WindowHidden(handle);
 
     WindowVisibilityObserver* observer(mAdaptor);
     observer->OnWindowHidden();
@@ -747,6 +767,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 +783,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 +813,7 @@ void Window::OnFocusChanged(bool focusIn)
       bridge->WindowUnfocused(handle);
     }
   }
+  mFocused = focusIn;
 }
 
 void Window::OnOutputTransformed()
@@ -922,6 +945,12 @@ void Window::OnAccessibilityEnabled()
   auto rootLayer  = mScene.GetRootLayer();
   auto accessible = Accessibility::Accessible::Get(rootLayer, true);
   bridge->AddTopLevelWindow(accessible);
+
+  if(mFocused)
+  {
+    Dali::Window handle(this);
+    bridge->WindowFocused(handle);
+  }
 }
 
 void Window::OnAccessibilityDisabled()
index dff9c28..ce91a7f 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.
@@ -65,6 +65,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;
 
   /**
@@ -152,6 +153,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 +393,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
@@ -677,6 +694,14 @@ public: // Signals
     return mAuxiliaryMessageSignal;
   }
 
+  /**
+   * @copydoc Dali::DevelWindow::AccessibilityHighlightSignal()
+   */
+  AccessibilityHighlightSignalType& AccessibilityHighlightSignal()
+  {
+    return mAccessibilityHighlightSignal;
+  }
+
 private:
   WindowRenderSurface* mWindowSurface; ///< The window rendering surface
   WindowBase*          mWindowBase;
@@ -687,6 +712,7 @@ private:
   bool                 mIconified : 1;
   bool                 mOpaqueState : 1;
   bool                 mWindowRotationAcknowledgement : 1;
+  bool                 mFocused : 1;
   Dali::Window         mParentWindow;
 
   OrientationPtr   mOrientation;
@@ -711,6 +737,7 @@ private:
   TransitionEffectEventSignalType         mTransitionEffectEventSignal;
   KeyboardRepeatSettingsChangedSignalType mKeyboardRepeatSettingsChangedSignal;
   AuxiliaryMessageSignalType              mAuxiliaryMessageSignal;
+  AccessibilityHighlightSignalType        mAccessibilityHighlightSignal;
 };
 
 } // namespace Adaptor
index eef4f6e..ef88a7b 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;
index 6ca0681..efadeda 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
index 6be7165..42a522c 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.
@@ -1188,6 +1188,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);
index 6bdbd10..d2dad57 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.
@@ -191,6 +191,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;
index dd15ec4..21f55fe 100644 (file)
@@ -508,9 +508,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 +567,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();
@@ -1532,6 +1530,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;
index bf43ea3..159e230 100644 (file)
@@ -230,6 +230,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;
index 3e00080..bb1a9cb 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
index 1e0e569..1fff77f 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;
index 3bac5a4..2837754 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);
index ae3a8c2..bbc403f 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;
index d352b4b..e0b2095 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 = 15;
+const unsigned int ADAPTOR_MICRO_VERSION = 18;
 const char* const  ADAPTOR_BUILD_DATE    = __DATE__ " " __TIME__;
 
 #ifdef DEBUG_ENABLED
index ae72b3e..b084e32 100644 (file)
@@ -17,7 +17,7 @@
 
 Name:       dali2-adaptor
 Summary:    The DALi Tizen Adaptor
-Version:    2.1.15
+Version:    2.1.18
 Release:    1
 Group:      System/Libraries
 License:    Apache-2.0 and BSD-3-Clause and MIT