Revert "[Tizen](ATSPI) squashed implementation"
[platform/core/uifw/dali-adaptor.git] / dali / internal / imaging / common / image-operations.cpp
old mode 100644 (file)
new mode 100755 (executable)
index 9a2ae6b..b44a024
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 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.
@@ -22,6 +22,7 @@
 #include <stddef.h>
 #include <cmath>
 #include <limits>
+#include <memory>
 #include <dali/integration-api/debug.h>
 #include <dali/public-api/common/dali-vector.h>
 #include <dali/public-api/math/vector2.h>
@@ -502,6 +503,7 @@ ImageDimensions CalculateDesiredDimensions( unsigned int bitmapWidth, unsigned i
  *
  * @note It allocates memory for the returned @p pixelsOut buffer.
  * @note Code got from https://www.codeproject.com/Articles/202/High-quality-image-rotation-rotate-by-shear by Eran Yariv.
+ * @note It may fail if malloc() fails to allocate memory.
  *
  * @param[in] pixelsIn The input buffer.
  * @param[in] widthIn The width of the input buffer.
@@ -510,8 +512,10 @@ ImageDimensions CalculateDesiredDimensions( unsigned int bitmapWidth, unsigned i
  * @param[out] pixelsOut The rotated output buffer.
  * @param[out] widthOut The width of the output buffer.
  * @param[out] heightOut The height of the output buffer.
+ *
+ * @return Whether the rotation succeded.
  */
-void Rotate90( const uint8_t* const pixelsIn,
+bool Rotate90( const uint8_t* const pixelsIn,
                unsigned int widthIn,
                unsigned int heightIn,
                unsigned int pixelSize,
@@ -525,6 +529,14 @@ void Rotate90( const uint8_t* const pixelsIn,
 
   // Allocate memory for the rotated buffer.
   pixelsOut = static_cast<uint8_t*>( malloc ( widthOut * heightOut * pixelSize ) );
+  if( nullptr == pixelsOut )
+  {
+    widthOut = 0u;
+    heightOut = 0u;
+
+    // Return if the memory allocations fails.
+    return false;
+  }
 
   // Rotate the buffer.
   for( unsigned int y = 0u; y < heightIn; ++y )
@@ -543,6 +555,8 @@ void Rotate90( const uint8_t* const pixelsIn,
       }
     }
   }
+
+  return true;
 }
 
 /**
@@ -550,14 +564,17 @@ void Rotate90( const uint8_t* const pixelsIn,
  *
  * @note It allocates memory for the returned @p pixelsOut buffer.
  * @note Code got from https://www.codeproject.com/Articles/202/High-quality-image-rotation-rotate-by-shear by Eran Yariv.
+ * @note It may fail if malloc() fails to allocate memory.
  *
  * @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] pixelSize The size of the pixel.
  * @param[out] pixelsOut The rotated output buffer.
+ *
+ * @return Whether the rotation succeded.
  */
-void Rotate180( const uint8_t* const pixelsIn,
+bool Rotate180( const uint8_t* const pixelsIn,
                 unsigned int widthIn,
                 unsigned int heightIn,
                 unsigned int pixelSize,
@@ -565,6 +582,11 @@ void Rotate180( const uint8_t* const pixelsIn,
 {
   // Allocate memory for the rotated buffer.
   pixelsOut = static_cast<uint8_t*>( malloc ( widthIn * heightIn * pixelSize ) );
+  if( nullptr == pixelsOut )
+  {
+    // Return if the memory allocations fails.
+    return false;
+  }
 
   // Rotate the buffer.
   for( unsigned int y = 0u; y < heightIn; ++y )
@@ -583,6 +605,8 @@ void Rotate180( const uint8_t* const pixelsIn,
       }
     }
   }
+
+  return true;
 }
 
 /**
@@ -590,6 +614,7 @@ void Rotate180( const uint8_t* const pixelsIn,
  *
  * @note It allocates memory for the returned @p pixelsOut buffer.
  * @note Code got from https://www.codeproject.com/Articles/202/High-quality-image-rotation-rotate-by-shear by Eran Yariv.
+ * @note It may fail if malloc() fails to allocate memory.
  *
  * @param[in] pixelsIn The input buffer.
  * @param[in] widthIn The width of the input buffer.
@@ -598,8 +623,10 @@ void Rotate180( const uint8_t* const pixelsIn,
  * @param[out] pixelsOut The rotated output buffer.
  * @param[out] widthOut The width of the output buffer.
  * @param[out] heightOut The height of the output buffer.
+ *
+ * @return Whether the rotation succeded.
  */
-void Rotate270( const uint8_t* const pixelsIn,
+bool Rotate270( const uint8_t* const pixelsIn,
                 unsigned int widthIn,
                 unsigned int heightIn,
                 unsigned int pixelSize,
@@ -613,6 +640,14 @@ void Rotate270( const uint8_t* const pixelsIn,
 
   // Allocate memory for the rotated buffer.
   pixelsOut = static_cast<uint8_t*>( malloc ( widthOut * heightOut * pixelSize ) );
+  if( nullptr == pixelsOut )
+  {
+    widthOut = 0u;
+    heightOut = 0u;
+
+    // Return if the memory allocations fails.
+    return false;
+  }
 
   // Rotate the buffer.
   for( unsigned int y = 0u; y < heightIn; ++y )
@@ -631,6 +666,8 @@ void Rotate270( const uint8_t* const pixelsIn,
       }
     }
   }
+
+  return true;
 }
 
 /**
@@ -1231,9 +1268,9 @@ void HalveScanlineInPlaceRGB888( unsigned char * const pixels, const unsigned in
     const unsigned int c23 = pixels[pixel * 3 + 5];
 
     // Save the averaged byte pixel components:
-    pixels[outPixel * 3]     = AverageComponent( c11, c21 );
-    pixels[outPixel * 3 + 1] = AverageComponent( c12, c22 );
-    pixels[outPixel * 3 + 2] = AverageComponent( c13, c23 );
+    pixels[outPixel * 3]     = static_cast<unsigned char>( AverageComponent( c11, c21 ) );
+    pixels[outPixel * 3 + 1] = static_cast<unsigned char>( AverageComponent( c12, c22 ) );
+    pixels[outPixel * 3 + 2] = static_cast<unsigned char>( AverageComponent( c13, c23 ) );
   }
 }
 
@@ -1284,8 +1321,8 @@ void HalveScanlineInPlace2Bytes( unsigned char * const pixels, const unsigned in
     const unsigned int c22 = pixels[pixel * 2 + 3];
 
     // Save the averaged byte pixel components:
-    pixels[outPixel * 2]     = AverageComponent( c11, c21 );
-    pixels[outPixel * 2 + 1] = AverageComponent( c12, c22 );
+    pixels[outPixel * 2]     = static_cast<unsigned char>( AverageComponent( c11, c21 ) );
+    pixels[outPixel * 2 + 1] = static_cast<unsigned char>( AverageComponent( c12, c22 ) );
   }
 }
 
@@ -1302,7 +1339,7 @@ void HalveScanlineInPlace1Byte( unsigned char * const pixels, const unsigned int
     const unsigned int c2 = pixels[pixel + 1];
 
     // Save the averaged byte pixel component:
-    pixels[outPixel] = AverageComponent( c1, c2 );
+    pixels[outPixel] = static_cast<unsigned char>( AverageComponent( c1, c2 ) );
   }
 }
 
@@ -1319,7 +1356,7 @@ void AverageScanlines1( const unsigned char * const scanline1,
 
   for( unsigned int component = 0; component < width; ++component )
   {
-    outputScanline[component] = AverageComponent( scanline1[component], scanline2[component] );
+    outputScanline[component] = static_cast<unsigned char>( AverageComponent( scanline1[component], scanline2[component] ) );
   }
 }
 
@@ -1332,7 +1369,7 @@ void AverageScanlines2( const unsigned char * const scanline1,
 
   for( unsigned int component = 0; component < width * 2; ++component )
   {
-    outputScanline[component] = AverageComponent( scanline1[component], scanline2[component] );
+    outputScanline[component] = static_cast<unsigned char>( AverageComponent( scanline1[component], scanline2[component] ) );
   }
 }
 
@@ -1345,7 +1382,7 @@ void AverageScanlines3( const unsigned char * const scanline1,
 
   for( unsigned int component = 0; component < width * 3; ++component )
   {
-    outputScanline[component] = AverageComponent( scanline1[component], scanline2[component] );
+    outputScanline[component] = static_cast<unsigned char>( AverageComponent( scanline1[component], scanline2[component] ) );
   }
 }
 
@@ -1433,7 +1470,7 @@ void DownscaleInPlacePow2( unsigned char * const pixels,
       }
       else
       {
-        DALI_ASSERT_DEBUG( false == "Inner branch conditions don't match outer branch." );
+        DALI_ASSERT_DEBUG( false && "Inner branch conditions don't match outer branch." );
       }
     }
   }
@@ -1647,9 +1684,9 @@ void PointSample3BPP( const uint8_t * inPixels,
       ///@ToDo: Optimise - Benchmark one 32bit load that will be unaligned 2/3 of the time + 3 rotate and masks, versus these three aligned byte loads, versus using an RGB packed, aligned(1) struct and letting compiler pick a strategy.
 
       // Output the pixel components:
-      outScanline[outX]     = c0;
-      outScanline[outX + 1] = c1;
-      outScanline[outX + 2] = c2;
+      outScanline[outX]     = static_cast<uint8_t>( c0 );
+      outScanline[outX + 1] = static_cast<uint8_t>( c1 );
+      outScanline[outX + 2] = static_cast<uint8_t>( c2 );
 
       // Increment the fixed-point input coordinate:
       inX += deltaX;
@@ -1689,7 +1726,7 @@ void PointSample( const unsigned char * inPixels,
     }
     else
     {
-      DALI_ASSERT_DEBUG( false == "Inner branch conditions don't match outer branch." );
+      DALI_ASSERT_DEBUG( 0 == "Inner branch conditions don't match outer branch." );
     }
   }
   else
@@ -1706,15 +1743,15 @@ namespace
 /** @brief Blend 4 pixels together using horizontal and vertical weights. */
 inline uint8_t BilinearFilter1BPPByte( uint8_t tl, uint8_t tr, uint8_t bl, uint8_t br, unsigned int fractBlendHorizontal, unsigned int fractBlendVertical )
 {
-  return BilinearFilter1Component( tl, tr, bl, br, fractBlendHorizontal, fractBlendVertical );
+  return static_cast<uint8_t>( BilinearFilter1Component( tl, tr, bl, br, fractBlendHorizontal, fractBlendVertical ) );
 }
 
 /** @copydoc BilinearFilter1BPPByte */
 inline Pixel2Bytes BilinearFilter2Bytes( Pixel2Bytes tl, Pixel2Bytes tr, Pixel2Bytes bl, Pixel2Bytes br, unsigned int fractBlendHorizontal, unsigned int fractBlendVertical )
 {
   Pixel2Bytes pixel;
-  pixel.l = BilinearFilter1Component( tl.l, tr.l, bl.l, br.l, fractBlendHorizontal, fractBlendVertical );
-  pixel.a = BilinearFilter1Component( tl.a, tr.a, bl.a, br.a, fractBlendHorizontal, fractBlendVertical );
+  pixel.l = static_cast<uint8_t>( BilinearFilter1Component( tl.l, tr.l, bl.l, br.l, fractBlendHorizontal, fractBlendVertical ) );
+  pixel.a = static_cast<uint8_t>( BilinearFilter1Component( tl.a, tr.a, bl.a, br.a, fractBlendHorizontal, fractBlendVertical ) );
   return pixel;
 }
 
@@ -1722,18 +1759,18 @@ inline Pixel2Bytes BilinearFilter2Bytes( Pixel2Bytes tl, Pixel2Bytes tr, Pixel2B
 inline Pixel3Bytes BilinearFilterRGB888( Pixel3Bytes tl, Pixel3Bytes tr, Pixel3Bytes bl, Pixel3Bytes br, unsigned int fractBlendHorizontal, unsigned int fractBlendVertical )
 {
   Pixel3Bytes pixel;
-  pixel.r = BilinearFilter1Component( tl.r, tr.r, bl.r, br.r, fractBlendHorizontal, fractBlendVertical );
-  pixel.g = BilinearFilter1Component( tl.g, tr.g, bl.g, br.g, fractBlendHorizontal, fractBlendVertical );
-  pixel.b = BilinearFilter1Component( tl.b, tr.b, bl.b, br.b, fractBlendHorizontal, fractBlendVertical );
+  pixel.r = static_cast<uint8_t>( BilinearFilter1Component( tl.r, tr.r, bl.r, br.r, fractBlendHorizontal, fractBlendVertical ) );
+  pixel.g = static_cast<uint8_t>( BilinearFilter1Component( tl.g, tr.g, bl.g, br.g, fractBlendHorizontal, fractBlendVertical ) );
+  pixel.b = static_cast<uint8_t>( BilinearFilter1Component( tl.b, tr.b, bl.b, br.b, fractBlendHorizontal, fractBlendVertical ) );
   return pixel;
 }
 
 /** @copydoc BilinearFilter1BPPByte */
 inline PixelRGB565 BilinearFilterRGB565( PixelRGB565 tl, PixelRGB565 tr, PixelRGB565 bl, PixelRGB565 br, unsigned int fractBlendHorizontal, unsigned int fractBlendVertical )
 {
-  const PixelRGB565 pixel = (BilinearFilter1Component( tl >> 11u, tr >> 11u, bl >> 11u, br >> 11u, fractBlendHorizontal, fractBlendVertical ) << 11u) +
+  const PixelRGB565 pixel = static_cast<PixelRGB565>( (BilinearFilter1Component( tl >> 11u, tr >> 11u, bl >> 11u, br >> 11u, fractBlendHorizontal, fractBlendVertical ) << 11u) +
                             (BilinearFilter1Component( (tl >> 5u) & 63u, (tr >> 5u) & 63u, (bl >> 5u) & 63u, (br >> 5u) & 63u, fractBlendHorizontal, fractBlendVertical ) << 5u) +
-                             BilinearFilter1Component( tl & 31u, tr & 31u, bl & 31u, br & 31u, fractBlendHorizontal, fractBlendVertical );
+                             BilinearFilter1Component( tl & 31u, tr & 31u, bl & 31u, br & 31u, fractBlendHorizontal, fractBlendVertical ) );
   return pixel;
 }
 
@@ -1741,10 +1778,10 @@ inline PixelRGB565 BilinearFilterRGB565( PixelRGB565 tl, PixelRGB565 tr, PixelRG
 inline Pixel4Bytes BilinearFilter4Bytes( Pixel4Bytes tl, Pixel4Bytes tr, Pixel4Bytes bl, Pixel4Bytes br, unsigned int fractBlendHorizontal, unsigned int fractBlendVertical )
 {
   Pixel4Bytes pixel;
-  pixel.r = BilinearFilter1Component( tl.r, tr.r, bl.r, br.r, fractBlendHorizontal, fractBlendVertical );
-  pixel.g = BilinearFilter1Component( tl.g, tr.g, bl.g, br.g, fractBlendHorizontal, fractBlendVertical );
-  pixel.b = BilinearFilter1Component( tl.b, tr.b, bl.b, br.b, fractBlendHorizontal, fractBlendVertical );
-  pixel.a = BilinearFilter1Component( tl.a, tr.a, bl.a, br.a, fractBlendHorizontal, fractBlendVertical );
+  pixel.r = static_cast<uint8_t>( BilinearFilter1Component( tl.r, tr.r, bl.r, br.r, fractBlendHorizontal, fractBlendVertical ) );
+  pixel.g = static_cast<uint8_t>( BilinearFilter1Component( tl.g, tr.g, bl.g, br.g, fractBlendHorizontal, fractBlendVertical ) );
+  pixel.b = static_cast<uint8_t>( BilinearFilter1Component( tl.b, tr.b, bl.b, br.b, fractBlendHorizontal, fractBlendVertical ) );
+  pixel.a = static_cast<uint8_t>( BilinearFilter1Component( tl.a, tr.a, bl.a, br.a, fractBlendHorizontal, fractBlendVertical ) );
   return pixel;
 }
 
@@ -1915,8 +1952,8 @@ void Resample( const unsigned char * __restrict__ inPixels,
     }
   }
 
-  Resampler* resamplers[numChannels];
-  Vector<float> samples[numChannels];
+  std::vector<Resampler*> resamplers( numChannels );
+  std::vector<Vector<float>> samples(numChannels);
 
   const int srcWidth = inputDimensions.GetWidth();
   const int srcHeight = inputDimensions.GetHeight();
@@ -2098,7 +2135,7 @@ void LinearSample( const unsigned char * __restrict__ inPixels,
     }
     else
     {
-      DALI_ASSERT_DEBUG( false == "Inner branch conditions don't match outer branch." );
+      DALI_ASSERT_DEBUG( 0 == "Inner branch conditions don't match outer branch." );
     }
   }
   else
@@ -2127,15 +2164,22 @@ void RotateByShear( const uint8_t* const pixelsIn,
     // Rotate image by 90 degrees into temporary image,
     // so it requires only an extra rotation angle
     // of -45.0 .. +45.0 to complete rotation.
-    Rotate90( pixelsIn,
-              widthIn,
-              heightIn,
-              pixelSize,
-              pixelsOut,
-              widthOut,
-              heightOut );
+    fastRotationPerformed = Rotate90( pixelsIn,
+                                      widthIn,
+                                      heightIn,
+                                      pixelSize,
+                                      pixelsOut,
+                                      widthOut,
+                                      heightOut );
+
+    if( !fastRotationPerformed )
+    {
+      DALI_LOG_INFO(gImageOpsLogFilter, Dali::Integration::Log::Verbose, "fast rotation failed\n");
+      // The fast rotation failed.
+      return;
+    }
+
     radians -= Math::PI_2;
-    fastRotationPerformed = true;
   }
   else if( ( radians > RAD_135 ) && ( radians <= RAD_225 ) )
   {
@@ -2144,15 +2188,22 @@ void RotateByShear( const uint8_t* const pixelsIn,
     // so it requires only an extra rotation angle
     // of -45.0 .. +45.0 to complete rotation.
 
-    Rotate180( pixelsIn,
-               widthIn,
-               heightIn,
-               pixelSize,
-               pixelsOut );
+    fastRotationPerformed = Rotate180( pixelsIn,
+                                       widthIn,
+                                       heightIn,
+                                       pixelSize,
+                                       pixelsOut );
+
+    if( !fastRotationPerformed )
+    {
+      DALI_LOG_INFO(gImageOpsLogFilter, Dali::Integration::Log::Verbose, "fast rotation failed\n");
+      // The fast rotation failed.
+      return;
+    }
+
     radians -= Math::PI;
     widthOut = widthIn;
     heightOut = heightIn;
-    fastRotationPerformed = true;
   }
   else if( ( radians > RAD_225 ) && ( radians <= RAD_315 ) )
   {
@@ -2161,15 +2212,22 @@ void RotateByShear( const uint8_t* const pixelsIn,
     // so it requires only an extra rotation angle
     // of -45.0 .. +45.0 to complete rotation.
 
-    Rotate270( pixelsIn,
-               widthIn,
-               heightIn,
-               pixelSize,
-               pixelsOut,
-               widthOut,
-               heightOut );
+    fastRotationPerformed = Rotate270( pixelsIn,
+                                       widthIn,
+                                       heightIn,
+                                       pixelSize,
+                                       pixelsOut,
+                                       widthOut,
+                                       heightOut );
+
+    if( !fastRotationPerformed )
+    {
+      DALI_LOG_INFO(gImageOpsLogFilter, Dali::Integration::Log::Verbose, "fast rotation failed\n");
+      // The fast rotation failed.
+      return;
+    }
+
     radians -= RAD_270;
-    fastRotationPerformed = true;
   }
 
   if( fabs( radians ) < Dali::Math::MACHINE_EPSILON_10 )
@@ -2181,8 +2239,8 @@ void RotateByShear( const uint8_t* const pixelsIn,
     return;
   }
 
-  const uint8_t* const firstHorizontalSkwePixelsIn = fastRotationPerformed ? pixelsOut : pixelsIn;
-  uint8_t*  tmpFirstHorizontalSkwePixelsIn = fastRotationPerformed ? pixelsOut : nullptr; // keep the pointer to free the memory.
+  const uint8_t* const firstHorizontalSkewPixelsIn = fastRotationPerformed ? pixelsOut : pixelsIn;
+  std::unique_ptr<uint8_t, void(*)(void*)> tmpPixelsInPtr( ( fastRotationPerformed ? pixelsOut : nullptr ), free );
 
   // Reset the input/output
   widthIn = widthOut;
@@ -2205,18 +2263,28 @@ void RotateByShear( const uint8_t* const pixelsIn,
   // Allocate the buffer for the 1st shear
   pixelsOut = static_cast<uint8_t*>( malloc( widthOut * heightOut * pixelSize ) );
 
+  if( nullptr == pixelsOut )
+  {
+    widthOut = 0u;
+    heightOut = 0u;
+
+    DALI_LOG_INFO(gImageOpsLogFilter, Dali::Integration::Log::Verbose, "malloc failed to allocate memory\n");
+
+    // The deleter of the tmpPixelsInPtr unique pointer is called freeing the memory allocated by the 'Fast rotations'.
+    // Nothing else to do if the memory allocation fails.
+    return;
+  }
+
   for( unsigned int y = 0u; y < heightOut; ++y )
   {
     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( firstHorizontalSkwePixelsIn, widthIn, pixelSize, pixelsOut, widthOut, y, intShear, shear - static_cast<float>( intShear ) );
+    HorizontalSkew( firstHorizontalSkewPixelsIn, widthIn, pixelSize, pixelsOut, widthOut, y, intShear, shear - static_cast<float>( intShear ) );
   }
 
-  // Free the memory allocated by the 'Fast Rotations'.
-  free( tmpFirstHorizontalSkwePixelsIn );
-
-  uint8_t* tmpPixelsIn = pixelsOut;
+  // Reset the 'pixel in' pointer with the output of the 'First Horizontal Skew' and free the memory allocated by the 'Fast Rotations'.
+  tmpPixelsInPtr.reset( pixelsOut );
   unsigned int tmpWidthIn = widthOut;
   unsigned int tmpHeightIn = heightOut;
 
@@ -2233,6 +2301,17 @@ void RotateByShear( const uint8_t* const pixelsIn,
   // Allocate the buffer for the 2nd shear
   pixelsOut = static_cast<uint8_t*>( malloc( widthOut * heightOut * pixelSize ) );
 
+  if( nullptr == pixelsOut )
+  {
+    widthOut = 0u;
+    heightOut = 0u;
+
+    DALI_LOG_INFO(gImageOpsLogFilter, Dali::Integration::Log::Verbose, "malloc failed to allocate memory\n");
+    // The deleter of the tmpPixelsInPtr unique pointer is called freeing the memory allocated by the 'First Horizontal Skew'.
+    // Nothing else to do if the memory allocation fails.
+    return;
+  }
+
   // Variable skew offset
   float offset = angleSinus * ( ( angleSinus > 0.f ) ? static_cast<float>( widthIn - 1u ) : -( static_cast<float>( widthIn ) - static_cast<float>( widthOut ) ) );
 
@@ -2240,14 +2319,11 @@ void RotateByShear( const uint8_t* const pixelsIn,
   for( column = 0u; column < widthOut; ++column, offset -= angleSinus )
   {
     const int shear = static_cast<int>( floor( offset ) );
-    VerticalSkew( tmpPixelsIn, tmpWidthIn, tmpHeightIn, pixelSize, pixelsOut, widthOut, heightOut, column, shear, offset - static_cast<float>( shear ) );
+    VerticalSkew( tmpPixelsInPtr.get(), tmpWidthIn, tmpHeightIn, pixelSize, pixelsOut, widthOut, heightOut, column, shear, offset - static_cast<float>( shear ) );
   }
-
-  // Free the memory allocated by the 'First Horizontal Skew'.
-  free( tmpPixelsIn );
-
+  // 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
-  tmpPixelsIn = pixelsOut;
+  tmpPixelsInPtr.reset( pixelsOut );
   tmpWidthIn = widthOut;
   tmpHeightIn = heightOut;
   pixelsOut = nullptr;
@@ -2262,18 +2338,74 @@ void RotateByShear( const uint8_t* const pixelsIn,
   // Allocate the buffer for the 3rd shear
   pixelsOut = static_cast<uint8_t*>( malloc( widthOut * heightOut * pixelSize ) );
 
+  if( nullptr == pixelsOut )
+  {
+    widthOut = 0u;
+    heightOut = 0u;
+
+    DALI_LOG_INFO(gImageOpsLogFilter, Dali::Integration::Log::Verbose, "malloc failed to allocate memory\n");
+    // The deleter of the tmpPixelsInPtr unique pointer is called freeing the memory allocated by the 'Vertical Skew'.
+    // Nothing else to do if the memory allocation fails.
+    return;
+  }
+
   offset =  ( angleSinus >= 0.f ) ? -angleSinus * angleTangent * static_cast<float>( widthIn - 1u ) : angleTangent * ( static_cast<float>( widthIn - 1u ) * -angleSinus + ( 1.f - static_cast<float>( heightOut ) ) );
 
   for( unsigned int y = 0u; y < heightOut; ++y, offset += angleTangent )
   {
     const int shear = static_cast<int>( floor( offset ) );
-    HorizontalSkew( tmpPixelsIn, tmpWidthIn, pixelSize, pixelsOut, widthOut, y, shear, offset - static_cast<float>( shear ) );
+    HorizontalSkew( tmpPixelsInPtr.get(), tmpWidthIn, pixelSize, pixelsOut, widthOut, y, shear, offset - static_cast<float>( shear ) );
   }
 
-  // Free the memory allocated by the 'First Horizontal Skew'.
-  free( tmpPixelsIn );
+  // The deleter of the tmpPixelsInPtr unique pointer is called freeing the memory allocated by the 'Vertical Skew'.
+  // @note Allocated memory by the last 'Horizontal Skew' has to be freed by the caller to this function.
+}
+
+void HorizontalShear( const uint8_t* const pixelsIn,
+                      unsigned int widthIn,
+                      unsigned int heightIn,
+                      unsigned int pixelSize,
+                      float radians,
+                      uint8_t*& pixelsOut,
+                      unsigned int& widthOut,
+                      unsigned int& heightOut )
+{
+  // Calculate the destination image dimensions.
+
+  const float absRadians = fabs( radians );
+
+  if( absRadians > Math::PI_4 )
+  {
+    // Can't shear more than 45 degrees.
+    widthOut = 0u;
+    heightOut = 0u;
 
-  // @note Allocated memory by the last 'Horizontal Skew' has to be freed by the called to this function.
+    DALI_LOG_INFO( gImageOpsLogFilter, Dali::Integration::Log::Verbose, "Can't shear more than 45 degrees (PI/4 radians). radians : %f\n", radians );
+    return;
+  }
+
+  widthOut = widthIn + static_cast<unsigned int>( absRadians * static_cast<float>( heightIn ) );
+  heightOut = heightIn;
+
+  // Allocate the buffer for the shear.
+  pixelsOut = static_cast<uint8_t*>( malloc( widthOut * heightOut * pixelSize ) );
+
+  if( nullptr == pixelsOut )
+  {
+    widthOut = 0u;
+    heightOut = 0u;
+
+    DALI_LOG_INFO( gImageOpsLogFilter, Dali::Integration::Log::Verbose, "malloc failed to allocate memory\n" );
+    return;
+  }
+
+  for( unsigned int y = 0u; y < heightOut; ++y )
+  {
+    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 ) );
+  }
 }
 
 } /* namespace Platform */