diff --git a/gnu/local.mk b/gnu/local.mk
index bed0c181e4..108cbe83ba 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -1000,8 +1000,6 @@ dist_patch_DATA =						\
   %D%/packages/patches/breezy-fix-gio.patch			\
   %D%/packages/patches/byobu-writable-status.patch		\
   %D%/packages/patches/bubblewrap-fix-locale-in-tests.patch	\
-  %D%/packages/patches/cairo-CVE-2018-19876.patch		\
-  %D%/packages/patches/cairo-CVE-2020-35492.patch		\
   %D%/packages/patches/calibre-no-updates-dialog.patch		\
   %D%/packages/patches/calibre-remove-test-sqlite.patch		\
   %D%/packages/patches/calibre-remove-test-unrar.patch		\
diff --git a/gnu/packages/gtk.scm b/gnu/packages/gtk.scm
index 67a0c0727e..b5312b4575 100644
--- a/gnu/packages/gtk.scm
+++ b/gnu/packages/gtk.scm
@@ -36,6 +36,7 @@
 ;;; Copyright © 2023 Sergiu Ivanov <sivanov@colimite.fr>
 ;;; Copyright © 2023 Zheng Junjie <873216071@qq.com>
 ;;; Copyright © 2023 Janneke Nieuwenhuizen <janneke@gnu.org>
+;;; Copyright © 2024 John Kehayias <john.kehayias@protonmail.com>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -120,7 +121,11 @@ (define-module (gnu packages gtk)
   #:use-module (gnu packages pulseaudio)
   #:use-module (srfi srfi-1)
   #:use-module (srfi srfi-26)
-  #:use-module (ice-9 match))
+  #:use-module (ice-9 match)
+  ;; Export cairo to break a dependency cycle, as gtk-doc is needed to build
+  ;; the documentation.  Use cairo for other packages and
+  ;; cairo-with-documentation as the public package.
+  #:export (cairo))

 (define-public appmenu-gtk-module
   (package
@@ -159,10 +164,10 @@ (define-public appmenu-gtk-module
     (home-page "https://gitlab.com/vala-panel-project/vala-panel-appmenu")
     (license (list license:lgpl3))))

-(define-public cairo
+(define cairo
   (package
     (name "cairo")
-    (version "1.16.0")
+    (version "1.18.0")
     (source
      (origin
        (method url-fetch)
@@ -170,30 +175,13 @@ (define-public cairo
         (string-append "https://cairographics.org/releases/cairo-"
                        version ".tar.xz"))
        (sha256
-        (base32 "0c930mk5xr2bshbdljv005j3j8zr47gqmkry3q6qgvqky6rjjysy"))
-       (patches (search-patches
-		 "cairo-CVE-2018-19876.patch"
-		 "cairo-CVE-2020-35492.patch"))))
-    (build-system glib-or-gtk-build-system)
-    (outputs '("out" "doc"))
+        (base32 "0r0by563s75xyzz0d0j1nmjqmdrk2x9agk7r57p3v8vqp4v0ffi4"))))
+    (build-system meson-build-system)
     (arguments
      `(#:tests? #f ; see http://lists.gnu.org/archive/html/bug-guix/2013-06/msg00085.html
+       #:glib-or-gtk? #t
        #:configure-flags
-       (list
-        "--disable-static"
-        ;; XXX: To be enabled.
-        ;; "--enable-gallium=yes"
-        ;; "--enable-gl=yes"
-        ;; " --enable-glesv2=yes"
-        ;; "--enable-glesv3=yes"
-        ;; "--enable-cogl=yes"
-        ;; "--enable-directfb=yes"
-        ;; "--enable-vg=yes"
-        "--enable-tee=yes"              ;needed for GNU IceCat
-        "--enable-xml=yes"              ;for cairo-xml support
-        (string-append "--with-html-dir="
-                       (assoc-ref %outputs "doc")
-                       "/share/gtk-doc/html"))))
+       (list "-Dtests=disabled")))
     (native-inputs
      `(,@(if (target-hurd?)
              '()
@@ -211,15 +199,10 @@ (define-public cairo
              '()
              `(("poppler" ,poppler)))))
     (propagated-inputs
-     `( ;; ("cogl" ,cogl)
-       ;; ("directfb" ,directfb)
-       ("fontconfig" ,fontconfig)
+     `(("fontconfig" ,fontconfig)
        ("freetype" ,freetype)
        ("glib" ,glib)
-       ;; ("gtk+" ,gtk+)
        ("libpng" ,libpng)
-       ;; ("librsvg" ,librsvg)
-       ;; ("opengl" ,mesa)
        ("pixman" ,pixman)
        ("x11" ,libx11)
        ("xcb" ,libxcb)
@@ -235,24 +218,50 @@ (define-public cairo
      ;; This project is dual-licensed.
      (list
       license:lgpl2.1+
-      license:mpl1.1))))
+      license:mpl1.1))
+    ;; Hide and have cairo-with-documentation public.
+    (properties '((hidden? . #t)))))
+
+(define-public cairo-with-documentation
+  ;; cairo's docs must be built in a separate package since it requires
+  ;; gtk-doc, which in turn depends on cairo.
+  (package/inherit cairo
+    (properties (alist-delete 'hidden? (package-properties cairo)))
+    (outputs (cons "doc" (package-outputs cairo)))
+    (native-inputs
+     (modify-inputs (package-native-inputs cairo)
+       (prepend gtk-doc)))
+    (arguments
+     (substitute-keyword-arguments (package-arguments cairo)
+       ((#:configure-flags flags ''())
+        #~(cons "-Dgtk_doc=true" #$flags))
+       ((#:phases phases '%standard-phases)
+        #~(modify-phases #$phases
+            (add-after 'install 'move-doc
+              (lambda* (#:key outputs #:allow-other-keys)
+                (mkdir-p (string-append #$output:doc "/share"))
+                (rename-file
+                 (string-append #$output "/share/gtk-doc")
+                 (string-append #$output:doc "/share/gtk-doc"))
+                ;; This directory is now empty so remove it.
+                (rmdir (string-append #$output "/share"))))))))))

 (define-public cairo-sans-poppler
   ;; Variant used to break the dependency cycle between Poppler and Cairo.
   (package/inherit cairo
-    (inputs (alist-delete "poppler" (package-inputs cairo)))
-    (properties `((hidden? . #t)))))
+    (inputs (alist-delete "poppler" (package-inputs cairo)))))

 (define-public cairo-xcb
   (package/inherit cairo
+    (properties (alist-delete 'hidden? (package-properties cairo)))
     (name "cairo-xcb")
     (inputs
      `(("mesa" ,mesa)
        ,@(package-inputs cairo)))
     (arguments
-     `(#:tests? #f
-       #:configure-flags
-       '("--enable-xlib-xcb" "--enable-gl" "--enable-egl")))
+     (substitute-keyword-arguments (package-arguments cairo)
+       ((#:configure-flags flags ''())
+        #~(cons "-Dxlib-xcb=enabled" #$flags))))
     (synopsis "2D graphics library (with X11 support)")))

 (define-public harfbuzz
diff --git a/gnu/packages/patches/cairo-CVE-2018-19876.patch b/gnu/packages/patches/cairo-CVE-2018-19876.patch
deleted file mode 100644
index c0fba2ecaa..0000000000
--- a/gnu/packages/patches/cairo-CVE-2018-19876.patch
+++ /dev/null
@@ -1,37 +0,0 @@
-Copied from Debian.
-
-From: Carlos Garcia Campos <cgarcia@igalia.com>
-Date: Mon, 19 Nov 2018 12:33:07 +0100
-Subject: ft: Use FT_Done_MM_Var instead of free when available in
- cairo_ft_apply_variations
-
-Fixes a crash when using freetype >= 2.9
-
-[This is considered to be security-sensitive because WebKitGTK+ sets its
-own memory allocator, which is not compatible with system free(), making
-this a remotely triggerable denial of service or memory corruption.]
-
-Origin: upstream, commit:90e85c2493fdfa3551f202ff10282463f1e36645
-Bug: https://gitlab.freedesktop.org/cairo/cairo/merge_requests/5
-Bug-Debian: https://bugs.debian.org/916389
-Bug-CVE: CVE-2018-19876
----
- src/cairo-ft-font.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
-diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c
-index 325dd61..981973f 100644
---- a/src/cairo-ft-font.c
-+++ b/src/cairo-ft-font.c
-@@ -2393,7 +2393,11 @@ skip:
- done:
-         free (coords);
-         free (current_coords);
-+#if HAVE_FT_DONE_MM_VAR
-+        FT_Done_MM_Var (face->glyph->library, ft_mm_var);
-+#else
-         free (ft_mm_var);
-+#endif
-     }
- }
-
diff --git a/gnu/packages/patches/cairo-CVE-2020-35492.patch b/gnu/packages/patches/cairo-CVE-2020-35492.patch
deleted file mode 100644
index e8b90fa5c5..0000000000
--- a/gnu/packages/patches/cairo-CVE-2020-35492.patch
+++ /dev/null
@@ -1,49 +0,0 @@
-Copied from Debian.
-
-From 03a820b173ed1fdef6ff14b4468f5dbc02ff59be Mon Sep 17 00:00:00 2001
-From: Heiko Lewin <heiko.lewin@worldiety.de>
-Date: Tue, 15 Dec 2020 16:48:19 +0100
-Subject: [PATCH] Fix mask usage in image-compositor
-
-[trimmed test case, since not used in Debian build]
-
----
- src/cairo-image-compositor.c                |   8 ++--
-
---- cairo-1.16.0.orig/src/cairo-image-compositor.c
-+++ cairo-1.16.0/src/cairo-image-compositor.c
-@@ -2601,14 +2601,14 @@ _inplace_src_spans (void *abstract_rende
- 		    unsigned num_spans)
- {
-     cairo_image_span_renderer_t *r = abstract_renderer;
--    uint8_t *m;
-+    uint8_t *m, *base = (uint8_t*)pixman_image_get_data(r->mask);
-     int x0;
-
-     if (num_spans == 0)
- 	return CAIRO_STATUS_SUCCESS;
-
-     x0 = spans[0].x;
--    m = r->_buf;
-+    m = base;
-     do {
- 	int len = spans[1].x - spans[0].x;
- 	if (len >= r->u.composite.run_length && spans[0].coverage == 0xff) {
-@@ -2646,7 +2646,7 @@ _inplace_src_spans (void *abstract_rende
- 				      spans[0].x, y,
- 				      spans[1].x - spans[0].x, h);
-
--	    m = r->_buf;
-+	    m = base;
- 	    x0 = spans[1].x;
- 	} else if (spans[0].coverage == 0x0) {
- 	    if (spans[0].x != x0) {
-@@ -2675,7 +2675,7 @@ _inplace_src_spans (void *abstract_rende
- #endif
- 	    }
-
--	    m = r->_buf;
-+	    m = base;
- 	    x0 = spans[1].x;
- 	} else {
- 	    *m++ = spans[0].coverage;
