From 074bd4d37f36fa8963e66aa0f8f9de3ff6cadba7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=99emysl=20Eric=20Janouch?= Date: Fri, 23 Jun 2023 22:28:09 +0200 Subject: Stop abusing Cairo user data, part 2 With the shift from cairo_surface_t, we've lost our ability to directly render vector surfaces, but it doesn't matter. --- fiv-thumbnail.c | 207 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 108 insertions(+), 99 deletions(-) (limited to 'fiv-thumbnail.c') diff --git a/fiv-thumbnail.c b/fiv-thumbnail.c index b1f0554..26d21f1 100644 --- a/fiv-thumbnail.c +++ b/fiv-thumbnail.c @@ -125,7 +125,7 @@ might_be_a_thumbnail(const char *path_or_uri) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -static cairo_surface_t * +static FivIoImage * render(GFile *target, GBytes *data, gboolean *color_managed, GError **error) { FivIoOpenContext ctx = { @@ -137,23 +137,22 @@ render(GFile *target, GBytes *data, gboolean *color_managed, GError **error) .warnings = g_ptr_array_new_with_free_func(g_free), }; - cairo_surface_t *surface = fiv_io_image_to_surface(fiv_io_open_from_data( - g_bytes_get_data(data, NULL), g_bytes_get_size(data), &ctx, error)); + FivIoImage *image = fiv_io_open_from_data( + g_bytes_get_data(data, NULL), g_bytes_get_size(data), &ctx, error); g_free((gchar *) ctx.uri); g_ptr_array_free(ctx.warnings, TRUE); if ((*color_managed = !!ctx.screen_profile)) fiv_io_profile_free(ctx.screen_profile); g_bytes_unref(data); - return surface; + return image; } // In principle similar to rescale_thumbnail() from fiv-browser.c. -static cairo_surface_t * -adjust_thumbnail(cairo_surface_t *thumbnail, double row_height) +static FivIoImage * +adjust_thumbnail(FivIoImage *thumbnail, double row_height) { // Hardcode orientation. - FivIoOrientation orientation = (uintptr_t) cairo_surface_get_user_data( - thumbnail, &fiv_io_key_orientation); + FivIoOrientation orientation = thumbnail->orientation; double w = 0, h = 0; cairo_matrix_t matrix = @@ -170,33 +169,40 @@ adjust_thumbnail(cairo_surface_t *thumbnail, double row_height) } // Vector images should not have orientation, this should handle them all. - FivIoRenderClosure *closure = - cairo_surface_get_user_data(thumbnail, &fiv_io_key_render); + FivIoRenderClosure *closure = thumbnail->render; if (closure && orientation <= FivIoOrientation0) { // This API doesn't accept non-uniform scaling; prefer a vertical fit. - cairo_surface_t *scaled = closure->render(closure, scale_y); + FivIoImage *scaled = closure->render(closure, scale_y); if (scaled) return scaled; } - // This will be CAIRO_FORMAT_INVALID with non-image surfaces, which is fine. - cairo_format_t format = cairo_image_surface_get_format(thumbnail); - if (format != CAIRO_FORMAT_INVALID && - orientation <= FivIoOrientation0 && scale_x == 1 && scale_y == 1) - return cairo_surface_reference(thumbnail); + if (orientation <= FivIoOrientation0 && scale_x == 1 && scale_y == 1) + return fiv_io_image_ref(thumbnail); + cairo_format_t format = thumbnail->format; int projected_width = round(scale_x * w); int projected_height = round(scale_y * h); - cairo_surface_t *scaled = cairo_image_surface_create( + FivIoImage *scaled = fiv_io_image_new( (format == CAIRO_FORMAT_RGB24 || format == CAIRO_FORMAT_RGB30) ? CAIRO_FORMAT_RGB24 : CAIRO_FORMAT_ARGB32, projected_width, projected_height); + if (!scaled) { + g_warning("image allocation failure"); + return fiv_io_image_ref(thumbnail); + } + + cairo_surface_t *surface = fiv_io_image_to_surface_noref(scaled); + cairo_t *cr = cairo_create(surface); + cairo_surface_destroy(surface); - cairo_t *cr = cairo_create(scaled); cairo_scale(cr, scale_x, scale_y); - cairo_set_source_surface(cr, thumbnail, 0, 0); + surface = fiv_io_image_to_surface_noref(thumbnail); + cairo_set_source_surface(cr, surface, 0, 0); + cairo_surface_destroy(surface); + cairo_pattern_t *pattern = cairo_get_source(cr); // CAIRO_FILTER_BEST, for some reason, works bad with CAIRO_FORMAT_RGB30. cairo_pattern_set_filter(pattern, CAIRO_FILTER_GOOD); @@ -208,9 +214,7 @@ adjust_thumbnail(cairo_surface_t *thumbnail, double row_height) // Note that this doesn't get triggered with oversize input surfaces, // even though nothing will be rendered. - if (cairo_surface_status(thumbnail) != CAIRO_STATUS_SUCCESS || - cairo_surface_status(scaled) != CAIRO_STATUS_SUCCESS || - cairo_pattern_status(pattern) != CAIRO_STATUS_SUCCESS || + if (cairo_pattern_status(pattern) != CAIRO_STATUS_SUCCESS || cairo_status(cr) != CAIRO_STATUS_SUCCESS) g_warning("thumbnail scaling failed"); @@ -218,27 +222,32 @@ adjust_thumbnail(cairo_surface_t *thumbnail, double row_height) return scaled; } -static cairo_surface_t * -orient_thumbnail(cairo_surface_t *surface) +static FivIoImage * +orient_thumbnail(FivIoImage *image) { - int orientation = (intptr_t) cairo_surface_get_user_data( - surface, &fiv_io_key_orientation); - if (orientation <= FivIoOrientation0) - return surface; + if (image->orientation <= FivIoOrientation0) + return image; double w = 0, h = 0; cairo_matrix_t matrix = - fiv_io_orientation_apply(surface, orientation, &w, &h); - cairo_surface_t *oriented = - cairo_image_surface_create(CAIRO_FORMAT_RGB24, w, h); + fiv_io_orientation_apply(image, image->orientation, &w, &h); + FivIoImage *oriented = fiv_io_image_new(image->format, w, h); + if (!oriented) { + g_warning("image allocation failure"); + return image; + } - cairo_t *cr = cairo_create(oriented); + cairo_surface_t *surface = fiv_io_image_to_surface_noref(oriented); + cairo_t *cr = cairo_create(surface); + cairo_surface_destroy(surface); + + surface = fiv_io_image_to_surface(image); cairo_set_source_surface(cr, surface, 0, 0); + cairo_surface_destroy(surface); cairo_pattern_set_matrix(cairo_get_source(cr), &matrix); cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); cairo_paint(cr); cairo_destroy(cr); - cairo_surface_destroy(surface); return oriented; } @@ -390,7 +399,7 @@ extract_libraw_unflip(int flip) } } -static cairo_surface_t * +static FivIoImage * extract_libraw_bitmap(libraw_processed_image_t *image, int flip, GError **error) { // Anything else is extremely rare. @@ -399,24 +408,26 @@ extract_libraw_bitmap(libraw_processed_image_t *image, int flip, GError **error) return NULL; } - cairo_surface_t *surface = cairo_image_surface_create( + FivIoImage *I = fiv_io_image_new( CAIRO_FORMAT_RGB24, image->width, image->height); - guint32 *out = (guint32 *) cairo_image_surface_get_data(surface); + if (!I) { + set_error(error, "image allocation failure"); + return NULL; + } + + guint32 *out = (guint32 *) I->data; const unsigned char *in = image->data; for (guint64 i = 0; i < image->width * image->height; in += 3) out[i++] = in[0] << 16 | in[1] << 8 | in[2]; - cairo_surface_mark_dirty(surface); - FivIoOrientation orient = extract_libraw_unflip(flip); - cairo_surface_set_user_data( - surface, &fiv_io_key_orientation, (void *) (intptr_t) orient, NULL); - return surface; + I->orientation = extract_libraw_unflip(flip); + return I; } -static cairo_surface_t * +static FivIoImage * extract_libraw(GFile *target, GMappedFile *mf, GError **error) { - cairo_surface_t *surface = NULL; + FivIoImage *I = NULL; libraw_data_t *iprc = libraw_init( LIBRAW_OPIONS_NO_MEMERR_CALLBACK | LIBRAW_OPIONS_NO_DATAERR_CALLBACK); if (!iprc) { @@ -467,11 +478,11 @@ extract_libraw(GFile *target, GMappedFile *mf, GError **error) switch (image->type) { gboolean dummy; case LIBRAW_IMAGE_JPEG: - surface = render( + I = render( target, g_bytes_new(image->data, image->data_size), &dummy, error); break; case LIBRAW_IMAGE_BITMAP: - surface = extract_libraw_bitmap(image, flip, error); + I = extract_libraw_bitmap(image, flip, error); break; default: set_error(error, "unsupported embedded thumbnail"); @@ -480,7 +491,7 @@ extract_libraw(GFile *target, GMappedFile *mf, GError **error) libraw_dcraw_clear_mem(image); fail: libraw_close(iprc); - return surface; + return I; } #endif // HAVE_LIBRAW @@ -506,30 +517,30 @@ fiv_thumbnail_extract(GFile *target, FivThumbnailSize max_size, GError **error) return NULL; } - cairo_surface_t *surface = NULL; + FivIoImage *image = NULL; #ifdef HAVE_LIBRAW - surface = extract_libraw(target, mf, error); + image = extract_libraw(target, mf, error); #else // ! HAVE_LIBRAW // TODO(p): Implement our own thumbnail extractors. set_error(error, "unsupported file"); #endif // ! HAVE_LIBRAW g_mapped_file_unref(mf); - if (!surface) + if (!image) return NULL; if (max_size < FIV_THUMBNAIL_SIZE_MIN || max_size > FIV_THUMBNAIL_SIZE_MAX) - return orient_thumbnail(surface); + return fiv_io_image_to_surface(orient_thumbnail(image)); - cairo_surface_t *result = - adjust_thumbnail(surface, fiv_thumbnail_sizes[max_size].size); - cairo_surface_destroy(surface); - return result; + FivIoImage *result = + adjust_thumbnail(image, fiv_thumbnail_sizes[max_size].size); + fiv_io_image_unref(image); + return fiv_io_image_to_surface(result); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - static WebPData -encode_thumbnail(cairo_surface_t *surface) +encode_thumbnail(FivIoImage *image) { WebPData bitstream = {}; WebPConfig config = {}; @@ -541,12 +552,12 @@ encode_thumbnail(cairo_surface_t *surface) if (!WebPValidateConfig(&config)) return bitstream; - bitstream.bytes = fiv_io_encode_webp(surface, &config, &bitstream.size); + bitstream.bytes = fiv_io_encode_webp(image, &config, &bitstream.size); return bitstream; } static void -save_thumbnail(cairo_surface_t *thumbnail, const char *path, GString *thum) +save_thumbnail(FivIoImage *thumbnail, const char *path, GString *thum) { WebPMux *mux = WebPMuxNew(); WebPData bitstream = encode_thumbnail(thumbnail); @@ -602,15 +613,15 @@ fiv_thumbnail_produce_for_search( return NULL; gboolean color_managed = FALSE; - cairo_surface_t *surface = render(target, data, &color_managed, error); - if (!surface) + FivIoImage *image = render(target, data, &color_managed, error); + if (!image) return NULL; // TODO(p): Might want to keep this a square. - cairo_surface_t *result = - adjust_thumbnail(surface, fiv_thumbnail_sizes[max_size].size); - cairo_surface_destroy(surface); - return result; + FivIoImage *result = + adjust_thumbnail(image, fiv_thumbnail_sizes[max_size].size); + fiv_io_image_unref(image); + return fiv_io_image_to_surface(result); } static cairo_surface_t * @@ -638,14 +649,14 @@ produce_fallback(GFile *target, FivThumbnailSize size, GError **error) return NULL; gboolean color_managed = FALSE; - cairo_surface_t *surface = render(target, data, &color_managed, error); - if (!surface) + FivIoImage *image = render(target, data, &color_managed, error); + if (!image) return NULL; - cairo_surface_t *result = - adjust_thumbnail(surface, fiv_thumbnail_sizes[size].size); - cairo_surface_destroy(surface); - return result; + FivIoImage *result = + adjust_thumbnail(image, fiv_thumbnail_sizes[size].size); + fiv_io_image_unref(image); + return fiv_io_image_to_surface(result); } cairo_surface_t * @@ -690,10 +701,10 @@ fiv_thumbnail_produce(GFile *target, FivThumbnailSize max_size, GError **error) } gboolean color_managed = FALSE; - cairo_surface_t *surface = + FivIoImage *image = render(target, g_mapped_file_get_bytes(mf), &color_managed, error); g_mapped_file_unref(mf); - if (!surface) + if (!image) return NULL; // Boilerplate copied from fiv_thumbnail_lookup(). @@ -709,12 +720,10 @@ fiv_thumbnail_produce(GFile *target, FivThumbnailSize max_size, GError **error) g_string_append_printf( thum, "%s%c%llu%c", THUMB_SIZE, 0, (unsigned long long) filesize, 0); - if (cairo_surface_get_type(surface) == CAIRO_SURFACE_TYPE_IMAGE) { - g_string_append_printf(thum, "%s%c%d%c", THUMB_IMAGE_WIDTH, 0, - cairo_image_surface_get_width(surface), 0); - g_string_append_printf(thum, "%s%c%d%c", THUMB_IMAGE_HEIGHT, 0, - cairo_image_surface_get_height(surface), 0); - } + g_string_append_printf(thum, "%s%c%u%c", THUMB_IMAGE_WIDTH, 0, + (unsigned) image->width, 0); + g_string_append_printf(thum, "%s%c%u%c", THUMB_IMAGE_HEIGHT, 0, + (unsigned) image->height, 0); // Without a CMM, no conversion is attempted. if (color_managed) { @@ -722,19 +731,19 @@ fiv_thumbnail_produce(GFile *target, FivThumbnailSize max_size, GError **error) thum, "%s%c%s%c", THUMB_COLORSPACE, 0, THUMB_COLORSPACE_SRGB, 0); } - cairo_surface_t *max_size_surface = NULL; + FivIoImage *max_size_image = NULL; for (int use = max_size; use >= FIV_THUMBNAIL_SIZE_MIN; use--) { - cairo_surface_t *scaled = - adjust_thumbnail(surface, fiv_thumbnail_sizes[use].size); + FivIoImage *scaled = + adjust_thumbnail(image, fiv_thumbnail_sizes[use].size); gchar *path = g_strdup_printf("%s/wide-%s/%s.webp", thumbnails_dir, fiv_thumbnail_sizes[use].thumbnail_spec_name, sum); save_thumbnail(scaled, path, thum); g_free(path); - if (!max_size_surface) - max_size_surface = scaled; + if (!max_size_image) + max_size_image = scaled; else - cairo_surface_destroy(scaled); + fiv_io_image_unref(scaled); } g_string_free(thum, TRUE); @@ -742,8 +751,8 @@ fiv_thumbnail_produce(GFile *target, FivThumbnailSize max_size, GError **error) g_free(thumbnails_dir); g_free(sum); g_free(uri); - cairo_surface_destroy(surface); - return max_size_surface; + fiv_io_image_unref(image); + return fiv_io_image_to_surface(max_size_image); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -793,23 +802,23 @@ read_wide_thumbnail(const char *path, const Stat *st, GError **error) if (!thumbnail_uri) return NULL; - cairo_surface_t *surface = fiv_io_image_to_surface( - fiv_io_open(&(FivIoOpenContext){.uri = thumbnail_uri}, error)); + FivIoImage *image = + fiv_io_open(&(FivIoOpenContext){.uri = thumbnail_uri}, error); g_free(thumbnail_uri); - if (!surface) + if (!image) return NULL; bool sRGB = false; - GBytes *thum = cairo_surface_get_user_data(surface, &fiv_io_key_thum); - if (!thum) { + if (!image->thum) { g_clear_error(error); set_error(error, "not a thumbnail"); - } else if (!check_wide_thumbnail_texts(thum, st, &sRGB)) { + } else if (!check_wide_thumbnail_texts(image->thum, st, &sRGB)) { g_clear_error(error); set_error(error, "mismatch"); } else { // TODO(p): Add a function or a non-valueless define to check // for CMM presence, then remove this ifdef. + cairo_surface_t *surface = fiv_io_image_to_surface(image); #ifdef HAVE_LCMS2 if (!sRGB) mark_thumbnail_lq(surface); @@ -817,21 +826,21 @@ read_wide_thumbnail(const char *path, const Stat *st, GError **error) return surface; } - cairo_surface_destroy(surface); + fiv_io_image_unref(image); return NULL; } static cairo_surface_t * read_png_thumbnail(const char *path, const Stat *st, GError **error) { - cairo_surface_t *surface = fiv_io_open_png_thumbnail(path, error); - if (!surface) + FivIoImage *image = fiv_io_open_png_thumbnail(path, error); + if (!image) return NULL; - GHashTable *texts = cairo_surface_get_user_data(surface, &fiv_io_key_text); + GHashTable *texts = image->text; if (!texts) { set_error(error, "not a thumbnail"); - cairo_surface_destroy(surface); + fiv_io_image_unref(image); return NULL; } @@ -843,16 +852,16 @@ read_png_thumbnail(const char *path, const Stat *st, GError **error) if (!text_uri || strcmp(text_uri, st->uri) || !text_mtime || atol(text_mtime) != st->mtime) { set_error(error, "mismatch or not a thumbnail"); - cairo_surface_destroy(surface); + fiv_io_image_unref(image); return NULL; } if (text_size && strtoull(text_size, NULL, 10) != st->size) { set_error(error, "file size mismatch"); - cairo_surface_destroy(surface); + fiv_io_image_unref(image); return NULL; } - return surface; + return fiv_io_image_to_surface(image); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -- cgit v1.2.3