Submitted By:            Xi Ruoyao <xry111 at xry111 dot site>
Date:                    2025-01-31
Initial Package Version: 4.16.12
Upstream Status:         Committed
Origin:                  Upstream MR 8158
Description:             Fix compatibility with libpng >= 1.6.45

From 58844ec795819df880ff0bf6b05a11999d0b9aff Mon Sep 17 00:00:00 2001
From: Alessandro Astone <alessandro.astone@canonical.com>
Date: Tue, 28 Jan 2025 18:05:07 +0100
Subject: [PATCH] png: handle cICP chunk via libpng API

libpng 1.6.45 has gained the ability to read and write the cICP chunk.

libpng will now recognize the cICP chunk as a "known" chunk and thus will
not present it as a "user" chunk anymore, breaking our handling.
We thus need to switch to using the API.

The png data changes because libpng writes the cICP chunk at a different
position than we were, so adjust the tests reference data accordingly.

Fixes: #7271
---
 gdk/loaders/gdkpng.c                          | 39 +++++++++++++++++--
 testsuite/gsk/meson.build                     | 18 ++++++---
 .../nodeparser/empty-texture-scale.ref.node   |  4 +-
 .../gsk/nodeparser/empty-texture.ref.node     |  4 +-
 .../gsk/nodeparser/texture-fail.ref.node      |  4 +-
 testsuite/gsk/nodeparser/texture-names.node   |  4 +-
 .../nodeparser/texture-scale-filters.ref.node | 16 ++++----
 .../texture-scale-unknown-filter.ref.node     |  4 +-
 8 files changed, 66 insertions(+), 27 deletions(-)

