X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali%2Finternal%2Fimaging%2Fcommon%2Fgif-loading.cpp;h=a3f34f0424f06d075f1b1db7a414303bc44f4f80;hb=3ff3d757a67b27cd14340e6fbd1cc4035d2cde8c;hp=6b0d709435cb8e915b2d059b55c5d4bd719bd52d;hpb=d4b5e04ef254fa25f7672bacb9cb0923a040d0ac;p=platform%2Fcore%2Fuifw%2Fdali-adaptor.git diff --git a/dali/internal/imaging/common/gif-loading.cpp b/dali/internal/imaging/common/gif-loading.cpp index 6b0d709..a3f34f0 100644 --- a/dali/internal/imaging/common/gif-loading.cpp +++ b/dali/internal/imaging/common/gif-loading.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -60,6 +61,8 @@ Debug::Filter* gGifLoadingLogFilter = Debug::Filter::New(Debug::NoLogging, false const int IMG_MAX_SIZE = 65000; constexpr size_t MAXIMUM_DOWNLOAD_IMAGE_SIZE = 50 * 1024 * 1024; +constexpr int LOCAL_CACHED_COLOR_GENERATE_THRESHOLD = 16; ///< Generate color map optimize only if colorCount * threshold < width * height, So we don't loop if image is small + #if GIFLIB_MAJOR < 5 const int DISPOSE_BACKGROUND = 2; /* Set area too background color */ const int DISPOSE_PREVIOUS = 3; /* Restore to previous content */ @@ -130,6 +133,16 @@ struct GifAnimationData bool animated; }; +struct GifCachedColorData +{ + GifCachedColorData() = default; + + // precalculated colormap table + std::vector globalCachedColor{}; + std::vector localCachedColor{}; + ColorMapObject* localCachedColorMap{nullptr}; // Weak-pointer of ColorMapObject. should be nullptr if image changed +}; + // Forward declaration struct GifAccessor; @@ -186,6 +199,7 @@ struct LoaderInfo FileData fileData; GifAnimationData animated; + GifCachedColorData cachedColor; std::unique_ptr gifAccessor{nullptr}; int imageNumber{0}; FileInfo fileInfo; @@ -246,7 +260,7 @@ struct GifAccessor { LoaderInfo::FileInfo* fi = reinterpret_cast(gifFileType->UserData); - if(fi->position >= fi->length) + if(DALI_UNLIKELY(fi->position >= fi->length)) { return 0; // if at or past end - no } @@ -280,23 +294,23 @@ bool LoaderInfo::FileData::LoadLocalFile() { Internal::Platform::FileReader fileReader(fileName); FILE* fp = fileReader.GetFile(); - if(fp == NULL) + if(DALI_UNLIKELY(fp == NULL)) { return false; } - if(fseek(fp, 0, SEEK_END) <= -1) + if(DALI_UNLIKELY(fseek(fp, 0, SEEK_END) <= -1)) { return false; } length = ftell(fp); - if(length <= -1) + if(DALI_UNLIKELY(length <= -1)) { return false; } - if((!fseek(fp, 0, SEEK_SET))) + if(DALI_LIKELY(!fseek(fp, 0, SEEK_SET))) { globalMap = reinterpret_cast(malloc(sizeof(GifByteType) * length)); length = fread(globalMap, sizeof(GifByteType), length, fp); @@ -316,17 +330,17 @@ bool LoaderInfo::FileData::LoadRemoteFile() size_t dataSize; succeeded = TizenPlatform::Network::DownloadRemoteFileIntoMemory(fileName, dataBuffer, dataSize, MAXIMUM_DOWNLOAD_IMAGE_SIZE); - if(succeeded) + if(DALI_LIKELY(succeeded)) { size_t blobSize = dataBuffer.Size(); - if(blobSize > 0U) + if(DALI_LIKELY(blobSize > 0U)) { // Open a file handle on the memory buffer: Dali::Internal::Platform::FileReader fileReader(dataBuffer, blobSize); FILE* const fp = fileReader.GetFile(); - if(NULL != fp) + if(DALI_LIKELY(NULL != fp)) { - if((!fseek(fp, 0, SEEK_SET))) + if(DALI_LIKELY(!fseek(fp, 0, SEEK_SET))) { globalMap = reinterpret_cast(malloc(sizeof(GifByteType) * blobSize)); length = fread(globalMap, sizeof(GifByteType), blobSize, fp); @@ -354,12 +368,12 @@ bool LoaderInfo::FileData::LoadRemoteFile() * @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) +inline std::uint32_t CombinePixelABGR(const std::uint32_t& a, const std::uint32_t& r, const std::uint32_t& g, const std::uint32_t& b) { return (((a) << 24) + ((b) << 16) + ((g) << 8) + (r)); } -inline int PixelLookup(ColorMapObject* colorMap, int index) +inline std::uint32_t PixelLookup(const ColorMapObject* const& colorMap, int index) { return CombinePixelABGR(0xFF, colorMap->Colors[index].Red, colorMap->Colors[index].Green, colorMap->Colors[index].Blue); } @@ -387,25 +401,47 @@ ImageFrame* FindFrame(const GifAnimationData& animated, int index) * @brief Fill in an image with a specific rgba color value. * * @param[in] data A pointer pointing to an image data - * @param[in] row A int containing the number of rows in an image + * @param[in] stride A int containing the number of stride in an image * @param[in] val A uint32_t containing rgba color value * @param[in] x X-coordinate used an offset to calculate pixel position * @param[in] y Y-coordinate used an offset to calculate pixel position * @param[in] width Width of the image * @param[in] height Height of the image */ -void FillImage(uint32_t* data, int row, uint32_t val, int x, int y, int width, int height) +void FillImage(uint32_t* data, int stride, uint32_t val, int x, int y, int width, int height) { - int xAxis, yAxis; uint32_t* pixelPosition; - for(yAxis = 0; yAxis < height; yAxis++) + // Boost time if stride == width and x == 0. We can assume that all pointer is continuous. + if(x == 0 && stride == width) { - pixelPosition = data + ((y + yAxis) * row) + x; - for(xAxis = 0; xAxis < width; xAxis++) + pixelPosition = data + (y * stride); + // Clear as white or transparent + // Special case. we can use memset. + if(val == 0x00 || val == 0xffffffffu) + { + const std::int8_t setupVal = val & 0xff; + memset(pixelPosition, setupVal, width * height * sizeof(std::uint32_t)); + } + else { - *pixelPosition = val; - pixelPosition++; + for(int byteCount = 0; byteCount < width * height; ++byteCount) + { + *pixelPosition = val; + ++pixelPosition; + } + } + } + else + { + for(int yAxis = 0; yAxis < height; ++yAxis) + { + pixelPosition = data + ((y + yAxis) * stride) + x; + for(int xAxis = 0; xAxis < width; ++xAxis) + { + *pixelPosition = val; + ++pixelPosition; + } } } } @@ -414,7 +450,7 @@ void FillImage(uint32_t* data, int row, uint32_t val, int x, int y, int width, i * @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] stride A int containing the number of stride 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 @@ -422,7 +458,7 @@ void FillImage(uint32_t* data, int row, uint32_t val, int x, int y, int width, i * @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) +void FillFrame(uint32_t* data, int stride, GifFileType* gif, FrameInfo* frameInfo, int x, int y, int w, int h) { // solid color fill for pre frame region if(frameInfo->transparent < 0) @@ -441,12 +477,12 @@ void FillFrame(uint32_t* data, int row, GifFileType* gif, FrameInfo* frameInfo, } 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); + FillImage(data, stride, 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); + FillImage(data, stride, 0, x, y, w, h); } } @@ -616,7 +652,7 @@ FrameInfo* NewFrame(GifAnimationData& animated, int transparent, int dispose, in * @brief Decode a gif image into rows then expand to 32bit into the destination * data pointer. */ -bool DecodeImage(GifFileType* gif, uint32_t* data, int rowpix, int xin, int yin, int transparent, int x, int y, int w, int h, bool fill) +bool DecodeImage(GifFileType* gif, GifCachedColorData& gifCachedColor, uint32_t* data, int rowpix, int xin, int yin, int transparent, int x, int y, int w, int h, bool fill) { int intoffset[] = {0, 4, 2, 1}; int intjump[] = {8, 8, 4, 2}; @@ -626,6 +662,9 @@ bool DecodeImage(GifFileType* gif, uint32_t* data, int rowpix, int xin, int yin, ColorMapObject* colorMap; uint32_t* p; + // cached color data. + const std::uint32_t* cachedColorPtr = nullptr; + // what we need is image size. SavedImage* sp; sp = &gif->SavedImages[gif->ImageCount - 1]; @@ -633,7 +672,7 @@ bool DecodeImage(GifFileType* gif, uint32_t* data, int rowpix, int xin, int yin, gifW = sp->ImageDesc.Width; gifH = sp->ImageDesc.Height; - if((gifW < w) || (gifH < h)) + if(DALI_UNLIKELY((gifW < w) || (gifH < h))) { DALI_LOG_ERROR("gifW : %d, w : %d, gifH : %d, h : %d\n", gifW, w, gifH, h); DALI_ASSERT_DEBUG(false && "Dimensions are bigger than the Gif image size"); @@ -643,7 +682,7 @@ bool DecodeImage(GifFileType* gif, uint32_t* data, int rowpix, int xin, int yin, // 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(malloc((gifH * sizeof(GifRowType)) + (gifW * gifH * sizeof(GifPixelType)))); - if(!rows) + if(DALI_UNLIKELY(!rows)) { goto on_error; } @@ -661,7 +700,7 @@ bool DecodeImage(GifFileType* gif, uint32_t* data, int rowpix, int xin, int yin, { for(yy = intoffset[i]; yy < gifH; yy += intjump[i]) { - if(DGifGetLine(gif, rows[yy], gifW) != GIF_OK) + if(DALI_UNLIKELY(DGifGetLine(gif, rows[yy], gifW) != GIF_OK)) { goto on_error; } @@ -673,7 +712,7 @@ bool DecodeImage(GifFileType* gif, uint32_t* data, int rowpix, int xin, int yin, { for(yy = 0; yy < gifH; yy++) { - if(DGifGetLine(gif, rows[yy], gifW) != GIF_OK) + if(DALI_UNLIKELY(DGifGetLine(gif, rows[yy], gifW) != GIF_OK)) { goto on_error; } @@ -684,65 +723,149 @@ bool DecodeImage(GifFileType* gif, uint32_t* data, int rowpix, int xin, int yin, if(gif->Image.ColorMap) { colorMap = gif->Image.ColorMap; + // use local cached color map without re-calculate cache. + if(gifCachedColor.localCachedColorMap == colorMap) + { + cachedColorPtr = gifCachedColor.localCachedColor.data(); + } + // else if w * h is big enough, generate local cached color. + else if(colorMap->ColorCount * LOCAL_CACHED_COLOR_GENERATE_THRESHOLD < w * h) + { + gifCachedColor.localCachedColor.resize(colorMap->ColorCount); + for(i = 0; i < colorMap->ColorCount; ++i) + { + gifCachedColor.localCachedColor[i] = PixelLookup(colorMap, i); + } + gifCachedColor.localCachedColorMap = colorMap; + + cachedColorPtr = gifCachedColor.localCachedColor.data(); + } } else { - colorMap = gif->SColorMap; + colorMap = gif->SColorMap; + cachedColorPtr = gifCachedColor.globalCachedColor.data(); } + // HARD-CODING optimize // 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++) + // if we use cachedColor, use it + if(cachedColorPtr) { - p = data + ((y + yy) * rowpix) + x; - for(xx = 0; xx < w; xx++) + for(yy = 0; yy < h; yy++) { - pix = rows[yin + yy][xin + xx]; - if(pix != transparent) + p = data + ((y + yy) * rowpix) + x; + for(xx = 0; xx < w; xx++) { - *p = PixelLookup(colorMap, pix); + pix = rows[yin + yy][xin + xx]; + if(pix != transparent) + { + *p = cachedColorPtr[pix]; + } + else + { + *p = 0; + } + p++; } - else + } + } + // 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++) { - *p = 0; + pix = rows[yin + yy][xin + xx]; + if(pix != transparent) + { + *p = PixelLookup(colorMap, pix); + } + else + { + *p = 0; + } + p++; } - p++; } } } // paste on top with transparent pixels untouched else { - for(yy = 0; yy < h; yy++) + // if we use cachedColor, use it + if(cachedColorPtr) { - p = data + ((y + yy) * rowpix) + x; - for(xx = 0; xx < w; xx++) + for(yy = 0; yy < h; yy++) { - pix = rows[yin + yy][xin + xx]; - if(pix != transparent) + p = data + ((y + yy) * rowpix) + x; + for(xx = 0; xx < w; xx++) { - *p = PixelLookup(colorMap, pix); + 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++; } - p++; } } } } else { - // walk pixels without worring about transparency at all - for(yy = 0; yy < h; yy++) + // if we use cachedColor, use it + if(cachedColorPtr) { - p = data + ((y + yy) * rowpix) + x; - for(xx = 0; xx < w; xx++) + // walk pixels without worring about transparency at all + for(yy = 0; yy < h; yy++) { - pix = rows[yin + yy][xin + xx]; - *p = PixelLookup(colorMap, pix); - p++; + 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++; + } } } } @@ -768,9 +891,10 @@ bool ReadHeader(LoaderInfo& loaderInfo, ImageProperties& prop, //output struct int* error) { - GifAnimationData& animated = loaderInfo.animated; - LoaderInfo::FileData& fileData = loaderInfo.fileData; - bool success = false; + GifAnimationData& animated = loaderInfo.animated; + GifCachedColorData& cachedColor = loaderInfo.cachedColor; + LoaderInfo::FileData& fileData = loaderInfo.fileData; + bool success = false; LoaderInfo::FileInfo fileInfo; GifRecordType rec; @@ -782,7 +906,7 @@ bool ReadHeader(LoaderInfo& loaderInfo, bool full = true; success = fileData.LoadFile(); - if(!success || !fileData.globalMap) + if(DALI_UNLIKELY(!success || !fileData.globalMap)) { success = false; DALI_LOG_ERROR("LOAD_ERROR_CORRUPT_FILE\n"); @@ -801,7 +925,7 @@ bool ReadHeader(LoaderInfo& loaderInfo, prop.h = gifAccessor.gif->SHeight; // if size is invalid - abort here - if((prop.w < 1) || (prop.h < 1) || (prop.w > IMG_MAX_SIZE) || (prop.h > IMG_MAX_SIZE) || IMG_TOO_BIG(prop.w, prop.h)) + if(DALI_UNLIKELY((prop.w < 1) || (prop.h < 1) || (prop.w > IMG_MAX_SIZE) || (prop.h > IMG_MAX_SIZE) || IMG_TOO_BIG(prop.w, prop.h))) { if(IMG_TOO_BIG(prop.w, prop.h)) { @@ -843,14 +967,14 @@ bool ReadHeader(LoaderInfo& loaderInfo, GifByteType* img; // get image desc - if(DGifGetImageDesc(gifAccessor.gif) == GIF_ERROR) + if(DALI_UNLIKELY(DGifGetImageDesc(gifAccessor.gif) == GIF_ERROR)) { success = false; DALI_LOG_ERROR("LOAD_ERROR_UNKNOWN_FORMAT\n"); break; } // skip decoding and just walk image to next - if(DGifGetCode(gifAccessor.gif, &img_code, &img) == GIF_ERROR) + if(DALI_UNLIKELY(DGifGetCode(gifAccessor.gif, &img_code, &img) == GIF_ERROR)) { success = false; DALI_LOG_ERROR("LOAD_ERROR_UNKNOWN_FORMAT\n"); @@ -873,7 +997,7 @@ bool ReadHeader(LoaderInfo& loaderInfo, { // allocate and save frame with field data frameInfo = NewFrame(animated, -1, 0, 0, imageNumber + 1); - if(!frameInfo) + if(DALI_UNLIKELY(!frameInfo)) { success = false; DALI_LOG_ERROR("LOAD_ERROR_RESOURCE_ALLOCATION_FAILED"); @@ -905,7 +1029,7 @@ bool ReadHeader(LoaderInfo& loaderInfo, int disposeMode = (ext[1] >> 2) & 0x7; int delay = (int(ext[3]) << 8) | int(ext[2]); frameInfo = NewFrame(animated, transparencyIndex, disposeMode, delay, imageNumber + 1); - if(!frameInfo) + if(DALI_UNLIKELY(!frameInfo)) { success = false; DALI_LOG_ERROR("LOAD_ERROR_RESOURCE_ALLOCATION_FAILED"); @@ -956,6 +1080,18 @@ bool ReadHeader(LoaderInfo& loaderInfo, animated.currentFrame = 1; + // cache global color map + ColorMapObject* colorMap = gifAccessor.gif->SColorMap; + if(colorMap) + { + cachedColor.globalCachedColor.resize(colorMap->ColorCount); + for(int i = 0; i < colorMap->ColorCount; ++i) + { + cachedColor.globalCachedColor[i] = PixelLookup(colorMap, i); + } + } + cachedColor.localCachedColorMap = nullptr; + // no errors in header scan etc. so set err and return value *error = 0; } @@ -990,7 +1126,7 @@ bool ReadNextFrame(LoaderInfo& loaderInfo, ImageProperties& prop, // use for w index = animated.currentFrame; // if index is invalid for animated image - error out - if((animated.animated) && ((index <= 0) || (index > animated.frameCount))) + if(DALI_UNLIKELY((animated.animated) && ((index <= 0) || (index > animated.frameCount)))) { DALI_LOG_ERROR("LOAD_ERROR_GENERIC"); return false; @@ -998,7 +1134,7 @@ bool ReadNextFrame(LoaderInfo& loaderInfo, ImageProperties& prop, // use for w // find the given frame index frame = FindFrame(animated, index); - if(!frame) + if(DALI_UNLIKELY(!frame)) { DALI_LOG_ERROR("LOAD_ERROR_CORRUPT_FILE\n"); return false; @@ -1023,13 +1159,13 @@ bool ReadNextFrame(LoaderInfo& loaderInfo, ImageProperties& prop, // use for w loaderInfo.fileInfo.map = fileData.globalMap; loaderInfo.fileInfo.length = fileData.length; loaderInfo.fileInfo.position = 0; - if(!loaderInfo.fileInfo.map) + if(DALI_UNLIKELY(!loaderInfo.fileInfo.map)) { DALI_LOG_ERROR("LOAD_ERROR_CORRUPT_FILE\n"); return false; } std::unique_ptr gifAccessor = std::make_unique(loaderInfo.fileInfo); - if(!gifAccessor->gif) + if(DALI_UNLIKELY(!gifAccessor->gif)) { DALI_LOG_ERROR("LOAD_ERROR_UNKNOWN_FORMAT\n"); return false; @@ -1044,7 +1180,7 @@ bool ReadNextFrame(LoaderInfo& loaderInfo, ImageProperties& prop, // use for w // walk through gif records in file to figure out info do { - if(DGifGetRecordType(loaderInfo.gifAccessor->gif, &rec) == GIF_ERROR) + if(DALI_UNLIKELY(DGifGetRecordType(loaderInfo.gifAccessor->gif, &rec) == GIF_ERROR)) { DALI_LOG_ERROR("LOAD_ERROR_UNKNOWN_FORMAT\n"); return false; @@ -1072,7 +1208,7 @@ bool ReadNextFrame(LoaderInfo& loaderInfo, ImageProperties& prop, // use for w ImageFrame* thisFrame = NULL; // get image desc - if(DGifGetImageDesc(loaderInfo.gifAccessor->gif) == GIF_ERROR) + if(DALI_UNLIKELY(DGifGetImageDesc(loaderInfo.gifAccessor->gif) == GIF_ERROR)) { DALI_LOG_ERROR("LOAD_ERROR_UNKNOWN_FORMAT\n"); return false; @@ -1090,7 +1226,7 @@ bool ReadNextFrame(LoaderInfo& loaderInfo, ImageProperties& prop, // use for w // allocate it thisFrame->data = new uint32_t[prop.w * prop.h]; - if(!thisFrame->data) + if(DALI_UNLIKELY(!thisFrame->data)) { DALI_LOG_ERROR("LOAD_ERROR_RESOURCE_ALLOCATION_FAILED"); return false; @@ -1129,7 +1265,7 @@ bool ReadNextFrame(LoaderInfo& loaderInfo, ImageProperties& prop, // use for w { // Find last preserved frame. lastPreservedFrame = FindFrame(animated, imageNumber - prevIndex); - if(!lastPreservedFrame) + if(DALI_UNLIKELY(!lastPreservedFrame)) { DALI_LOG_ERROR("LOAD_ERROR_LAST_PRESERVED_FRAME_NOT_FOUND"); return false; @@ -1146,7 +1282,7 @@ bool ReadNextFrame(LoaderInfo& loaderInfo, ImageProperties& prop, // use for w // now draw this frame on top frameInfo = &(thisFrame->info); ClipCoordinates(prop.w, prop.h, &xin, &yin, frameInfo->x, frameInfo->y, frameInfo->w, frameInfo->h, &x, &y, &w, &h); - if(!DecodeImage(loaderInfo.gifAccessor->gif, thisFrame->data, prop.w, xin, yin, frameInfo->transparent, x, y, w, h, first)) + if(DALI_UNLIKELY(!DecodeImage(loaderInfo.gifAccessor->gif, loaderInfo.cachedColor, thisFrame->data, prop.w, xin, yin, frameInfo->transparent, x, y, w, h, first))) { DALI_LOG_ERROR("LOAD_ERROR_CORRUPT_FILE\n"); return false; @@ -1172,7 +1308,7 @@ bool ReadNextFrame(LoaderInfo& loaderInfo, ImageProperties& prop, // use for w FillFrame(reinterpret_cast(pixels), prop.w, loaderInfo.gifAccessor->gif, frameInfo, 0, 0, prop.w, prop.h); // and decode the gif with overwriting - if(!DecodeImage(loaderInfo.gifAccessor->gif, reinterpret_cast(pixels), prop.w, xin, yin, frameInfo->transparent, x, y, w, h, true)) + if(DALI_UNLIKELY(!DecodeImage(loaderInfo.gifAccessor->gif, loaderInfo.cachedColor, reinterpret_cast(pixels), prop.w, xin, yin, frameInfo->transparent, x, y, w, h, true))) { DALI_LOG_ERROR("LOAD_ERROR_CORRUPT_FILE\n"); return false; @@ -1186,7 +1322,7 @@ bool ReadNextFrame(LoaderInfo& loaderInfo, ImageProperties& prop, // use for w else { // skip decoding and just walk image to next - if(DGifGetCode(loaderInfo.gifAccessor->gif, &img_code, &img) == GIF_ERROR) + if(DALI_UNLIKELY(DGifGetCode(loaderInfo.gifAccessor->gif, &img_code, &img) == GIF_ERROR)) { DALI_LOG_ERROR("LOAD_ERROR_UNKNOWN_FORMAT\n"); return false; @@ -1238,7 +1374,8 @@ struct GifLoading::Impl public: Impl(const std::string& url, bool isLocalResource) : mUrl(url), - mLoadSucceeded(true) + mLoadSucceeded(true), + mMutex() { loaderInfo.gifAccessor = nullptr; int error; @@ -1258,6 +1395,7 @@ public: LoaderInfo loaderInfo; ImageProperties imageProperties; bool mLoadSucceeded; + Mutex mMutex; }; AnimatedImageLoadingPtr GifLoading::New(const std::string& url, bool isLocalResource) @@ -1279,7 +1417,9 @@ bool GifLoading::LoadNextNFrames(uint32_t frameStartIndex, int count, std::vecto { int error; bool ret = false; - if(!mImpl->mLoadSucceeded) + + Mutex::ScopedLock lock(mImpl->mMutex); + if(DALI_UNLIKELY(!mImpl->mLoadSucceeded)) { return false; } @@ -1316,6 +1456,7 @@ Dali::Devel::PixelBuffer GifLoading::LoadFrame(uint32_t frameIndex) return pixelBuffer; } + Mutex::ScopedLock lock(mImpl->mMutex); DALI_LOG_INFO(gGifLoadingLogFilter, Debug::Concise, "LoadFrame( frameIndex:%d )\n", frameIndex); pixelBuffer = Dali::Devel::PixelBuffer::New(mImpl->imageProperties.w, mImpl->imageProperties.h, Dali::Pixel::RGBA8888);