PixelBuffer::Rotate() amendments. 62/190162/2
authorVictor Cebollada <v.cebollada@samsung.com>
Mon, 17 Sep 2018 09:53:24 +0000 (10:53 +0100)
committerVictor Cebollada <v.cebollada@samsung.com>
Thu, 27 Sep 2018 12:50:42 +0000 (13:50 +0100)
* The Rotate() method returns true if success.
* Checks memory allocations to avoid issues
  with static code analyzers.
* Some amendments in doxygen doc.

Change-Id: I4b45b29d15ad0f6d05ff5f912e19c49b836300a3
Signed-off-by: Victor Cebollada <v.cebollada@samsung.com>
dali/devel-api/adaptor-framework/pixel-buffer.cpp
dali/devel-api/adaptor-framework/pixel-buffer.h
dali/internal/imaging/common/image-operations.cpp
dali/internal/imaging/common/image-operations.h
dali/internal/imaging/common/pixel-buffer-impl.cpp
dali/internal/imaging/common/pixel-buffer-impl.h

index b041c96..f8d12b2 100644 (file)
@@ -126,9 +126,9 @@ bool PixelBuffer::GetMetadata( Property::Map& metadata ) const
   return GetImplementation(*this).GetMetadata(metadata);
 }
 
-void PixelBuffer::Rotate( Degree angle )
+bool PixelBuffer::Rotate( Degree angle )
 {
-  GetImplementation(*this).Rotate( angle );
+  return GetImplementation(*this).Rotate( angle );
 }
 
 } // namespace Devel
index 21a2c91..a63a623 100755 (executable)
@@ -221,13 +221,15 @@ public:
   /**
    * @brief Rotates the pixel buffer by the given angle.
    *
-   * @note Operation valid for pixel formats: A8, L8, LA88, RGB888, RGB8888, BGR8888, RGBA8888 and BGRA8888. Does nothing otherwise.
+   * @note Operation valid for pixel formats: A8, L8, LA88, RGB888, RGB8888, BGR8888, RGBA8888 and BGRA8888. Fails otherwise.
    * @note The operation does nothing for angles equivalent to 0 degrees: -360, 360, 720, etc.
    * @note If the pixel buffer does rotate, all the pointers to the internal pixel buffer retrieved by the method GetPixelBuffer() become invalid.
    *
    * @param[in] angle The angle in degrees.
+   *
+   * @return @e false if the rotation fails (invalid pixel format or memory issues).
    */
-  void Rotate( Degree angle );
+  bool Rotate( Degree angle );
 
 public:
 
index d4716b1..662d775 100755 (executable)
@@ -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;
 }
 
 /**
@@ -2127,15 +2164,21 @@ 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 )
+    {
+      // The fast rotation failed.
+      return;
+    }
+
     radians -= Math::PI_2;
-    fastRotationPerformed = true;
   }
   else if( ( radians > RAD_135 ) && ( radians <= RAD_225 ) )
   {
@@ -2144,15 +2187,21 @@ 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 )
+    {
+      // The fast rotation failed.
+      return;
+    }
+
     radians -= Math::PI;
     widthOut = widthIn;
     heightOut = heightIn;
-    fastRotationPerformed = true;
   }
   else if( ( radians > RAD_225 ) && ( radians <= RAD_315 ) )
   {
@@ -2161,15 +2210,21 @@ 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 )
+    {
+      // The fast rotation failed.
+      return;
+    }
+
     radians -= RAD_270;
-    fastRotationPerformed = true;
   }
 
   if( fabs( radians ) < Dali::Math::MACHINE_EPSILON_10 )
@@ -2181,8 +2236,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 +2260,26 @@ 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;
+
+    // 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 +2296,16 @@ 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;
+
+    // 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 +2313,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 +2332,26 @@ 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;
+
+    // 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 );
-
-  // @note Allocated memory by the last 'Horizontal Skew' has to be freed by the called to this function.
+  // 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.
 }
 
 } /* namespace Platform */
index 7226c16..c78f8fe 100644 (file)
@@ -384,6 +384,11 @@ void Resample( const unsigned char * __restrict__ inPixels,
 /**
  * @brief Rotates the input image with an implementation of the 'Rotate by Shear' algorithm.
  *
+ * @pre @p pixelsIn must not alias @p pixelsOut. The input image should be a totally
+ * separate buffer from the output buffer.
+ *
+ * @note This function allocates memory in @p pixelsOut which has to be released by calling @e free()
+ *
  * @param[in] pixelsIn The input buffer.
  * @param[in] widthIn The width of the input buffer.
  * @param[in] heightIn The height of the input buffer.
index cef8aa3..3bcb4ef 100644 (file)
@@ -215,7 +215,7 @@ void PixelBuffer::AllocateFixedSize( uint32_t size )
   mBufferSize = size;
 }
 
-void PixelBuffer::Rotate( Degree angle )
+bool PixelBuffer::Rotate( Degree angle )
 {
   // Check first if Rotate() can perform the operation in the current pixel buffer.
 
@@ -246,7 +246,7 @@ void PixelBuffer::Rotate( Degree angle )
   {
     // Can't rotate the pixel buffer with the current pixel format.
     DALI_LOG_ERROR( "Can't rotate the pixel buffer with the current pixel format\n" );
-    return;
+    return false;
   }
 
   float radians = Radian( angle ).radian;
@@ -258,7 +258,7 @@ void PixelBuffer::Rotate( Degree angle )
   if( radians < Dali::Math::MACHINE_EPSILON_10 )
   {
     // Nothing to do if the angle is zero.
-    return;
+    return true;
   }
 
   const unsigned int pixelSize = Pixel::GetBytesPerPixel( mPixelFormat );
@@ -273,13 +273,21 @@ void PixelBuffer::Rotate( Degree angle )
                            mWidth,
                            mHeight );
 
-  // Release the memory of the current pixel buffer.
-  ReleaseBuffer();
+  // Check whether the rotation succedded and set the new pixel buffer data.
+  const bool success = nullptr != pixelsOut;
 
-  // Set the new pixel buffer.
-  mBuffer = pixelsOut;
-  pixelsOut = nullptr;
-  mBufferSize = mWidth * mHeight * pixelSize;
+  if( success )
+  {
+    // Release the memory of the current pixel buffer.
+    ReleaseBuffer();
+
+    // Set the new pixel buffer.
+    mBuffer = pixelsOut;
+    pixelsOut = nullptr;
+    mBufferSize = mWidth * mHeight * pixelSize;
+  }
+
+  return success;
 }
 
 void PixelBuffer::ScaleAndCrop( float scaleFactor, ImageDimensions cropDimensions )
@@ -455,9 +463,6 @@ void PixelBuffer::MultiplyColorByAlpha()
   }
 }
 
-
-
-
 }// namespace Adaptor
 }// namespace Internal
 }// namespace Dali
index a6a3b75..b0fe5ce 100644 (file)
@@ -215,7 +215,7 @@ public:
   /**
    * @copydoc Devel::PixelBuffer::Rotate()
    */
-  void Rotate( Degree angle );
+  bool Rotate( Degree angle );
 
 private:
   /*