mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 03:47:35 +00:00
LibGfx: gracefully handle GIFs with frame decode errors
GIFLoader now tracks the state of errors during the decoding process and will fall back to displaying the first frame of the GIF if any of the subsequent frames fail to decode.
This commit is contained in:
parent
7480034942
commit
fa57083552
1 changed files with 35 additions and 14 deletions
|
@ -81,11 +81,17 @@ struct LogicalScreen {
|
|||
struct GIFLoadingContext {
|
||||
enum State {
|
||||
NotDecoded = 0,
|
||||
Error,
|
||||
FrameDescriptorsLoaded,
|
||||
FrameComplete,
|
||||
};
|
||||
State state { NotDecoded };
|
||||
enum ErrorState {
|
||||
NoError = 0,
|
||||
FailedToDecodeAllFrames,
|
||||
FailedToDecodeAnyFrame,
|
||||
FailedToLoadFrameDescriptors,
|
||||
};
|
||||
ErrorState error_state { NoError };
|
||||
const u8* data { nullptr };
|
||||
size_t data_size { 0 };
|
||||
LogicalScreen logical_screen {};
|
||||
|
@ -374,10 +380,10 @@ static bool decode_frame(GIFLoadingContext& context, size_t frame_index)
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
context.current_frame = frame_index;
|
||||
context.state = GIFLoadingContext::State::FrameComplete;
|
||||
context.current_frame = i;
|
||||
context.state = GIFLoadingContext::State::FrameComplete;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -624,13 +630,13 @@ GIFImageDecoderPlugin::~GIFImageDecoderPlugin() { }
|
|||
|
||||
IntSize GIFImageDecoderPlugin::size()
|
||||
{
|
||||
if (m_context->state == GIFLoadingContext::State::Error) {
|
||||
if (m_context->error_state == GIFLoadingContext::ErrorState::FailedToLoadFrameDescriptors) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (m_context->state < GIFLoadingContext::State::FrameDescriptorsLoaded) {
|
||||
if (!load_gif_frame_descriptors(*m_context)) {
|
||||
m_context->state = GIFLoadingContext::State::Error;
|
||||
m_context->error_state = GIFLoadingContext::ErrorState::FailedToLoadFrameDescriptors;
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
@ -669,9 +675,13 @@ bool GIFImageDecoderPlugin::sniff()
|
|||
|
||||
bool GIFImageDecoderPlugin::is_animated()
|
||||
{
|
||||
if (m_context->error_state != GIFLoadingContext::ErrorState::NoError) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_context->state < GIFLoadingContext::State::FrameDescriptorsLoaded) {
|
||||
if (!load_gif_frame_descriptors(*m_context)) {
|
||||
m_context->state = GIFLoadingContext::State::Error;
|
||||
m_context->error_state = GIFLoadingContext::ErrorState::FailedToLoadFrameDescriptors;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -681,9 +691,13 @@ bool GIFImageDecoderPlugin::is_animated()
|
|||
|
||||
size_t GIFImageDecoderPlugin::loop_count()
|
||||
{
|
||||
if (m_context->error_state != GIFLoadingContext::ErrorState::NoError) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (m_context->state < GIFLoadingContext::State::FrameDescriptorsLoaded) {
|
||||
if (!load_gif_frame_descriptors(*m_context)) {
|
||||
m_context->state = GIFLoadingContext::State::Error;
|
||||
m_context->error_state = GIFLoadingContext::ErrorState::FailedToLoadFrameDescriptors;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -693,9 +707,13 @@ size_t GIFImageDecoderPlugin::loop_count()
|
|||
|
||||
size_t GIFImageDecoderPlugin::frame_count()
|
||||
{
|
||||
if (m_context->error_state != GIFLoadingContext::ErrorState::NoError) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (m_context->state < GIFLoadingContext::State::FrameDescriptorsLoaded) {
|
||||
if (!load_gif_frame_descriptors(*m_context)) {
|
||||
m_context->state = GIFLoadingContext::State::Error;
|
||||
m_context->error_state = GIFLoadingContext::ErrorState::FailedToLoadFrameDescriptors;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -705,20 +723,23 @@ size_t GIFImageDecoderPlugin::frame_count()
|
|||
|
||||
ImageFrameDescriptor GIFImageDecoderPlugin::frame(size_t i)
|
||||
{
|
||||
if (m_context->state == GIFLoadingContext::State::Error) {
|
||||
if (m_context->error_state >= GIFLoadingContext::ErrorState::FailedToDecodeAnyFrame) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (m_context->state < GIFLoadingContext::State::FrameDescriptorsLoaded) {
|
||||
if (!load_gif_frame_descriptors(*m_context)) {
|
||||
m_context->state = GIFLoadingContext::State::Error;
|
||||
m_context->error_state = GIFLoadingContext::ErrorState::FailedToLoadFrameDescriptors;
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
if (!decode_frame(*m_context, i)) {
|
||||
m_context->state = GIFLoadingContext::State::Error;
|
||||
return {};
|
||||
if (m_context->error_state == GIFLoadingContext::ErrorState::NoError && !decode_frame(*m_context, i)) {
|
||||
if (m_context->state < GIFLoadingContext::State::FrameComplete || !decode_frame(*m_context, 0)) {
|
||||
m_context->error_state = GIFLoadingContext::ErrorState::FailedToDecodeAnyFrame;
|
||||
return {};
|
||||
}
|
||||
m_context->error_state = GIFLoadingContext::ErrorState::FailedToDecodeAllFrames;
|
||||
}
|
||||
|
||||
ImageFrameDescriptor frame {};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue