File D122158-FF129.patch of Package firefox

diff -urN firefox-117.0.1-orig/image/DecoderFactory.cpp firefox-117.0.1/image/DecoderFactory.cpp
--- firefox-117.0.1-orig/image/DecoderFactory.cpp	2023-09-12 10:42:00.000000000 +0900
+++ firefox-117.0.1/image/DecoderFactory.cpp	2023-09-23 16:45:47.120595375 +0900
@@ -235,7 +235,12 @@
   }
 
   MOZ_ASSERT(aType == DecoderType::GIF || aType == DecoderType::PNG ||
-                 aType == DecoderType::WEBP || aType == DecoderType::AVIF,
+                 aType == DecoderType::WEBP || aType == DecoderType::AVIF
+#ifdef MOZ_JXL
+                 || aType == DecoderType::JXL,
+#else
+             ,
+#endif
              "Calling CreateAnimationDecoder for non-animating DecoderType");
 
   // Create an anonymous decoder. Interaction with the SurfaceCache and the
@@ -290,7 +295,12 @@
   // rediscover it is animated).
   DecoderType type = aDecoder->GetType();
   MOZ_ASSERT(type == DecoderType::GIF || type == DecoderType::PNG ||
-                 type == DecoderType::WEBP || type == DecoderType::AVIF,
+                 type == DecoderType::WEBP || type == DecoderType::AVIF
+#ifdef MOZ_JXL
+                 || type == DecoderType::JXL,
+#else
+             ,
+#endif
              "Calling CloneAnimationDecoder for non-animating DecoderType");
 
   RefPtr<Decoder> decoder = GetDecoder(type, nullptr, /* aIsRedecode = */ true);
diff -urN firefox-117.0.1-orig/image/decoders/nsJXLDecoder.cpp firefox-117.0.1/image/decoders/nsJXLDecoder.cpp
--- firefox-117.0.1-orig/image/decoders/nsJXLDecoder.cpp	2023-09-23 16:40:10.359785179 +0900
+++ firefox-117.0.1/image/decoders/nsJXLDecoder.cpp	2023-09-23 16:41:18.941986704 +0900
@@ -47,8 +47,12 @@
       mParallelRunner(
           JxlThreadParallelRunnerMake(nullptr, PreferredThreadCount())),
       mUsePipeTransform(true),
