mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-22 12:35:14 +00:00
LibGfx: Fix handling of partially corrupt GIFs
GIF loader was completely failing when encountering errors with frame descriptors or individual frames, even when some frames were successfully loaded. Now we attempt to decode at least some frames and fail only when no frames can be decoded at all.
This commit is contained in:
parent
54351e7327
commit
57d0c563e0
Notes:
github-actions[bot]
2025-03-20 15:13:57 +00:00
Author: https://github.com/aplefull Commit: https://github.com/LadybirdBrowser/ladybird/commit/57d0c563e03 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/4019 Reviewed-by: https://github.com/gmta ✅
4 changed files with 26 additions and 14 deletions
|
@ -468,29 +468,31 @@ size_t GIFImageDecoderPlugin::first_animated_frame_index()
|
|||
|
||||
ErrorOr<ImageFrameDescriptor> GIFImageDecoderPlugin::frame(size_t index, Optional<IntSize>)
|
||||
{
|
||||
if (m_context->error_state >= GIFLoadingContext::ErrorState::FailedToDecodeAnyFrame) {
|
||||
if (m_context->error_state == GIFLoadingContext::ErrorState::FailedToDecodeAnyFrame) {
|
||||
return Error::from_string_literal("GIFImageDecoderPlugin: Decoding failed");
|
||||
}
|
||||
|
||||
if (m_context->state < GIFLoadingContext::State::FrameDescriptorsLoaded) {
|
||||
if (auto result = load_gif_frame_descriptors(*m_context); result.is_error()) {
|
||||
m_context->error_state = GIFLoadingContext::ErrorState::FailedToLoadFrameDescriptors;
|
||||
return result.release_error();
|
||||
|
||||
// If we failed to load frame descriptors but we have some images, we can still try to decode them.
|
||||
if (m_context->images.is_empty()) {
|
||||
return result.release_error();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_context->error_state == GIFLoadingContext::ErrorState::NoError) {
|
||||
if (auto result = decode_frame(*m_context, index); result.is_error()) {
|
||||
if (m_context->state < GIFLoadingContext::State::FrameComplete) {
|
||||
m_context->error_state = GIFLoadingContext::ErrorState::FailedToDecodeAnyFrame;
|
||||
return result.release_error();
|
||||
}
|
||||
if (auto result = decode_frame(*m_context, 0); result.is_error()) {
|
||||
m_context->error_state = GIFLoadingContext::ErrorState::FailedToDecodeAnyFrame;
|
||||
return result.release_error();
|
||||
}
|
||||
m_context->error_state = GIFLoadingContext::ErrorState::FailedToDecodeAllFrames;
|
||||
if (auto result = decode_frame(*m_context, index); result.is_error()) {
|
||||
if (m_context->state < GIFLoadingContext::State::FrameComplete) {
|
||||
m_context->error_state = GIFLoadingContext::ErrorState::FailedToDecodeAnyFrame;
|
||||
return result.release_error();
|
||||
}
|
||||
if (auto result = decode_frame(*m_context, 0); result.is_error()) {
|
||||
m_context->error_state = GIFLoadingContext::ErrorState::FailedToDecodeAnyFrame;
|
||||
return result.release_error();
|
||||
}
|
||||
m_context->error_state = GIFLoadingContext::ErrorState::FailedToDecodeAllFrames;
|
||||
}
|
||||
|
||||
ImageFrameDescriptor frame {};
|
||||
|
|
|
@ -93,7 +93,7 @@ TEST_CASE(test_ico_malformed_frame)
|
|||
|
||||
TEST_CASE(test_gif)
|
||||
{
|
||||
auto file = TRY_OR_FAIL(Core::MappedFile::map(TEST_INPUT("download-animation.gif"sv)));
|
||||
auto file = TRY_OR_FAIL(Core::MappedFile::map(TEST_INPUT("gif/download-animation.gif"sv)));
|
||||
EXPECT(Gfx::GIFImageDecoderPlugin::sniff(file->bytes()));
|
||||
auto plugin_decoder = TRY_OR_FAIL(Gfx::GIFImageDecoderPlugin::create(file->bytes()));
|
||||
|
||||
|
@ -105,6 +105,16 @@ TEST_CASE(test_gif)
|
|||
EXPECT(frame.duration == 400);
|
||||
}
|
||||
|
||||
TEST_CASE(test_corrupted_gif)
|
||||
{
|
||||
auto file = TRY_OR_FAIL(Core::MappedFile::map(TEST_INPUT("gif/corrupted.gif"sv)));
|
||||
EXPECT(Gfx::GIFImageDecoderPlugin::sniff(file->bytes()));
|
||||
auto plugin_decoder = TRY_OR_FAIL(Gfx::GIFImageDecoderPlugin::create(file->bytes()));
|
||||
|
||||
auto frame = TRY_OR_FAIL(plugin_decoder->frame(0));
|
||||
EXPECT_EQ(plugin_decoder->frame_count(), 1u);
|
||||
}
|
||||
|
||||
TEST_CASE(test_gif_without_global_color_table)
|
||||
{
|
||||
Array<u8, 35> gif_data {
|
||||
|
|
BIN
Tests/LibGfx/test-inputs/gif/corrupted.gif
Normal file
BIN
Tests/LibGfx/test-inputs/gif/corrupted.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
Loading…
Add table
Reference in a new issue