diff --git a/gdk/loaders/gdkpng.c b/gdk/loaders/gdkpng.c
index 212e3de1776..b82fd05ebdb 100644
--- a/gdk/loaders/gdkpng.c
+++ b/gdk/loaders/gdkpng.c
@@ -130,6 +130,7 @@ png_simple_warning_callback (png_structp     png,
 /* }}} */
 /* {{{ Color profile handling */
 
+#if PNG_LIBPNG_VER < 10645
 typedef struct
 {
   gboolean cicp_chunk_read;
@@ -174,6 +175,7 @@ gdk_png_get_color_state_from_cicp (const CICPData  *data,
 
   return gdk_color_state_new_for_cicp (&cicp, error);
 }
+#endif
 
 static GdkColorState *
 gdk_png_get_color_state (png_struct  *png,
@@ -181,16 +183,35 @@ gdk_png_get_color_state (png_struct  *png,
                          GError     **error)
 {
   GdkColorState *color_state;
-  CICPData *cicp;
   int intent;
 
-  cicp = png_get_user_chunk_ptr (png);
+#if PNG_LIBPNG_VER >= 10645
+  png_byte color_primaries;
+  png_byte transfer_function;
+  png_byte matrix_coefficients;
+  png_byte range;
 
-  if (cicp->cicp_chunk_read)
+  if (png_get_cICP (png, info, &color_primaries, &transfer_function, &matrix_coefficients, &range))
     {
       GError *local_error = NULL;
+      GdkCicp cicp;
 
+      cicp.color_primaries = color_primaries;
+      cicp.transfer_function = transfer_function;
+      cicp.matrix_coefficients = matrix_coefficients;
+      cicp.range = range;
+
+      color_state = gdk_color_state_new_for_cicp (&cicp, error);
+#else
+  CICPData *cicp;
+
+  cicp = png_get_user_chunk_ptr (png);
+  if (cicp->cicp_chunk_read)
+    {
+      GError *local_error = NULL;
       color_state = gdk_png_get_color_state_from_cicp (cicp, &local_error);
+#endif
+
       if (color_state)
         {
           g_debug ("Color state from cICP data: %s", gdk_color_state_get_name (color_state));
@@ -236,6 +257,13 @@ gdk_png_set_color_state (png_struct    *png,
 
   if (cicp)
     {
+#if PNG_LIBPNG_VER >= 10645
+      png_set_cICP (png, info,
+                    (png_byte) cicp->color_primaries,
+                    (png_byte) cicp->transfer_function,
+                    (png_byte) 0 /* png only supports this */,
+                    (png_byte) cicp->range);
+#else
       png_unknown_chunk chunk = {
         .name = { 'c', 'I', 'C', 'P', '\0' },
         .data = chunk_data,
@@ -249,6 +277,7 @@ gdk_png_set_color_state (png_struct    *png,
       chunk_data[3] = (png_byte) cicp->range;
 
       png_set_unknown_chunks (png, info, &chunk, 1);
+#endif
     }
   else
     {
@@ -287,7 +316,9 @@ gdk_load_png (GBytes      *bytes,
   GdkColorState *color_state;
   GdkTexture *texture;
   int bpp;
+#if PNG_LIBPNG_VER < 10645
   CICPData cicp = { FALSE, };
+#endif
 
   G_GNUC_UNUSED gint64 before = GDK_PROFILER_CURRENT_TIME;
 
@@ -309,7 +340,9 @@ gdk_load_png (GBytes      *bytes,
     g_error ("Out of memory");
 
   png_set_read_fn (png, &io, png_read_func);
+#if PNG_LIBPNG_VER < 10645
   png_set_read_user_chunk_fn (png, &cicp, png_read_chunk_func);
+#endif
 
   if (sigsetjmp (png_jmpbuf (png), 1))
     {
diff --git a/testsuite/gsk/meson.build b/testsuite/gsk/meson.build
index 6e2ee41fa75..72b6174f609 100644
--- a/testsuite/gsk/meson.build
+++ b/testsuite/gsk/meson.build
@@ -380,9 +380,7 @@ node_parser_tests = [
   'empty-subsurface.ref.node',
   'empty-text.node',
   'empty-text.ref.node',
-  'empty-texture.node',
   'empty-texture.ref.node',
-  'empty-texture-scale.node',
   'empty-texture-scale.ref.node',
   'empty-transform.node',
   'empty-transform.ref.node',
@@ -442,14 +440,10 @@ node_parser_tests = [
   'text-font-options-error.ref.node',
   'text-font-options-error.ref.errors',
   'text-no-color.node',
-  'texture-fail.node',
   'texture-fail.ref.node',
   'texture-fail.errors',
-  'texture-names.node',
-  'texture-scale-filters.node',
   'texture-scale-filters.ref.node',
   'texture-scale-unknown-filter.errors',
-  'texture-scale-unknown-filter.node',
   'texture-scale-unknown-filter.ref.node',
   'transform-fail.node',
   'transform-fail.ref.node',
@@ -458,6 +452,18 @@ node_parser_tests = [
   #'widgetfactory.node',
 ]
 
+# libpng 1.6.45 changes the chunk order. These ref tests can only pass on libpng >=1.6.45
+if png_dep.version().version_compare('>=1.6.45')
+node_parser_tests += [
+  'empty-texture-scale.node',
+  'empty-texture.node',
+  'texture-fail.node',
+  'texture-names.node',
+  'texture-scale-filters.node',
+  'texture-scale-unknown-filter.node',
+]
+endif
+
 foreach test : node_parser_tests
   if test.endswith('.node') and not test.endswith('.ref.node')
     test('parser ' + test, node_parser,
diff --git a/testsuite/gsk/nodeparser/empty-texture-scale.ref.node b/testsuite/gsk/nodeparser/empty-texture-scale.ref.node
index d91d33481dd..3bf6759a40b 100644
--- a/testsuite/gsk/nodeparser/empty-texture-scale.ref.node
+++ b/testsuite/gsk/nodeparser/empty-texture-scale.ref.node
@@ -1,8 +1,8 @@
 texture-scale {
   bounds: 0 0 50 50;
   texture: url("data:image/png;base64,\
-iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAAXNSR0IArs4c6QAAAARjSUNQAQ0A\
-AZxpOzIAAAApSURBVBiVY/zPcOY/AxpgZDBhRBdjQhfABQZQIYajGRgYGLB5cCh4BgDPjgXd7dTX\
+iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABGNJQ1ABDQABnGk7MgAAAAFzUkdC\
+AK7OHOkAAAApSURBVBiVY/zPcOY/AxpgZDBhRBdjQhfABQZQIYajGRgYGLB5cCh4BgDPjgXd7dTX\
 FQAAAABJRU5ErkJggg==\
 ");
 }
diff --git a/testsuite/gsk/nodeparser/empty-texture.ref.node b/testsuite/gsk/nodeparser/empty-texture.ref.node
index 4a52442007d..bebc47a93b1 100644
--- a/testsuite/gsk/nodeparser/empty-texture.ref.node
+++ b/testsuite/gsk/nodeparser/empty-texture.ref.node
@@ -1,8 +1,8 @@
 texture {
   bounds: 0 0 50 50;
   texture: url("data:image/png;base64,\
-iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAAXNSR0IArs4c6QAAAARjSUNQAQ0A\
-AZxpOzIAAAApSURBVBiVY/zPcOY/AxpgZDBhRBdjQhfABQZQIYajGRgYGLB5cCh4BgDPjgXd7dTX\
+iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABGNJQ1ABDQABnGk7MgAAAAFzUkdC\
+AK7OHOkAAAApSURBVBiVY/zPcOY/AxpgZDBhRBdjQhfABQZQIYajGRgYGLB5cCh4BgDPjgXd7dTX\
 FQAAAABJRU5ErkJggg==\
 ");
 }
diff --git a/testsuite/gsk/nodeparser/texture-fail.ref.node b/testsuite/gsk/nodeparser/texture-fail.ref.node
index 4a52442007d..bebc47a93b1 100644
--- a/testsuite/gsk/nodeparser/texture-fail.ref.node
+++ b/testsuite/gsk/nodeparser/texture-fail.ref.node
@@ -1,8 +1,8 @@
 texture {
   bounds: 0 0 50 50;
   texture: url("data:image/png;base64,\
-iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAAXNSR0IArs4c6QAAAARjSUNQAQ0A\
-AZxpOzIAAAApSURBVBiVY/zPcOY/AxpgZDBhRBdjQhfABQZQIYajGRgYGLB5cCh4BgDPjgXd7dTX\
+iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABGNJQ1ABDQABnGk7MgAAAAFzUkdC\
+AK7OHOkAAAApSURBVBiVY/zPcOY/AxpgZDBhRBdjQhfABQZQIYajGRgYGLB5cCh4BgDPjgXd7dTX\
 FQAAAABJRU5ErkJggg==\
 ");
 }
diff --git a/testsuite/gsk/nodeparser/texture-names.node b/testsuite/gsk/nodeparser/texture-names.node
index c03aef5571c..2656455007d 100644
--- a/testsuite/gsk/nodeparser/texture-names.node
+++ b/testsuite/gsk/nodeparser/texture-names.node
@@ -1,8 +1,8 @@
 texture {
   bounds: 0 0 1 1;
   texture: "texture1" url("data:image/png;base64,\
-iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARjSUNQAQ0A\
-AZxpOzIAAAANSURBVAiZY/jPwPAfAAUAAf+rzjaJAAAAAElFTkSuQmCC\
+iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAABGNJQ1ABDQABnGk7MgAAAAFzUkdC\
+AK7OHOkAAAANSURBVAiZY/jPwPAfAAUAAf+rzjaJAAAAAElFTkSuQmCC\
 ");
 }
 texture {
diff --git a/testsuite/gsk/nodeparser/texture-scale-filters.ref.node b/testsuite/gsk/nodeparser/texture-scale-filters.ref.node
index ac17829ce7d..f9b66bf6a81 100644
--- a/testsuite/gsk/nodeparser/texture-scale-filters.ref.node
+++ b/testsuite/gsk/nodeparser/texture-scale-filters.ref.node
@@ -1,30 +1,30 @@
 texture-scale {
   bounds: 0 0 50 50;
   texture: url("data:image/png;base64,\
-iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAAXNSR0IArs4c6QAAAARjSUNQAQ0A\
-AZxpOzIAAAAYSURBVBiVY/zPwPCfgQjARIyiUYXUUwgAPZwCEvXDjugAAAAASUVORK5CYII=\
+iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABGNJQ1ABDQABnGk7MgAAAAFzUkdC\
+AK7OHOkAAAAYSURBVBiVY/zPwPCfgQjARIyiUYXUUwgAPZwCEvXDjugAAAAASUVORK5CYII=\
 ");
 }
 texture-scale {
   bounds: 0 0 50 50;
   texture: url("data:image/png;base64,\
-iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAAXNSR0IArs4c6QAAAARjSUNQAQ0A\
-AZxpOzIAAAAYSURBVBiVY/zPwPCfgQjARIyiUYXUUwgAPZwCEvXDjugAAAAASUVORK5CYII=\
+iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABGNJQ1ABDQABnGk7MgAAAAFzUkdC\
+AK7OHOkAAAAYSURBVBiVY/zPwPCfgQjARIyiUYXUUwgAPZwCEvXDjugAAAAASUVORK5CYII=\
 ");
 }
 texture-scale {
   bounds: 0 0 50 50;
   filter: nearest;
   texture: url("data:image/png;base64,\
-iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAAXNSR0IArs4c6QAAAARjSUNQAQ0A\
-AZxpOzIAAAAYSURBVBiVY/zPwPCfgQjARIyiUYXUUwgAPZwCEvXDjugAAAAASUVORK5CYII=\
+iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABGNJQ1ABDQABnGk7MgAAAAFzUkdC\
+AK7OHOkAAAAYSURBVBiVY/zPwPCfgQjARIyiUYXUUwgAPZwCEvXDjugAAAAASUVORK5CYII=\
 ");
 }
 texture-scale {
   bounds: 0 0 50 50;
   filter: trilinear;
   texture: url("data:image/png;base64,\
-iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAAXNSR0IArs4c6QAAAARjSUNQAQ0A\
-AZxpOzIAAAAYSURBVBiVY/zPwPCfgQjARIyiUYXUUwgAPZwCEvXDjugAAAAASUVORK5CYII=\
+iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABGNJQ1ABDQABnGk7MgAAAAFzUkdC\
+AK7OHOkAAAAYSURBVBiVY/zPwPCfgQjARIyiUYXUUwgAPZwCEvXDjugAAAAASUVORK5CYII=\
 ");
 }
diff --git a/testsuite/gsk/nodeparser/texture-scale-unknown-filter.ref.node b/testsuite/gsk/nodeparser/texture-scale-unknown-filter.ref.node
index d91d33481dd..3bf6759a40b 100644
--- a/testsuite/gsk/nodeparser/texture-scale-unknown-filter.ref.node
+++ b/testsuite/gsk/nodeparser/texture-scale-unknown-filter.ref.node
@@ -1,8 +1,8 @@
 texture-scale {
   bounds: 0 0 50 50;
   texture: url("data:image/png;base64,\
-iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAAXNSR0IArs4c6QAAAARjSUNQAQ0A\
-AZxpOzIAAAApSURBVBiVY/zPcOY/AxpgZDBhRBdjQhfABQZQIYajGRgYGLB5cCh4BgDPjgXd7dTX\
+iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABGNJQ1ABDQABnGk7MgAAAAFzUkdC\
+AK7OHOkAAAApSURBVBiVY/zPcOY/AxpgZDBhRBdjQhfABQZQIYajGRgYGLB5cCh4BgDPjgXd7dTX\
 FQAAAABJRU5ErkJggg==\
 ");
 }
-- 
GitLab