From 6d5aaa995f80500d5ba3c1b9fae2538d855db002 Mon Sep 17 00:00:00 2001 From: Jehan Date: Mon, 11 Sep 2023 15:58:44 +0200 Subject: [PATCH] app: new storage format for the text layer parasite implies XCF version bump. The new parasite format cannot be loaded by old versions of GIMP. This means we must bump the XCF version (even though technically we didn't really touch the XCF format itself because text layers are stored in a hackish way, yet text layers are just too important nowadays to not care). Nevertheless if an old XCF with text layers was loaded and the text layers left untouched, the old parasite will be saved back as-is. Therefore no need to bump the XCF version in this specific case. Only when we created new text layers or edited existing ones. --- app/core/gimpimage.c | 14 ++++++++++++++ app/text/gimptext-parasite.c | 5 +++-- app/text/gimptext-parasite.h | 1 + app/text/gimptextlayer-xcf.c | 10 ++++++++-- app/text/gimptextlayer.c | 15 ++++++++++----- app/text/gimptextlayer.h | 9 +++++---- app/xcf/xcf.c | 1 + 7 files changed, 42 insertions(+), 13 deletions(-) diff --git a/app/core/gimpimage.c b/app/core/gimpimage.c index c838b6e682..6c994ab08e 100644 --- a/app/core/gimpimage.c +++ b/app/core/gimpimage.c @@ -82,6 +82,8 @@ #include "gimptemplate.h" #include "gimpundostack.h" +#include "text/gimptextlayer.h" + #include "vectors/gimpvectors.h" #include "gimp-log.h" @@ -2961,6 +2963,17 @@ gimp_image_get_xcf_version (GimpImage *image, "GIMP 3.0")); version = MAX (17, version); } + + if (GIMP_IS_TEXT_LAYER (layer) && + /* If we loaded an old XCF and didn't touch the text layers, then we + * just resave the text layer as-is. No need to bump the XCF version. + */ + ! GIMP_TEXT_LAYER (layer)->text_parasite_is_old) + { + ADD_REASON (g_strdup_printf (_("Format of font information in text layer was changed in %s"), + "GIMP 3.0")); + version = MAX (19, version); + } } g_list_free (items); @@ -3127,6 +3140,7 @@ gimp_image_get_xcf_version (GimpImage *image, case 16: case 17: case 18: + case 19: if (gimp_version) *gimp_version = 300; if (version_string) *version_string = "GIMP 3.0"; break; diff --git a/app/text/gimptext-parasite.c b/app/text/gimptext-parasite.c index f6933b6e4c..fa670c5ee1 100644 --- a/app/text/gimptext-parasite.c +++ b/app/text/gimptext-parasite.c @@ -67,6 +67,7 @@ gimp_text_to_parasite (GimpText *text) GimpText * gimp_text_from_parasite (const GimpParasite *parasite, Gimp *gimp, + gboolean *before_xcf_v19, GError **error) { GimpText *text; @@ -83,17 +84,17 @@ gimp_text_from_parasite (const GimpParasite *parasite, parasite_data = (gchar *) gimp_parasite_get_data (parasite, ¶site_data_size); if (parasite_data) { - gboolean is_old = strstr (parasite_data, "\"GimpFont\"") == NULL; gboolean has_markup = g_str_has_prefix (parasite_data, "(markup "); GimpParasite *new_parasite = NULL; GString *new_data; + *before_xcf_v19 = (strstr (parasite_data, "\"GimpFont\"") == NULL); /* This is for backward compatibility with older xcf files. * font used to be serialized as a string, but now it is serialized/deserialized as * GimpFont, so the object Type name is inserted for the GimpFont deserialization function to be called. * And more importantly, fonts in the markup are extracted into their own fields for deserialization. */ - if (is_old) + if (*before_xcf_v19) { new_data = g_string_new (parasite_data); g_string_replace (new_data, "\")\n(font", "\")\n(font \"GimpFont\"", 1); diff --git a/app/text/gimptext-parasite.h b/app/text/gimptext-parasite.h index eae1087b0d..58767b7b05 100644 --- a/app/text/gimptext-parasite.h +++ b/app/text/gimptext-parasite.h @@ -26,6 +26,7 @@ const gchar * gimp_text_parasite_name (void) G_GNUC_CONST; GimpParasite * gimp_text_to_parasite (GimpText *text); GimpText * gimp_text_from_parasite (const GimpParasite *parasite, Gimp *gimp, + gboolean *before_xcf_v19, GError **error); const gchar * gimp_text_gdyntext_parasite_name (void) G_GNUC_CONST; diff --git a/app/text/gimptextlayer-xcf.c b/app/text/gimptextlayer-xcf.c index 8a93d0f8e8..89b78eef7f 100644 --- a/app/text/gimptextlayer-xcf.c +++ b/app/text/gimptextlayer-xcf.c @@ -58,6 +58,7 @@ gimp_text_layer_xcf_load_hack (GimpLayer **layer) const gchar *name; GimpText *text = NULL; const GimpParasite *parasite; + gboolean before_xcf_v19 = FALSE; g_return_val_if_fail (layer != NULL, FALSE); g_return_val_if_fail (GIMP_IS_LAYER (*layer), FALSE); @@ -71,6 +72,7 @@ gimp_text_layer_xcf_load_hack (GimpLayer **layer) text = gimp_text_from_parasite (parasite, gimp_item_get_image (GIMP_ITEM (*layer))->gimp, + &before_xcf_v19, &error); if (error) @@ -94,7 +96,10 @@ gimp_text_layer_xcf_load_hack (GimpLayer **layer) parasite = gimp_item_parasite_find (GIMP_ITEM (*layer), name); if (parasite) - text = gimp_text_from_gdyntext_parasite (parasite); + { + text = gimp_text_from_gdyntext_parasite (parasite); + before_xcf_v19 = TRUE; + } } if (text) @@ -102,7 +107,8 @@ gimp_text_layer_xcf_load_hack (GimpLayer **layer) *layer = gimp_text_layer_from_layer (*layer, text); /* let the text layer knows what parasite was used to create it */ - GIMP_TEXT_LAYER (*layer)->text_parasite = name; + GIMP_TEXT_LAYER (*layer)->text_parasite = name; + GIMP_TEXT_LAYER (*layer)->text_parasite_is_old = before_xcf_v19; } return (text != NULL); diff --git a/app/text/gimptextlayer.c b/app/text/gimptextlayer.c index 1147b1e324..a5d728f0df 100644 --- a/app/text/gimptextlayer.c +++ b/app/text/gimptextlayer.c @@ -191,9 +191,10 @@ gimp_text_layer_class_init (GimpTextLayerClass *klass) static void gimp_text_layer_init (GimpTextLayer *layer) { - layer->text = NULL; - layer->text_parasite = NULL; - layer->private = gimp_text_layer_get_instance_private (layer); + layer->text = NULL; + layer->text_parasite = NULL; + layer->text_parasite_is_old = FALSE; + layer->private = gimp_text_layer_get_instance_private (layer); } static void @@ -300,7 +301,10 @@ gimp_text_layer_duplicate (GimpItem *item, /* this is just the parasite name, not a pointer to the parasite */ if (layer->text_parasite) - new_layer->text_parasite = layer->text_parasite; + { + new_layer->text_parasite = layer->text_parasite; + new_layer->text_parasite_is_old = layer->text_parasite_is_old; + } new_layer->private->base_dir = layer->private->base_dir; } @@ -617,7 +621,8 @@ gimp_text_layer_text_changed (GimpTextLayer *layer) */ gimp_item_parasite_detach (GIMP_ITEM (layer), layer->text_parasite, FALSE); - layer->text_parasite = NULL; + layer->text_parasite = NULL; + layer->text_parasite_is_old = FALSE; } if (layer->text->box_mode == GIMP_TEXT_BOX_DYNAMIC) diff --git a/app/text/gimptextlayer.h b/app/text/gimptextlayer.h index 87c61a724d..53a233ff0a 100644 --- a/app/text/gimptextlayer.h +++ b/app/text/gimptextlayer.h @@ -41,10 +41,11 @@ struct _GimpTextLayer GimpLayer layer; GimpText *text; - const gchar *text_parasite; /* parasite name that this text was set from, - * and that should be removed when the text - * is changed. - */ + const gchar *text_parasite; /* parasite name that this text was set from, + * and that should be removed when the text + * is changed. + */ + gboolean text_parasite_is_old; /* Format before XCF 19. */ gboolean auto_rename; gboolean modified; diff --git a/app/xcf/xcf.c b/app/xcf/xcf.c index 6164f55734..edf7fae186 100644 --- a/app/xcf/xcf.c +++ b/app/xcf/xcf.c @@ -87,6 +87,7 @@ static GimpXcfLoaderFunc * const xcf_loaders[] = xcf_load_image, /* version 16 */ xcf_load_image, /* version 17 */ xcf_load_image, /* version 18 */ + xcf_load_image, /* version 19 */ };