summaryrefslogtreecommitdiff
path: root/image/decoders
diff options
context:
space:
mode:
authorJob Bautista <jobbautista9@protonmail.com>2022-12-02 13:28:34 +0800
committerJob Bautista <jobbautista9@protonmail.com>2022-12-02 13:28:34 +0800
commitdaf859d84c27e715caec0e2fa4462a5d9faf5634 (patch)
treef93b93b51d6c701244b9e723271126be6c6218a0 /image/decoders
parentb66e0ffdc447bfde0b9c7c1e65992d5b6b895727 (diff)
downloaduxp-daf859d84c27e715caec0e2fa4462a5d9faf5634.tar.gz
Issue #2048 - Add progressive decoding for JPEG-XL.
Based on Mozilla phab D122159, intended for bug 1709815. Also moved the temporary RGBA and premultiplication fixes to a macro, since progressive decoding also needs these fixes.
Diffstat (limited to 'image/decoders')
-rw-r--r--image/decoders/nsJXLDecoder.cpp97
-rw-r--r--image/decoders/nsJXLDecoder.h1
2 files changed, 68 insertions, 30 deletions
diff --git a/image/decoders/nsJXLDecoder.cpp b/image/decoders/nsJXLDecoder.cpp
index b001a46997..85276f409a 100644
--- a/image/decoders/nsJXLDecoder.cpp
+++ b/image/decoders/nsJXLDecoder.cpp
@@ -36,6 +36,21 @@ namespace image {
} \
} while (0);
+// FIXME: Quick and dirty BGRA to RGBA conversion.
+// We currently have a channel ordering mis-match here.
+#define JXL_RGBA_FIX \
+for (uint8_t* pixPtr = rowPtr; pixPtr < rowPtr + mInfo.xsize * 4; pixPtr+=4){ \
+ std::swap(pixPtr[0], pixPtr[2]);
+
+// FIXME: Pre-multiply, too
+#define JXL_PREMULTIPLY_FIX \
+ if (pixPtr[3] < 255) { \
+ pixPtr[0]=((uint16_t)pixPtr[0]*(uint16_t)pixPtr[3]) >> 8; \
+ pixPtr[1]=((uint16_t)pixPtr[1]*(uint16_t)pixPtr[3]) >> 8; \
+ pixPtr[2]=((uint16_t)pixPtr[2]*(uint16_t)pixPtr[3]) >> 8; \
+ } \
+}
+
static LazyLogModule sJXLLog("JXLDecoder");
nsJXLDecoder::nsJXLDecoder(RasterImage* aImage)
@@ -118,6 +133,28 @@ nsJXLDecoder::ReadJXLData(const char* aData, size_t aLength)
size_t remaining = JxlDecoderReleaseInput(mDecoder.get());
mBuffer.clear();
JXL_TRY_BOOL(mBuffer.append(aData + aLength - remaining, remaining));
+
+ if (mNumFrames == 0 && InFrame()) {
+ // If an image was flushed by JxlDecoderFlushImage, then we know that
+ // JXL_DEC_FRAME has already been run and there is a pipe.
+ if (JxlDecoderFlushImage(mDecoder.get()) == JXL_DEC_SUCCESS) {
+ // A full frame partial image is written to the buffer.
+ mPipe.ResetToFirstRow();
+ for (uint8_t* rowPtr = mOutBuffer.begin();
+ rowPtr < mOutBuffer.end(); rowPtr += mInfo.xsize * 4) {
+ JXL_RGBA_FIX JXL_PREMULTIPLY_FIX;
+ uint8_t* rowToWrite = rowPtr;
+ mPipe.WriteBuffer(reinterpret_cast<uint32_t*>(rowToWrite));
+ }
+
+ if (Maybe<SurfaceInvalidRect> invalidRect =
+ mPipe.TakeInvalidRect()) {
+ PostInvalidation(invalidRect->mInputSpaceRect,
+ Some(invalidRect->mOutputSpaceRect));
+ }
+ }
+ }
+
return Transition::ContinueUnbuffered(State::JXL_DATA);
}
@@ -158,22 +195,6 @@ nsJXLDecoder::ReadJXLData(const char* aData, size_t aLength)
return Transition::TerminateSuccess();
}
- break;
- }
-
- case JXL_DEC_NEED_IMAGE_OUT_BUFFER: {
- size_t size = 0;
- JxlPixelFormat format{4, JXL_TYPE_UINT8, JXL_LITTLE_ENDIAN, 0};
- JXL_TRY(JxlDecoderImageOutBufferSize(mDecoder.get(), &format, &size));
-
- mOutBuffer.clear();
- JXL_TRY_BOOL(mOutBuffer.growBy(size));
- JXL_TRY(JxlDecoderSetImageOutBuffer(mDecoder.get(), &format,
- mOutBuffer.begin(), size));
- break;
- }
-
- case JXL_DEC_FULL_IMAGE: {
Maybe<AnimationParams> animParams;
if (!IsFirstFrameDecode()) {
animParams.emplace(AnimationParams {
@@ -182,9 +203,16 @@ nsJXLDecoder::ReadJXLData(const char* aData, size_t aLength)
});
}
+ SurfacePipeFlags pipeFlags = SurfacePipeFlags();
+
+ if (mNumFrames == 0) {
+ // The first frame may be displayed progressively.
+ pipeFlags |= SurfacePipeFlags::PROGRESSIVE_DISPLAY;
+ }
+
Maybe<SurfacePipe> pipe = SurfacePipeFactory::CreateSurfacePipe(
this, Size(), OutputSize(), FullFrame(), SurfaceFormat::B8G8R8A8,
- animParams, SurfacePipeFlags());
+ animParams, pipeFlags);
if (!pipe) {
MOZ_LOG(sJXLLog, LogLevel::Debug,
@@ -192,23 +220,32 @@ nsJXLDecoder::ReadJXLData(const char* aData, size_t aLength)
return Transition::TerminateFailure();
}
+ mPipe = std::move(*pipe);
+
+ break;
+ }
+
+ case JXL_DEC_NEED_IMAGE_OUT_BUFFER: {
+ size_t size = 0;
+ JxlPixelFormat format{4, JXL_TYPE_UINT8, JXL_LITTLE_ENDIAN, 0};
+ JXL_TRY(JxlDecoderImageOutBufferSize(mDecoder.get(), &format, &size));
+
+ mOutBuffer.clear();
+ JXL_TRY_BOOL(mOutBuffer.growBy(size));
+ JXL_TRY(JxlDecoderSetImageOutBuffer(mDecoder.get(), &format,
+ mOutBuffer.begin(), size));
+ break;
+ }
+
+ case JXL_DEC_FULL_IMAGE: {
+ mPipe.ResetToFirstRow();
for (uint8_t* rowPtr = mOutBuffer.begin(); rowPtr < mOutBuffer.end();
rowPtr += mInfo.xsize * 4) {
- // FIXME: Quick and dirty BGRA to RGBA conversion.
- // We currently have a channel ordering mis-match here.
- for (uint8_t* pixPtr = rowPtr; pixPtr < rowPtr + mInfo.xsize * 4; pixPtr+=4){
- std::swap(pixPtr[0], pixPtr[2]);
- // Pre-multiply, too
- if (pixPtr[3] < 255) {
- pixPtr[0]=((uint16_t)pixPtr[0]*(uint16_t)pixPtr[3]) >> 8;
- pixPtr[1]=((uint16_t)pixPtr[1]*(uint16_t)pixPtr[3]) >> 8;
- pixPtr[2]=((uint16_t)pixPtr[2]*(uint16_t)pixPtr[3]) >> 8;
- }
- }
- pipe->WriteBuffer(reinterpret_cast<uint32_t*>(rowPtr));
+ JXL_RGBA_FIX JXL_PREMULTIPLY_FIX;
+ mPipe.WriteBuffer(reinterpret_cast<uint32_t*>(rowPtr));
}
- if (Maybe<SurfaceInvalidRect> invalidRect = pipe->TakeInvalidRect()) {
+ if (Maybe<SurfaceInvalidRect> invalidRect = mPipe.TakeInvalidRect()) {
PostInvalidation(invalidRect->mInputSpaceRect,
Some(invalidRect->mOutputSpaceRect));
}
diff --git a/image/decoders/nsJXLDecoder.h b/image/decoders/nsJXLDecoder.h
index 6badd33124..3cabcfb9b0 100644
--- a/image/decoders/nsJXLDecoder.h
+++ b/image/decoders/nsJXLDecoder.h
@@ -49,6 +49,7 @@ class nsJXLDecoder final : public Decoder {
uint32_t mNumFrames;
FrameTimeout mTimeout;
gfx::SurfaceFormat mSurfaceFormat;
+ SurfacePipe mPipe;
bool mContinue;
};