Implement another animation frame disposal method
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user