Skip to content

Commit 9566ccd

Browse files
committed
Fix pixbuf loader bug due to a double to uint64_t cast.
1 parent 5d8e3ce commit 9566ccd

File tree

1 file changed

+12
-8
lines changed

1 file changed

+12
-8
lines changed

contrib/gdk-pixbuf/loader.c

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ typedef struct {
2222
struct _AvifAnimation {
2323
GdkPixbufAnimation parent;
2424
GArray * frames;
25+
uint64_t animation_time;
2526

2627
GdkPixbufModuleSizeFunc size_func;
2728
GdkPixbufModuleUpdatedFunc updated_func;
@@ -140,16 +141,10 @@ static gboolean avif_animation_iter_advance(GdkPixbufAnimationIter * iter, const
140141
size_t prev_frame = avif_iter->current_frame;
141142
uint64_t elapsed_time = current_time->tv_sec * 1000 + current_time->tv_usec / 1000 - avif_iter->time_offset;
142143

143-
/*
144-
* duration in seconds stored in a double which is cast to uint64_t
145-
* is the precision loss here significant?
146-
*/
147-
uint64_t animation_time = (uint64_t)(context->decoder->duration * 1000);
148-
149-
if (context->decoder->repetitionCount > 0 && elapsed_time > animation_time * context->decoder->repetitionCount) {
144+
if (context->decoder->repetitionCount > 0 && elapsed_time > context->animation_time * context->decoder->repetitionCount) {
150145
avif_iter->current_frame = context->decoder->imageCount - 1;
151146
} else {
152-
elapsed_time = elapsed_time % animation_time;
147+
elapsed_time = elapsed_time % context->animation_time;
153148

154149
avif_iter->current_frame = 0;
155150
uint64_t frame_duration;
@@ -163,6 +158,7 @@ static gboolean avif_animation_iter_advance(GdkPixbufAnimationIter * iter, const
163158
elapsed_time -= frame_duration;
164159
avif_iter->current_frame++;
165160
}
161+
avif_iter->current_frame = avif_iter->current_frame % context->decoder->imageCount;
166162
}
167163

168164
return prev_frame != avif_iter->current_frame;
@@ -423,6 +419,7 @@ static gboolean avif_context_try_load(AvifAnimation * context, GError ** error)
423419
AvifAnimationFrame frame;
424420
frame.pixbuf = set_pixbuf(context, error);
425421
frame.duration_ms = (uint64_t)(decoder->imageTiming.duration * 1000);
422+
context->animation_time = frame.duration_ms;
426423

427424
if (frame.pixbuf == NULL) {
428425
return FALSE;
@@ -447,6 +444,13 @@ static gboolean avif_context_try_load(AvifAnimation * context, GError ** error)
447444
frame.pixbuf = set_pixbuf(context, error);
448445
frame.duration_ms = (uint64_t)(decoder->imageTiming.duration * 1000);
449446

447+
if (frame.pixbuf == NULL) {
448+
return FALSE;
449+
}
450+
451+
/* We don't use the animation duration from the AVIF structure directly due to precision problems */
452+
context->animation_time += frame.duration_ms;
453+
450454
g_array_append_val(context->frames, frame);
451455
}
452456
return TRUE;

0 commit comments

Comments
 (0)