From 6e80a3b5c8aaa408bb1333dfc2f7595d0772997b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=99emysl=20Eric=20Janouch?= Date: Wed, 5 Aug 2026 01:58:57 +0200 Subject: [PATCH] Extract a function --- fiv-io.c | 162 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 84 insertions(+), 78 deletions(-) diff --git a/fiv-io.c b/fiv-io.c index c0bf716..c5b0315 100644 --- a/fiv-io.c +++ b/fiv-io.c @@ -393,6 +393,87 @@ struct load_wuffs_frame_context { FivIoImage *restore_previous; ///< Canvas before the previous frame }; +static bool +load_wuffs_frame_compose(struct load_wuffs_frame_context *ctx, + FivIoImage **image, const wuffs_base__frame_config *fc, GError **error) +{ + // Copy the previous frame to a new image. + FivIoImage *prev = ctx->result_tail, *canvas = fiv_io_image_new( + prev->format, prev->width, prev->height); + if (!canvas) { + set_error(error, "image allocation failure"); + return false; + } + + 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. + wuffs_base__rect_ie_u32 bounds = + wuffs_base__frame_config__bounds(&ctx->last_fc); + // TODO(p): This field needs to be colour-managed. + wuffs_base__color_u32_argb_premul bg = + wuffs_base__frame_config__background_color(&ctx->last_fc); + + double a = (bg >> 24) / 255., r = 0, g = 0, b = 0; + if (a) { + r = (uint8_t) (bg >> 16) / 255. / a; + g = (uint8_t) (bg >> 8) / 255. / a; + b = (uint8_t) (bg) / 255. / a; + } + + cairo_surface_t *surface = fiv_io_image_to_surface_noref(canvas); + cairo_t *cr = cairo_create(surface); + cairo_surface_destroy(surface); + 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); + } + + 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"); + return false; + } + memcpy(ctx->restore_previous->data, canvas->data, + canvas->stride * canvas->height); + } + + // Paint the current frame over that, within its bounds. + bounds = wuffs_base__frame_config__bounds(fc); + 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_clip(cr); + + cairo_set_operator(cr, + wuffs_base__frame_config__overwrite_instead_of_blend(fc) + ? CAIRO_OPERATOR_SOURCE + : CAIRO_OPERATOR_OVER); + + surface = fiv_io_image_to_surface_noref(*image); + cairo_set_source_surface(cr, surface, 0, 0); + cairo_surface_destroy(surface); + cairo_paint(cr); + cairo_destroy(cr); + + fiv_io_image_unref(*image); + *image = canvas; + return true; +} + static bool load_wuffs_frame(struct load_wuffs_frame_context *ctx, GError **error) { @@ -491,84 +572,9 @@ load_wuffs_frame(struct load_wuffs_frame_context *ctx, GError **error) } // Single-frame images get a fast path, animations are are handled slowly: - if (wuffs_base__frame_config__index(&fc) > 0) { - // Copy the previous frame to a new image. - FivIoImage *prev = ctx->result_tail, *canvas = fiv_io_image_new( - prev->format, prev->width, prev->height); - if (!canvas) { - set_error(error, "image allocation failure"); - goto fail; - } - - 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. - wuffs_base__rect_ie_u32 bounds = - wuffs_base__frame_config__bounds(&ctx->last_fc); - // TODO(p): This field needs to be colour-managed. - wuffs_base__color_u32_argb_premul bg = - wuffs_base__frame_config__background_color(&ctx->last_fc); - - double a = (bg >> 24) / 255., r = 0, g = 0, b = 0; - if (a) { - r = (uint8_t) (bg >> 16) / 255. / a; - g = (uint8_t) (bg >> 8) / 255. / a; - b = (uint8_t) (bg) / 255. / a; - } - - cairo_surface_t *surface = fiv_io_image_to_surface_noref(canvas); - cairo_t *cr = cairo_create(surface); - cairo_surface_destroy(surface); - 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); - } - - 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. - bounds = wuffs_base__frame_config__bounds(&fc); - 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_clip(cr); - - cairo_set_operator(cr, - wuffs_base__frame_config__overwrite_instead_of_blend(&fc) - ? CAIRO_OPERATOR_SOURCE - : CAIRO_OPERATOR_OVER); - - surface = fiv_io_image_to_surface_noref(image); - cairo_set_source_surface(cr, surface, 0, 0); - cairo_surface_destroy(surface); - cairo_paint(cr); - cairo_destroy(cr); - - fiv_io_image_unref(image); - image = canvas; - } + if (wuffs_base__frame_config__index(&fc) > 0 && + !load_wuffs_frame_compose(ctx, &image, &fc, error)) + goto fail; if (ctx->meta_exif) image->exif = g_bytes_ref(ctx->meta_exif);