From b7078c17f1bef6350c893b0f87f9726b6a115120 Mon Sep 17 00:00:00 2001
From: Sergey Fedorov <barracuda@macos-powerpc.org>
Date: Fri, 31 Jul 2026 15:26:49 +0000
Subject: [PATCH] formats/svg: support librsvg 2.40

librsvg 2.41 rewrote the library in Rust, which rules it out on
platforms without a Rust toolchain (PowerPC among them); 2.40.x is
the last usable series there. The decoder only used three pieces of
the newer API, all with direct old-API equivalents:

* rsvg_handle_render_document() -> emulated with a cairo
  translate/scale of the viewport plus rsvg_handle_render_cairo();
  the transform composes with the caller's rotation/flip transforms
  exactly like the viewport-based renderer does.
* rsvg_handle_get_intrinsic_dimensions() in get_canvas() ->
  rsvg_handle_get_dimensions(), which resolves units and viewbox
  into pixels itself.
* the RsvgRectangle/RsvgLength types -> a local RsvgRectangle
  definition; RsvgLength is only needed in the new-API branches.

Everything is guarded by LIBRSVG_CHECK_VERSION(2, 46, 0), so builds
against modern librsvg are unchanged. The meson requirement is
relaxed to >= 2.40 accordingly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G6m1eevhAns3j85HMZYKna
---
 meson.build         |  2 +-
 src/formats/svg.cpp | 48 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 49 insertions(+), 1 deletion(-)

diff --git a/meson.build b/meson.build
index ff0f7da..926d4a5 100644
--- meson.build
+++ meson.build
@@ -95,7 +95,7 @@ jp2 = dependency('libopenjp2', required: get_option('jp2'))
 jxl = dependency('libjxl', required: get_option('jxl'))
 jxl_threads = dependency('libjxl_threads', required: get_option('jxl'))
 png = dependency('libpng', required: get_option('png'))
-rsvg = dependency('librsvg-2.0', version: '>=2.46', required: get_option('svg'))
+rsvg = dependency('librsvg-2.0', version: '>=2.40', required: get_option('svg'))
 tiff = dependency('libtiff-4', required: get_option('tiff'))
 sixel = dependency('libsixel', required: get_option('sixel'))
 raw = dependency('libraw', required: get_option('raw'))
diff --git a/src/formats/svg.cpp b/src/formats/svg.cpp
index c530e90..4b1f625 100644
--- src/formats/svg.cpp
+++ src/formats/svg.cpp
@@ -10,6 +10,35 @@
 #include <librsvg/rsvg.h>
 #pragma GCC diagnostic pop
 
+#if !LIBRSVG_CHECK_VERSION(2, 46, 0)
+// librsvg before 2.46 (e.g. 2.40.x, the last pre-Rust series) lacks
+// the viewport-based render API and the intrinsic-dimension queries;
+// map what the code below needs onto the old cairo-based API.
+struct RsvgRectangle {
+    double x;
+    double y;
+    double width;
+    double height;
+};
+
+static void compat_render_document(RsvgHandle* svg, cairo_t* cr,
+                                   const RsvgRectangle* viewport)
+{
+    RsvgDimensionData dim;
+    rsvg_handle_get_dimensions(svg, &dim);
+    cairo_save(cr);
+    cairo_translate(cr, viewport->x, viewport->y);
+    if (dim.width > 0 && dim.height > 0) {
+        cairo_scale(cr, viewport->width / dim.width,
+                    viewport->height / dim.height);
+    }
+    rsvg_handle_render_cairo(svg, cr);
+    cairo_restore(cr);
+}
+#define rsvg_handle_render_document(svg, cr, viewport, error) \
+    compat_render_document((svg), (cr), (viewport))
+#endif
+
 #include <cstring>
 #include <format>
 #include <memory>
@@ -90,6 +119,7 @@ private:
     {
         RsvgRectangle canvas {};
 
+#if LIBRSVG_CHECK_VERSION(2, 46, 0)
         RsvgLength svg_w;
         RsvgLength svg_h;
         RsvgRectangle viewbox;
@@ -112,6 +142,18 @@ private:
             canvas.width = CANVAS_SIZE_DEF_PX;
             canvas.height = CANVAS_SIZE_DEF_PX;
         }
+#else
+        // The old API resolves units and viewbox into pixels itself.
+        RsvgDimensionData dim;
+        rsvg_handle_get_dimensions(svg, &dim);
+        if (dim.width > 0 && dim.height > 0) {
+            canvas.width = dim.width;
+            canvas.height = dim.height;
+        } else {
+            canvas.width = CANVAS_SIZE_DEF_PX;
+            canvas.height = CANVAS_SIZE_DEF_PX;
+        }
+#endif
 
         if (canvas.width < CANVAS_SIZE_MIN_PX ||
             canvas.height < CANVAS_SIZE_MIN_PX) {
@@ -137,6 +179,11 @@ private:
      */
     static std::string get_format(RsvgHandle* svg)
     {
+#if !LIBRSVG_CHECK_VERSION(2, 46, 0)
+        RsvgDimensionData dim;
+        rsvg_handle_get_dimensions(svg, &dim);
+        return std::format("SVG {}x{}px", dim.width, dim.height);
+#else
         RsvgLength svg_w;
         RsvgLength svg_h;
         RsvgRectangle viewbox;
@@ -198,6 +245,7 @@ private:
                                   static_cast<int>(svg_h.length), units);
         }
         return format;
+#endif
     }
 
 private:
