Merge "[AT-SPI] Rework intercepting key events" into devel/master
[platform/core/uifw/dali-adaptor.git] / dali / internal / imaging / common / loader-jpeg-turbo.cpp
index 2911341..86daa1f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023 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.
@@ -56,7 +56,10 @@ const char* CHROMINANCE_SUBSAMPLING_OPTIONS_ENV[] = {"DALI_ENABLE_DECODE_JPEG_TO
                                                      "DALI_ENABLE_DECODE_JPEG_TO_YUV_420",
                                                      "",
                                                      "DALI_ENABLE_DECODE_JPEG_TO_YUV_440",
-                                                     "DALI_ENABLE_DECODE_JPEG_TO_YUV_411"};
+                                                     "DALI_ENABLE_DECODE_JPEG_TO_YUV_411",
+                                                     "DALI_ENABLE_DECODE_JPEG_TO_YUV_441"};
+
+const int CHROMINANCE_SUBSAMPLING_OPTIONS_ENV_COUNT = sizeof(CHROMINANCE_SUBSAMPLING_OPTIONS_ENV) / sizeof(CHROMINANCE_SUBSAMPLING_OPTIONS_ENV[0]);
 
 static bool gSubsamplingFormatTable[TJ_NUMSAMP] = {
   false,
@@ -93,14 +96,20 @@ static bool IsSubsamplingFormatEnabled(int chrominanceSubsampling)
   {
     for(int i = 0; i < TJ_NUMSAMP; i++)
     {
-      auto valueString           = Dali::EnvironmentVariable::GetEnvironmentVariable(CHROMINANCE_SUBSAMPLING_OPTIONS_ENV[i]);
+      const char* envName        = DALI_LIKELY(i < CHROMINANCE_SUBSAMPLING_OPTIONS_ENV_COUNT) ? CHROMINANCE_SUBSAMPLING_OPTIONS_ENV[i] : "";
+      auto        valueString    = Dali::EnvironmentVariable::GetEnvironmentVariable(envName);
       gSubsamplingFormatTable[i] = valueString ? std::atoi(valueString) : false;
     }
 
     gIsSubsamplingFormatTableInitialized = true;
   }
 
-  return gSubsamplingFormatTable[chrominanceSubsampling];
+  if(DALI_UNLIKELY(chrominanceSubsampling >= TJ_NUMSAMP))
+  {
+    DALI_LOG_WARNING("WARNING! Input subsampling value [%d] is bigger than turbojpeg library support [%d]\n", chrominanceSubsampling, TJ_NUMSAMP);
+  }
+
+  return chrominanceSubsampling < TJ_NUMSAMP ? gSubsamplingFormatTable[chrominanceSubsampling] : false;
 }
 
 /**
@@ -885,7 +894,7 @@ bool DecodeJpeg(const Dali::ImageLoader::Input& input, std::vector<Dali::Devel::
       auto planeSize = tjPlaneSizeYUV(i, scaledPostXformWidth, 0, scaledPostXformHeight, chrominanceSubsampling);
 
       uint8_t* buffer = static_cast<uint8_t*>(malloc(planeSize));
-      if(!buffer)
+      if(DALI_UNLIKELY(!buffer))
       {
         DALI_LOG_ERROR("Buffer allocation is failed [%d]\n", planeSize);
         pixelBuffers.clear();
@@ -973,6 +982,12 @@ bool DecodeJpeg(const Dali::ImageLoader::Input& input, std::vector<Dali::Devel::
 
       uint8_t* cmykBuffer = static_cast<uint8_t*>(malloc(sizeof(uint8_t) * scaledPostXformWidth * scaledPostXformHeight * cmykBytesPerPixel));
 
+      if(DALI_UNLIKELY(!cmykBuffer))
+      {
+        DALI_LOG_ERROR("cmykBuffer allocation is failed [%zu]\n", sizeof(uint8_t) * scaledPostXformWidth * scaledPostXformHeight * cmykBytesPerPixel);
+        return false;
+      }
+
       decodeResult = tjDecompress2(jpeg.get(), jpegBufferPtr, jpegBufferSize, reinterpret_cast<uint8_t*>(cmykBuffer), scaledPreXformWidth, 0, scaledPreXformHeight, pixelLibJpegType, flags);
       if(DALI_UNLIKELY(decodeResult == -1 && IsJpegDecodingFailed()))
       {
@@ -1013,6 +1028,11 @@ bool EncodeToJpeg(const uint8_t* const pixelBuffer, Vector<uint8_t>& encodedPixe
 
   switch(pixelFormat)
   {
+    case Pixel::L8:
+    {
+      jpegPixelFormat = TJPF_GRAY;
+      break;
+    }
     case Pixel::RGB888:
     {
       jpegPixelFormat = TJPF_RGB;
@@ -1032,7 +1052,7 @@ bool EncodeToJpeg(const uint8_t* const pixelBuffer, Vector<uint8_t>& encodedPixe
     }
     default:
     {
-      DALI_LOG_ERROR("Unsupported pixel format for encoding to JPEG.\n");
+      DALI_LOG_ERROR("Unsupported pixel format for encoding to JPEG. Format enum : [%d]\n", pixelFormat);
       return false;
     }
   }
@@ -1180,7 +1200,7 @@ bool TransformSize(int requiredWidth, int requiredHeight, FittingMode::Type fitt
     // Internal jpeg downscaling is the same as our BOX_X sampling modes so only
     // apply it if the application requested one of those:
     // (use a switch case here so this code will fail to compile if other modes are added)
-    bool downscale = true;
+    bool useTurboJpegScaleFactor = true;
     switch(samplingMode)
     {
       case SamplingMode::BOX:
@@ -1188,26 +1208,30 @@ bool TransformSize(int requiredWidth, int requiredHeight, FittingMode::Type fitt
       case SamplingMode::BOX_THEN_LINEAR:
       case SamplingMode::DONT_CARE:
       {
-        downscale = true;
+        useTurboJpegScaleFactor = true;
         break;
       }
       case SamplingMode::NO_FILTER:
       case SamplingMode::NEAREST:
       case SamplingMode::LINEAR:
       {
-        downscale = false;
+        useTurboJpegScaleFactor = false;
         break;
       }
     }
 
-    int scaleFactorIndex(0);
-    if(downscale)
+    int scaleFactorIndex(-1);
+    int fittedScaledWidth(postXformImageWidth);
+    int fittedScaledHeight(postXformImageHeight);
+    if(useTurboJpegScaleFactor)
     {
       // Find nearest supported scaling factor (factors are in sequential order, getting smaller)
-      for(int i = 1; i < numFactors; ++i)
+      for(int i = 0; i < numFactors; ++i)
       {
-        bool widthLessRequired  = TJSCALED(postXformImageWidth, factors[i]) < requiredWidth;
-        bool heightLessRequired = TJSCALED(postXformImageHeight, factors[i]) < requiredHeight;
+        int  scaledWidth        = TJSCALED(postXformImageWidth, factors[i]);
+        int  scaledHeight       = TJSCALED(postXformImageHeight, factors[i]);
+        bool widthLessRequired  = scaledWidth < requiredWidth;
+        bool heightLessRequired = scaledHeight < requiredHeight;
         // If either scaled dimension is smaller than the desired one, we were done at the last iteration
         if((fittingMode == FittingMode::SCALE_TO_FILL) && (widthLessRequired || heightLessRequired))
         {
@@ -1229,31 +1253,41 @@ bool TransformSize(int requiredWidth, int requiredHeight, FittingMode::Type fitt
           break;
         }
         // This factor stays is within our fitting mode constraint so remember it:
-        scaleFactorIndex = i;
+        scaleFactorIndex   = i;
+        fittedScaledWidth  = scaledWidth;
+        fittedScaledHeight = scaledHeight;
       }
     }
 
+    const int maxTextureSize = static_cast<int>(Dali::GetMaxTextureSize());
+
     // Regardless of requested size, downscale to avoid exceeding the maximum texture size:
-    for(int i = scaleFactorIndex; i < numFactors; ++i)
+    if(fittedScaledWidth >= maxTextureSize ||
+       fittedScaledHeight >= maxTextureSize)
     {
-      // Continue downscaling to below maximum texture size (if possible)
-      scaleFactorIndex = i;
-
-      if(TJSCALED(postXformImageWidth, (factors[i])) < static_cast<int>(Dali::GetMaxTextureSize()) &&
-         TJSCALED(postXformImageHeight, (factors[i])) < static_cast<int>(Dali::GetMaxTextureSize()))
+      for(int i = scaleFactorIndex + 1; i < numFactors; ++i)
       {
-        // Current scale-factor downscales to below maximum texture size
-        break;
+        // Continue downscaling to below maximum texture size (if possible)
+        scaleFactorIndex   = i;
+        fittedScaledWidth  = TJSCALED(postXformImageWidth, factors[i]);
+        fittedScaledHeight = TJSCALED(postXformImageHeight, factors[i]);
+
+        if(fittedScaledWidth < maxTextureSize &&
+           fittedScaledHeight < maxTextureSize)
+        {
+          // Current scale-factor downscales to below maximum texture size
+          break;
+        }
       }
     }
 
     // We have finally chosen the scale-factor, return width/height values
-    if(scaleFactorIndex > 0)
+    if(scaleFactorIndex >= 0 && scaleFactorIndex < numFactors)
     {
       preXformImageWidth   = TJSCALED(preXformImageWidth, (factors[scaleFactorIndex]));
       preXformImageHeight  = TJSCALED(preXformImageHeight, (factors[scaleFactorIndex]));
-      postXformImageWidth  = TJSCALED(postXformImageWidth, (factors[scaleFactorIndex]));
-      postXformImageHeight = TJSCALED(postXformImageHeight, (factors[scaleFactorIndex]));
+      postXformImageWidth  = fittedScaledWidth;
+      postXformImageHeight = fittedScaledHeight;
     }
   }