Support WebP format 24/237124/1
authorSeungho, Baek <sbsh.baek@samsung.com>
Wed, 10 Jun 2020 07:04:07 +0000 (16:04 +0900)
committerSeungho, Baek <sbsh.baek@samsung.com>
Thu, 25 Jun 2020 05:13:00 +0000 (14:13 +0900)
 - Make animated-image-loading interface for gif and webp.
 - Animated WebP requires WEBP_DEMUX_ABI_VERSION 0x0107 or later

Change-Id: I5331163e2b0d68a6ef7cb5a06d6e59a5140ffca9
Signed-off-by: Seungho, Baek <sbsh.baek@samsung.com>
14 files changed:
automated-tests/src/dali-adaptor/utc-Dali-GifLoading.cpp
build/tizen/CMakeLists.txt
dali/devel-api/adaptor-framework/animated-image-loading.cpp [new file with mode: 0644]
dali/devel-api/adaptor-framework/animated-image-loading.h [new file with mode: 0644]
dali/devel-api/adaptor-framework/gif-loading.cpp [deleted file]
dali/devel-api/adaptor-framework/gif-loading.h [deleted file]
dali/devel-api/file.list
dali/internal/imaging/common/animated-image-loading-impl.h [new file with mode: 0644]
dali/internal/imaging/common/gif-loading.cpp [new file with mode: 0644]
dali/internal/imaging/common/gif-loading.h [new file with mode: 0644]
dali/internal/imaging/common/webp-loading.cpp [new file with mode: 0644]
dali/internal/imaging/common/webp-loading.h [new file with mode: 0644]
dali/internal/imaging/file.list
packaging/dali-adaptor.spec

index 6a4fa8706d25f25816d69c2a0b7f1afe60848ef8..b87ce8eb6084423ee897bd34dca8cf1d401f987b 100755 (executable)
@@ -18,7 +18,7 @@
 #include <stdlib.h>
 #include <dali/dali.h>
 #include <dali-test-suite-utils.h>
-#include <dali/devel-api/adaptor-framework/gif-loading.h>
+#include <dali/devel-api/adaptor-framework/animated-image-loading.h>
 
 using namespace Dali;
 
@@ -50,38 +50,57 @@ void VerifyLoad( std::vector<Dali::PixelData>& pixelDataList, Dali::Vector<uint3
 }
 }
 
-void utc_dali_gif_loader_startup(void)
+void utc_dali_animated_image_loader_startup(void)
 {
   test_return_value = TET_UNDEF;
 }
 
-void utc_dali_gif_loader_cleanup(void)
+void utc_dali_animated_image_loader_cleanup(void)
 {
   test_return_value = TET_PASS;
 }
 
-int UtcDaliGifLoadingP(void)
+int UtcDaliAnimatedImageLoadingP(void)
 {
   std::vector<Dali::PixelData> pixelDataList;
   Dali::Vector<uint32_t> frameDelayList;
 
-  std::unique_ptr<Dali::GifLoading> gifLoading = GifLoading::New( gGif_100_None, true );
-  bool succeed = gifLoading->LoadAllFrames( pixelDataList, 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();
-  gifLoading = GifLoading::New( gGif_100_Prev, true );
-  succeed = gifLoading->LoadAllFrames( pixelDataList, frameDelayList );
+  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();
-  gifLoading = GifLoading::New( gGif_100_Bgnd, true );
-  succeed = gifLoading->LoadAllFrames( pixelDataList, frameDelayList );
+  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 );
@@ -90,28 +109,27 @@ int UtcDaliGifLoadingP(void)
   END_TEST;
 }
 
-int UtcDaliGifLoadingN(void)
+int UtcDaliAnimatedImageLoadingN(void)
 {
   std::vector<Dali::PixelData> pixelDataList;
   Dali::Vector<uint32_t> frameDelayList;
 
-  std::unique_ptr<Dali::GifLoading> gifLoading = GifLoading::New( gGifNonExist, true );
-  bool succeed = gifLoading->LoadAllFrames( pixelDataList, 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 );
-  DALI_TEST_EQUALS( frameDelayList.Size(), 0u, TEST_LOCATION );
 
   END_TEST;
 }
 
-int UtcDaliGifLoadingGetImageSizeP(void)
+int UtcDaliAnimatedImageLoadingGetImageSizeP(void)
 {
-  std::unique_ptr<Dali::GifLoading> gifLoading = GifLoading::New( gGif_100_None, true );
-  ImageDimensions imageSize = gifLoading->GetImageSize();
+  Dali::AnimatedImageLoading animatedImageLoading = Dali::AnimatedImageLoading::New( gGif_100_None, true );
+  ImageDimensions imageSize = animatedImageLoading.GetImageSize();
 
   // Check that the image size is [100, 100]
   DALI_TEST_EQUALS( imageSize.GetWidth(), 100u, TEST_LOCATION );
@@ -120,12 +138,12 @@ int UtcDaliGifLoadingGetImageSizeP(void)
   END_TEST;
 }
 
