Implement another animation frame disposal method

This commit is contained in:
2026-08-05 01:47:35 +02:00
parent 4a9c850105
commit e424e903a4
+23 -10
View File
@@ -390,6 +390,7 @@ struct load_wuffs_frame_context {
FivIoImage *result; ///< The resulting image (referenced)
FivIoImage *result_tail; ///< The final animation frame
FivIoImage *restore_previous; ///< Canvas before the previous frame
};
static bool
@@ -499,7 +500,11 @@ load_wuffs_frame(struct load_wuffs_frame_context *ctx, GError **error)
goto fail;
}
memcpy(canvas->data, prev->data, prev->stride * prev->height);
FivIoImage *base = ctx->restore_previous
? ctx->restore_previous
: prev;
memcpy(canvas->data, base->data, base->stride * base->height);
g_clear_pointer(&ctx->restore_previous, fiv_io_image_unref);
// Apply that frame's disposal method.
// XXX: We do not expect opaque pictures to receive holes this way.
@@ -519,21 +524,28 @@ load_wuffs_frame(struct load_wuffs_frame_context *ctx, GError **error)
cairo_surface_t *surface = fiv_io_image_to_surface_noref(canvas);
cairo_t *cr = cairo_create(surface);
cairo_surface_destroy(surface);
switch (wuffs_base__frame_config__disposal(&ctx->last_fc)) {
case WUFFS_BASE__ANIMATION_DISPOSAL__RESTORE_BACKGROUND:
if (wuffs_base__frame_config__disposal(&ctx->last_fc) ==
WUFFS_BASE__ANIMATION_DISPOSAL__RESTORE_BACKGROUND) {
cairo_rectangle(cr, bounds.min_incl_x, bounds.min_incl_y,
bounds.max_excl_x - bounds.min_incl_x,
bounds.max_excl_y - bounds.min_incl_y);
cairo_set_source_rgba(cr, r, g, b, a);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_fill(cr);
break;
case WUFFS_BASE__ANIMATION_DISPOSAL__RESTORE_PREVIOUS:
// TODO(p): Implement, it seems tricky.
// Might need another surface to keep track of the state.
break;
case WUFFS_BASE__ANIMATION_DISPOSAL__NONE:
break;
}
if (wuffs_base__frame_config__disposal(&fc) ==
WUFFS_BASE__ANIMATION_DISPOSAL__RESTORE_PREVIOUS) {
ctx->restore_previous = fiv_io_image_new(
canvas->format, canvas->width, canvas->height);
if (!ctx->restore_previous) {
cairo_destroy(cr);
fiv_io_image_unref(canvas);
set_error(error, "image allocation failure");
goto fail;
}
memcpy(ctx->restore_previous->data, canvas->data,
canvas->stride * canvas->height);
}
// Paint the current frame over that, within its bounds.
@@ -763,6 +775,7 @@ fail:
g_clear_pointer(&ctx.meta_exif, g_bytes_unref);
g_clear_pointer(&ctx.meta_iccp, g_bytes_unref);
g_clear_pointer(&ctx.meta_xmp, g_bytes_unref);
g_clear_pointer(&ctx.restore_previous, fiv_io_image_unref);
g_clear_pointer(&ctx.source, fiv_io_profile_free);
return ctx.result;
}