-      mCMSLine(nullptr) {
-  int events = JXL_DEC_BASIC_INFO | JXL_DEC_FULL_IMAGE;
+      mCMSLine(nullptr),
+      mNumFrames(0),
+      mTimeout(FrameTimeout::Forever()),
+      mSurfaceFormat(SurfaceFormat::OS_RGBX),
+      mContinue(false) {
+  int events = JXL_DEC_BASIC_INFO | JXL_DEC_FRAME | JXL_DEC_FULL_IMAGE;
 
   if (mCMSMode != CMSMode::Off) {
     events |= JXL_DEC_COLOR_ENCODING;
@@ -97,14 +101,19 @@
 
 LexerTransition<nsJXLDecoder::State> nsJXLDecoder::ReadJXLData(
     const char* aData, size_t aLength) {
-  const uint8_t* input = (const uint8_t*)aData;
-  size_t length = aLength;
-  if (mBuffer.length() != 0) {
-    JXL_TRY_BOOL(mBuffer.append(aData, aLength));
-    input = mBuffer.begin();
-    length = mBuffer.length();
+  // Ignore data we have already read.
+  // This will only occur as a result of a yield for animation.
+  if (!mContinue) {
+    const uint8_t* input = (const uint8_t*)aData;
+    size_t length = aLength;
+    if (mBuffer.length() != 0) {
+      JXL_TRY_BOOL(mBuffer.append(aData, aLength));
+      input = mBuffer.begin();
+      length = mBuffer.length();
+    }
+    JXL_TRY(JxlDecoderSetInput(mDecoder.get(), input, length));
   }
-  JXL_TRY(JxlDecoderSetInput(mDecoder.get(), input, length));
+  mContinue = false;
 
   while (true) {
     JxlDecoderStatus status = JxlDecoderProcessInput(mDecoder.get());
@@ -129,10 +138,11 @@
         }
 
         if (mInfo.alpha_bits > 0) {
+          mSurfaceFormat = SurfaceFormat::OS_RGBA;
           PostHasTransparency();
         }
 
-        if (IsMetadataDecode()) {
+        if (!mInfo.have_animation && IsMetadataDecode()) {
           return Transition::TerminateSuccess();
         }
 
@@ -151,17 +161,6 @@
         break;
       }
 
-      case JXL_DEC_NEED_IMAGE_OUT_BUFFER: {
-        size_t size = 0;
-        JXL_TRY(JxlDecoderImageOutBufferSize(mDecoder.get(), &mFormat, &size));
-
-        mOutBuffer.clear();
-        JXL_TRY_BOOL(mOutBuffer.growBy(size));
-        JXL_TRY(JxlDecoderSetImageOutBuffer(mDecoder.get(), &mFormat,
-                                            mOutBuffer.begin(), size));
-        break;
-      }
-
       case JXL_DEC_COLOR_ENCODING: {
         size_t size = 0;
         JXL_TRY(JxlDecoderGetICCProfileSize(
@@ -211,16 +210,73 @@
         break;
       }
 
+      case JXL_DEC_FRAME: {
+        if (mInfo.have_animation) {
+          JXL_TRY(JxlDecoderGetFrameHeader(mDecoder.get(), &mFrameHeader));
+          int32_t duration = (int32_t)(1000.0 * mFrameHeader.duration *
+                                       mInfo.animation.tps_denominator /
+                                       mInfo.animation.tps_numerator);
+
+          mTimeout = FrameTimeout::FromRawMilliseconds(duration);
+
+          if (!HasAnimation()) {
+            PostIsAnimated(mTimeout);
+          }
+        }
+
+        bool is_last = mInfo.have_animation ? mFrameHeader.is_last : true;
+        MOZ_LOG(sJXLLog, LogLevel::Debug,
+                ("[this=%p] nsJXLDecoder::ReadJXLData - frame %d, is_last %d, "
+                 "metadata decode %d, first frame decode %d\n",
+                 this, mNumFrames, is_last, IsMetadataDecode(),
+                 IsFirstFrameDecode()));
+
+        if (IsMetadataDecode()) {
+          return Transition::TerminateSuccess();
+        }
+
+        break;
+      }
+
+      case JXL_DEC_NEED_IMAGE_OUT_BUFFER: {
+        size_t size = 0;
+        JXL_TRY(JxlDecoderImageOutBufferSize(mDecoder.get(), &mFormat, &size));
+
+        mOutBuffer.clear();
+        JXL_TRY_BOOL(mOutBuffer.growBy(size));
+        JXL_TRY(JxlDecoderSetImageOutBuffer(mDecoder.get(), &mFormat,
+                                            mOutBuffer.begin(), size));
+        break;
+      }
+
       case JXL_DEC_FULL_IMAGE: {
         OrientedIntSize size(mInfo.xsize, mInfo.ysize);
 
+        Maybe<AnimationParams> animParams;
+        if (!IsFirstFrameDecode()) {
+          animParams.emplace(FullFrame().ToUnknownRect(), mTimeout, mNumFrames,
+                             BlendMethod::SOURCE, DisposalMethod::CLEAR);
+        }
+
+        SurfacePipeFlags pipeFlags = SurfacePipeFlags();
+
+        if (mSurfaceFormat == SurfaceFormat::OS_RGBA &&
+            !(GetSurfaceFlags() & SurfaceFlags::NO_PREMULTIPLY_ALPHA)) {
+          pipeFlags |= SurfacePipeFlags::PREMULTIPLY_ALPHA;
+        }
+
         qcms_transform* pipeTransform =
             mUsePipeTransform ? mTransform : nullptr;
 
         Maybe<SurfacePipe> pipe = SurfacePipeFactory::CreateSurfacePipe(
             this, size, OutputSize(), FullFrame(), SurfaceFormat::R8G8B8A8,
-            SurfaceFormat::OS_RGBA, Nothing(), pipeTransform,
-            SurfacePipeFlags());
+            mSurfaceFormat, animParams, pipeTransform, pipeFlags);
+
+        if (!pipe) {
+          MOZ_LOG(sJXLLog, LogLevel::Debug,
+                  ("[this=%p] nsJXLDecoder::ReadJXLData - no pipe\n", this));
+          return Transition::TerminateFailure();
+        }
 
         for (uint8_t* rowPtr = mOutBuffer.begin(); rowPtr < mOutBuffer.end();
              rowPtr += mInfo.xsize * mChannels) {
@@ -238,8 +294,26 @@
           PostInvalidation(invalidRect->mInputSpaceRect,
                            Some(invalidRect->mOutputSpaceRect));
         }
-        PostFrameStop();
-        PostDecodeDone();
+
+        Opacity opacity = mSurfaceFormat == SurfaceFormat::OS_RGBA
+                              ? Opacity::SOME_TRANSPARENCY
+                              : Opacity::FULLY_OPAQUE;
+        PostFrameStop(opacity);
+
+        if (!IsFirstFrameDecode() && mInfo.have_animation &&
+            !mFrameHeader.is_last) {
+          mNumFrames++;
+          mContinue = true;
+          // Notify for a new frame but there may be data in the current buffer
+          // that can immediately be processed.
+          return Transition::ToAfterYield(State::JXL_DATA);
+        }
+        [[fallthrough]];  // We are done.
+      }
+
+      case JXL_DEC_SUCCESS: {
+        PostLoopCount(HasAnimation() ? (int32_t)mInfo.animation.num_loops - 1
+                                      : 0);
         return Transition::TerminateSuccess();
       }
     }
diff -urN firefox-117.0.1-orig/image/decoders/nsJXLDecoder.h firefox-117.0.1/image/decoders/nsJXLDecoder.h
--- firefox-117.0.1-orig/image/decoders/nsJXLDecoder.h	2023-09-23 16:40:10.359785179 +0900
+++ firefox-117.0.1/image/decoders/nsJXLDecoder.h	2023-09-23 16:41:18.941986704 +0900
@@ -49,10 +49,16 @@
   Vector<uint8_t> mOutBuffer;
   JxlBasicInfo mInfo;
   JxlPixelFormat mFormat;
+  JxlFrameHeader mFrameHeader;
 
   bool mUsePipeTransform;
   uint8_t mChannels;
   uint8_t* mCMSLine;
+
+  uint32_t mNumFrames;
+  FrameTimeout mTimeout;
+  gfx::SurfaceFormat mSurfaceFormat;
+  bool mContinue;
 };
 
 }  // namespace mozilla::image
openSUSE Build Service is sponsored by