mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 02:57:36 +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 {
|
struct GIFLoadingContext {
|
||||||
enum State {
|
enum State {
|
||||||
NotDecoded = 0,
|
NotDecoded = 0,
|
||||||
Error,
|
|
||||||
FrameDescriptorsLoaded,
|
FrameDescriptorsLoaded,
|
||||||
FrameComplete,
|
FrameComplete,
|
||||||
};
|
};
|
||||||
State state { NotDecoded };
|
State state { NotDecoded };
|
||||||
|
enum ErrorState {
|
||||||
|
NoError = 0,
|
||||||
|
FailedToDecodeAllFrames,
|
||||||
|
FailedToDecodeAnyFrame,
|
||||||
|
FailedToLoadFrameDescriptors,
|
||||||
|
};
|
||||||
|
ErrorState error_state { NoError };
|
||||||
const u8* data { nullptr };
|
const u8* data { nullptr };
|
||||||
size_t data_size { 0 };
|
size_t data_size { 0 };
|
||||||
LogicalScreen logical_screen {};
|
LogicalScreen logical_screen {};
|
||||||
|
@ -374,10 +380,10 @@ static bool decode_frame(GIFLoadingContext& context, size_t frame_index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
context.current_frame = frame_index;
|
context.current_frame = i;
|
||||||
context.state = GIFLoadingContext::State::FrameComplete;
|
context.state = GIFLoadingContext::State::FrameComplete;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -624,13 +630,13 @@ GIFImageDecoderPlugin::~GIFImageDecoderPlugin() { }
|
||||||
|
|
||||||
IntSize GIFImageDecoderPlugin::size()
|
IntSize GIFImageDecoderPlugin::size()
|
||||||
{
|
{
|
||||||
if (m_context->state == GIFLoadingContext::State::Error) {
|
if (m_context->error_state == GIFLoadingContext::ErrorState::FailedToLoadFrameDescriptors) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_context->state < GIFLoadingContext::State::FrameDescriptorsLoaded) {
|
if (m_context->state < GIFLoadingContext::State::FrameDescriptorsLoaded) {
|
||||||
if (!load_gif_frame_descriptors(*m_context)) {
|
if (!load_gif_frame_descriptors(*m_context)) {
|
||||||
m_context->state = GIFLoadingContext::State::Error;
|
m_context->error_state = GIFLoadingContext::ErrorState::FailedToLoadFrameDescriptors;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -669,9 +675,13 @@ bool GIFImageDecoderPlugin::sniff()
|
||||||
|
|
||||||
bool GIFImageDecoderPlugin::is_animated()
|
bool GIFImageDecoderPlugin::is_animated()
|
||||||
{
|
{
|
||||||
|
if (m_context->error_state != GIFLoadingContext::ErrorState::NoError) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_context->state < GIFLoadingContext::State::FrameDescriptorsLoaded) {
|
if (m_context->state < GIFLoadingContext::State::FrameDescriptorsLoaded) {
|
||||||
if (!load_gif_frame_descriptors(*m_context)) {
|
if (!load_gif_frame_descriptors(*m_context)) {
|
||||||
m_context->state = GIFLoadingContext::State::Error;
|
m_context->error_state = GIFLoadingContext::ErrorState::FailedToLoadFrameDescriptors;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -681,9 +691,13 @@ bool GIFImageDecoderPlugin::is_animated()
|
||||||
|
|
||||||
size_t GIFImageDecoderPlugin::loop_count()
|
size_t GIFImageDecoderPlugin::loop_count()
|
||||||
{
|
{
|
||||||
|
if (m_context->error_state != GIFLoadingContext::ErrorState::NoError) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_context->state < GIFLoadingContext::State::FrameDescriptorsLoaded) {
|
if (m_context->state < GIFLoadingContext::State::FrameDescriptorsLoaded) {
|
||||||
if (!load_gif_frame_descriptors(*m_context)) {
|
if (!load_gif_frame_descriptors(*m_context)) {
|
||||||
m_context->state = GIFLoadingContext::State::Error;
|
m_context->error_state = GIFLoadingContext::ErrorState::FailedToLoadFrameDescriptors;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -693,9 +707,13 @@ size_t GIFImageDecoderPlugin::loop_count()
|
||||||
|
|
||||||
size_t GIFImageDecoderPlugin::frame_count()
|
size_t GIFImageDecoderPlugin::frame_count()
|
||||||
{
|
{
|
||||||
|
if (m_context->error_state != GIFLoadingContext::ErrorState::NoError) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_context->state < GIFLoadingContext::State::FrameDescriptorsLoaded) {
|
if (m_context->state < GIFLoadingContext::State::FrameDescriptorsLoaded) {
|
||||||
if (!load_gif_frame_descriptors(*m_context)) {
|
if (!load_gif_frame_descriptors(*m_context)) {
|
||||||
m_context->state = GIFLoadingContext::State::Error;
|
m_context->error_state = GIFLoadingContext::ErrorState::FailedToLoadFrameDescriptors;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -705,20 +723,23 @@ size_t GIFImageDecoderPlugin::frame_count()
|
||||||
|
|
||||||
ImageFrameDescriptor GIFImageDecoderPlugin::frame(size_t i)
|
ImageFrameDescriptor GIFImageDecoderPlugin::frame(size_t i)
|
||||||
{
|
{
|
||||||
if (m_context->state == GIFLoadingContext::State::Error) {
|
if (m_context->error_state >= GIFLoadingContext::ErrorState::FailedToDecodeAnyFrame) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_context->state < GIFLoadingContext::State::FrameDescriptorsLoaded) {
|
if (m_context->state < GIFLoadingContext::State::FrameDescriptorsLoaded) {
|
||||||
if (!load_gif_frame_descriptors(*m_context)) {
|
if (!load_gif_frame_descriptors(*m_context)) {
|
||||||
m_context->state = GIFLoadingContext::State::Error;
|
m_context->error_state = GIFLoadingContext::ErrorState::FailedToLoadFrameDescriptors;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!decode_frame(*m_context, i)) {
|
if (m_context->error_state == GIFLoadingContext::ErrorState::NoError && !decode_frame(*m_context, i)) {
|
||||||
m_context->state = GIFLoadingContext::State::Error;
|
if (m_context->state < GIFLoadingContext::State::FrameComplete || !decode_frame(*m_context, 0)) {
|
||||||
return {};
|
m_context->error_state = GIFLoadingContext::ErrorState::FailedToDecodeAnyFrame;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
m_context->error_state = GIFLoadingContext::ErrorState::FailedToDecodeAllFrames;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageFrameDescriptor frame {};
|
ImageFrameDescriptor frame {};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue