[dali_2.3.33] Merge branch 'devel/master'
[platform/core/uifw/dali-adaptor.git] / dali / internal / imaging / common / gif-loading.cpp
index 4ca7dd4..c35899a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
   ((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;     \
+#define PRINT_ERROR_AND_EXIT(errorFormat, ...)  \
+  do                                            \
+  {                                             \
+    DALI_LOG_ERROR(errorFormat, ##__VA_ARGS__); \
+    if(rows)                                    \
+    {                                           \
+      free(rows);                               \
+    }                                           \
+    return ret;                                 \
   } while(0)
 
 namespace Dali
@@ -311,8 +315,13 @@ bool LoaderInfo::FileData::LoadLocalFile()
 
   if(DALI_LIKELY(!fseek(fp, 0, SEEK_SET)))
   {
-    globalMap = reinterpret_cast<GifByteType*>(malloc(sizeof(GifByteType) * length));
-    length    = fread(globalMap, sizeof(GifByteType), length, fp);
+    globalMap = reinterpret_cast<GifByteType*>(malloc(sizeof(GifByteType) * static_cast<unsigned long long>(length)));
+    if(DALI_UNLIKELY(globalMap == nullptr))
+    {
+      DALI_LOG_ERROR("malloc is failed. request malloc size : %llu\n", sizeof(GifByteType) * static_cast<unsigned long long>(length));
+      return false;
+    }
+    length = fread(globalMap, sizeof(GifByteType), length, fp);
   }
   else
   {
@@ -342,8 +351,15 @@ bool LoaderInfo::FileData::LoadRemoteFile()
         if(DALI_LIKELY(!fseek(fp, 0, SEEK_SET)))
         {
           globalMap = reinterpret_cast<GifByteType*>(malloc(sizeof(GifByteType) * blobSize));
-          length    = fread(globalMap, sizeof(GifByteType), blobSize, fp);
-          succeeded = true;
+          if(DALI_UNLIKELY(globalMap == nullptr))
+          {
+            DALI_LOG_ERROR("malloc is failed. request malloc size : %zu\n", sizeof(GifByteType) * blobSize);
+          }
+          else
+          {
+            length    = fread(globalMap, sizeof(GifByteType), blobSize, fp);
+            succeeded = true;
+          }
         }
         else
         {
@@ -641,6 +657,207 @@ FrameInfo* NewFrame(GifAnimationData& animated, int transparent, int dispose, in
   return &(animated.frames.back().info);
 }
 
+/// FILL (overwrite with transparency kept)
+void FillOverwriteWithTransparencyKept(
+  const std::uint32_t*& cachedColorPtr,
+  int&                  xx,
+  int&                  yy,
+  const int             x,
+  const int             y,
+  const int             w,
+  const int             h,
+  const int             xin,
+  const int             yin,
+  const int             rowpix,
+  const int             transparent,
+  const uint32_t        fillColor,
+  int&                  pix,
+  uint32_t*&            p,
+  uint32_t*&            data,
+  GifRowType*&          rows,
+  ColorMapObject*&      colorMap)
+{
+  // if we use cachedColor, use it
+  if(cachedColorPtr)
+  {
+    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 = cachedColorPtr[pix];
+        }
+        else
+        {
+          *p = fillColor;
+        }
+        p++;
+      }
+    }
+  }
+  // we don't have cachedColor. use PixelLookup function.
+  else
+  {
+    for(yy = 0; yy < h; yy++)
+    {
+      p = data + ((y + yy) * rowpix) + x;
+      for(xx = 0; xx < w; xx++)
+      {
+        pix = rows[yin + yy][xin + xx];
+        if(pix != transparent)
+        {
+          *p = PixelLookup(colorMap, pix);
+        }
+        else
+        {
+          *p = fillColor;
+        }
+        p++;
+      }
+    }
+  }
+}
+
+/// Paste on top with transparent pixels untouched
+void PasteOnTopWithTransparentPixelsUntouched(
+  const std::uint32_t*& cachedColorPtr,
+  int&                  xx,
+  int&                  yy,
+  const int             x,
+  const int             y,
+  const int             w,
+  const int             h,
+  const int             xin,
+  const int             yin,
+  const int             rowpix,
+  const int             transparent,
+  const uint32_t        fillColor,
+  int&                  pix,
+  uint32_t*&            p,
+  uint32_t*&            data,
+  GifRowType*&          rows,
+  ColorMapObject*&      colorMap)
+{
+  // if we use cachedColor, use it
+  if(cachedColorPtr)
+  {
+    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 = cachedColorPtr[pix];
+        }
+        p++;
+      }
+    }
+  }
+  // we don't have cachedColor. use PixelLookup function.
+  else
+  {
+    for(yy = 0; yy < h; yy++)
+    {
+      p = data + ((y + yy) * rowpix) + x;
+      for(xx = 0; xx < w; xx++)
+      {
+        pix = rows[yin + yy][xin + xx];
+        if(pix != transparent)
+        {
+          *p = PixelLookup(colorMap, pix);
+        }
+        p++;
+      }
+    }
+  }
+}
+
+void HandleTransparentPixels(
+  const bool            fill,
+  const std::uint32_t*& cachedColorPtr,
+  int&                  xx,
+  int&                  yy,
+  const int             x,
+  const int             y,
+  const int             w,
+  const int             h,
+  const int             xin,
+  const int             yin,
+  const int             rowpix,
+  const int             transparent,
+  const uint32_t        fillColor,
+  int&                  pix,
+  uint32_t*&            p,
+  uint32_t*&            data,
+  GifRowType*&          rows,
+  ColorMapObject*&      colorMap)
+{
+  if(fill)
+  {
+    FillOverwriteWithTransparencyKept(cachedColorPtr, xx, yy, x, y, w, h, xin, yin, rowpix, transparent, fillColor, pix, p, data, rows, colorMap);
+  }
+  else
+  {
+    PasteOnTopWithTransparentPixelsUntouched(cachedColorPtr, xx, yy, x, y, w, h, xin, yin, rowpix, transparent, fillColor, pix, p, data, rows, colorMap);
+  }
+}
+
+void HandleNonTransparentPixels(
+  const std::uint32_t*& cachedColorPtr,
+  int&                  xx,
+  int&                  yy,
+  const int             x,
+  const int             y,
+  const int             w,
+  const int             h,
+  const int             xin,
+  const int             yin,
+  const int             rowpix,
+  const int             transparent,
+  const uint32_t        fillColor,
+  int&                  pix,
+  uint32_t*&            p,
+  uint32_t*&            data,
+  GifRowType*&          rows,
+  ColorMapObject*&      colorMap)
+{
+  // if we use cachedColor, use it
+  if(cachedColorPtr)
+  {
+    // walk pixels without worring about transparency at all
+    for(yy = 0; yy < h; yy++)
+    {
+      p = data + ((y + yy) * rowpix) + x;
+      for(xx = 0; xx < w; xx++)
+      {
+        pix = rows[yin + yy][xin + xx];
+        *p  = cachedColorPtr[pix];
+        p++;
+      }
+    }
+  }
+  // we don't have cachedColor. use PixelLookup function.
+  else
+  {
+    // 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++;
+      }
+    }
+  }
+}
+
 /**
  * @brief Decode a gif image into rows then expand to 32bit into the destination
  * data pointer.
@@ -669,7 +886,7 @@ bool DecodeImage(GifFileType* gif, GifCachedColorData& gifCachedColor, uint32_t*
   {
     DALI_LOG_ERROR("gifW : %d, w : %d, gifH : %d, h : %d\n", gifW, w, gifH, h);
     DALI_ASSERT_DEBUG(false && "Dimensions are bigger than the Gif image size");
-    goto on_error;
+    PRINT_ERROR_AND_EXIT("GIF Loader: Dimensions are bigger than the Gif image size! gifW : %d, w : %d, gifH : %d, h : %d\n", gifW, w, gifH, h);
   }
 
   // build a blob of memory to have pointers to rows of pixels
@@ -677,7 +894,7 @@ bool DecodeImage(GifFileType* gif, GifCachedColorData& gifCachedColor, uint32_t*
   rows = static_cast<GifRowType*>(malloc((gifH * sizeof(GifRowType)) + (gifW * gifH * sizeof(GifPixelType))));
   if(DALI_UNLIKELY(!rows))
   {
-    goto on_error;
+    PRINT_ERROR_AND_EXIT("GIF Loader: malloc failed! gifW : %d, w : %d, gifH : %d, h : %d\n", gifW, w, gifH, h);
   }
 
   // fill in the pointers at the start
@@ -695,7 +912,7 @@ bool DecodeImage(GifFileType* gif, GifCachedColorData& gifCachedColor, uint32_t*
       {
         if(DALI_UNLIKELY(DGifGetLine(gif, rows[yy], gifW) != GIF_OK))
         {
-          goto on_error;
+          PRINT_ERROR_AND_EXIT("GIF Loader: Decode failed at line %d! gifW : %d, gifH : %d, rows[yy] : %d, i : %d, intoffset[i] : %d, intjump[i] : %d\n", yy, gifW, gifH, rows[yy], i, intoffset[i], intjump[i]);
         }
       }
     }
@@ -707,7 +924,7 @@ bool DecodeImage(GifFileType* gif, GifCachedColorData& gifCachedColor, uint32_t*
     {
       if(DALI_UNLIKELY(DGifGetLine(gif, rows[yy], gifW) != GIF_OK))
       {
-        goto on_error;
+        PRINT_ERROR_AND_EXIT("GIF Loader: Decode failed at line %d! gifW : %d, gifH : %d, rows[yy] : %d\n", yy, gifW, gifH, rows[yy]);
       }
     }
   }
@@ -738,132 +955,152 @@ bool DecodeImage(GifFileType* gif, GifCachedColorData& gifCachedColor, uint32_t*
   // 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)
+    HandleTransparentPixels(fill, cachedColorPtr, xx, yy, x, y, w, h, xin, yin, rowpix, transparent, fillColor, pix, p, data, rows, colorMap);
+  }
+  else
+  {
+    HandleNonTransparentPixels(cachedColorPtr, xx, yy, x, y, w, h, xin, yin, rowpix, transparent, fillColor, pix, p, data, rows, colorMap);
+  }
+  ret = true;
+
+  if(rows)
+  {
+    free(rows);
+  }
+  return ret;
+}
+
+/// Walk through gif records in file to figure out info while reading the header
+void WalkThroughGifRecordsWhileReadingHeader(
+  const GifAccessor&     gifAccessor,
+  GifRecordType&         rec,
+  int&                   imageNumber,
+  FrameInfo*&            frameInfo,
+  bool&                  full,
+  const ImageProperties& prop,
+  GifAnimationData&      animated,
+  int&                   loopCount,
+  bool&                  success)
+{
+  do
+  {
+    if(DGifGetRecordType(gifAccessor.gif, &rec) == GIF_ERROR)
     {
-      // if we use cachedColor, use it
-      if(cachedColorPtr)
+      // 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)
       {
-        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 = cachedColorPtr[pix];
-            }
-            else
-            {
-              *p = fillColor;
-            }
-            p++;
-          }
-        }
+        success = true;
       }
-      // we don't have cachedColor. use PixelLookup function.
       else
       {
-        for(yy = 0; yy < h; yy++)
-        {
-          p = data + ((y + yy) * rowpix) + x;
-          for(xx = 0; xx < w; xx++)
-          {
-            pix = rows[yin + yy][xin + xx];
-            if(pix != transparent)
-            {
-              *p = PixelLookup(colorMap, pix);
-            }
-            else
-            {
-              *p = fillColor;
-            }
-            p++;
-          }
-        }
+        success = false;
+        DALI_LOG_ERROR("LOAD_ERROR_UNKNOWN_FORMAT\n");
       }
+      break;
     }
-    // paste on top with transparent pixels untouched
-    else
+
+    // get image description section
+    if(rec == IMAGE_DESC_RECORD_TYPE)
     {
-      // if we use cachedColor, use it
-      if(cachedColorPtr)
+      int          img_code;
+      GifByteType* img;
+
+      // get image desc
+      if(DALI_UNLIKELY(DGifGetImageDesc(gifAccessor.gif) == GIF_ERROR))
       {
-        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 = cachedColorPtr[pix];
-            }
-            p++;
-          }
-        }
+        success = false;
+        DALI_LOG_ERROR("LOAD_ERROR_UNKNOWN_FORMAT\n");
+        break;
       }
-      // we don't have cachedColor. use PixelLookup function.
+      // skip decoding and just walk image to next
+      if(DALI_UNLIKELY(DGifGetCode(gifAccessor.gif, &img_code, &img) == GIF_ERROR))
+      {
+        success = false;
+        DALI_LOG_ERROR("LOAD_ERROR_UNKNOWN_FORMAT\n");
+        break;
+      }
+      // skip till next...
+      while(img)
+      {
+        img = NULL;
+        DGifGetCodeNext(gifAccessor.gif, &img);
+      }
+      // store geometry in the last frame info data
+      if(frameInfo)
+      {
+        StoreFrameInfo(gifAccessor.gif, frameInfo);
+        CheckTransparency(full, frameInfo, prop.w, prop.h);
+      }
+      // or if we dont have a frameInfo entry - create one even for stills
       else
       {
-        for(yy = 0; yy < h; yy++)
+        // allocate and save frame with field data
+        frameInfo = NewFrame(animated, -1, 0, 0, imageNumber + 1);
+        if(DALI_UNLIKELY(!frameInfo))
         {
-          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++;
-          }
+          success = false;
+          DALI_LOG_ERROR("LOAD_ERROR_RESOURCE_ALLOCATION_FAILED");
+          break;
         }
+        // store geometry info from gif image
+        StoreFrameInfo(gifAccessor.gif, frameInfo);
+        // check for transparency/alpha
+        CheckTransparency(full, frameInfo, prop.w, prop.h);
       }
+      imageNumber++;
     }
-  }
-  else
-  {
-    // if we use cachedColor, use it
-    if(cachedColorPtr)
+    // we have an extension code block - for animated gifs for sure
+    else if(rec == EXTENSION_RECORD_TYPE)
     {
-      // walk pixels without worring about transparency at all
-      for(yy = 0; yy < h; yy++)
+      int          ext_code;
+      GifByteType* ext = NULL;
+
+      // get the first extension entry
+      DGifGetExtension(gifAccessor.gif, &ext_code, &ext);
+      while(ext)
       {
-        p = data + ((y + yy) * rowpix) + x;
-        for(xx = 0; xx < w; xx++)
+        // graphic control extension - for animated gif data
+        // and transparent index + flag
+        if(ext_code == 0xf9)
         {
-          pix = rows[yin + yy][xin + xx];
-          *p  = cachedColorPtr[pix];
-          p++;
+          // 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(DALI_UNLIKELY(!frameInfo))
+          {
+            success = false;
+            DALI_LOG_ERROR("LOAD_ERROR_RESOURCE_ALLOCATION_FAILED");
+            break;
+          }
         }
-      }
-    }
-    // we don't have cachedColor. use PixelLookup function.
-    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++)
+        // netscape extension indicating loop count.
+        else if(ext_code == 0xff) /* application extension */
         {
-          pix = rows[yin + yy][xin + xx];
-          *p  = PixelLookup(colorMap, pix);
-          p++;
+          if(!strncmp(reinterpret_cast<char*>(&ext[1]), "NETSCAPE2.0", 11) ||
+             !strncmp(reinterpret_cast<char*>(&ext[1]), "ANIMEXTS1.0", 11))
+          {
+            ext = NULL;
+            DGifGetExtensionNext(gifAccessor.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(gifAccessor.gif, &ext);
       }
     }
-  }
-  ret = true;
-
-on_error:
-  if(rows)
-  {
-    free(rows);
-  }
-  return ret;
+  } while(rec != TERMINATE_RECORD_TYPE && success);
 }
 
 /**
@@ -925,127 +1162,8 @@ bool ReadHeader(LoaderInfo&      loaderInfo,
       }
       else
       {
-        // walk through gif records in file to figure out info
         success = true;
-        do
-        {
-          if(DGifGetRecordType(gifAccessor.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)
-            {
-              success = true;
-            }
-            else
-            {
-              success = false;
-              DALI_LOG_ERROR("LOAD_ERROR_UNKNOWN_FORMAT\n");
-            }
-            break;
-          }
-
-          // get image description section
-          if(rec == IMAGE_DESC_RECORD_TYPE)
-          {
-            int          img_code;
-            GifByteType* img;
-
-            // get image desc
-            if(DALI_UNLIKELY(DGifGetImageDesc(gifAccessor.gif) == GIF_ERROR))
-            {
-              success = false;
-              DALI_LOG_ERROR("LOAD_ERROR_UNKNOWN_FORMAT\n");
-              break;
-            }
-            // skip decoding and just walk image to next
-            if(DALI_UNLIKELY(DGifGetCode(gifAccessor.gif, &img_code, &img) == GIF_ERROR))
-            {
-              success = false;
-              DALI_LOG_ERROR("LOAD_ERROR_UNKNOWN_FORMAT\n");
-              break;
-            }
-            // skip till next...
-            while(img)
-            {
-              img = NULL;
-              DGifGetCodeNext(gifAccessor.gif, &img);
-            }
-            // store geometry in the last frame info data
-            if(frameInfo)
-            {
-              StoreFrameInfo(gifAccessor.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(DALI_UNLIKELY(!frameInfo))
-              {
-                success = false;
-                DALI_LOG_ERROR("LOAD_ERROR_RESOURCE_ALLOCATION_FAILED");
-                break;
-              }
-              // store geometry info from gif image
-              StoreFrameInfo(gifAccessor.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 = NULL;
-
-            // get the first extension entry
-            DGifGetExtension(gifAccessor.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(DALI_UNLIKELY(!frameInfo))
-                {
-                  success = false;
-                  DALI_LOG_ERROR("LOAD_ERROR_RESOURCE_ALLOCATION_FAILED");
-                  break;
-                }
-              }
-              // 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(gifAccessor.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(gifAccessor.gif, &ext);
-            }
-          }
-        } while(rec != TERMINATE_RECORD_TYPE && success);
+        WalkThroughGifRecordsWhileReadingHeader(gifAccessor, rec, imageNumber, frameInfo, full, prop, animated, loopCount, success);
 
         if(success)
         {
@@ -1078,10 +1196,234 @@ bool ReadHeader(LoaderInfo&      loaderInfo,
         }
       }
     }
+    else
+    {
+      success = false;
+      DALI_LOG_ERROR("LOAD_ERROR_UNKNOWN_FORMAT\n");
+    }
   }
   return success;
 }
 
+/// Walk through gif records in file to figure out info
+bool WalkThroughGifRecords(
+  GifRecordType&         rec,
+  LoaderInfo&            loaderInfo,
+  GifAnimationData&      animated,
+  int&                   imageNumber,
+  const int&             index,
+  FrameInfo*&            frameInfo,
+  const ImageProperties& prop,
+  ImageFrame*&           lastPreservedFrame,
+  unsigned char*&        pixels)
+{
+  do
+  {
+    if(DALI_UNLIKELY(DGifGetRecordType(loaderInfo.gifAccessor->gif, &rec) == GIF_ERROR))
+    {
+      DALI_LOG_ERROR("LOAD_ERROR_UNKNOWN_FORMAT\n");
+      return false;
+    }
+
+    if(rec == EXTENSION_RECORD_TYPE)
+    {
+      int          ext_code;
+      GifByteType* ext = NULL;
+      DGifGetExtension(loaderInfo.gifAccessor->gif, &ext_code, &ext);
+
+      while(ext)
+      {
+        ext = NULL;
+        DGifGetExtensionNext(loaderInfo.gifAccessor->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(DALI_UNLIKELY(DGifGetImageDesc(loaderInfo.gifAccessor->gif) == GIF_ERROR))
+      {
+        DALI_LOG_ERROR("LOAD_ERROR_UNKNOWN_FORMAT\n");
+        return false;
+      }
+
+      // 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(DALI_UNLIKELY(!thisFrame->data))
+        {
+          DALI_LOG_ERROR("LOAD_ERROR_RESOURCE_ALLOCATION_FAILED");
+          return false;
+        }
+
+        // Lazy fill background color feature.
+        // DecodeImage function draw range is EQUAL with previous FillImage range,
+        // We don't need to fill background that time.
+        // It will try to reduce the number of FillImage API call
+        // Note : We might check overlapping. But that operation looks expensive
+        // So, just optimize only if EQUAL case.
+        bool     updateBackgroundColorLazy = false;
+        uint32_t backgroundColor           = 0u;
+        int      prevX                     = 0;
+        int      prevY                     = 0;
+        int      prevW                     = 0;
+        int      prevH                     = 0;
+
+        // if we have no prior frame OR prior frame data... empty
+        if((!previousFrame) || (!previousFrame->data))
+        {
+          first                     = true;
+          frameInfo                 = &(thisFrame->info);
+          updateBackgroundColorLazy = true;
+          backgroundColor           = 0u;
+          prevX                     = 0;
+          prevY                     = 0;
+          prevW                     = prop.w;
+          prevH                     = prop.h;
+        }
+        // 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)
+          {
+            updateBackgroundColorLazy = true;
+            backgroundColor           = GetBackgroundColor(loaderInfo.gifAccessor->gif, frameInfo);
+            prevX                     = x;
+            prevY                     = y;
+            prevW                     = w;
+            prevH                     = h;
+          }
+          else if(frameInfo->dispose == DISPOSE_PREVIOUS) // GIF_DISPOSE_RESTORE
+          {
+            int prevIndex = 2;
+            do
+            {
+              // Find last preserved frame.
+              lastPreservedFrame = FindFrame(animated, imageNumber - prevIndex);
+              if(DALI_UNLIKELY(!lastPreservedFrame))
+              {
+                DALI_LOG_ERROR("LOAD_ERROR_LAST_PRESERVED_FRAME_NOT_FOUND");
+                return false;
+              }
+              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(updateBackgroundColorLazy)
+        {
+          // If this frame's x,y,w,h is not equal with previous x,y,w,h, FillImage. else, don't fill
+          if(prevX != x || prevY != y || prevW != w || prevH != h)
+          {
+            FillImage(thisFrame->data, prop.w, backgroundColor, prevX, prevY, prevW, prevH);
+            // Don't send background color information to DecodeImage function.
+            updateBackgroundColorLazy = false;
+          }
+        }
+        if(DALI_UNLIKELY(!DecodeImage(loaderInfo.gifAccessor->gif, loaderInfo.cachedColor, thisFrame->data, prop.w, xin, yin, frameInfo->transparent, x, y, w, h, first || updateBackgroundColorLazy, backgroundColor)))
+        {
+          DALI_LOG_ERROR("LOAD_ERROR_CORRUPT_FILE\n");
+          return false;
+        }
+
+        // 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 only if x,y,w,h is not whole image.
+          if(x != 0 || y != 0 || w != static_cast<int>(prop.w) || h != static_cast<int>(prop.h))
+          {
+            const std::uint32_t backgroundColor = GetBackgroundColor(loaderInfo.gifAccessor->gif, frameInfo);
+            FillImage(reinterpret_cast<uint32_t*>(pixels), prop.w, backgroundColor, 0, 0, prop.w, prop.h);
+          }
+
+          // and decode the gif with overwriting
+          if(DALI_UNLIKELY(!DecodeImage(loaderInfo.gifAccessor->gif, loaderInfo.cachedColor, reinterpret_cast<uint32_t*>(pixels), prop.w, xin, yin, frameInfo->transparent, x, y, w, h, true, 0u)))
+          {
+            DALI_LOG_ERROR("LOAD_ERROR_CORRUPT_FILE\n");
+            return false;
+          }
+
+          // 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(DALI_UNLIKELY(DGifGetCode(loaderInfo.gifAccessor->gif, &img_code, &img) == GIF_ERROR))
+        {
+          DALI_LOG_ERROR("LOAD_ERROR_UNKNOWN_FORMAT\n");
+          return false;
+        }
+
+        while(img)
+        {
+          img = NULL;
+          DGifGetCodeNext(loaderInfo.gifAccessor->gif, &img);
+        }
+      }
+
+      imageNumber++;
+      // if we found the image we wanted - get out of here
+      if(imageNumber > index)
+      {
+        break;
+      }
+    }
+  } while(rec != TERMINATE_RECORD_TYPE);
+
+  return true;
+}
+
 /**
  * @brief Reader next frame of the gif file and populates structures accordingly.
  *
@@ -1158,210 +1500,10 @@ bool ReadNextFrame(LoaderInfo& loaderInfo, ImageProperties& prop, //  use for w
     // 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(!WalkThroughGifRecords(rec, loaderInfo, animated, imageNumber, index, frameInfo, prop, lastPreservedFrame, pixels))
     {
-      if(DALI_UNLIKELY(DGifGetRecordType(loaderInfo.gifAccessor->gif, &rec) == GIF_ERROR))
-      {
-        DALI_LOG_ERROR("LOAD_ERROR_UNKNOWN_FORMAT\n");
-        return false;
-      }
-
-      if(rec == EXTENSION_RECORD_TYPE)
-      {
-        int          ext_code;
-        GifByteType* ext = NULL;
-        DGifGetExtension(loaderInfo.gifAccessor->gif, &ext_code, &ext);
-
-        while(ext)
-        {
-          ext = NULL;
-          DGifGetExtensionNext(loaderInfo.gifAccessor->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(DALI_UNLIKELY(DGifGetImageDesc(loaderInfo.gifAccessor->gif) == GIF_ERROR))
-        {
-          DALI_LOG_ERROR("LOAD_ERROR_UNKNOWN_FORMAT\n");
-          return false;
-        }
-
-        // 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(DALI_UNLIKELY(!thisFrame->data))
-          {
-            DALI_LOG_ERROR("LOAD_ERROR_RESOURCE_ALLOCATION_FAILED");
-            return false;
-          }
-
-          // Lazy fill background color feature.
-          // DecodeImage function draw range is EQUAL with previous FillImage range,
-          // We don't need to fill background that time.
-          // It will try to reduce the number of FillImage API call
-          // Note : We might check overlapping. But that operation looks expensive
-          // So, just optimize only if EQUAL case.
-          bool     updateBackgroundColorLazy = false;
-          uint32_t backgroundColor           = 0u;
-          int      prevX                     = 0;
-          int      prevY                     = 0;
-          int      prevW                     = 0;
-          int      prevH                     = 0;
-
-          // if we have no prior frame OR prior frame data... empty
-          if((!previousFrame) || (!previousFrame->data))
-          {
-            first                     = true;
-            frameInfo                 = &(thisFrame->info);
-            updateBackgroundColorLazy = true;
-            backgroundColor           = 0u;
-            prevX                     = 0;
-            prevY                     = 0;
-            prevW                     = prop.w;
-            prevH                     = prop.h;
-          }
-          // 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)
-            {
-              updateBackgroundColorLazy = true;
-              backgroundColor           = GetBackgroundColor(loaderInfo.gifAccessor->gif, frameInfo);
-              prevX                     = x;
-              prevY                     = y;
-              prevW                     = w;
-              prevH                     = h;
-            }
-            else if(frameInfo->dispose == DISPOSE_PREVIOUS) // GIF_DISPOSE_RESTORE
-            {
-              int prevIndex = 2;
-              do
-              {
-                // Find last preserved frame.
-                lastPreservedFrame = FindFrame(animated, imageNumber - prevIndex);
-                if(DALI_UNLIKELY(!lastPreservedFrame))
-                {
-                  DALI_LOG_ERROR("LOAD_ERROR_LAST_PRESERVED_FRAME_NOT_FOUND");
-                  return false;
-                }
-                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(updateBackgroundColorLazy)
-          {
-            // If this frame's x,y,w,h is not equal with previous x,y,w,h, FillImage. else, don't fill
-            if(prevX != x || prevY != y || prevW != w || prevH != h)
-            {
-              FillImage(thisFrame->data, prop.w, backgroundColor, prevX, prevY, prevW, prevH);
-              // Don't send background color information to DecodeImage function.
-              updateBackgroundColorLazy = false;
-            }
-          }
-          if(DALI_UNLIKELY(!DecodeImage(loaderInfo.gifAccessor->gif, loaderInfo.cachedColor, thisFrame->data, prop.w, xin, yin, frameInfo->transparent, x, y, w, h, first || updateBackgroundColorLazy, backgroundColor)))
-          {
-            DALI_LOG_ERROR("LOAD_ERROR_CORRUPT_FILE\n");
-            return false;
-          }
-
-          // 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 only if x,y,w,h is not whole image.
-            if(x != 0 || y != 0 || w != static_cast<int>(prop.w) || h != static_cast<int>(prop.h))
-            {
-              const std::uint32_t backgroundColor = GetBackgroundColor(loaderInfo.gifAccessor->gif, frameInfo);
-              FillImage(reinterpret_cast<uint32_t*>(pixels), prop.w, backgroundColor, 0, 0, prop.w, prop.h);
-            }
-
-            // and decode the gif with overwriting
-            if(DALI_UNLIKELY(!DecodeImage(loaderInfo.gifAccessor->gif, loaderInfo.cachedColor, reinterpret_cast<uint32_t*>(pixels), prop.w, xin, yin, frameInfo->transparent, x, y, w, h, true, 0u)))
-            {
-              DALI_LOG_ERROR("LOAD_ERROR_CORRUPT_FILE\n");
-              return false;
-            }
-
-            // 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(DALI_UNLIKELY(DGifGetCode(loaderInfo.gifAccessor->gif, &img_code, &img) == GIF_ERROR))
-          {
-            DALI_LOG_ERROR("LOAD_ERROR_UNKNOWN_FORMAT\n");
-            return false;
-          }
-
-          while(img)
-          {
-            img = NULL;
-            DGifGetCodeNext(loaderInfo.gifAccessor->gif, &img);
-          }
-        }
-
-        imageNumber++;
-        // if we found the image we wanted - get out of here
-        if(imageNumber > index)
-        {
-          break;
-        }
-      }
-    } while(rec != TERMINATE_RECORD_TYPE);
+      return false;
+    }
 
     // if we are at the end of the animation or not animated, close file
     loaderInfo.imageNumber = imageNumber;
@@ -1396,7 +1538,7 @@ public:
     mLoadSucceeded(false),
     mMutex()
   {
-    loaderInfo.gifAccessor = nullptr;
+    loaderInfo.gifAccessor              = nullptr;
     loaderInfo.fileData.fileName        = mUrl.c_str();
     loaderInfo.fileData.isLocalResource = isLocalResource;
   }
@@ -1411,6 +1553,10 @@ public:
     }
 
     mLoadSucceeded = ReadHeader(loaderInfo, imageProperties);
+    if(!mLoadSucceeded)
+    {
+      DALI_LOG_ERROR("ReadHeader is failed [%s]\n", mUrl.c_str());
+    }
     return mLoadSucceeded;
   }
 
@@ -1442,7 +1588,7 @@ GifLoading::~GifLoading()
   delete mImpl;
 }
 
-Dali::Devel::PixelBuffer GifLoading::LoadFrame(uint32_t frameIndex)
+Dali::Devel::PixelBuffer GifLoading::LoadFrame(uint32_t frameIndex, ImageDimensions desiredSize)
 {
   int                      error;
   Dali::Devel::PixelBuffer pixelBuffer;