-int UtcDaliGifLoadingGetImageSizeN(void)
+int UtcDaliAnimatedImageLoadingGetImageSizeN(void)
 {
-  std::unique_ptr<Dali::GifLoading> gifLoading = GifLoading::New( gGifNonExist, true );
-  ImageDimensions imageSize = gifLoading->GetImageSize();
+  Dali::AnimatedImageLoading animatedImageLoading = Dali::AnimatedImageLoading::New( gGifNonExist, true );
+  ImageDimensions imageSize = animatedImageLoading.GetImageSize();
 
-  // Check that it returns zero size when the gif is not valid
+  // Check that it returns zero size when the animated image is not valid
   DALI_TEST_EQUALS( imageSize.GetWidth(), 0u, TEST_LOCATION );
   DALI_TEST_EQUALS( imageSize.GetHeight(), 0u, TEST_LOCATION );
 
index 7c56a829f8fd84e410822978647176c937ce7f93..a83d807c8c0ce99bd2b0771e90a03afdf13f10b3 100644 (file)
@@ -176,11 +176,13 @@ IF( UNIX )
   ENDIF()
 ENDIF()
 
+SET( REQUIRED_LIBS ${REQUIRED_LIBS} webp webpdemux )
+
 TARGET_LINK_LIBRARIES( ${name}
                        ${DALI_LDFLAGS}
-  ${REQUIRED_LIBS}
-  ${OPTIONAL_LIBS}
-  ${COVERAGE}
+                       ${REQUIRED_LIBS}
+                       ${OPTIONAL_LIBS}
+                       ${COVERAGE}
 )
 
 SET_TARGET_PROPERTIES( ${name}
diff --git a/dali/devel-api/adaptor-framework/animated-image-loading.cpp b/dali/devel-api/adaptor-framework/animated-image-loading.cpp
new file mode 100644 (file)
index 0000000..f2a9afa
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/devel-api/adaptor-framework/animated-image-loading.h>
+
+// INTERNAL HEADER
+#include <dali/internal/imaging/common/animated-image-loading-impl.h>
+#include <dali/internal/imaging/common/gif-loading.h>
+#include <dali/internal/imaging/common/webp-loading.h>
+
+namespace Dali
+{
+
+AnimatedImageLoading::AnimatedImageLoading()
+{
+}
+
+AnimatedImageLoading AnimatedImageLoading::New( const std::string& url, bool isLocalResource )
+{
+
+  const std::size_t urlSize = url.length();
+
+  Internal::Adaptor::AnimatedImageLoadingPtr internal = NULL;
+  if(urlSize >= 4){ // Avoid throwing out_of_range or failing silently if exceptions are turned-off on the compare(). (http://www.cplusplus.com/reference/string/string/compare/)
+    if( !url.compare( urlSize - 4, 4, ".gif" )
+        || !url.compare( urlSize - 4, 4, ".GIF" ) )
+    {
+      internal = Internal::Adaptor::GifLoading::New( url, isLocalResource );
+    }
+  }
+  if(urlSize >= 5){ // Avoid throwing out_of_range or failing silently if exceptions are turned-off on the compare(). (http://www.cplusplus.com/reference/string/string/compare/)
+    if( !url.compare( urlSize - 5, 5, ".webp" )
+        || !url.compare( urlSize - 5, 5, ".WEBP" ) )
+    {
+      internal = Internal::Adaptor::WebPLoading::New( url, isLocalResource );
+    }
+  }
+
+  return AnimatedImageLoading( internal.Get() );
+}
+
+AnimatedImageLoading AnimatedImageLoading::DownCast( BaseHandle handle )
+{
+  return AnimatedImageLoading( dynamic_cast< Internal::Adaptor::AnimatedImageLoading* >( handle.GetObjectPtr() ) );
+}
+
+AnimatedImageLoading::~AnimatedImageLoading()
+{
+}
+
+bool AnimatedImageLoading::LoadNextNFrames( uint32_t frameStartIndex, int count, std::vector<Dali::PixelData>& pixelData )
+{
+  return GetImplementation( *this ).LoadNextNFrames( frameStartIndex, count, pixelData );
+}
+
+ImageDimensions AnimatedImageLoading::GetImageSize() const
+{
+  return GetImplementation( *this ).GetImageSize();
+}
+
+uint32_t AnimatedImageLoading::GetImageCount() const
+{
+  return GetImplementation( *this ).GetImageCount();
+}
+
+uint32_t AnimatedImageLoading::GetFrameInterval( uint32_t frameIndex ) const
+{
+  return GetImplementation( *this ).GetFrameInterval( frameIndex );
+}
+
+AnimatedImageLoading::AnimatedImageLoading( Internal::Adaptor::AnimatedImageLoading* internal )
+: BaseHandle( internal )
+{
+}
+
+} // namespace Dali
diff --git a/dali/devel-api/adaptor-framework/animated-image-loading.h b/dali/devel-api/adaptor-framework/animated-image-loading.h
new file mode 100644 (file)
index 0000000..7c0a69b
--- /dev/null
@@ -0,0 +1,150 @@
+#ifndef DALI_ANIMATED_IMAGE_LOADING_H
+#define DALI_ANIMATED_IMAGE_LOADING_H
+
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/math/uint-16-pair.h>
+#include <dali/public-api/object/base-handle.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+
+class PixelData;
+typedef Dali::Uint16Pair ImageDimensions;
+
+/**
+ * @addtogroup dali_adaptor_framework
+ * @{
+ */
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class AnimatedImageLoading;
+}
+}
+
+/**
+ * Class to manage loading frames of an animated image in small chunks. Lazy initializes only when
+ * data is actually needed.
+ * Note, once the Animated Image has loaded, the undecoded data will reside in memory until this object
+ * is released. (This is to speed up frame loads, which would otherwise have to re-acquire the
+ * data from disk)
+ */
+class DALI_ADAPTOR_API AnimatedImageLoading : public BaseHandle
+{
+public:
+
+  /**
+   * Create a GifLoading with the given url and resourceType.
+   * @param[in] url The url of the animated image to load
+   * @param[in] isLocalResource The true or false whether this is a local resource.
+   * @return A newly created GifLoading.
+   */
+  static AnimatedImageLoading New( const std::string& url, bool isLocalResource );
+
+  /**
+   * @brief Constructor
+   */
+  AnimatedImageLoading();
+
+  /**
+   * @brief Downcast an Object handle to Capture handle.
+   *
+   * If handle points to a Capture object the downcast produces valid
+   * handle. If not the returned handle is left uninitialized.
+   *
+   * @param[in] handle to An object.
+   * @return handle to a Capture object or an uninitialized handle.
+   */
+  static AnimatedImageLoading DownCast( BaseHandle handle );
+
+
+  /**
+   * @brief Copy constructor.
+   *
+   * @param[in] copy The AnimatedImageLoading to copy
+   */
+  AnimatedImageLoading(const AnimatedImageLoading& copy) = default;
+
+  /**
+   * @brief Assignment operator
+   *
+   * @param[in] rhs The AnimatedImageLoading to copy
+   * @return A reference to this
+   */
+  AnimatedImageLoading& operator=(const AnimatedImageLoading& rhs) = default;
+
+  /**
+   * @brief Destructor
+   */
+  ~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 Get the size of a animated image.
+   *
+   * @return The width and height in pixels of the animated image.
+   */
+  ImageDimensions GetImageSize() const;
+
+  /**
+   * @brief Get the number of frames in this animated image.
+   */
+  uint32_t GetImageCount() const;
+
+  /**
+   * @brief Get the frame interval of the frame index
+   *
+   * @note The frame is needed to be loaded before this function is called.
+   *
+   * @return The time interval of the frame(microsecond).
+   */
+  uint32_t GetFrameInterval( uint32_t frameIndex ) const;
+
+public: // Not intended for application developers
+  /// @cond internal
+  /**
+   * @brief This constructor is used by New() methods.
+   *
+   * @param[in] internal A pointer to a newly allocated Dali resource.
+   */
+  explicit DALI_INTERNAL AnimatedImageLoading( Internal::Adaptor::AnimatedImageLoading* internal );
+  /// @endcond
+};
+
+} // namespace Dali
+
+#endif // DALI_ANIMATED_IMAGE_LOADING_H
diff --git a/dali/devel-api/adaptor-framework/gif-loading.cpp b/dali/devel-api/adaptor-framework/gif-loading.cpp
deleted file mode 100755 (executable)
index e49fbc8..0000000
+++ /dev/null
@@ -1,1313 +0,0 @@
-/*
- * 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * Copyright notice for the EFL:
- * Copyright (C) EFL developers (see AUTHORS)
- */
-
-// CLASS HEADER
-#include <dali/devel-api/adaptor-framework/gif-loading.h>
-
-// EXTERNAL INCLUDES
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <gif_lib.h>
-#include <cstring>
-#include <dali/integration-api/debug.h>
-#include <dali/public-api/images/pixel-data.h>
-#include <dali/internal/imaging/common/file-download.h>
-#include <dali/internal/system/common/file-reader.h>
-
-#define IMG_TOO_BIG( w, h )                                                        \
-  ( ( static_cast<unsigned long long>(w) * static_cast<unsigned long long>(h) ) >= \
-    ( (1ULL << (29 * (sizeof(void *) / 4))) - 2048) )
-
-#define LOADERR( x )                              \
-  do {                                            \
-    DALI_LOG_ERROR( x );                          \
-    goto on_error;                                \
-  } while ( 0 )
-
-namespace Dali
-{
-
-namespace
-{
-#if defined(DEBUG_ENABLED)
-Debug::Filter *gGifLoadingLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_GIF_LOADING" );
-#endif
-
-const int IMG_MAX_SIZE = 65000;
-constexpr size_t MAXIMUM_DOWNLOAD_IMAGE_SIZE  = 50 * 1024 * 1024;
-
-#if GIFLIB_MAJOR < 5
-const int DISPOSE_BACKGROUND = 2;       /* Set area too background color */
-const int DISPOSE_PREVIOUS = 3;         /* Restore to previous content */
-#endif
-
-struct FrameInfo
-{
-  FrameInfo()
-  : x( 0 ),
-    y( 0 ),
-    w( 0 ),
-    h( 0 ),
-    delay( 0 ),
-    transparent( -1 ),
-    dispose( DISPOSE_BACKGROUND ),
-    interlace( 0 )
-  {
-  }
-
-  int x, y, w, h;
-  unsigned short delay; // delay time in 1/100ths of a sec
-  short transparent : 10; // -1 == not, anything else == index
-  short dispose : 6; // 0, 1, 2, 3 (others invalid)
-  short interlace : 1; // interlaced or not
-};
-
-struct ImageFrame
-{
-  ImageFrame()
-  : index( 0 ),
-    data( nullptr ),
-    info(),
-    loaded( false )
-  {
-  }
-
-  ~ImageFrame()
-  {
-  }
-
-  int       index;
-  uint32_t  *data;     /* frame decoding data */
-  FrameInfo  info;     /* special image type info */
-  bool loaded : 1;
-};
-
-struct GifAnimationData
-{
-  GifAnimationData()
-  : frames( ),
-    frameCount( 0 ),
-    loopCount( 0 ),
-    currentFrame( 0 ),
-    animated( false )
-  {
-  }
-
-  std::vector<ImageFrame> frames;
-  int frameCount;
-  int loopCount;
-  int currentFrame;
-  bool animated;
-};
-
-struct LoaderInfo
-{
-  LoaderInfo()
-  : gif( nullptr ) ,
-    imageNumber ( 0 )
-  {
-  }
-
-  struct FileData
-  {
-    FileData()
-    : fileName( nullptr ),
-      globalMap ( nullptr ),
-      length( 0 ),
-      isLocalResource( true )
-    {
-    }
-
-    const char *fileName;  /**< The absolute path of the file. */
-    unsigned char *globalMap ;      /**< A pointer to the entire contents of the file that have been mapped with mmap(2). */
-    long long length;  /**< The length of the file in bytes. */
-    bool isLocalResource; /**< The flag whether the file is a local resource */
-  };
-
-  struct FileInfo
-  {
-    FileInfo()
-    : map( nullptr ),
-      position( 0 ),
-      length( 0 )
-    {
-    }
-
-    unsigned char *map;
-    int position, length; // yes - gif uses ints for file sizes.
-  };
-
-  FileData fileData;
-  GifAnimationData animated;
-  GifFileType *gif;
-  int imageNumber;
-  FileInfo fileInfo;
-};
-
-struct ImageProperties
-{
-  ImageProperties()
-  : w( 0 ),
-    h( 0 ),
-    alpha( 0 )
-  {
-  }
-
-  unsigned int w;
-  unsigned int h;
-  bool alpha;
-};
-
-/**
- * @brief This combines R, G, B and Alpha values into a single 32-bit (ABGR) value.
- *
- * @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.
- */
-inline int CombinePixelABGR( int a, int r, int g, int b )
-{
-  return ( ((a) << 24) + ((b) << 16) + ((g) << 8) + (r) );
-}
-
-inline int PixelLookup( ColorMapObject *colorMap, int index )
-{
-  return CombinePixelABGR( 0xFF, colorMap->Colors[index].Red, colorMap->Colors[index].Green, colorMap->Colors[index].Blue );
-}
-
-/**
- * @brief Brute force find frame index - gifs are normally small so ok for now.
- *
- * @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.
- */
-ImageFrame *FindFrame( const GifAnimationData &animated, int index )
-{
-  for( auto &&elem : animated.frames )
-  {
-    if( elem.index == index )
-    {
-      return const_cast<ImageFrame *>( &elem );
-    }
-  }
-  return nullptr;
-}
-
-/**
- * @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] 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 )
-{
-  int xAxis, yAxis;
-  uint32_t *pixelPosition;
-
-  for( yAxis = 0; yAxis < height; yAxis++ )
-  {
-    pixelPosition = data + ((y + yAxis) * row) + x;
-    for( xAxis = 0; xAxis < width; xAxis++ )
-    {
-      *pixelPosition = val;
-      pixelPosition++;
-    }
-  }
-}
-
-/**
- * @brief Fill a rgba data pixle blob with a frame color (bg or trans)
- *
- * @param[in] data A pointer pointing to an image data
- * @param[in] row A int containing the number of rows in an image
- * @param[in] gif A pointer pointing to GIF File Type
- * @param[in] frameInfo A pointer pointing to Frame Information data
- * @param[in] x X-coordinate used an offset to calculate pixel position
- * @param[in] y Y-coordinate used an offset to calculate pixel position
- * @param[in] width Width of the image
- * @param[in] height Height of the image
- */
-void FillFrame( uint32_t *data, int row, GifFileType *gif, FrameInfo *frameInfo, int x, int y, int w, int h )
-{
-  // solid color fill for pre frame region
-  if( frameInfo->transparent < 0 )
-  {
-    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;
-    // 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 );
-  }
-}
-
-/**
- * @brief Store common fields from gif file info into frame info
- *
- * @param[in] gif A pointer pointing to GIF File Type
- * @param[in] frameInfo A pointer pointing to Frame Information data
- */
-void StoreFrameInfo( GifFileType *gif, FrameInfo *frameInfo )
-{
-  frameInfo->x = gif->Image.Left;
-  frameInfo->y = gif->Image.Top;
-  frameInfo->w = gif->Image.Width;
-  frameInfo->h = gif->Image.Height;
-  frameInfo->interlace = gif->Image.Interlace;
-}
-
-/**
- * @brief Check if image fills "screen space" and if so, if it is transparent
- * at all then the image could be transparent - OR if image doesnt fill,
- * then it could be trasnparent (full coverage of screen). Some gifs will
- * be recognized as solid here for faster rendering, but not all.
- *
- * @param[out] full A boolean to show whether image is transparent or not
- * @param[in] frameInfo A pointer pointing to Frame Information data
- * @param[in] width Width of the image
- * @param[in] height Height of the image
- */
-void CheckTransparency( bool &full, FrameInfo *frameInfo, int width, int height )
-{
-  if( ( frameInfo->x == 0 ) && ( frameInfo->y == 0 ) &&
-      ( frameInfo->w == width ) && ( frameInfo->h == height ) )
-  {
-    if( frameInfo->transparent >= 0 )
-    {
-      full = false;
-    }
-  }
-  else
-  {
-    full = false;
-  }
-}
-
-/**
- * @brief Fix coords and work out an x and y inset in orig data if out of image bounds.
- */
-void ClipCoordinates( int imageWidth, int imageHeight, int *xin, int *yin, int x0, int y0, int w0, int h0, int *x, int *y, int *w, int *h )
-{
-  if( x0 < 0 )
-  {
-    w0 += x0;
-    *xin = -x0;
-    x0 = 0;
-  }
-  if( (x0 + w0) > imageWidth )
-  {
-    w0 = imageWidth - x0;
-  }
-  if( y0 < 0 )
-  {
-    h0 += y0;
-    *yin = -y0;
-    y0 = 0;
-  }
-  if( (y0 + h0) > imageHeight )
-  {
-    h0 = imageHeight - y0;
-  }
-  *x = x0;
-  *y = y0;
-  *w = w0;
-  *h = h0;
-}
-
-/**
- * @brief Flush out rgba frame images to save memory but skip current,
- * previous and lastPreservedFrame frames (needed for dispose mode DISPOSE_PREVIOUS)
- *
- * @param[in] animated A structure containing GIF animation data
- * @param[in] width Width of the image
- * @param[in] height Height of the image
- * @param[in] thisframe The current frame
- * @param[in] prevframe The previous frame
- * @param[in] lastPreservedFrame The last preserved frame
- */
-void FlushFrames( GifAnimationData &animated, int width, int height, ImageFrame *thisframe, ImageFrame *prevframe, ImageFrame *lastPreservedFrame )
-{
-  DALI_LOG_INFO( gGifLoadingLogFilter, Debug::Concise, "FlushFrames() START \n" );
-
-  // target is the amount of memory we want to be under for stored frames
-  int total = 0, target = 512 * 1024;
-
-  // total up the amount of memory used by stored frames for this image
-  for( auto &&frame : animated.frames )
-  {
-    if( frame.data )
-    {
-      total++;
-    }
-  }
-  total *= ( width * height * sizeof( uint32_t ) );
-
-  DALI_LOG_INFO( gGifLoadingLogFilter, Debug::Concise, "Total used frame size: %d\n", total );
-
-  // If we use more than target (512k) for frames - flush
-  if( total > target )
-  {
-    // Clean frames (except current and previous) until below target
-    for( auto &&frame : animated.frames )
-    {
-      if( (frame.index != thisframe->index) && (!prevframe || frame.index != prevframe->index) &&
-          (!lastPreservedFrame || frame.index != lastPreservedFrame->index) )
-      {
-        if( frame.data != nullptr )
-        {
-          delete[] frame.data;
-          frame.data = nullptr;
-
-          // subtract memory used and if below target - stop flush
-          total -= ( width * height * sizeof( uint32_t ) );
-          if( total < target )
-          {
-            break;
-          }
-        }
-      }
-    }
-  }
-
-  DALI_LOG_INFO( gGifLoadingLogFilter, Debug::Concise, "FlushFrames() END \n" );
-}
-
-/**
- * @brief allocate frame and frame info and append to list and store fields.
- *
- * @param[in] animated A structure containing GIF animation data
- * @param[in] transparent Transparent index of the new frame
- * @param[in] dispose Dispose mode of new frame
- * @param[in] delay The frame delay of new frame
- * @param[in] index The index of new frame
- */
-FrameInfo *NewFrame( GifAnimationData &animated, int transparent, int dispose, int delay, int index )
-{
-  ImageFrame frame;
-
-  // record transparent index to be used or -1 if none
-  // for this SPECIFIC frame
-  frame.info.transparent = transparent;
-  // record dispose mode (3 bits)
-  frame.info.dispose = dispose;
-  // record delay (2 bytes so max 65546 /100 sec)
-  frame.info.delay = delay;
-  // record the index number we are at
-  frame.index = index;
-  // that frame is stored AT image/screen size
-
-  animated.frames.push_back( frame );
-
-  DALI_LOG_INFO( gGifLoadingLogFilter, Debug::Concise, "NewFrame: animated.frames.size() = %d\n", animated.frames.size() );
-
-  return &( animated.frames.back().info );
-}
-
-/**
- * @brief Copy data from gif file into buffer.
- *
- * @param[in] gifFileType A pointer pointing to GIF File Type
- * @param[out] buffer A pointer to buffer containing GIF raw data
- * @param[in] len The length in bytes to be copied
- * @return The data length of the image in bytes
- */
-int FileRead( GifFileType *gifFileType, GifByteType *buffer, int length )
-{
-  LoaderInfo::FileInfo *fi = reinterpret_cast<LoaderInfo::FileInfo *>( gifFileType->UserData );
-
-  if( fi->position >= fi->length )
-  {
-    return 0; // if at or past end - no
-  }
-  if( (fi->position + length) >= fi->length )
-  {
-    length = fi->length - fi->position;
-  }
-  memcpy( buffer, fi->map + fi->position, length );
-  fi->position += length;
-  return length;
-}
-
-/**
- * @brief Decode a gif image into rows then expand to 32bit into the destination
- * data pointer.
- */
-bool DecodeImage( GifFileType *gif, uint32_t *data, int rowpix, int xin, int yin,
-                  int transparent, int x, int y, int w, int h, bool fill )
-{
-  int intoffset[] = {0, 4, 2, 1};
-  int intjump[] = {8, 8, 4, 2};
-  int i, xx, yy, pix, gifW, gifH;
-  GifRowType *rows = NULL;
-  bool ret = false;
-  ColorMapObject *colorMap;
-  uint32_t *p;
-
-  // what we need is image size.
-  SavedImage *sp;
-  sp = &gif->SavedImages[ gif->ImageCount - 1 ];
-  if( !sp )
-  {
-    goto on_error;
-  }
-
-  gifW = sp->ImageDesc.Width;
-  gifH = sp->ImageDesc.Height;
-
-  if( ( gifW < w ) || ( gifH < h ) )
-  {
-    DALI_ASSERT_DEBUG( false && "Dimensions are bigger than the Gif image size");
-    goto on_error;
-  }
-
-  // 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 )
-  {
-    goto on_error;
-  }
-
-  // fill in the pointers at the start
-  for( yy = 0; yy < gifH; yy++ )
-  {
-    rows[yy] = reinterpret_cast<unsigned char *>(rows) + (gifH * sizeof(GifRowType)) + (yy * gifW * sizeof(GifPixelType));
-  }
-
-  // if gif is interlaced, walk interlace pattern and decode into rows
-  if( gif->Image.Interlace )
-  {
-    for( i = 0; i < 4; i++ )
-    {
-      for( yy = intoffset[i]; yy < gifH; yy += intjump[i] )
-      {
-        if( DGifGetLine( gif, rows[yy], gifW ) != GIF_OK )
-        {
-          goto on_error;
-        }
-      }
-    }
-  }
-  // normal top to bottom - decode into rows
-  else
-  {
-    for( yy = 0; yy < gifH; yy++ )
-    {
-      if( DGifGetLine( gif, rows[yy], gifW ) != GIF_OK )
-      {
-        goto on_error;
-      }
-    }
-  }
-
-  // work out what colormap to use
-  if( gif->Image.ColorMap )
-  {
-    colorMap = gif->Image.ColorMap;
-  }
-  else
-  {
-    colorMap = gif->SColorMap;
-  }
-
-  // if we need to deal with transparent pixels at all...
-  if( transparent >= 0 )
-  {
-    // if we are told to FILL (overwrite with transparency kept)
-    if( fill )
-    {
-      for( yy = 0; yy < h; yy++ )
-      {
-        p = data + ((y + yy) * rowpix) + x;
-        for( xx = 0; xx < w; xx++ )
-        {
-          pix = rows[yin + yy][xin + xx];
-          if( pix != transparent )
-          {
-            *p = PixelLookup( colorMap, pix );
-          }
-          else
-          {
-            *p = 0;
-          }
-          p++;
-        }
-      }
-    }
-    // paste on top with transparent pixels untouched
-    else
-    {
-      for( yy = 0; yy < h; yy++ )
-      {
-        p = data + ((y + yy) * rowpix) + x;
-        for( xx = 0; xx < w; xx++ )
-        {
-          pix = rows[yin + yy][xin + xx];
-          if( pix != transparent )
-          {
-            *p = PixelLookup( colorMap, pix );
-          }
-          p++;
-        }
-      }
-    }
-  }
-  else
-  {
-    // walk pixels without worring about transparency at all
-    for( yy = 0; yy < h; yy++ )
-    {
-      p = data + ((y + yy) * rowpix) + x;
-      for( xx = 0; xx < w; xx++ )
-      {
-        pix = rows[yin + yy][xin + xx];
-        *p = PixelLookup( colorMap, pix );
-        p++;
-      }
-    }
-  }
-  ret = true;
-
-on_error:
-  if( rows )
-  {
-    free( rows );
-  }
-  return ret;
-}
-
-/**
- * @brief Reader header from the gif file and populates structures accordingly.
- *
- * @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 )
-{
-  GifAnimationData &animated = loaderInfo.animated;
-  LoaderInfo::FileData &fileData = loaderInfo.fileData;
-  bool ret = false;
-  LoaderInfo::FileInfo fileInfo;
-  GifRecordType rec;
-  GifFileType *gif = NULL;
-  // it is possible which gif file have error midle of frames,
-  // in that case we should play gif file until meet error frame.
-  int imageNumber = 0;
-  int loopCount = -1;
-  FrameInfo *frameInfo = NULL;
-  bool full = true;
-
-  if( fileData.isLocalResource )
-  {
-    Internal::Platform::FileReader fileReader( fileData.fileName );
-    FILE *fp = fileReader.GetFile();
-    if( fp == NULL )
-    {
-      return false;
-    }
-
-    if( fseek( fp, 0, SEEK_END ) <= -1 )
-    {
-      return false;
-    }
-
-    fileData.length = ftell( fp );
-    if( fileData.length <= -1 )
-    {
-      return false;
-    }
-
-    if( ( ! fseek( fp, 0, SEEK_SET ) ) )
-    {
-      fileData.globalMap = reinterpret_cast<GifByteType*>( malloc(sizeof( GifByteType ) * fileData.length ) );
-      fileData.length = fread( fileData.globalMap, sizeof( GifByteType ), fileData.length, fp);
-      fileInfo.map = fileData.globalMap;
-    }
-    else
-    {
-      return false;
-    }
-  }
-  else
-  {
-    // remote file
-    bool succeeded;
-    Dali::Vector<uint8_t> dataBuffer;
-    size_t dataSize;
-
-    succeeded = TizenPlatform::Network::DownloadRemoteFileIntoMemory( fileData.fileName, dataBuffer, dataSize,
-                                                                      MAXIMUM_DOWNLOAD_IMAGE_SIZE );
-    if( succeeded )
-    {
-      size_t blobSize = dataBuffer.Size();
-      if( 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( ( ! fseek( fp, 0, SEEK_SET ) ) )
-          {
-            fileData.globalMap = reinterpret_cast<GifByteType*>( malloc(sizeof( GifByteType ) * blobSize ) );
-            fileData.length = fread( fileData.globalMap, sizeof( GifByteType ), blobSize, fp);
-            fileInfo.map = fileData.globalMap;
-          }
-          else
-          {
-            DALI_LOG_ERROR( "Error seeking within file\n" );
-          }
-        }
-        else
-        {
-          DALI_LOG_ERROR( "Error reading file\n" );
-        }
-      }
-    }
-  }
-
-  if( !fileInfo.map )
-  {
-    LOADERR("LOAD_ERROR_CORRUPT_FILE");
-  }
-  fileInfo.length = fileData.length;
-  fileInfo.position = 0;
-
-// actually ask libgif to open the file
-#if GIFLIB_MAJOR >= 5
-  gif = DGifOpen( &fileInfo, FileRead, NULL );
-#else
-  gif = DGifOpen( &fileInfo, FileRead );
-#endif
-
-  if (!gif)
-  {
-    LOADERR("LOAD_ERROR_UNKNOWN_FORMAT");
-  }
-
-  // get the gif "screen size" (the actual image size)
-  prop.w = gif->SWidth;
-  prop.h = 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( IMG_TOO_BIG(prop.w, prop.h) )
-    {
-      LOADERR("LOAD_ERROR_RESOURCE_ALLOCATION_FAILED");
-    }
-    LOADERR("LOAD_ERROR_GENERIC");
-  }
-  // walk through gif records in file to figure out info
-  do
-  {
-    if( DGifGetRecordType(gif, &rec) == GIF_ERROR )
-    {
-      // if we have a gif that ends part way through a sequence
-      // (or animation) consider it valid and just break - no error
-      if( imageNumber > 1 )
-      {
-        break;
-      }
-      LOADERR("LOAD_ERROR_UNKNOWN_FORMAT");
-    }
-
-    // get image description section
-    if( rec == IMAGE_DESC_RECORD_TYPE )
-    {
-      int img_code;
-      GifByteType *img;
-
-      // get image desc
-      if( DGifGetImageDesc(gif) == GIF_ERROR )
-      {
-        LOADERR("LOAD_ERROR_UNKNOWN_FORMAT");
-      }
-      // skip decoding and just walk image to next
-      if( DGifGetCode(gif, &img_code, &img) == GIF_ERROR )
-      {
-        LOADERR("LOAD_ERROR_UNKNOWN_FORMAT");
-      }
-      // skip till next...
-      while( img )
-      {
-        img = NULL;
-        DGifGetCodeNext( gif, &img );
-      }
-      // store geometry in the last frame info data
-      if( frameInfo )
-      {
-        StoreFrameInfo( gif, frameInfo );
-        CheckTransparency( full, frameInfo, prop.w, prop.h );
-      }
-      // or if we dont have a frameInfo entry - create one even for stills
-      else
-      {
-        // allocate and save frame with field data
-        frameInfo = NewFrame( animated, -1, 0, 0, imageNumber + 1 );
-        if (!frameInfo)
-        {
-          LOADERR("LOAD_ERROR_RESOURCE_ALLOCATION_FAILED");
-        }
-        // store geometry info from gif image
-        StoreFrameInfo( gif, frameInfo );
-        // check for transparency/alpha
-        CheckTransparency( full, frameInfo, prop.w, prop.h );
-      }
-      imageNumber++;
-    }
-    // we have an extension code block - for animated gifs for sure
-    else if( rec == EXTENSION_RECORD_TYPE )
-    {
-      int ext_code;
-      GifByteType *ext;
-
-      ext = NULL;
-      // get the first extension entry
-      DGifGetExtension( gif, &ext_code, &ext );
-      while( ext )
-      {
-        // graphic control extension - for animated gif data
-        // and transparent index + flag
-        if( ext_code == 0xf9 )
-        {
-          // create frame and store it in image
-          int transparencyIndex = (ext[1] & 1) ? ext[4] : -1;
-          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 )
-          {
-            LOADERR("LOAD_ERROR_RESOURCE_ALLOCATION_FAILED");
-          }
-        }
-        // netscape extension indicating loop count.
-        else if( ext_code == 0xff ) /* application extension */
-        {
-          if( !strncmp(reinterpret_cast<char *>(&ext[1]), "NETSCAPE2.0", 11) ||
-              !strncmp(reinterpret_cast<char *>(&ext[1]), "ANIMEXTS1.0", 11) )
-          {
-            ext = NULL;
-            DGifGetExtensionNext( gif, &ext );
-            if( ext[1] == 0x01 )
-            {
-              loopCount = (int(ext[3]) << 8) | int(ext[2]);
-              if( loopCount > 0 )
-              {
-                loopCount++;
-              }
-            }
-          }
-        }
-        // and continue onto the next extension entry
-        ext = NULL;
-        DGifGetExtensionNext( gif, &ext );
-      }
-    }
-  } while( rec != TERMINATE_RECORD_TYPE );
-
-  // if the gif main says we have more than one image or our image counting
-  // says so, then this image is animated - indicate this
-  if( (gif->ImageCount > 1) || (imageNumber > 1) )
-  {
-    animated.animated = 1;
-    animated.loopCount = loopCount;
-  }
-  animated.frameCount = std::min( gif->ImageCount, imageNumber );
-
-  if( !full )
-  {
-    prop.alpha = 1;
-  }
-
-  animated.currentFrame = 1;
-
-  // no errors in header scan etc. so set err and return value
-  *error = 0;
-  ret = true;
-
-on_error: // jump here on any errors to clean up
-#if (GIFLIB_MAJOR > 5) || ((GIFLIB_MAJOR == 5) && (GIFLIB_MINOR >= 1))
-  if( gif )
-  {
-    DGifCloseFile( gif, NULL );
-  }
-#else
-  if( gif )
-  {
-    DGifCloseFile( gif );
-  }
-#endif
-
-  return ret;
-}
-
-/**
- * @brief Reader next frame of the gif file and populates structures accordingly.
- *
- * @param[in] loaderInfo A LoaderInfo structure containing file descriptor and other data about GIF.
- * @param[in/out] prop A ImageProperties structure containing information about gif data.
- * @param[out] pixels A pointer to buffer which will contain all pixel data of the frame on return.
- * @param[out] error Error code
- * @return The true or false whether reading was successful or not.
- */
-bool ReadNextFrame( LoaderInfo &loaderInfo, ImageProperties &prop, //  use for w and h
-                    unsigned char *pixels, int *error )
-{
-  GifAnimationData &animated = loaderInfo.animated;
-  LoaderInfo::FileData &fileData = loaderInfo.fileData;
-  bool ret = false;
-  GifRecordType rec;
-  GifFileType *gif = NULL;
-  int index = 0, imageNumber = 0;
-  FrameInfo *frameInfo;
-  ImageFrame *frame = NULL;
-  ImageFrame *lastPreservedFrame = NULL;
-
-  index = animated.currentFrame;
-
-  // if index is invalid for animated image - error out
-  if ((animated.animated) && ((index <= 0) || (index > animated.frameCount)))
-  {
-    LOADERR("LOAD_ERROR_GENERIC");
-  }
-
-  // find the given frame index
-  frame = FindFrame( animated, index );
-  if( frame )
-  {
-    if( (frame->loaded) && (frame->data) )
-    {
-      // frame is already there and decoded - jump to end
-      goto on_ok;
-    }
-  }
-  else
-  {
-    LOADERR("LOAD_ERROR_CORRUPT_FILE");
-  }
-
-open_file:
-  // actually ask libgif to open the file
-  gif = loaderInfo.gif;
-  if( !gif )
-  {
-    loaderInfo.fileInfo.map = fileData.globalMap ;
-    if( !loaderInfo.fileInfo.map )
-    {
-      LOADERR("LOAD_ERROR_CORRUPT_FILE");
-    }
-    loaderInfo.fileInfo.length = fileData.length;
-    loaderInfo.fileInfo.position = 0;
-
-#if GIFLIB_MAJOR >= 5
-    gif = DGifOpen( &( loaderInfo.fileInfo ), FileRead, NULL );
-#else
-    gif = DGifOpen( &( loaderInfo.fileInfo ), FileRead );
-#endif
-    // if gif open failed... get out of here
-    if( !gif )
-    {
-      LOADERR("LOAD_ERROR_UNKNOWN_FORMAT");
-    }
-    loaderInfo.gif = gif;
-    loaderInfo.imageNumber = 1;
-  }
-
-  // if we want to go backwards, we likely need/want to re-decode from the
-  // start as we have nothing to build on
-  if( (index > 0) && (index < loaderInfo.imageNumber) && (animated.animated) )
-  {
-#if (GIFLIB_MAJOR > 5) || ((GIFLIB_MAJOR == 5) && (GIFLIB_MINOR >= 1))
-    if( loaderInfo.gif )
-      DGifCloseFile( loaderInfo.gif, NULL );
-#else
-    if( loaderInfo.gif )
-      DGifCloseFile( loaderInfo.gif );
-#endif
-    loaderInfo.gif = NULL;
-    loaderInfo.imageNumber = 0;
-    goto open_file;
-  }
-
-  // our current position is the previous frame we decoded from the file
-  imageNumber = loaderInfo.imageNumber;
-
-  // walk through gif records in file to figure out info
-  do
-  {
-    if( DGifGetRecordType( gif, &rec ) == GIF_ERROR )
-    {
-      LOADERR("LOAD_ERROR_UNKNOWN_FORMAT");
-    }
-
-    if( rec == EXTENSION_RECORD_TYPE )
-    {
-      int ext_code;
-      GifByteType *ext = NULL;
-      DGifGetExtension( gif, &ext_code, &ext );
-
-      while( ext )
-      {
-        ext = NULL;
-        DGifGetExtensionNext( gif, &ext );
-      }
-    }
-    // get image description section
-    else if( rec == IMAGE_DESC_RECORD_TYPE )
-    {
-      int xin = 0, yin = 0, x = 0, y = 0, w = 0, h = 0;
-      int img_code;
-      GifByteType *img;
-      ImageFrame *previousFrame = NULL;
-      ImageFrame *thisFrame = NULL;
-
-      // get image desc
-      if( DGifGetImageDesc(gif) == GIF_ERROR )
-      {
-        LOADERR("LOAD_ERROR_UNKNOWN_FORMAT");
-      }
-
-      // get the previous frame entry AND the current one to fill in
-      previousFrame = FindFrame(animated, imageNumber - 1);
-      thisFrame = FindFrame(animated, imageNumber);
-
-      // if we have a frame AND we're animated AND we have no data...
-      if( (thisFrame) && (!thisFrame->data) && (animated.animated) )
-      {
-        bool first = false;
-
-        // allocate it
-        thisFrame->data = new uint32_t[prop.w * prop.h];
-
-        if( !thisFrame->data )
-        {
-          LOADERR("LOAD_ERROR_RESOURCE_ALLOCATION_FAILED");
-        }
-
-        // 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) );
-        }
-        // we have a prior frame to copy data from...
-        else
-        {
-          frameInfo = &( previousFrame->info );
-
-          // fix coords of sub image in case it goes out...
-          ClipCoordinates( prop.w, prop.h, &xin, &yin,
-                           frameInfo->x, frameInfo->y, frameInfo->w, frameInfo->h,
-                           &x, &y, &w, &h );
-
-          // if dispose mode is not restore - then copy pre frame
-          if( frameInfo->dispose != DISPOSE_PREVIOUS )
-          {
-            memcpy( thisFrame->data, previousFrame->data, prop.w * prop.h * sizeof(uint32_t) );
-          }
-
-          // if dispose mode is "background" then fill with bg
-          if( frameInfo->dispose == DISPOSE_BACKGROUND )
-          {
-            FillFrame( thisFrame->data, prop.w, gif, frameInfo, x, y, w, h );
-          }
-          else if( frameInfo->dispose == DISPOSE_PREVIOUS ) // GIF_DISPOSE_RESTORE
-          {
-            int prevIndex = 2;
-            do
-            {
-              // Find last preserved frame.
-              lastPreservedFrame = FindFrame( animated, imageNumber - prevIndex );
-              if( ! lastPreservedFrame )
-              {
-                LOADERR( "LOAD_ERROR_LAST_PRESERVED_FRAME_NOT_FOUND" );
-              }
-              prevIndex++;
-            } while( lastPreservedFrame && lastPreservedFrame->info.dispose == DISPOSE_PREVIOUS );
-
-            if ( lastPreservedFrame )
-            {
-              memcpy( thisFrame->data, lastPreservedFrame->data, prop.w * prop.h * sizeof(uint32_t) );
-            }
-          }
-        }
-        // 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( gif, thisFrame->data, prop.w,
-                          xin, yin, frameInfo->transparent,
-                          x, y, w, h, first) )
-        {
-          LOADERR("LOAD_ERROR_CORRUPT_FILE");
-        }
-
-        // mark as loaded and done
-        thisFrame->loaded = true;
-
-        FlushFrames( animated, prop.w, prop.h, thisFrame, previousFrame, lastPreservedFrame );
-      }
-      // if we have a frame BUT the image is not animated. different
-      // path
-      else if( (thisFrame) && (!thisFrame->data) && (!animated.animated) )
-      {
-        // if we don't have the data decoded yet - decode it
-        if( (!thisFrame->loaded) || (!thisFrame->data) )
-        {
-          // use frame info but we WONT allocate frame pixels
-          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, gif, frameInfo, 0, 0, prop.w, prop.h );
-
-          // and decode the gif with overwriting
-          if( !DecodeImage( gif, reinterpret_cast<uint32_t *>(pixels), prop.w,
-                            xin, yin, frameInfo->transparent, x, y, w, h, true) )
-          {
-            LOADERR("LOAD_ERROR_CORRUPT_FILE");
-          }
-
-          // mark as loaded and done
-          thisFrame->loaded = true;
-        }
-        // flush mem we don't need (at expense of decode cpu)
-      }
-      else
-      {
-        // skip decoding and just walk image to next
-        if( DGifGetCode( gif, &img_code, &img ) == GIF_ERROR )
-        {
-          LOADERR("LOAD_ERROR_UNKNOWN_FORMAT");
-        }
-
-        while( img )
-        {
-          img = NULL;
-          DGifGetCodeNext( gif, &img );
-        }
-      }
-
-      imageNumber++;
-      // if we found the image we wanted - get out of here
-      if( imageNumber > index )
-      {
-        break;
-      }
-    }
-  } while( rec != TERMINATE_RECORD_TYPE );
-
-  // if we are at the end of the animation or not animated, close file
-  loaderInfo.imageNumber = imageNumber;
-  if( (animated.frameCount <= 1) || (rec == TERMINATE_RECORD_TYPE) )
-  {
-#if (GIFLIB_MAJOR > 5) || ((GIFLIB_MAJOR == 5) && (GIFLIB_MINOR >= 1))
-    if( loaderInfo.gif )
-    {
-      DGifCloseFile( loaderInfo.gif, NULL );
-    }
-#else
-    if( loaderInfo.gif )
-    {
-      DGifCloseFile( loaderInfo.gif );
-    }
-#endif
-
-    loaderInfo.gif = NULL;
-    loaderInfo.imageNumber = 0;
-  }
-
-on_ok:
-  // no errors in header scan etc. so set err and return value
-  *error = 0;
-  ret = true;
-
-  // if it was an animated image we need to copy the data to the
-  // pixels for the image from the frame holding the data
-  if( animated.animated && frame->data )
-  {
-    memcpy( pixels, frame->data, prop.w * prop.h * sizeof( uint32_t ) );
-  }
-
-on_error: // jump here on any errors to clean up
-  return ret;
-}
-
-} // unnamed namespace
-
-struct GifLoading::Impl
-{
-public:
-  Impl( const std::string& url, bool isLocalResource )
-  : mUrl( url )
-  {
-    loaderInfo.gif = nullptr;
-    int error;
-    loaderInfo.fileData.fileName = mUrl.c_str();
-    loaderInfo.fileData.isLocalResource = isLocalResource;
-
-    ReadHeader( loaderInfo, imageProperties, &error );
-  }
-
-  // Moveable but not copyable
-
-  Impl( const Impl& ) = delete;
-  Impl& operator=( const Impl& ) = delete;
-  Impl( Impl&& ) = default;
-  Impl& operator=( Impl&& ) = default;
-
-  ~Impl()
-  {
-    if( loaderInfo.fileData.globalMap  )
-    {
-      free( loaderInfo.fileData.globalMap );
-      loaderInfo.fileData.globalMap  = nullptr;
-    }
-
-    // Delete all image frames
-    for( auto &&frame : loaderInfo.animated.frames )
-    {
-      if( frame.data != nullptr )
-      {
-        // De-allocate memory of the frame data.
-        delete[] frame.data;
-        frame.data = nullptr;
-      }
-    }
-  }
-
-  std::string mUrl;
-  LoaderInfo loaderInfo;
-  ImageProperties imageProperties;
-};
-
-std::unique_ptr<GifLoading> GifLoading::New( const std::string &url, bool isLocalResource )
-{
-  return std::unique_ptr<GifLoading>( new GifLoading( url, isLocalResource ) );
-}
-
-GifLoading::GifLoading( const std::string &url, bool isLocalResource )
-: mImpl( new GifLoading::Impl( url, isLocalResource ) )
-{
-}
-
-
-GifLoading::~GifLoading()
-{
-  delete mImpl;
-}
-
-bool GifLoading::LoadNextNFrames( int frameStartIndex, int count, std::vector<Dali::PixelData> &pixelData )
-{
-  int error;
-  bool ret = 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;
-}
-
-bool GifLoading::LoadAllFrames( std::vector<Dali::PixelData> &pixelData, Dali::Vector<uint32_t> &frameDelays )
-{
-  if( LoadFrameDelays( frameDelays ) )
-  {
-    return LoadNextNFrames( 0, mImpl->loaderInfo.animated.frameCount, pixelData );
-  }
-  return false;
-}
-
-ImageDimensions GifLoading::GetImageSize()
-{
-  return ImageDimensions( mImpl->imageProperties.w, mImpl->imageProperties.h );
-}
-
-int GifLoading::GetImageCount()
-{
-  return mImpl->loaderInfo.animated.frameCount;
-}
-
-bool GifLoading::LoadFrameDelays( Dali::Vector<uint32_t> &frameDelays )
-{
-  frameDelays.Clear();
-
-  for( auto &&elem : mImpl->loaderInfo.animated.frames )
-  {
-    // Read frame delay time, multiply 10 to change time unit to milliseconds
-    frameDelays.PushBack( elem.info.delay * 10 );
-  }
-
-  return true;
-}
-
-} // namespace Dali
diff --git a/dali/devel-api/adaptor-framework/gif-loading.h b/dali/devel-api/adaptor-framework/gif-loading.h
deleted file mode 100755 (executable)
index 6143f15..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-#ifndef DALI_INTERNAL_GIF_LOADING_H
-#define DALI_INTERNAL_GIF_LOADING_H
-
-/*
- * 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-// EXTERNAL INCLUDES
-#include <cstdint>
-#include <memory>
-#include <dali/public-api/math/rect.h>
-#include <dali/public-api/common/dali-vector.h>
-#include <dali/public-api/common/vector-wrapper.h>
-#include <dali/public-api/math/uint-16-pair.h>
-
-// INTERNAL INCLUDES
-#include <dali/public-api/dali-adaptor-common.h>
-
-namespace Dali
-{
-class PixelData;
-typedef Dali::Uint16Pair ImageDimensions;
-
-/**
- * Class to manage loading frames of an animated gif in small chunks. Lazy initializes only when
- * data is actually needed.
- * Note, once the GIF has loaded, the undecoded data will reside in memory until this object
- * is released. (This is to speed up frame loads, which would otherwise have to re-acquire the
- * data from disk)
- */
-class DALI_ADAPTOR_API GifLoading
-{
-public:
-
-  /**
-   * Create a GifLoading with the given url and resourceType.
-   * @param[in] url The url of the gif image to load
-   * @param[in] isLocalResource The true or false whether this is a local resource.
-   * @return A newly created GifLoading.
-   */
-  static std::unique_ptr<GifLoading> New( const std::string& url, bool isLocalResource );
-
-  /**
-   * @brief Constructor
-   *
-   * Construct a Loader with the given URL
-   * @param[in] url The url of the gif image to load
-   * @param[in] isLocalResource The true or false whether this is a local resource.
-   */
-  GifLoading( const std::string& url, bool isLocalResource );
-
-  // Moveable but not copyable
-
-  GifLoading( const GifLoading& ) = delete;
-  GifLoading& operator=( const GifLoading& ) = delete;
-  GifLoading( GifLoading&& ) = default;
-  GifLoading& operator=( GifLoading&& ) = default;
-
-  /**
-   * @brief Destructor
-   */
-  ~GifLoading();
-
-  /**
-   * @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( int frameStartIndex, int count, std::vector<Dali::PixelData>& pixelData );
-
-  /**
-   * @brief Load all frames of an animated gif file.
-   *
-   * @note This function will load the entire gif into memory if not already loaded.
-   *
-   * @param[out] pixelData The loaded pixel data for each frame.
-   * @param[out] frameDelays The loaded delay time for each frame.
-   *
-   * @return True if the loading succeeded, false otherwise.
-   */
-  bool LoadAllFrames( std::vector<Dali::PixelData>& pixelData, Dali::Vector<uint32_t>& frameDelays );
-
-  /**
-   * @brief Get the size of a gif image.
-   *
-   * @note This function will load the entire gif into memory if not already loaded.
-   *
-   * @return The width and height in pixels of the gif image.
-   */
-  ImageDimensions GetImageSize();
-
-  /**
-   * @brief Get the number of frames in this gif.
-   *
-   * @note This function will load the entire gif into memory if not already loaded.
-   */
-  int GetImageCount();
-
-  /**
-   * @brief Load the frame delay counts into the provided array.
-   *
-   * @note This function will load the entire gif into memory if not already loaded.
-   * @param[in] frameDelays a vector to write the frame delays into
-   * @return true if the frame delays were successfully loaded
-   */
-  bool LoadFrameDelays( Dali::Vector<uint32_t>& frameDelays );
-
-private:
-  struct Impl;
-  Impl* mImpl;
-};
-
-} // namespace Dali
-
-#endif // DALI_INTERNAL_GIF_LOADING_H
index b7e8f1ff2a1e0b827455c4b39b1c3754ec27fef8..789939d6a4a2228483841e307d6fb4890808e64e 100755 (executable)
@@ -2,6 +2,7 @@
 
 SET( devel_api_src_files
   ${adaptor_devel_api_dir}/adaptor-framework/accessibility-adaptor.cpp
+  ${adaptor_devel_api_dir}/adaptor-framework/animated-image-loading.cpp
   ${adaptor_devel_api_dir}/adaptor-framework/application-devel.cpp
   ${adaptor_devel_api_dir}/adaptor-framework/bitmap-saver.cpp
   ${adaptor_devel_api_dir}/adaptor-framework/clipboard.cpp
@@ -14,7 +15,6 @@ SET( devel_api_src_files
   ${adaptor_devel_api_dir}/adaptor-framework/file-loader.cpp
   ${adaptor_devel_api_dir}/adaptor-framework/file-stream.cpp
   ${adaptor_devel_api_dir}/adaptor-framework/image-loading.cpp
-  ${adaptor_devel_api_dir}/adaptor-framework/gif-loading.cpp
   ${adaptor_devel_api_dir}/adaptor-framework/input-method-context.cpp
   ${adaptor_devel_api_dir}/adaptor-framework/input-method-options.cpp
   ${adaptor_devel_api_dir}/adaptor-framework/native-image-source-devel.cpp
@@ -42,6 +42,7 @@ SET( devel_api_adaptor_framework_header_files
   ${adaptor_devel_api_dir}/adaptor-framework/accessibility-action-handler.h
   ${adaptor_devel_api_dir}/adaptor-framework/accessibility-gesture-handler.h
   ${adaptor_devel_api_dir}/adaptor-framework/accessibility-gesture-event.h
+  ${adaptor_devel_api_dir}/adaptor-framework/animated-image-loading.h
   ${adaptor_devel_api_dir}/adaptor-framework/application-devel.h
   ${adaptor_devel_api_dir}/adaptor-framework/atspi-accessibility.h
   ${adaptor_devel_api_dir}/adaptor-framework/bitmap-saver.h
@@ -59,7 +60,6 @@ SET( devel_api_adaptor_framework_header_files
   ${adaptor_devel_api_dir}/adaptor-framework/image-loader-input.h
   ${adaptor_devel_api_dir}/adaptor-framework/image-loader-plugin.h
   ${adaptor_devel_api_dir}/adaptor-framework/image-loading.h
-  ${adaptor_devel_api_dir}/adaptor-framework/gif-loading.h
   ${adaptor_devel_api_dir}/adaptor-framework/input-method-context.h
   ${adaptor_devel_api_dir}/adaptor-framework/input-method-options.h
   ${adaptor_devel_api_dir}/adaptor-framework/keyboard.h
diff --git a/dali/internal/imaging/common/animated-image-loading-impl.h b/dali/internal/imaging/common/animated-image-loading-impl.h
new file mode 100644 (file)
index 0000000..759eb09
--- /dev/null
@@ -0,0 +1,118 @@
+#ifndef DALI_INTERNAL_ANIMATED_IMAGE_LOADING_IMPL_H
+#define DALI_INTERNAL_ANIMATED_IMAGE_LOADING_IMPL_H
+
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/math/uint-16-pair.h>
+#include <dali/public-api/common/intrusive-ptr.h>
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+#include <dali/devel-api/adaptor-framework/animated-image-loading.h>
+
+namespace Dali
+{
+class PixelData;
+typedef Dali::Uint16Pair ImageDimensions;
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class AnimatedImageLoading;
+typedef IntrusivePtr<AnimatedImageLoading> AnimatedImageLoadingPtr;
+
+/**
+ * Class interface for animated image loading.
+ * Each loading classes for animated image file format(e.g., gif and webp) needs to inherit this interface
+ */
+class AnimatedImageLoading : public BaseObject
+{
+public:
+
+  /**
+   * @copydoc Dali::AnimatedImageLoading::New()
+   */
+  static AnimatedImageLoadingPtr New( const std::string& url, bool isLocalResource );
+
+  AnimatedImageLoading() = default;
+
+  // Moveable but not copyable
+  AnimatedImageLoading( const AnimatedImageLoading& );
+  AnimatedImageLoading& operator=( const AnimatedImageLoading& );
+  AnimatedImageLoading( AnimatedImageLoading&& ) = default;
+  AnimatedImageLoading& operator=( AnimatedImageLoading&& ) = default;
+
+  /**
+   * @brief Destructor
+   */
+  virtual ~AnimatedImageLoading() = default;
+
+  /**
+   * @copydoc Dali::AnimatedImageLoading::LoadNextNFrames()
+   */
+  virtual bool LoadNextNFrames( uint32_t frameStartIndex, int count, std::vector<Dali::PixelData>& pixelData ) = 0;
+
+  /**
+   * @copydoc Dali::AnimatedImageLoading::GetImageSize()
+   */
+  virtual ImageDimensions GetImageSize() const = 0;
+
+  /**
+   * @copydoc Dali::AnimatedImageLoading::GetImageCount()
+   */
+  virtual uint32_t GetImageCount() const = 0;
+
+  /**
+   * @copydoc Dali::AnimatedImageLoading::LoadFrameDelays()
+   */
+  virtual uint32_t GetFrameInterval( uint32_t frameIndex ) const = 0;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+// Helpers for api forwarding methods
+
+inline Internal::Adaptor::AnimatedImageLoading& GetImplementation( Dali::AnimatedImageLoading& handle)
+{
+  DALI_ASSERT_ALWAYS( handle && "AnimatedImageLoading handle is empty" );
+
+  BaseObject& object = handle.GetBaseObject();
+
+  return static_cast< Internal::Adaptor::AnimatedImageLoading& >( object );
+}
+
+inline const Internal::Adaptor::AnimatedImageLoading& GetImplementation( const Dali::AnimatedImageLoading& handle )
+{
+  DALI_ASSERT_ALWAYS( handle && "AnimatedImageLoading handle is empty" );
+
+  const BaseObject& object = handle.GetBaseObject();
+
+  return static_cast< const Internal::Adaptor::AnimatedImageLoading& >( object );
+}
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_ANIMATED_IMAGE_LOADING_IMPL_H
diff --git a/dali/internal/imaging/common/gif-loading.cpp b/dali/internal/imaging/common/gif-loading.cpp
new file mode 100644 (file)
index 0000000..187d91c
--- /dev/null
@@ -0,0 +1,1306 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Copyright notice for the EFL:
+ * Copyright (C) EFL developers (see AUTHORS)
+ */
+
+// CLASS HEADER
+#include <dali/internal/imaging/common/gif-loading.h>
+
+// EXTERNAL INCLUDES
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <gif_lib.h>
+#include <cstring>
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/images/pixel-data.h>
+#include <dali/internal/imaging/common/file-download.h>
+#include <dali/internal/system/common/file-reader.h>
+
+#define IMG_TOO_BIG( w, h )                                                        \
+  ( ( static_cast<unsigned long long>(w) * static_cast<unsigned long long>(h) ) >= \
+    ( (1ULL << (29 * (sizeof(void *) / 4))) - 2048) )
+
+#define LOADERR( x )                              \
+  do {                                            \
+    DALI_LOG_ERROR( x );                          \
+    goto on_error;                                \
+  } while ( 0 )
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Debug::Filter *gGifLoadingLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_GIF_LOADING" );
+#endif
+
+const int IMG_MAX_SIZE = 65000;
+constexpr size_t MAXIMUM_DOWNLOAD_IMAGE_SIZE  = 50 * 1024 * 1024;
+
+#if GIFLIB_MAJOR < 5
+const int DISPOSE_BACKGROUND = 2;       /* Set area too background color */
+const int DISPOSE_PREVIOUS = 3;         /* Restore to previous content */
+#endif
+
+struct FrameInfo
+{
+  FrameInfo()
+  : x( 0 ),
+    y( 0 ),
+    w( 0 ),
+    h( 0 ),
+    delay( 0 ),
+    transparent( -1 ),
+    dispose( DISPOSE_BACKGROUND ),
+    interlace( 0 )
+  {
+  }
+
+  int x, y, w, h;
+  unsigned short delay; // delay time in 1/100ths of a sec
+  short transparent : 10; // -1 == not, anything else == index
+  short dispose : 6; // 0, 1, 2, 3 (others invalid)
+  short interlace : 1; // interlaced or not
+};
+
+struct ImageFrame
+{
+  ImageFrame()
+  : index( 0 ),
+    data( nullptr ),
+    info(),
+    loaded( false )
+  {
+  }
+
+  ~ImageFrame()
+  {
+  }
+
+  int       index;
+  uint32_t  *data;     /* frame decoding data */
+  FrameInfo  info;     /* special image type info */
+  bool loaded : 1;
+};
+
+struct GifAnimationData
+{
+  GifAnimationData()
+  : frames( ),
+    frameCount( 0 ),
+    loopCount( 0 ),
+    currentFrame( 0 ),
+    animated( false )
+  {
+  }
+
+  std::vector<ImageFrame> frames;
+  int frameCount;
+  int loopCount;
+  int currentFrame;
+  bool animated;
+};
+
+struct LoaderInfo
+{
+  LoaderInfo()
+  : gif( nullptr ) ,
+    imageNumber ( 0 )
+  {
+  }
+
+  struct FileData
+  {
+    FileData()
+    : fileName( nullptr ),
+      globalMap ( nullptr ),
+      length( 0 ),
+      isLocalResource( true )
+    {
+    }
+
+    const char *fileName;  /**< The absolute path of the file. */
+    unsigned char *globalMap ;      /**< A pointer to the entire contents of the file that have been mapped with mmap(2). */
+    long long length;  /**< The length of the file in bytes. */
+    bool isLocalResource; /**< The flag whether the file is a local resource */
+  };
+
+  struct FileInfo
+  {
+    FileInfo()
+    : map( nullptr ),
+      position( 0 ),
+      length( 0 )
+    {
+    }
+
+    unsigned char *map;
+    int position, length; // yes - gif uses ints for file sizes.
+  };
+
+  FileData fileData;
+  GifAnimationData animated;
+  GifFileType *gif;
+  int imageNumber;
+  FileInfo fileInfo;
+};
+
+struct ImageProperties
+{
+  ImageProperties()
+  : w( 0 ),
+    h( 0 ),
+    alpha( 0 )
+  {
+  }
+
+  unsigned int w;
+  unsigned int h;
+  bool alpha;
+};
+
+/**
+ * @brief This combines R, G, B and Alpha values into a single 32-bit (ABGR) value.
+ *
+ * @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.
+ */
+inline int CombinePixelABGR( int a, int r, int g, int b )
+{
+  return ( ((a) << 24) + ((b) << 16) + ((g) << 8) + (r) );
+}
+
+inline int PixelLookup( ColorMapObject *colorMap, int index )
+{
+  return CombinePixelABGR( 0xFF, colorMap->Colors[index].Red, colorMap->Colors[index].Green, colorMap->Colors[index].Blue );
+}
+
+/**
+ * @brief Brute force find frame index - gifs are normally small so ok for now.
+ *
+ * @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.
+ */
+ImageFrame *FindFrame( const GifAnimationData &animated, int index )
+{
+  for( auto &&elem : animated.frames )
+  {
+    if( elem.index == index )
+    {
+      return const_cast<ImageFrame *>( &elem );
+    }
+  }
+  return nullptr;
+}
+
+/**
+ * @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] 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 )
+{
+  int xAxis, yAxis;
+  uint32_t *pixelPosition;
+
+  for( yAxis = 0; yAxis < height; yAxis++ )
+  {
+    pixelPosition = data + ((y + yAxis) * row) + x;
+    for( xAxis = 0; xAxis < width; xAxis++ )
+    {
+      *pixelPosition = val;
+      pixelPosition++;
+    }
+  }
+}
+
+/**
+ * @brief Fill a rgba data pixle blob with a frame color (bg or trans)
+ *
+ * @param[in] data A pointer pointing to an image data
+ * @param[in] row A int containing the number of rows in an image
+ * @param[in] gif A pointer pointing to GIF File Type
+ * @param[in] frameInfo A pointer pointing to Frame Information data
+ * @param[in] x X-coordinate used an offset to calculate pixel position
+ * @param[in] y Y-coordinate used an offset to calculate pixel position
+ * @param[in] width Width of the image
+ * @param[in] height Height of the image
+ */
+void FillFrame( uint32_t *data, int row, GifFileType *gif, FrameInfo *frameInfo, int x, int y, int w, int h )
+{
+  // solid color fill for pre frame region
+  if( frameInfo->transparent < 0 )
+  {
+    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;
+    // 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 );
+  }
+}
+
+/**
+ * @brief Store common fields from gif file info into frame info
+ *
+ * @param[in] gif A pointer pointing to GIF File Type
+ * @param[in] frameInfo A pointer pointing to Frame Information data
+ */
+void StoreFrameInfo( GifFileType *gif, FrameInfo *frameInfo )
+{
+  frameInfo->x = gif->Image.Left;
+  frameInfo->y = gif->Image.Top;
+  frameInfo->w = gif->Image.Width;
+  frameInfo->h = gif->Image.Height;
+  frameInfo->interlace = gif->Image.Interlace;
+}
+
+/**
+ * @brief Check if image fills "screen space" and if so, if it is transparent
+ * at all then the image could be transparent - OR if image doesnt fill,
+ * then it could be trasnparent (full coverage of screen). Some gifs will
+ * be recognized as solid here for faster rendering, but not all.
+ *
+ * @param[out] full A boolean to show whether image is transparent or not
+ * @param[in] frameInfo A pointer pointing to Frame Information data
+ * @param[in] width Width of the image
+ * @param[in] height Height of the image
+ */
+void CheckTransparency( bool &full, FrameInfo *frameInfo, int width, int height )
+{
+  if( ( frameInfo->x == 0 ) && ( frameInfo->y == 0 ) &&
+      ( frameInfo->w == width ) && ( frameInfo->h == height ) )
+  {
+    if( frameInfo->transparent >= 0 )
+    {
+      full = false;
+    }
+  }
+  else
+  {
+    full = false;
+  }
+}
+
+/**
+ * @brief Fix coords and work out an x and y inset in orig data if out of image bounds.
+ */
+void ClipCoordinates( int imageWidth, int imageHeight, int *xin, int *yin, int x0, int y0, int w0, int h0, int *x, int *y, int *w, int *h )
+{
+  if( x0 < 0 )
+  {
+    w0 += x0;
+    *xin = -x0;
+    x0 = 0;
+  }
+  if( (x0 + w0) > imageWidth )
+  {
+    w0 = imageWidth - x0;
+  }
+  if( y0 < 0 )
+  {
+    h0 += y0;
+    *yin = -y0;
+    y0 = 0;
+  }
+  if( (y0 + h0) > imageHeight )
+  {
+    h0 = imageHeight - y0;
+  }
+  *x = x0;
+  *y = y0;
+  *w = w0;
+  *h = h0;
+}
+
+/**
+ * @brief Flush out rgba frame images to save memory but skip current,
+ * previous and lastPreservedFrame frames (needed for dispose mode DISPOSE_PREVIOUS)
+ *
+ * @param[in] animated A structure containing GIF animation data
+ * @param[in] width Width of the image
+ * @param[in] height Height of the image
+ * @param[in] thisframe The current frame
+ * @param[in] prevframe The previous frame
+ * @param[in] lastPreservedFrame The last preserved frame
+ */
+void FlushFrames( GifAnimationData &animated, int width, int height, ImageFrame *thisframe, ImageFrame *prevframe, ImageFrame *lastPreservedFrame )
+{
+  DALI_LOG_INFO( gGifLoadingLogFilter, Debug::Concise, "FlushFrames() START \n" );
+
+  // target is the amount of memory we want to be under for stored frames
+  int total = 0, target = 512 * 1024;
+
+  // total up the amount of memory used by stored frames for this image
+  for( auto &&frame : animated.frames )
+  {
+    if( frame.data )
+    {
+      total++;
+    }
+  }
+  total *= ( width * height * sizeof( uint32_t ) );
+
+  DALI_LOG_INFO( gGifLoadingLogFilter, Debug::Concise, "Total used frame size: %d\n", total );
+
+  // If we use more than target (512k) for frames - flush
+  if( total > target )
+  {
+    // Clean frames (except current and previous) until below target
+    for( auto &&frame : animated.frames )
+    {
+      if( (frame.index != thisframe->index) && (!prevframe || frame.index != prevframe->index) &&
+          (!lastPreservedFrame || frame.index != lastPreservedFrame->index) )
+      {
+        if( frame.data != nullptr )
+        {
+          delete[] frame.data;
+          frame.data = nullptr;
+
+          // subtract memory used and if below target - stop flush
+          total -= ( width * height * sizeof( uint32_t ) );
+          if( total < target )
+          {
+            break;
+          }
+        }
+      }
+    }
+  }
+
+  DALI_LOG_INFO( gGifLoadingLogFilter, Debug::Concise, "FlushFrames() END \n" );
+}
+
+/**
+ * @brief allocate frame and frame info and append to list and store fields.
+ *
+ * @param[in] animated A structure containing GIF animation data
+ * @param[in] transparent Transparent index of the new frame
+ * @param[in] dispose Dispose mode of new frame
+ * @param[in] delay The frame delay of new frame
+ * @param[in] index The index of new frame
+ */
+FrameInfo *NewFrame( GifAnimationData &animated, int transparent, int dispose, int delay, int index )
+{
+  ImageFrame frame;
+
+  // record transparent index to be used or -1 if none
+  // for this SPECIFIC frame
+  frame.info.transparent = transparent;
+  // record dispose mode (3 bits)
+  frame.info.dispose = dispose;
+  // record delay (2 bytes so max 65546 /100 sec)
+  frame.info.delay = delay;
+  // record the index number we are at
+  frame.index = index;
+  // that frame is stored AT image/screen size
+
+  animated.frames.push_back( frame );
+
+  DALI_LOG_INFO( gGifLoadingLogFilter, Debug::Concise, "NewFrame: animated.frames.size() = %d\n", animated.frames.size() );
+
+  return &( animated.frames.back().info );
+}
+
+/**
+ * @brief Copy data from gif file into buffer.
+ *
+ * @param[in] gifFileType A pointer pointing to GIF File Type
+ * @param[out] buffer A pointer to buffer containing GIF raw data
+ * @param[in] len The length in bytes to be copied
+ * @return The data length of the image in bytes
+ */
+int FileRead( GifFileType *gifFileType, GifByteType *buffer, int length )
+{
+  LoaderInfo::FileInfo *fi = reinterpret_cast<LoaderInfo::FileInfo *>( gifFileType->UserData );
+
+  if( fi->position >= fi->length )
+  {
+    return 0; // if at or past end - no
+  }
+  if( (fi->position + length) >= fi->length )
+  {
+    length = fi->length - fi->position;
+  }
+  memcpy( buffer, fi->map + fi->position, length );
+  fi->position += length;
+  return length;
+}
+
+/**
+ * @brief Decode a gif image into rows then expand to 32bit into the destination
+ * data pointer.
+ */
+bool DecodeImage( GifFileType *gif, uint32_t *data, int rowpix, int xin, int yin,
+                  int transparent, int x, int y, int w, int h, bool fill )
+{
+  int intoffset[] = {0, 4, 2, 1};
+  int intjump[] = {8, 8, 4, 2};
+  int i, xx, yy, pix, gifW, gifH;
+  GifRowType *rows = NULL;
+  bool ret = false;
+  ColorMapObject *colorMap;
+  uint32_t *p;
+
+  // what we need is image size.
+  SavedImage *sp;
+  sp = &gif->SavedImages[ gif->ImageCount - 1 ];
+  if( !sp )
+  {
+    goto on_error;
+  }
+
+  gifW = sp->ImageDesc.Width;
+  gifH = sp->ImageDesc.Height;
+
+  if( ( gifW < w ) || ( gifH < h ) )
+  {
+    DALI_ASSERT_DEBUG( false && "Dimensions are bigger than the Gif image size");
+    goto on_error;
+  }
+
+  // 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 )
+  {
+    goto on_error;
+  }
+
+  // fill in the pointers at the start
+  for( yy = 0; yy < gifH; yy++ )
+  {
+    rows[yy] = reinterpret_cast<unsigned char *>(rows) + (gifH * sizeof(GifRowType)) + (yy * gifW * sizeof(GifPixelType));
+  }
+
+  // if gif is interlaced, walk interlace pattern and decode into rows
+  if( gif->Image.Interlace )
+  {
+    for( i = 0; i < 4; i++ )
+    {
+      for( yy = intoffset[i]; yy < gifH; yy += intjump[i] )
+      {
+        if( DGifGetLine( gif, rows[yy], gifW ) != GIF_OK )
+        {
+          goto on_error;
+        }
+      }
+    }
+  }
+  // normal top to bottom - decode into rows
+  else
+  {
+    for( yy = 0; yy < gifH; yy++ )
+    {
+      if( DGifGetLine( gif, rows[yy], gifW ) != GIF_OK )
+      {
+        goto on_error;
+      }
+    }
+  }
+
+  // work out what colormap to use
+  if( gif->Image.ColorMap )
+  {
+    colorMap = gif->Image.ColorMap;
+  }
+  else
+  {
+    colorMap = gif->SColorMap;
+  }
+
+  // if we need to deal with transparent pixels at all...
+  if( transparent >= 0 )
+  {
+    // if we are told to FILL (overwrite with transparency kept)
+    if( fill )
+    {
+      for( yy = 0; yy < h; yy++ )
+      {
+        p = data + ((y + yy) * rowpix) + x;
+        for( xx = 0; xx < w; xx++ )
+        {
+          pix = rows[yin + yy][xin + xx];
+          if( pix != transparent )
+          {
+            *p = PixelLookup( colorMap, pix );
+          }
+          else
+          {
+            *p = 0;
+          }
+          p++;
+        }
+      }
+    }
+    // paste on top with transparent pixels untouched
+    else
+    {
+      for( yy = 0; yy < h; yy++ )
+      {
+        p = data + ((y + yy) * rowpix) + x;
+        for( xx = 0; xx < w; xx++ )
+        {
+          pix = rows[yin + yy][xin + xx];
+          if( pix != transparent )
+          {
+            *p = PixelLookup( colorMap, pix );
+          }
+          p++;
+        }
+      }
+    }
+  }
+  else
+  {
+    // walk pixels without worring about transparency at all
+    for( yy = 0; yy < h; yy++ )
+    {
+      p = data + ((y + yy) * rowpix) + x;
+      for( xx = 0; xx < w; xx++ )
+      {
+        pix = rows[yin + yy][xin + xx];
+        *p = PixelLookup( colorMap, pix );
+        p++;
+      }
+    }
+  }
+  ret = true;
+
+on_error:
+  if( rows )
+  {
+    free( rows );
+  }
+  return ret;
+}
+
+/**
+ * @brief Reader header from the gif file and populates structures accordingly.
+ *
+ * @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 )
+{
+  GifAnimationData &animated = loaderInfo.animated;
+  LoaderInfo::FileData &fileData = loaderInfo.fileData;
+  bool ret = false;
+  LoaderInfo::FileInfo fileInfo;
+  GifRecordType rec;
+  GifFileType *gif = NULL;
+  // it is possible which gif file have error midle of frames,
+  // in that case we should play gif file until meet error frame.
+  int imageNumber = 0;
+  int loopCount = -1;
+  FrameInfo *frameInfo = NULL;
+  bool full = true;
+
+  if( fileData.isLocalResource )
+  {
+    Internal::Platform::FileReader fileReader( fileData.fileName );
+    FILE *fp = fileReader.GetFile();
+    if( fp == NULL )
+    {
+      return false;
+    }
+
+    if( fseek( fp, 0, SEEK_END ) <= -1 )
+    {
+      return false;
+    }
+
+    fileData.length = ftell( fp );
+    if( fileData.length <= -1 )
+    {
+      return false;
+    }
+
+    if( ( ! fseek( fp, 0, SEEK_SET ) ) )
+    {
+      fileData.globalMap = reinterpret_cast<GifByteType*>( malloc(sizeof( GifByteType ) * fileData.length ) );
+      fileData.length = fread( fileData.globalMap, sizeof( GifByteType ), fileData.length, fp);
+      fileInfo.map = fileData.globalMap;
+    }
+    else
+    {
+      return false;
+    }
+  }
+  else
+  {
+    // remote file
+    bool succeeded;
+    Dali::Vector<uint8_t> dataBuffer;
+    size_t dataSize;
+
+    succeeded = TizenPlatform::Network::DownloadRemoteFileIntoMemory( fileData.fileName, dataBuffer, dataSize,
+                                                                      MAXIMUM_DOWNLOAD_IMAGE_SIZE );
+    if( succeeded )
+    {
+      size_t blobSize = dataBuffer.Size();
+      if( 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( ( ! fseek( fp, 0, SEEK_SET ) ) )
+          {
+            fileData.globalMap = reinterpret_cast<GifByteType*>( malloc(sizeof( GifByteType ) * blobSize ) );
+            fileData.length = fread( fileData.globalMap, sizeof( GifByteType ), blobSize, fp);
+            fileInfo.map = fileData.globalMap;
+          }
+          else
+          {
+            DALI_LOG_ERROR( "Error seeking within file\n" );
+          }
+        }
+        else
+        {
+          DALI_LOG_ERROR( "Error reading file\n" );
+        }
+      }
+    }
+  }
+
+  if( !fileInfo.map )
+  {
+    LOADERR("LOAD_ERROR_CORRUPT_FILE");
+  }
+  fileInfo.length = fileData.length;
+  fileInfo.position = 0;
+
+// actually ask libgif to open the file
+#if GIFLIB_MAJOR >= 5
+  gif = DGifOpen( &fileInfo, FileRead, NULL );
+#else
+  gif = DGifOpen( &fileInfo, FileRead );
+#endif
+
+  if (!gif)
+  {
+    LOADERR("LOAD_ERROR_UNKNOWN_FORMAT");
+  }
+
+  // get the gif "screen size" (the actual image size)
+  prop.w = gif->SWidth;
+  prop.h = 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( IMG_TOO_BIG(prop.w, prop.h) )
+    {
+      LOADERR("LOAD_ERROR_RESOURCE_ALLOCATION_FAILED");
+    }
+    LOADERR("LOAD_ERROR_GENERIC");
+  }
+  // walk through gif records in file to figure out info
+  do
+  {
+    if( DGifGetRecordType(gif, &rec) == GIF_ERROR )
+    {
+      // if we have a gif that ends part way through a sequence
+      // (or animation) consider it valid and just break - no error
+      if( imageNumber > 1 )
+      {
+        break;
+      }
+      LOADERR("LOAD_ERROR_UNKNOWN_FORMAT");
+    }
+
+    // get image description section
+    if( rec == IMAGE_DESC_RECORD_TYPE )
+    {
+      int img_code;
+      GifByteType *img;
+
+      // get image desc
+      if( DGifGetImageDesc(gif) == GIF_ERROR )
+      {
+        LOADERR("LOAD_ERROR_UNKNOWN_FORMAT");
+      }
+      // skip decoding and just walk image to next
+      if( DGifGetCode(gif, &img_code, &img) == GIF_ERROR )
+      {
+        LOADERR("LOAD_ERROR_UNKNOWN_FORMAT");
+      }
+      // skip till next...
+      while( img )
+      {
+        img = NULL;
+        DGifGetCodeNext( gif, &img );
+      }
+      // store geometry in the last frame info data
+      if( frameInfo )
+      {
+        StoreFrameInfo( gif, frameInfo );
+        CheckTransparency( full, frameInfo, prop.w, prop.h );
+      }
+      // or if we dont have a frameInfo entry - create one even for stills
+      else
+      {
+        // allocate and save frame with field data
+        frameInfo = NewFrame( animated, -1, 0, 0, imageNumber + 1 );
+        if (!frameInfo)
+        {
+          LOADERR("LOAD_ERROR_RESOURCE_ALLOCATION_FAILED");
+        }
+        // store geometry info from gif image
+        StoreFrameInfo( gif, frameInfo );
+        // check for transparency/alpha
+        CheckTransparency( full, frameInfo, prop.w, prop.h );
+      }
+      imageNumber++;
+    }
+    // we have an extension code block - for animated gifs for sure
+    else if( rec == EXTENSION_RECORD_TYPE )
+    {
+      int ext_code;
+      GifByteType *ext;
+
+      ext = NULL;
+      // get the first extension entry
+      DGifGetExtension( gif, &ext_code, &ext );
+      while( ext )
+      {
+        // graphic control extension - for animated gif data
+        // and transparent index + flag
+        if( ext_code == 0xf9 )
+        {
+          // create frame and store it in image
+          int transparencyIndex = (ext[1] & 1) ? ext[4] : -1;
+          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 )
+          {
+            LOADERR("LOAD_ERROR_RESOURCE_ALLOCATION_FAILED");
+          }
+        }
+        // netscape extension indicating loop count.
+        else if( ext_code == 0xff ) /* application extension */
+        {
+          if( !strncmp(reinterpret_cast<char *>(&ext[1]), "NETSCAPE2.0", 11) ||
+              !strncmp(reinterpret_cast<char *>(&ext[1]), "ANIMEXTS1.0", 11) )
+          {
+            ext = NULL;
+            DGifGetExtensionNext( gif, &ext );
+            if( ext[1] == 0x01 )
+            {
+              loopCount = (int(ext[3]) << 8) | int(ext[2]);
+              if( loopCount > 0 )
+              {
+                loopCount++;
+              }
+            }
+          }
+        }
+        // and continue onto the next extension entry
+        ext = NULL;
+        DGifGetExtensionNext( gif, &ext );
+      }
+    }
+  } while( rec != TERMINATE_RECORD_TYPE );
+
+  // if the gif main says we have more than one image or our image counting
+  // says so, then this image is animated - indicate this
+  if( (gif->ImageCount > 1) || (imageNumber > 1) )
+  {
+    animated.animated = 1;
+    animated.loopCount = loopCount;
+  }
+  animated.frameCount = std::min( gif->ImageCount, imageNumber );
+
+  if( !full )
+  {
+    prop.alpha = 1;
+  }
+
+  animated.currentFrame = 1;
+
+  // no errors in header scan etc. so set err and return value
+  *error = 0;
+  ret = true;
+
+on_error: // jump here on any errors to clean up
+#if (GIFLIB_MAJOR > 5) || ((GIFLIB_MAJOR == 5) && (GIFLIB_MINOR >= 1))
+  if( gif )
+  {
+    DGifCloseFile( gif, NULL );
+  }
+#else
+  if( gif )
+  {
+    DGifCloseFile( gif );
+  }
+#endif
+
+  return ret;
+}
+
+/**
+ * @brief Reader next frame of the gif file and populates structures accordingly.
+ *
+ * @param[in] loaderInfo A LoaderInfo structure containing file descriptor and other data about GIF.
+ * @param[in/out] prop A ImageProperties structure containing information about gif data.
+ * @param[out] pixels A pointer to buffer which will contain all pixel data of the frame on return.
+ * @param[out] error Error code
+ * @return The true or false whether reading was successful or not.
+ */
+bool ReadNextFrame( LoaderInfo &loaderInfo, ImageProperties &prop, //  use for w and h
+                    unsigned char *pixels, int *error )
+{
+  GifAnimationData &animated = loaderInfo.animated;
+  LoaderInfo::FileData &fileData = loaderInfo.fileData;
+  bool ret = false;
+  GifRecordType rec;
+  GifFileType *gif = NULL;
+  int index = 0, imageNumber = 0;
+  FrameInfo *frameInfo;
+  ImageFrame *frame = NULL;
+  ImageFrame *lastPreservedFrame = NULL;
+
+  index = animated.currentFrame;
+
+  // if index is invalid for animated image - error out
+  if ((animated.animated) && ((index <= 0) || (index > animated.frameCount)))
+  {
+    LOADERR("LOAD_ERROR_GENERIC");
+  }
+
+  // find the given frame index
+  frame = FindFrame( animated, index );
+  if( frame )
+  {
+    if( (frame->loaded) && (frame->data) )
+    {
+      // frame is already there and decoded - jump to end
+      goto on_ok;
+    }
+  }
+  else
+  {
+    LOADERR("LOAD_ERROR_CORRUPT_FILE");
+  }
+
+open_file:
+  // actually ask libgif to open the file
+  gif = loaderInfo.gif;
+  if( !gif )
+  {
+    loaderInfo.fileInfo.map = fileData.globalMap ;
+    if( !loaderInfo.fileInfo.map )
+    {
+      LOADERR("LOAD_ERROR_CORRUPT_FILE");
+    }
+    loaderInfo.fileInfo.length = fileData.length;
+    loaderInfo.fileInfo.position = 0;
+
+#if GIFLIB_MAJOR >= 5
+    gif = DGifOpen( &( loaderInfo.fileInfo ), FileRead, NULL );
+#else
+    gif = DGifOpen( &( loaderInfo.fileInfo ), FileRead );
+#endif
+    // if gif open failed... get out of here
+    if( !gif )
+    {
+      LOADERR("LOAD_ERROR_UNKNOWN_FORMAT");
+    }
+    loaderInfo.gif = gif;
+    loaderInfo.imageNumber = 1;
+  }
+
+  // if we want to go backwards, we likely need/want to re-decode from the
+  // start as we have nothing to build on
+  if( (index > 0) && (index < loaderInfo.imageNumber) && (animated.animated) )
+  {
+#if (GIFLIB_MAJOR > 5) || ((GIFLIB_MAJOR == 5) && (GIFLIB_MINOR >= 1))
+    if( loaderInfo.gif )
+      DGifCloseFile( loaderInfo.gif, NULL );
+#else
+    if( loaderInfo.gif )
+      DGifCloseFile( loaderInfo.gif );
+#endif
+    loaderInfo.gif = NULL;
+    loaderInfo.imageNumber = 0;
+    goto open_file;
+  }
+
+  // our current position is the previous frame we decoded from the file
+  imageNumber = loaderInfo.imageNumber;
+
+  // walk through gif records in file to figure out info
+  do
+  {
+    if( DGifGetRecordType( gif, &rec ) == GIF_ERROR )
+    {
+      LOADERR("LOAD_ERROR_UNKNOWN_FORMAT");
+    }
+
+    if( rec == EXTENSION_RECORD_TYPE )
+    {
+      int ext_code;
+      GifByteType *ext = NULL;
+      DGifGetExtension( gif, &ext_code, &ext );
+
+      while( ext )
+      {
+        ext = NULL;
+        DGifGetExtensionNext( gif, &ext );
+      }
+    }
+    // get image description section
+    else if( rec == IMAGE_DESC_RECORD_TYPE )
+    {
+      int xin = 0, yin = 0, x = 0, y = 0, w = 0, h = 0;
+      int img_code;
+      GifByteType *img;
+      ImageFrame *previousFrame = NULL;
+      ImageFrame *thisFrame = NULL;
+
+      // get image desc
+      if( DGifGetImageDesc(gif) == GIF_ERROR )
+      {
+        LOADERR("LOAD_ERROR_UNKNOWN_FORMAT");
+      }
+
+      // get the previous frame entry AND the current one to fill in
+      previousFrame = FindFrame(animated, imageNumber - 1);
+      thisFrame = FindFrame(animated, imageNumber);
+
+      // if we have a frame AND we're animated AND we have no data...
+      if( (thisFrame) && (!thisFrame->data) && (animated.animated) )
+      {
+        bool first = false;
+
+        // allocate it
+        thisFrame->data = new uint32_t[prop.w * prop.h];
+
+        if( !thisFrame->data )
+        {
+          LOADERR("LOAD_ERROR_RESOURCE_ALLOCATION_FAILED");
+        }
+
+        // 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) );
+        }
+        // we have a prior frame to copy data from...
+        else
+        {
+          frameInfo = &( previousFrame->info );
+
+          // fix coords of sub image in case it goes out...
+          ClipCoordinates( prop.w, prop.h, &xin, &yin,
+                           frameInfo->x, frameInfo->y, frameInfo->w, frameInfo->h,
+                           &x, &y, &w, &h );
+
+          // if dispose mode is not restore - then copy pre frame
+          if( frameInfo->dispose != DISPOSE_PREVIOUS )
+          {
+            memcpy( thisFrame->data, previousFrame->data, prop.w * prop.h * sizeof(uint32_t) );
+          }
+
+          // if dispose mode is "background" then fill with bg
+          if( frameInfo->dispose == DISPOSE_BACKGROUND )
+          {
+            FillFrame( thisFrame->data, prop.w, gif, frameInfo, x, y, w, h );
+          }
+          else if( frameInfo->dispose == DISPOSE_PREVIOUS ) // GIF_DISPOSE_RESTORE
+          {
+            int prevIndex = 2;
+            do
+            {
+              // Find last preserved frame.
+              lastPreservedFrame = FindFrame( animated, imageNumber - prevIndex );
+              if( ! lastPreservedFrame )
+              {
+                LOADERR( "LOAD_ERROR_LAST_PRESERVED_FRAME_NOT_FOUND" );
+              }
+              prevIndex++;
+            } while( lastPreservedFrame && lastPreservedFrame->info.dispose == DISPOSE_PREVIOUS );
+
+            if ( lastPreservedFrame )
+            {
+              memcpy( thisFrame->data, lastPreservedFrame->data, prop.w * prop.h * sizeof(uint32_t) );
+            }
+          }
+        }
+        // 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( gif, thisFrame->data, prop.w,
+                          xin, yin, frameInfo->transparent,
+                          x, y, w, h, first) )
+        {
+          LOADERR("LOAD_ERROR_CORRUPT_FILE");
+        }
+
+        // mark as loaded and done
+        thisFrame->loaded = true;
+
+        FlushFrames( animated, prop.w, prop.h, thisFrame, previousFrame, lastPreservedFrame );
+      }
+      // if we have a frame BUT the image is not animated. different
+      // path
+      else if( (thisFrame) && (!thisFrame->data) && (!animated.animated) )
+      {
+        // if we don't have the data decoded yet - decode it
+        if( (!thisFrame->loaded) || (!thisFrame->data) )
+        {
+          // use frame info but we WONT allocate frame pixels
+          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, gif, frameInfo, 0, 0, prop.w, prop.h );
+
+          // and decode the gif with overwriting
+          if( !DecodeImage( gif, reinterpret_cast<uint32_t *>(pixels), prop.w,
+                            xin, yin, frameInfo->transparent, x, y, w, h, true) )
+          {
+            LOADERR("LOAD_ERROR_CORRUPT_FILE");
+          }
+
+          // mark as loaded and done
+          thisFrame->loaded = true;
+        }
+        // flush mem we don't need (at expense of decode cpu)
+      }
+      else
+      {
+        // skip decoding and just walk image to next
+        if( DGifGetCode( gif, &img_code, &img ) == GIF_ERROR )
+        {
+          LOADERR("LOAD_ERROR_UNKNOWN_FORMAT");
+        }
+
+        while( img )
+        {
+          img = NULL;
+          DGifGetCodeNext( gif, &img );
+        }
+      }
+
+      imageNumber++;
+      // if we found the image we wanted - get out of here
+      if( imageNumber > index )
+      {
+        break;
+      }
+    }
+  } while( rec != TERMINATE_RECORD_TYPE );
+
+  // if we are at the end of the animation or not animated, close file
+  loaderInfo.imageNumber = imageNumber;
+  if( (animated.frameCount <= 1) || (rec == TERMINATE_RECORD_TYPE) )
+  {
+#if (GIFLIB_MAJOR > 5) || ((GIFLIB_MAJOR == 5) && (GIFLIB_MINOR >= 1))
+    if( loaderInfo.gif )
+    {
+      DGifCloseFile( loaderInfo.gif, NULL );
+    }
+#else
+    if( loaderInfo.gif )
+    {
+      DGifCloseFile( loaderInfo.gif );
+    }
+#endif
+
+    loaderInfo.gif = NULL;
+    loaderInfo.imageNumber = 0;
+  }
+
+on_ok:
+  // no errors in header scan etc. so set err and return value
+  *error = 0;
+  ret = true;
+
+  // if it was an animated image we need to copy the data to the
+  // pixels for the image from the frame holding the data
+  if( animated.animated && frame->data )
+  {
+    memcpy( pixels, frame->data, prop.w * prop.h * sizeof( uint32_t ) );
+  }
+
+on_error: // jump here on any errors to clean up
+  return ret;
+}
+
+} // unnamed namespace
+
+struct GifLoading::Impl
+{
+public:
+  Impl( const std::string& url, bool isLocalResource )
+  : mUrl( url )
+  {
+    loaderInfo.gif = nullptr;
+    int error;
+    loaderInfo.fileData.fileName = mUrl.c_str();
+    loaderInfo.fileData.isLocalResource = isLocalResource;
+
+    ReadHeader( loaderInfo, imageProperties, &error );
+  }
+
+  // Moveable but not copyable
+
+  Impl( const Impl& ) = delete;
+  Impl& operator=( const Impl& ) = delete;
+  Impl( Impl&& ) = default;
+  Impl& operator=( Impl&& ) = default;
+
+  ~Impl()
+  {
+    if( loaderInfo.fileData.globalMap  )
+    {
+      free( loaderInfo.fileData.globalMap );
+      loaderInfo.fileData.globalMap  = nullptr;
+    }
+
+    // Delete all image frames
+    for( auto &&frame : loaderInfo.animated.frames )
+    {
+      if( frame.data != nullptr )
+      {
+        // De-allocate memory of the frame data.
+        delete[] frame.data;
+        frame.data = nullptr;
+      }
+    }
+  }
+
+  std::string mUrl;
+  LoaderInfo loaderInfo;
+  ImageProperties imageProperties;
+};
+
+AnimatedImageLoadingPtr GifLoading::New( const std::string &url, bool isLocalResource )
+{
+  return AnimatedImageLoadingPtr( new GifLoading( url, isLocalResource ) );
+}
+
+GifLoading::GifLoading( const std::string &url, bool isLocalResource )
+: mImpl( new GifLoading::Impl( url, isLocalResource ) )
+{
+}
+
+
+GifLoading::~GifLoading()
+{
+  delete mImpl;
+}
+
+bool GifLoading::LoadNextNFrames( uint32_t frameStartIndex, int count, std::vector<Dali::PixelData> &pixelData )
+{
+  int error;
+  bool ret = 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;
+}
+
+ImageDimensions GifLoading::GetImageSize() const
+{
+  return ImageDimensions( mImpl->imageProperties.w, mImpl->imageProperties.h );
+}
+
+uint32_t GifLoading::GetImageCount() const
+{
+  return mImpl->loaderInfo.animated.frameCount;
+}
+
+uint32_t GifLoading::GetFrameInterval( uint32_t frameIndex ) const
+{
+  return mImpl->loaderInfo.animated.frames[frameIndex].info.delay * 10;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
\ No newline at end of file
diff --git a/dali/internal/imaging/common/gif-loading.h b/dali/internal/imaging/common/gif-loading.h
new file mode 100644 (file)
index 0000000..4ee7565
--- /dev/null
@@ -0,0 +1,118 @@
+#ifndef DALI_INTERNAL_GIF_LOADING_H
+#define DALI_INTERNAL_GIF_LOADING_H
+
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+// EXTERNAL INCLUDES
+#include <cstdint>
+#include <memory>
+#include <dali/public-api/math/rect.h>
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/math/uint-16-pair.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+#include <dali/internal/imaging/common/animated-image-loading-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Class to manage loading frames of an animated gif in small chunks. Lazy initializes only when
+ * data is actually needed.
+ * Note, once the GIF has loaded, the undecoded data will reside in memory until this object
+ * is released. (This is to speed up frame loads, which would otherwise have to re-acquire the
+ * data from disk)
+ */
+class GifLoading: public Internal::Adaptor::AnimatedImageLoading
+{
+public:
+
+  /**
+   * Create a GifLoading with the given url and resourceType.
+   * @param[in] url The url of the gif image to load
+   * @param[in] isLocalResource The true or false whether this is a local resource.
+   * @return A newly created GifLoading.
+   */
+  static AnimatedImageLoadingPtr New( const std::string& url, bool isLocalResource );
+
+  /**
+   * @brief Constructor
+   *
+   * Construct a Loader with the given URL
+   * @param[in] url The url of the gif image to load
+   * @param[in] isLocalResource The true or false whether this is a local resource.
+   */
+  GifLoading( const std::string& url, bool isLocalResource );
+
+  /**
+   * @brief Destructor
+   */
+  ~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 Get the size of a gif image.
+   *
+   * @return The width and height in pixels of the gif image.
+   */
+  ImageDimensions GetImageSize() const override;
+
+  /**
+   * @brief Get the number of frames in this gif.
+   */
+  uint32_t GetImageCount() const override;
+
+  /**
+   * @brief Get the frame interval of the frame index
+   *
+   * @note The frame is needed to be loaded before this function is called.
+   *
+   * @return The time interval of the frame(microsecond).
+   */
+  uint32_t GetFrameInterval( uint32_t frameIndex ) const override;
+
+private:
+  struct Impl;
+  Impl* mImpl;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_GIF_LOADING_H
diff --git a/dali/internal/imaging/common/webp-loading.cpp b/dali/internal/imaging/common/webp-loading.cpp
new file mode 100644 (file)
index 0000000..78e2e11
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/imaging/common/webp-loading.h>
+
+// EXTERNAL INCLUDES
+#include <webp/decode.h>
+#include <webp/demux.h>
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/images/pixel-data.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <cstring>
+#include <dali/internal/imaging/common/file-download.h>
+#include <dali/internal/system/common/file-reader.h>
+
+typedef unsigned char WebPByteType;
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter *gWebPLoadingLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_GIF_LOADING" );
+#endif
+
+constexpr size_t MAXIMUM_DOWNLOAD_IMAGE_SIZE  = 50 * 1024 * 1024;
+
+}
+
+struct WebPLoading::Impl
+{
+public:
+  Impl( const std::string& url, bool isLocalResource )
+  : mUrl( url ),
+    mLoadingFrame( 0 )
+  {
+#if WEBP_DEMUX_ABI_VERSION > 0x0101
+    if( ReadWebPInformation( isLocalResource ) )
+    {
+      WebPAnimDecoderOptions webPAnimDecoderOptions;
+      WebPAnimDecoderOptionsInit( &webPAnimDecoderOptions );
+      webPAnimDecoderOptions.color_mode = MODE_RGBA;
+      mWebPAnimDecoder = WebPAnimDecoderNew( &mWebPData, &webPAnimDecoderOptions );
+      WebPAnimDecoderGetInfo( mWebPAnimDecoder, &mWebPAnimInfo );
+      mTimeStamp.assign( mWebPAnimInfo.frame_count, 0 );
+    }
+#endif
+  }
+
+  bool ReadWebPInformation( bool isLocalResource )
+  {
+#if WEBP_DEMUX_ABI_VERSION > 0x0101
+    WebPDataInit( &mWebPData );
+    if( isLocalResource )
+    {
+      Internal::Platform::FileReader fileReader( mUrl );
+      FILE *fp = fileReader.GetFile();
+      if( fp == NULL )
+      {
+        return false;
+      }
+
+      if( fseek( fp, 0, SEEK_END ) <= -1 )
+      {
+        return false;
+      }
+
+      mWebPData.size = ftell( fp );
+      if( ( ! fseek( fp, 0, SEEK_SET ) ) )
+      {
+        unsigned char *WebPDataBuffer;
+        WebPDataBuffer = reinterpret_cast<WebPByteType*>( malloc(sizeof( WebPByteType ) * mWebPData.size ) );
+        mWebPData.size = fread( WebPDataBuffer, sizeof( WebPByteType ), mWebPData.size, fp );
+        mWebPData.bytes = WebPDataBuffer;
+      }
+      else
+      {
+        return false;
+      }
+    }
+    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 )
+      {
+        size_t blobSize = dataBuffer.Size();
+        if( 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( ( ! fseek( fp, 0, SEEK_SET ) ) )
+            {
+              unsigned char *WebPDataBuffer;
+              WebPDataBuffer = reinterpret_cast<WebPByteType*>( malloc(sizeof( WebPByteType ) * blobSize ) );
+              mWebPData.size = fread( WebPDataBuffer, sizeof( WebPByteType ), mWebPData.size, fp );
+              mWebPData.bytes = WebPDataBuffer;
+            }
+            else
+            {
+              DALI_LOG_ERROR( "Error seeking within file\n" );
+            }
+          }
+          else
+          {
+            DALI_LOG_ERROR( "Error reading file\n" );
+          }
+        }
+      }
+    }
+    return true;
+#else
+    return false;
+#endif
+  }
+
+  // Moveable but not copyable
+
+  Impl( const Impl& ) = delete;
+  Impl& operator=( const Impl& ) = delete;
+  Impl( Impl&& ) = default;
+  Impl& operator=( Impl&& ) = default;
+
+  ~Impl()
+  {
+#if WEBP_DEMUX_ABI_VERSION > 0x0101
+    if( &mWebPData != NULL )
+    {
+      free( (void*)mWebPData.bytes );
+      mWebPData.bytes = nullptr;
+      WebPDataInit( &mWebPData );
+    }
+    if( mWebPAnimDecoder )
+    {
+      WebPAnimDecoderDelete(mWebPAnimDecoder);
+    }
+#endif
+  }
+
+  std::string mUrl;
+  std::vector<uint32_t> mTimeStamp;
+  uint32_t mLoadingFrame;
+
+#if WEBP_DEMUX_ABI_VERSION > 0x0101
+  WebPData mWebPData;
+  WebPAnimDecoder* mWebPAnimDecoder;
+  WebPAnimInfo mWebPAnimInfo;
+#endif
+};
+
+AnimatedImageLoadingPtr WebPLoading::New( const std::string &url, bool isLocalResource )
+{
+#if WEBP_DEMUX_ABI_VERSION <= 0x0101
+  DALI_LOG_ERROR( "The system do not support Animated WebP format.\n" );
+#endif
+  return AnimatedImageLoadingPtr( new WebPLoading( url, isLocalResource ) );
+}
+
+WebPLoading::WebPLoading( const std::string &url, bool isLocalResource )
+: mImpl( new WebPLoading::Impl( url, isLocalResource ) )
+{
+}
+
+WebPLoading::~WebPLoading()
+{
+  delete mImpl;
+}
+
+bool WebPLoading::LoadNextNFrames( uint32_t frameStartIndex, int count, std::vector<Dali::PixelData> &pixelData )
+{
+#if WEBP_DEMUX_ABI_VERSION > 0x0101
+  if( frameStartIndex  >= mImpl->mWebPAnimInfo.frame_count )
+  {
+    return false;
+  }
+
+  DALI_LOG_INFO( gWebPLoadingLogFilter, Debug::Concise, "LoadNextNFrames( frameStartIndex:%d, count:%d )\n", frameStartIndex, count );
+
+  if( mImpl->mLoadingFrame > frameStartIndex  )
+  {
+    mImpl->mLoadingFrame = 0;
+    WebPAnimDecoderReset( mImpl->mWebPAnimDecoder );
+  }
+
+  for( ; mImpl->mLoadingFrame < frameStartIndex ; ++mImpl->mLoadingFrame )
+  {
+    uint8_t* frameBuffer;
+    int timestamp;
+    WebPAnimDecoderGetNext( mImpl->mWebPAnimDecoder, &frameBuffer, &timestamp );
+    mImpl->mTimeStamp[mImpl->mLoadingFrame] = timestamp;
+  }
+
+  for( int i = 0; i < count; ++i )
+  {
+    const int bufferSize = mImpl->mWebPAnimInfo.canvas_width * mImpl->mWebPAnimInfo.canvas_height * sizeof( uint32_t );
+    uint8_t* frameBuffer;
+    int timestamp;
+    WebPAnimDecoderGetNext( mImpl->mWebPAnimDecoder, &frameBuffer, &timestamp );
+
+    auto pixelBuffer = new uint8_t[ bufferSize ];
+    memcpy( pixelBuffer, frameBuffer, bufferSize );
+    mImpl->mTimeStamp[mImpl->mLoadingFrame] = timestamp;
+
+    if( pixelBuffer )
+    {
+      pixelData.push_back( Dali::PixelData::New( pixelBuffer, bufferSize,
+                                                 mImpl->mWebPAnimInfo.canvas_width, mImpl->mWebPAnimInfo.canvas_height,
+                                                 Dali::Pixel::RGBA8888, Dali::PixelData::DELETE_ARRAY) );
+    }
+
+    mImpl->mLoadingFrame++;
+    if( mImpl->mLoadingFrame >= mImpl->mWebPAnimInfo.frame_count )
+    {
+      mImpl->mLoadingFrame = 0;
+      WebPAnimDecoderReset( mImpl->mWebPAnimDecoder );
+    }
+  }
+
+  return true;
+#else
+  return false;
+#endif
+}
+
+ImageDimensions WebPLoading::GetImageSize() const
+{
+#if WEBP_DEMUX_ABI_VERSION > 0x0101
+  return ImageDimensions( mImpl->mWebPAnimInfo.canvas_width, mImpl->mWebPAnimInfo.canvas_height );
+#else
+  return ImageDimensions();
+#endif
+}
+
+uint32_t WebPLoading::GetImageCount() const
+{
+#if WEBP_DEMUX_ABI_VERSION > 0x0101
+  return mImpl->mWebPAnimInfo.frame_count;
+#else
+  return 0u;
+#endif
+}
+
+uint32_t WebPLoading::GetFrameInterval( uint32_t frameIndex ) const
+{
+  if( frameIndex >= GetImageCount() )
+  {
+    return 0u;
+  }
+  else
+  {
+    if( frameIndex > 0 )
+    {
+      return mImpl->mTimeStamp[frameIndex] - mImpl->mTimeStamp[frameIndex - 1];
+    }
+    return mImpl->mTimeStamp[frameIndex];
+  }
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
\ No newline at end of file
diff --git a/dali/internal/imaging/common/webp-loading.h b/dali/internal/imaging/common/webp-loading.h
new file mode 100644 (file)
index 0000000..01bd4e3
--- /dev/null
@@ -0,0 +1,121 @@
+#ifndef DALI_INTERNAL_WEBP_LOADING_H
+#define DALI_INTERNAL_WEBP_LOADING_H
+
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+// EXTERNAL INCLUDES
+#include <cstdint>
+#include <memory>
+#include <dali/public-api/math/rect.h>
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/math/uint-16-pair.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+#include <dali/internal/imaging/common/animated-image-loading-impl.h>
+
+namespace Dali
+{
+class PixelData;
+typedef Dali::Uint16Pair ImageDimensions;
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Class to manage loading frames of an animated webp in small chunks. Lazy initializes only when
+ * data is actually needed.
+ * Note, once the WEBP has loaded, the undecoded data will reside in memory until this object
+ * is released. (This is to speed up frame loads, which would otherwise have to re-acquire the
+ * data from disk)
+ */
+class WebPLoading: public Internal::Adaptor::AnimatedImageLoading
+{
+public:
+
+  /**
+   * Create a WebPLoading with the given url and resourceType.
+   * @param[in] url The url of the webp image to load
+   * @param[in] isLocalResource The true or false whether this is a local resource.
+   * @return A newly created WebPLoading.
+   */
+  static AnimatedImageLoadingPtr New( const std::string& url, bool isLocalResource );
+
+  /**
+   * @brief Constructor
+   *
+   * Construct a Loader with the given URL
+   * @param[in] url The url of the webp image to load
+   * @param[in] isLocalResource The true or false whether this is a local resource.
+   */
+  WebPLoading( const std::string& url, bool isLocalResource );
+
+
+  /**
+   * @brief Destructor
+   */
+  ~WebPLoading() override;
+
+  /**
+   * @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
+   */
+  bool LoadNextNFrames( uint32_t frameStartIndex, int count, std::vector<Dali::PixelData>& pixelData ) override;
+
+  /**
+   * @brief Get the size of a webp image.
+   *
+   * @return The width and height in pixels of the webp image.
+   */
+  ImageDimensions GetImageSize() const override;
+
+  /**
+   * @brief Get the number of frames in this webp.
+   */
+  uint32_t GetImageCount() const override;
+
+  /**
+   * @brief Get the frame interval of the frame index
+   *
+   * @note The frame is needed to be loaded before this function is called.
+   *
+   * @return The time interval of the frame(microsecond).
+   */
+  uint32_t GetFrameInterval( uint32_t frameIndex ) const override;
+
+private:
+  struct Impl;
+  Impl* mImpl;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_WEBP_LOADING_H
index 6558e96927a3a08e17ae62aa778a9cc5b080e257..c91ffcfc1442878f2fc7612228d7e6cc9055ecb4 100644 (file)
@@ -18,6 +18,8 @@ SET( adaptor_imaging_common_src_files
     ${adaptor_imaging_dir}/common/loader-png.cpp
     ${adaptor_imaging_dir}/common/loader-wbmp.cpp
     ${adaptor_imaging_dir}/common/pixel-manipulation.cpp
+    ${adaptor_imaging_dir}/common/gif-loading.cpp
+    ${adaptor_imaging_dir}/common/webp-loading.cpp
 )
 
 # module: imaging, backend: tizen
index 0e7a46903e8f093ac422e09c5eaad04b678d6c15..6d7bafc71987fc493d138279d4a16a30a8a24c5d 100644 (file)
@@ -56,6 +56,10 @@ BuildRequires:  pkgconfig
 BuildRequires:  gawk
 BuildRequires:  cmake
 BuildRequires:  giflib-devel
+BuildRequires:  pkgconfig(libwebp)
+BuildRequires:  pkgconfig(libwebpdecoder)
+BuildRequires:  pkgconfig(libwebpdemux)
+BuildRequires:  pkgconfig(libwebpmux)
 BuildRequires:  pkgconfig(fontconfig)
 BuildRequires:  libjpeg-turbo-devel
 BuildRequires:  pkgconfig(vconf)