mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-29 20:07:30 +09:00
Issue #2041 - Add animation support for JPEG-XL.
Based on Mozilla phab D122158, intended for bug 1709818.
This commit is contained in:
parent
9b4c0ef4e9
commit
042b8f37ae
3 changed files with 94 additions and 12 deletions
|
|
@ -204,6 +204,11 @@ DecoderFactory::CreateAnimationDecoder(DecoderType aType,
|
||||||
|
|
||||||
MOZ_ASSERT(aType == DecoderType::GIF || aType == DecoderType::PNG ||
|
MOZ_ASSERT(aType == DecoderType::GIF || aType == DecoderType::PNG ||
|
||||||
aType == DecoderType::WEBP,
|
aType == DecoderType::WEBP,
|
||||||
|
#ifdef MOZ_JXL
|
||||||
|
|| aType == DecoderType::JXL,
|
||||||
|
#else
|
||||||
|
,
|
||||||
|
#endif
|
||||||
"Calling CreateAnimationDecoder for non-animating DecoderType");
|
"Calling CreateAnimationDecoder for non-animating DecoderType");
|
||||||
|
|
||||||
// Create an anonymous decoder. Interaction with the SurfaceCache and the
|
// Create an anonymous decoder. Interaction with the SurfaceCache and the
|
||||||
|
|
|
||||||
|
|
@ -45,9 +45,14 @@ nsJXLDecoder::nsJXLDecoder(RasterImage* aImage)
|
||||||
Transition::TerminateSuccess()),
|
Transition::TerminateSuccess()),
|
||||||
mDecoder(JxlDecoderMake(nullptr)),
|
mDecoder(JxlDecoderMake(nullptr)),
|
||||||
mParallelRunner(
|
mParallelRunner(
|
||||||
JxlThreadParallelRunnerMake(nullptr, PreferredThreadCount())) {
|
JxlThreadParallelRunnerMake(nullptr, PreferredThreadCount())),
|
||||||
|
mNumFrames(0),
|
||||||
|
mTimeout(FrameTimeout::Forever()),
|
||||||
|
mSurfaceFormat(SurfaceFormat::B8G8R8X8),
|
||||||
|
mContinue(false) {
|
||||||
JxlDecoderSubscribeEvents(mDecoder.get(),
|
JxlDecoderSubscribeEvents(mDecoder.get(),
|
||||||
JXL_DEC_BASIC_INFO | JXL_DEC_FULL_IMAGE);
|
JXL_DEC_BASIC_INFO | JXL_DEC_FRAME |
|
||||||
|
JXL_DEC_FULL_IMAGE);
|
||||||
JxlDecoderSetParallelRunner(mDecoder.get(), JxlThreadParallelRunner,
|
JxlDecoderSetParallelRunner(mDecoder.get(), JxlThreadParallelRunner,
|
||||||
mParallelRunner.get());
|
mParallelRunner.get());
|
||||||
|
|
||||||
|
|
@ -88,6 +93,9 @@ nsJXLDecoder::DoDecode(SourceBufferIterator& aIterator, IResumable* aOnResume)
|
||||||
LexerTransition<nsJXLDecoder::State>
|
LexerTransition<nsJXLDecoder::State>
|
||||||
nsJXLDecoder::ReadJXLData(const char* aData, size_t aLength)
|
nsJXLDecoder::ReadJXLData(const char* aData, size_t aLength)
|
||||||
{
|
{
|
||||||
|
// 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;
|
const uint8_t* input = (const uint8_t*)aData;
|
||||||
size_t length = aLength;
|
size_t length = aLength;
|
||||||
if (mBuffer.length() != 0) {
|
if (mBuffer.length() != 0) {
|
||||||
|
|
@ -96,6 +104,8 @@ nsJXLDecoder::ReadJXLData(const char* aData, size_t aLength)
|
||||||
length = mBuffer.length();
|
length = mBuffer.length();
|
||||||
}
|
}
|
||||||
JXL_TRY(JxlDecoderSetInput(mDecoder.get(), input, length));
|
JXL_TRY(JxlDecoderSetInput(mDecoder.get(), input, length));
|
||||||
|
}
|
||||||
|
mContinue = false;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
JxlDecoderStatus status = JxlDecoderProcessInput(mDecoder.get());
|
JxlDecoderStatus status = JxlDecoderProcessInput(mDecoder.get());
|
||||||
|
|
@ -117,9 +127,37 @@ nsJXLDecoder::ReadJXLData(const char* aData, size_t aLength)
|
||||||
if (mInfo.alpha_bits > 0) {
|
if (mInfo.alpha_bits > 0) {
|
||||||
PostHasTransparency();
|
PostHasTransparency();
|
||||||
}
|
}
|
||||||
|
if (!mInfo.have_animation && IsMetadataDecode()) {
|
||||||
|
return Transition::TerminateSuccess();
|
||||||
|
}
|
||||||
|
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()) {
|
if (IsMetadataDecode()) {
|
||||||
return Transition::TerminateSuccess();
|
return Transition::TerminateSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -136,9 +174,24 @@ nsJXLDecoder::ReadJXLData(const char* aData, size_t aLength)
|
||||||
}
|
}
|
||||||
|
|
||||||
case JXL_DEC_FULL_IMAGE: {
|
case JXL_DEC_FULL_IMAGE: {
|
||||||
|
Maybe<AnimationParams> animParams;
|
||||||
|
if (!IsFirstFrameDecode()) {
|
||||||
|
animParams.emplace(AnimationParams {
|
||||||
|
FullFrame().ToUnknownRect(), mTimeout, mNumFrames,
|
||||||
|
BlendMethod::SOURCE, DisposalMethod::CLEAR
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Maybe<SurfacePipe> pipe = SurfacePipeFactory::CreateSurfacePipe(
|
Maybe<SurfacePipe> pipe = SurfacePipeFactory::CreateSurfacePipe(
|
||||||
this, Size(), OutputSize(), FullFrame(), SurfaceFormat::B8G8R8A8,
|
this, Size(), OutputSize(), FullFrame(), SurfaceFormat::B8G8R8A8,
|
||||||
Nothing(), SurfacePipeFlags());
|
animParams, SurfacePipeFlags());
|
||||||
|
|
||||||
|
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();
|
for (uint8_t* rowPtr = mOutBuffer.begin(); rowPtr < mOutBuffer.end();
|
||||||
rowPtr += mInfo.xsize * 4) {
|
rowPtr += mInfo.xsize * 4) {
|
||||||
// FIXME: Quick and dirty BGRA to RGBA conversion.
|
// FIXME: Quick and dirty BGRA to RGBA conversion.
|
||||||
|
|
@ -159,8 +212,26 @@ nsJXLDecoder::ReadJXLData(const char* aData, size_t aLength)
|
||||||
PostInvalidation(invalidRect->mInputSpaceRect,
|
PostInvalidation(invalidRect->mInputSpaceRect,
|
||||||
Some(invalidRect->mOutputSpaceRect));
|
Some(invalidRect->mOutputSpaceRect));
|
||||||
}
|
}
|
||||||
PostFrameStop();
|
|
||||||
PostDecodeDone();
|
Opacity opacity = mSurfaceFormat == SurfaceFormat::B8G8R8A8
|
||||||
|
? 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);
|
||||||
|
}
|
||||||
|
MOZ_FALLTHROUGH; // We are done.
|
||||||
|
}
|
||||||
|
|
||||||
|
case JXL_DEC_SUCCESS: {
|
||||||
|
PostDecodeDone(HasAnimation() ? (int32_t)mInfo.animation.num_loops - 1
|
||||||
|
: 0);
|
||||||
return Transition::TerminateSuccess();
|
return Transition::TerminateSuccess();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,12 @@ class nsJXLDecoder final : public Decoder {
|
||||||
Vector<uint8_t> mBuffer;
|
Vector<uint8_t> mBuffer;
|
||||||
Vector<uint8_t> mOutBuffer;
|
Vector<uint8_t> mOutBuffer;
|
||||||
JxlBasicInfo mInfo{};
|
JxlBasicInfo mInfo{};
|
||||||
|
JxlFrameHeader mFrameHeader;
|
||||||
|
|
||||||
|
uint32_t mNumFrames;
|
||||||
|
FrameTimeout mTimeout;
|
||||||
|
gfx::SurfaceFormat mSurfaceFormat;
|
||||||
|
bool mContinue;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace image
|
} // namespace image
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue