Hi everybody,

For those who are interested: here is an updated version of my cairo patch.

Cairomm is not used any longer. Fonts are opened via freetype, so all kind of 
glyphs should print fine ... I hope. Most postscript procedures from 
music-drawing-routines now have cairo equivalents,  I expect that the 
requirements of most simple scores are met.

If we kick out ghostscript the \postscript markup will die a lonely death. We 
could introduce a \cairo markup command instead....

If we kick out ghostscript \epsfile probably will be kicked out too, we 
probably need to implement a \pdffile command (and for that we'll need poppler).

Kicking out ghostscript completely means that a significant amount of work 
would be needed to adapt building of our documentation.

SVGs can be generated via cairo,  ...  PNGs can be generated via cairo ... the 
same is true for a lot of other file formats.

What will happen to the --pspdfopt options? It's not clear if similar 
functionality can be implemented via cairo.

Comments?

Knut

>From 8f7bfa79f5a46e0b7a83b42cddfb663ca6cac362 Mon Sep 17 00:00:00 2001
From: Knut Petersen <knup...@gmail.com>
Date: Tue, 8 Jun 2021 23:09:02 +0200
Subject: [PATCH] CAIRO: playing and testing version 2

This is just a sketch to show how we could use cairo
to get rid of ghostscript. The code is minimal, just
enough to demonstrate that this way is possible.

In addition to 'filename.ps' and/or 'filename.pdf' a
file 'filename.cairo.pdf' will be produced by cairo
if the command line option '-c' is given.

The most commonly used drawing primitives are supported,
but don't expect everything to work.

Printing all kinds of glyphs should work fine, also
expect lines, round boxes, circles, ellipses, polygons,
paths (e.g. slurs and ties) to print correctly.

More exotic features will not work right now: hyperlinks,
pdf metadata, rotation etc ...

This code introduces a dependency on cairo 1.16(+).
Cairomm, used in version 1, is abandoned.
---
 aclocal.m4           |  12 +
 config.make.in       |   5 +-
 configure.ac         |   1 +
 lily/cairo.cc        | 739 +++++++++++++++++++++++++++++++++++++++++++
 lily/main.cc         |  10 +
 scm/framework-ps.scm |  15 +
 scm/lily.scm         |   2 +
 scm/output-ps.scm    |  13 +
 8 files changed, 795 insertions(+), 2 deletions(-)
 create mode 100644 lily/cairo.cc

diff --git a/aclocal.m4 b/aclocal.m4
index 0897ead7ab..094585a090 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -857,6 +857,18 @@ AC_DEFUN(STEPMAKE_GOBJECT, [
     fi
 ])
 
+AC_DEFUN(STEPMAKE_CAIRO, [
+    PKG_CHECK_MODULES(CAIRO, $1 >= $3, have_cairo=yes, true)
+    if test "$have_cairo" = yes; then
+        AC_DEFINE(HAVE_CAIRO)
+        AC_SUBST(CAIRO_CFLAGS)
+        AC_SUBST(CAIRO_LIBS)
+    else
+        r="cairo-devel"
+        ver="`$PKG_CONFIG --modversion $1`"
+        STEPMAKE_ADD_ENTRY($2, ["$r >= $3 (installed: $ver)"])
+    fi
+])
 
 AC_DEFUN(STEPMAKE_FREETYPE2, [
     PKG_CHECK_MODULES(FREETYPE2, $1 >= $3, have_freetype2=yes, true)
diff --git a/config.make.in b/config.make.in
index a2f40565ce..395833ca07 100644
--- a/config.make.in
+++ b/config.make.in
@@ -13,10 +13,10 @@ AR = @AR@
 BISON = @BISON@
 CC = @CC@
 CONFIG_CPPFLAGS = $(FLEXLEXER_CPPFLAGS) @CPPFLAGS@
-CONFIG_CXXFLAGS = @CXXFLAGS@ $(GUILE_CFLAGS) $(FREETYPE2_CFLAGS) $(PANGO_FT2_CFLAGS)
+CONFIG_CXXFLAGS = @CXXFLAGS@ $(GUILE_CFLAGS) $(FREETYPE2_CFLAGS) $(PANGO_FT2_CFLAGS) @CAIRO_CFLAGS@
 CONFIG_DEFINES = @DEFINES@
 CONFIG_LDFLAGS = @LDFLAGS@
-CONFIG_LIBS = @LIBS@ @EXTRA_LIBS@ @GLIB_LIBS@ @GUILE_LIBS@ @PANGO_FT2_LIBS@ @FONTCONFIG_LIBS@ @FREETYPE2_LIBS@
+CONFIG_LIBS = @LIBS@ @EXTRA_LIBS@ @GLIB_LIBS@ @GUILE_LIBS@ @PANGO_FT2_LIBS@ @FONTCONFIG_LIBS@ @FREETYPE2_LIBS@ @CAIRO_LIBS@
 CROSS = @cross_compiling@
 CXX = @CXX@
 CXXABI_LIBS = @CXXABI_LIBS@
@@ -31,6 +31,7 @@ FLEX = @FLEX@
 FONTCONFIG_LIBS = @FONTCONFIG_LIBS@
 FONTFORGE = @FONTFORGE@
 FREETYPE2_LIBS = @FREETYPE2_LIBS@
+CAIRO_LIBS = @CAIRO_LIBS@
 GLIB_LIBS = @GLIB_LIBS@ @GOBJECT_LIBS@
 GS_API = @GS_API@
 GS920 = @GS920@
diff --git a/configure.ac b/configure.ac
index 5806508371..1452b8eb3f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -320,6 +320,7 @@ if test "$have_pangoft2_with_otf_feature" != yes ; then
 fi
 STEPMAKE_FONTCONFIG(fontconfig, REQUIRED, 2.4.0)
 STEPMAKE_FREETYPE2(freetype2, REQUIRED, 2.3.9)
+STEPMAKE_CAIRO(cairo, REQUIRED, 1.16.0)
 STEPMAKE_GLIB(glib-2.0, REQUIRED, 2.38)
 STEPMAKE_GOBJECT(gobject-2.0, REQUIRED, 2.38)
 
diff --git a/lily/cairo.cc b/lily/cairo.cc
new file mode 100644
index 0000000000..dd7edc9d25
--- /dev/null
+++ b/lily/cairo.cc
@@ -0,0 +1,739 @@
+/*
+  This file is part of LilyPond, the GNU music typesetter.
+
+  Copyright (C) 2021 Knut Petersen <knup...@gmail.com>
+
+  LilyPond is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  LilyPond is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "freetype.hh"
+#include "international.hh"
+#include "lily-guile.hh"
+#include "open-type-font.hh"
+#include "program-option.hh"
+#include "warn.hh"
+
+#include <cairo.h>
+#include <cairo-pdf.h>
+#include <cairo-ft.h>
+#include <map>
+#include <string>
+
+using std::string;
+using std::map;
+
+double lily_output_units;
+double lily_output_scale;
+double lily_page_height;
+double lily_page_width;
+double lily_paper_height;
+double lily_paper_width;
+double lily_staff_line_thickness;
+double lily_line_width;
+double lily_staff_height;
+string lily_basename;
+
+double deg = M_PI / 180.0;
+double sf;
+
+string cairo_pdf_filename;
+cairo_surface_t *surface;
+cairo_t *cr;
+
+struct lyfontdata {
+  FT_Face ftf;
+  cairo_font_face_t *cf;
+  double scale;
+};
+
+map<string,lyfontdata> fontmap = {};
+
+
+
+LY_DEFINE(ly_cairo_use_font, "ly:cairo-use-font",
+          3, 0, 0, (SCM name, SCM file, SCM index),
+          "CAIRO: Use font name from file with index.")
+{
+  if (!from_scm<bool> (ly_get_option (ly_symbol2scm ("cairotest"))))
+    return SCM_UNSPECIFIED;
+  LY_ASSERT_TYPE (scm_is_string, name, 1);
+  LY_ASSERT_TYPE (scm_is_string, file, 2);
+  string fn = ly_scm2string (name);
+  string fi = ly_scm2string (file);
+  int ix = 0;
+  if (scm_is_integer (index))
+    ix = from_scm<int> (index);
+  debug_output (_f ("cairo-use-font: name: %s, file: %s, index: %d", fn.c_str(), fi.c_str(), ix));
+  map<string,lyfontdata>::iterator itfm = fontmap.find(fn);
+  if (itfm == fontmap.end()) {
+    cairo_user_data_key_t key;
+    FT_Face ft_face = open_ft_face (fi,ix);
+    if (!FT_HAS_GLYPH_NAMES(ft_face))
+      error (_f ("Font '%s' from file '%s' does not have a glyph name table!",fn,fi));
+    cairo_font_face_t *font_face = cairo_ft_font_face_create_for_ft_face (ft_face, 0);
+    cairo_status_t status = cairo_font_face_set_user_data (font_face, &key, ft_face, (cairo_destroy_func_t) FT_Done_Face);
+    if (status) {
+     cairo_font_face_destroy (font_face);
+     FT_Done_Face (ft_face);
+     error (_f ("Cannot use font '%s' from file '%s'", fn, fi));
+    }
+    fontmap.insert(make_pair(fn, (lyfontdata) {ft_face, font_face, -1.0}));
+    debug_output (_f("  inserted font %s loaded from %s in fontmap",fn, fi));
+  }
+  return SCM_UNSPECIFIED;
+}
+
+
+
+LY_DEFINE(ly_cairo_def_scaled_font, "ly:cairo-def-scaled-font",
+          3, 0, 0, (SCM scaledname, SCM fontname, SCM scaling),
+          "CAIRO: Define scaledname as name for font fontname scaled size scaling."
+          " Has to be used after ly:cairo-use-font.")
+{
+  if (!from_scm<bool> (ly_get_option (ly_symbol2scm ("cairotest"))))
+    return SCM_UNSPECIFIED;
+  LY_ASSERT_TYPE (scm_is_string, scaledname, 1);
+  LY_ASSERT_TYPE (scm_is_string, fontname, 2);
+  LY_ASSERT_TYPE (scm_is_real, scaling, 3);
+  string sn = ly_scm2string (scaledname);
+  string fn = ly_scm2string (fontname);
+  double scalefac = from_scm<Real> (scaling);
+  debug_output (_f ("cairo-def-scaled-font: scaledname: %s, fontname: %s, scaling: %f", sn.c_str(), fn.c_str(), scalefac));
+  map<string,lyfontdata>::iterator itsn = fontmap.find(sn);
+  map<string,lyfontdata>::iterator itfn = fontmap.find(fn);
+  // abort if fontname is unknown
+  if (itfn == fontmap.end())
+    error (_f ("ly:cairo-def-scaled-font: execute ly:cairo-use-font before you try to scale a font!"));
+  else if (itsn == fontmap.end())
+    fontmap.insert (make_pair(sn, (lyfontdata) {itfn->second.ftf, itfn->second.cf, scalefac}));
+  // no else, ignore request if scaledname is already defined,
+  return SCM_UNSPECIFIED;
+}
+
+
+
+LY_DEFINE(ly_cairo_show_named_glyph, "ly:cairo-show-named-glyph",
+          2, 0, 0, (SCM scaledname, SCM glyphname),
+          "CAIRO: show a named glyph of a scaled font.")
+{
+  if (!from_scm<bool> (ly_get_option (ly_symbol2scm ("cairotest"))))
+    return SCM_UNSPECIFIED;
+  LY_ASSERT_TYPE (scm_is_string, scaledname, 1);
+  LY_ASSERT_TYPE (scm_is_string, glyphname, 2);
+  string sn = ly_scm2string (scaledname);
+  string g = ly_scm2string (glyphname);
+  debug_output (_f ("show_named_glyph: scaledfont: %s glyph: %s",sn.c_str(), g.c_str()));
+  map<string,lyfontdata>::iterator itfm = fontmap.find(sn);
+  if (itfm == fontmap.end())
+    error (_f("ly:cairo-show-named-glyph: font %s has not been opened.",sn.c_str()));
+  if (itfm->second.scale < 0.0)
+    error (_f("ly:cairo-show-named-glyph: font %s is not known as a scaled font.",sn.c_str()));
+  cairo_set_font_face(cr,itfm->second.cf);
+  cairo_set_font_size(cr,itfm->second.scale * lily_output_units);
+  double cx, cy;
+  cairo_get_current_point(cr,&cx, &cy);
+  cairo_glyph_t oneglyph = {FT_Get_Name_Index(itfm->second.ftf,g.c_str()), cx, cy};
+  cairo_show_glyphs (cr,&oneglyph,1);
+  return SCM_UNSPECIFIED;
+}
+
+
+
+LY_DEFINE(ly_cairo_print_glyphs, "ly:cairo-print-glyphs",
+          4, 0, 0, (SCM fontname, SCM size, SCM count, SCM glyphs),
+          "CAIRO: equivalent of our postscript procedure print_glyphs.")
+{
+  if (!from_scm<bool> (ly_get_option (ly_symbol2scm ("cairotest"))))
+    return SCM_UNSPECIFIED;
+  LY_ASSERT_TYPE (scm_is_string, fontname, 1);
+  LY_ASSERT_TYPE (scm_is_real, size, 2);
+  LY_ASSERT_TYPE (scm_is_integer, count, 3);
+  string fn = ly_scm2string (fontname);
+  double sz = from_scm<Real> (size);
+  double sumw = 0.0;
+  double startx, starty;
+  cairo_get_current_point(cr,&startx, &starty);
+  int n = from_scm<int> (count);
+  debug_output (_f ("print_glyphs font: %s, size: %.12f, glyph count: %d", fn.c_str(), sz, n));
+  map<string,lyfontdata>::iterator itfm = fontmap.find(fn);
+  if (itfm != fontmap.end())
+    cairo_set_font_face(cr,itfm->second.cf);
+  else
+    error (_f("ly:cairo-print-glyphs detected that font %s has not been opened.",fn.c_str()));
+  cairo_set_font_size(cr,sz * lily_output_units);
+  for(int i=0;i<n;i++) {
+    auto wxyg = scm_list_ref(glyphs,to_scm(i));
+    double w = from_scm<Real>(scm_car(wxyg));
+    double x = from_scm<Real>(scm_cadr(wxyg));
+    double y = from_scm<Real>(scm_caddr(wxyg));
+    string g = ly_scm2string(scm_cadddr(wxyg));
+    cairo_glyph_t oneglyph = {FT_Get_Name_Index(itfm->second.ftf,g.c_str()),startx + (x + sumw)*sf, starty-y*sf};
+    cairo_show_glyphs (cr,&oneglyph,1);
+    sumw = sumw + w;
+  }
+  return SCM_UNSPECIFIED;
+}
+
+
+
+LY_DEFINE(ly_cairo_path, "ly:cairo-path",
+          2, 3, 0, (SCM thickness, SCM exps, SCM cap, SCM join, SCM  filled),
+          "Cairo: draw a path. Accept the moveto, rmoveto lineto, rlineto, curveto, rcurveto and closepath postscript "
+          "operators with the required number of arguments. ")
+{
+  if (!from_scm<bool> (ly_get_option (ly_symbol2scm ("cairotest"))))
+    return SCM_UNSPECIFIED;
+  LY_ASSERT_TYPE (scm_is_real, thickness, 1);
+  LY_ASSERT_TYPE (scm_is_pair, exps, 2);
+  // Set linewidth
+  double blot = from_scm<Real> (thickness);
+  cairo_set_line_width(cr,sf * blot);
+  // Set line-caps-style, default to 'round
+  if (!SCM_UNBNDP (cap)) {
+    if (scm_is_eq (cap, ly_symbol2scm ("butt")))
+      cairo_set_line_cap(cr,CAIRO_LINE_CAP_BUTT);
+    else if (scm_is_eq (cap, ly_symbol2scm ("square")))
+      cairo_set_line_cap(cr,CAIRO_LINE_CAP_SQUARE);
+  } else
+      cairo_set_line_cap(cr,CAIRO_LINE_CAP_ROUND);
+  // Set line-join-style, default to 'round
+  if (!SCM_UNBNDP (join)) {
+    if (scm_is_eq (join, ly_symbol2scm ("miter")))
+      cairo_set_line_join(cr,CAIRO_LINE_JOIN_MITER);
+    else if (scm_is_eq (join, ly_symbol2scm ("bevel")))
+      cairo_set_line_join(cr,CAIRO_LINE_JOIN_BEVEL);
+  } else
+      cairo_set_line_join(cr,CAIRO_LINE_JOIN_ROUND);
+  // save to be able to undo cairo_translate
+  cairo_save(cr);
+  // translate: current point is new cairo origin
+  double cpx, cpy;
+  cairo_get_current_point(cr,&cpx, &cpy);
+  cairo_translate(cr,cpx,cpy);
+  // evaluate drawing primitives given in exps
+  for (;scm_is_pair (exps); exps = scm_cdr (exps)) {
+    SCM head = scm_car (exps);
+    if (scm_is_symbol (head)) {
+      if (scm_is_eq (head, ly_symbol2scm ("moveto"))) {
+        debug_output(_f("PATH: moveto"));
+        cairo_move_to(cr,
+          sf*from_scm<Real> (scm_list_ref(exps,to_scm(1))),
+          -sf*from_scm<Real> (scm_list_ref(exps,to_scm(2))));
+      } else if (scm_is_eq (head, ly_symbol2scm ("rmoveto"))){
+        debug_output(_f("PATH: rmoveto"));
+        cairo_rel_move_to(cr,
+          sf*from_scm<Real> (scm_list_ref(exps,to_scm(1))),
+          -sf*from_scm<Real> (scm_list_ref(exps,to_scm(2))));
+      } else if (scm_is_eq (head, ly_symbol2scm ("lineto"))){
+        debug_output(_f("PATH: lineto"));
+        cairo_line_to(cr,
+          sf*from_scm<Real> (scm_list_ref(exps,to_scm(1))),
+          -sf*from_scm<Real> (scm_list_ref(exps,to_scm(2))));
+      } else if (scm_is_eq (head, ly_symbol2scm ("rlineto"))){
+        debug_output(_f("PATH: rlineto"));
+        cairo_rel_line_to(cr,
+          sf*from_scm<Real> (scm_list_ref(exps,to_scm(1))),
+          -sf*from_scm<Real> (scm_list_ref(exps,to_scm(2))));
+      } else if (scm_is_eq (head, ly_symbol2scm ("curveto"))){
+        debug_output(_f("PATH: curveto"));
+        cairo_curve_to(cr,
+          sf*from_scm<Real> (scm_list_ref(exps,to_scm(1))),
+          -sf*from_scm<Real> (scm_list_ref(exps,to_scm(2))),
+          sf*from_scm<Real> (scm_list_ref(exps,to_scm(3))),
+          -sf*from_scm<Real> (scm_list_ref(exps,to_scm(4))),
+          sf*from_scm<Real> (scm_list_ref(exps,to_scm(5))),
+          -sf*from_scm<Real> (scm_list_ref(exps,to_scm(6))));
+      } else if (scm_is_eq (head, ly_symbol2scm ("rcurveto"))){
+        debug_output(_f("PATH: rcurveto"));
+        cairo_rel_curve_to(cr,
+          sf*from_scm<Real> (scm_list_ref(exps,to_scm(1))),
+          -sf*from_scm<Real> (scm_list_ref(exps,to_scm(2))),
+          sf*from_scm<Real> (scm_list_ref(exps,to_scm(3))),
+          -sf*from_scm<Real> (scm_list_ref(exps,to_scm(4))),
+          sf*from_scm<Real> (scm_list_ref(exps,to_scm(5))),
+          -sf*from_scm<Real> (scm_list_ref(exps,to_scm(6))));
+      } else if (scm_is_eq (head, ly_symbol2scm ("closepath"))){
+        debug_output(_f("PATH: closepath"));
+        cairo_close_path(cr);
+      } else {
+        error(_f("PATH: Unexpected postscript operator! "));
+      }
+    }
+  }
+  // stroke / fill according to user wishes
+  bool fill = false;
+  if (!SCM_UNBNDP (filled)) {
+    LY_ASSERT_TYPE (scm_is_bool, filled, 5);
+    fill = from_scm<bool> (filled);
+  }
+  if (!fill)
+    cairo_stroke(cr);
+  else if (blot > 0.0) {
+    cairo_stroke_preserve(cr);
+    cairo_fill(cr);
+  }
+  else
+    cairo_fill(cr);
+  // undo cr->translate
+  cairo_restore(cr);
+  //
+  return SCM_UNSPECIFIED;
+}
+
+
+
+LY_DEFINE (ly_cairo_showpage, "ly:cairo-showpage",
+           0, 0, 0, (),
+           "CAIRO:  equivalent of the postscript primitive showpage.")
+{
+  if (!from_scm<bool> (ly_get_option (ly_symbol2scm ("cairotest"))))
+    return SCM_UNSPECIFIED;
+  debug_output (_f ("showpage"));
+  cairo_show_page(cr);
+  return SCM_UNSPECIFIED;
+}
+
+
+
+LY_DEFINE (ly_cairo_restore, "ly:cairo-restore",
+           0, 0, 0, (),
+           "CAIRO:  equivalent of the postscript primitive restore.")
+{
+  if (!from_scm<bool> (ly_get_option (ly_symbol2scm ("cairotest"))))
+    return SCM_UNSPECIFIED;
+  debug_output (_f ("restore"));
+  cairo_restore(cr);
+  return SCM_UNSPECIFIED;
+}
+
+
+
+LY_DEFINE (ly_cairo_save, "ly:cairo-save",
+           0, 0, 0, (),
+           "CAIRO:  equivalent of the postscript primitive save.")
+{
+  if (!from_scm<bool> (ly_get_option (ly_symbol2scm ("cairotest"))))
+    return SCM_UNSPECIFIED;
+  debug_output (_f ("save"));
+  cairo_save(cr);
+  return SCM_UNSPECIFIED;
+}
+
+
+
+LY_DEFINE (ly_cairo_moveto, "ly:cairo-moveto",
+           2, 0, 0, (SCM varx, SCM vary),
+           "CAIRO: equivalent of the postscript primitive moveto.")
+{
+  if (!from_scm<bool> (ly_get_option (ly_symbol2scm ("cairotest"))))
+    return SCM_UNSPECIFIED;
+  LY_ASSERT_TYPE (scm_is_real, varx, 1);
+  LY_ASSERT_TYPE (scm_is_real, vary, 2);
+  double x=from_scm<Real> (varx);
+  double y=from_scm<Real> (vary);
+  debug_output (_f ("moveto x: %f y: %f", x, y));
+  cairo_move_to(cr,x*sf,-y*sf);
+  return SCM_UNSPECIFIED;
+}
+
+
+
+LY_DEFINE (ly_cairo_set_basename, "ly:cairo-set-basename",
+           1, 0, 0, (SCM str),
+           "CAIRO: set lily-basename.")
+{
+  if (!from_scm<bool> (ly_get_option (ly_symbol2scm ("cairotest"))))
+    return SCM_UNSPECIFIED;
+  LY_ASSERT_TYPE (scm_is_string, str, 1);
+  lily_basename = ly_scm2string (str);
+  cairo_pdf_filename = lily_basename + ".cairo.pdf";
+  debug_output (_f ("set-basename:             %s",lily_basename));
+  debug_output (_f ("cairo_pdf_filename is     %s",cairo_pdf_filename));
+  return SCM_UNSPECIFIED;
+}
+
+
+
+LY_DEFINE (ly_cairo_set_lily_output_units, "ly:cairo-set-lily-output-units",
+           1, 0, 0, (SCM val),
+           "CAIRO: set lily-output-units.")
+{
+  if (!from_scm<bool> (ly_get_option (ly_symbol2scm ("cairotest"))))
+    return SCM_UNSPECIFIED;
+  LY_ASSERT_TYPE (scm_is_real, val, 1);
+  lily_output_units = from_scm<Real> (val);
+  sf = lily_output_units * lily_output_scale;
+  debug_output (_f ("set-lily-output-units:    %f, sf: %f",lily_output_units, sf));
+  return SCM_UNSPECIFIED;
+}
+
+
+
+LY_DEFINE (ly_cairo_set_output_scale, "ly:cairo-set-output-scale",
+           1, 0, 0, (SCM val),
+           "CAIRO: set output-scale.")
+{
+  if (!from_scm<bool> (ly_get_option (ly_symbol2scm ("cairotest"))))
+    return SCM_UNSPECIFIED;
+  LY_ASSERT_TYPE (scm_is_real, val, 1);
+  lily_output_scale = from_scm<Real> (val);
+  sf = lily_output_units * lily_output_scale;
+  debug_output (_f ("set-output-scale:         %f sf: %f",lily_output_scale, sf));
+  return SCM_UNSPECIFIED;
+}
+
+
+
+LY_DEFINE (ly_cairo_set_page_height, "ly:cairo-set-page-height",
+           1, 0, 0, (SCM val),
+           "CAIRO: set page-height.")
+{
+  if (!from_scm<bool> (ly_get_option (ly_symbol2scm ("cairotest"))))
+    return SCM_UNSPECIFIED;
+  LY_ASSERT_TYPE (scm_is_real, val, 1);
+  lily_page_height = from_scm<Real> (val);
+  debug_output (_f ("set-page-height:          %f",lily_page_height));
+  return SCM_UNSPECIFIED;
+}
+
+
+
+LY_DEFINE (ly_cairo_set_page_width, "ly:cairo-set-page-width",
+           1, 0, 0, (SCM val),
+           "CAIRO: set page-width.")
+{
+  if (!from_scm<bool> (ly_get_option (ly_symbol2scm ("cairotest"))))
+    return SCM_UNSPECIFIED;
+  LY_ASSERT_TYPE (scm_is_real, val, 1);
+  lily_page_width = from_scm<Real> (val);
+  debug_output (_f ("set-page-width:           %f",lily_page_width));
+  return SCM_UNSPECIFIED;
+}
+
+
+
+LY_DEFINE (ly_cairo_set_paper_height, "ly:cairo-set-paper-height",
+           1, 0, 0, (SCM val),
+           "CAIRO: set paper-height.")
+{
+  if (!from_scm<bool> (ly_get_option (ly_symbol2scm ("cairotest"))))
+    return SCM_UNSPECIFIED;
+  LY_ASSERT_TYPE (scm_is_real, val, 1);
+  lily_paper_height = from_scm<Real> (val);
+  debug_output (_f("CAIRO: Starting pdf, creating the surface."));
+  debug_output (_f ("set-paper-height:         %f",lily_paper_height));
+  // This assumes that lily_paper_height is set after lily_paper_width and pdf_file_name
+  surface = cairo_pdf_surface_create(cairo_pdf_filename.c_str(), lily_paper_width, lily_paper_height);
+  cr = cairo_create(surface);
+  cairo_set_source_rgba(cr,0, 0, 0, 1);
+  return SCM_UNSPECIFIED;
+}
+
+
+
+LY_DEFINE (ly_cairo_set_paper_width, "ly:cairo-set-paper-width",
+           1, 0, 0, (SCM val),
+           "CAIRO: set paper-width.")
+{
+  if (!from_scm<bool> (ly_get_option (ly_symbol2scm ("cairotest"))))
+    return SCM_UNSPECIFIED;
+  LY_ASSERT_TYPE (scm_is_real, val, 1);
+  lily_paper_width = from_scm<Real> (val);
+  debug_output (_f ("set-paper-width:          %f",lily_paper_width));
+  return SCM_UNSPECIFIED;
+}
+
+
+
+LY_DEFINE (ly_cairo_set_staff_line_thickness, "ly:cairo-set-staff-line-thickness",
+           1, 0, 0, (SCM val),
+           "CAIRO: set staff-line-thickness.")
+{
+  if (!from_scm<bool> (ly_get_option (ly_symbol2scm ("cairotest"))))
+    return SCM_UNSPECIFIED;
+  LY_ASSERT_TYPE (scm_is_real, val, 1);
+  lily_staff_line_thickness = from_scm<Real> (val);
+  debug_output (_f ("set-staff-line-thickness: %f",lily_staff_line_thickness));
+  return SCM_UNSPECIFIED;
+}
+
+
+
+LY_DEFINE (ly_cairo_set_line_width, "ly:cairo-set-line-width",
+           1, 0, 0, (SCM val),
+           "CAIRO: set line-width.")
+{
+  if (!from_scm<bool> (ly_get_option (ly_symbol2scm ("cairotest"))))
+    return SCM_UNSPECIFIED;
+  LY_ASSERT_TYPE (scm_is_real, val, 1);
+  lily_line_width= from_scm<Real> (val);
+  debug_output (_f ("set-line-width:           %f",lily_line_width));
+  return SCM_UNSPECIFIED;
+}
+
+
+
+LY_DEFINE (ly_cairo_set_staff_height, "ly:cairo-set-staff-height",
+           1, 0, 0, (SCM val),
+           "CAIRO: set staff-height.")
+{
+  if (!from_scm<bool> (ly_get_option (ly_symbol2scm ("cairotest"))))
+    return SCM_UNSPECIFIED;
+  LY_ASSERT_TYPE (scm_is_real, val, 1);
+  lily_staff_height = from_scm<Real> (val);
+  debug_output (_f ("set-staff-height:         %f",lily_staff_height));
+  return SCM_UNSPECIFIED;
+}
+
+
+
+LY_DEFINE (ly_cairo_setrgbcolor, "ly:cairo-setrgbcolor",
+           3, 0, 0, (SCM varr, SCM varg, SCM varb),
+           "CAIRO equivalent of the postscript primitive setrgbcolor.")
+{
+  if (!from_scm<bool> (ly_get_option (ly_symbol2scm ("cairotest"))))
+    return SCM_UNSPECIFIED;
+  LY_ASSERT_TYPE (scm_is_real, varr, 1);
+  LY_ASSERT_TYPE (scm_is_real, varg, 2);
+  LY_ASSERT_TYPE (scm_is_real, varb, 3);
+  double r = from_scm<Real> (varr);
+  double g = from_scm<Real> (varg);
+  double b = from_scm<Real> (varb);
+  cairo_set_source_rgba(cr,r, g, b, 1.0);
+  debug_output (_f ("setrgbcolor r:%f g:%f b:%f", r, g, b));
+  return SCM_UNSPECIFIED;
+}
+
+
+
+LY_DEFINE (ly_cairo_setrgbacolor, "ly:cairo-setrgbacolor",
+           4, 0, 0, (SCM varr, SCM varg, SCM varb, SCM vara),
+           "CAIRO equivalent of our postscript procedure setrgbacolor"
+           " defined in music-drawing-routines.ps.")
+{
+  if (!from_scm<bool> (ly_get_option (ly_symbol2scm ("cairotest"))))
+    return SCM_UNSPECIFIED;
+  LY_ASSERT_TYPE (scm_is_real, varr, 1);
+  LY_ASSERT_TYPE (scm_is_real, varg, 2);
+  LY_ASSERT_TYPE (scm_is_real, varb, 3);
+  LY_ASSERT_TYPE (scm_is_real, vara, 4);
+  double r = from_scm<Real> (varr);
+  double g = from_scm<Real> (varg);
+  double b = from_scm<Real> (varb);
+  double a = from_scm<Real> (vara);
+  cairo_set_source_rgba(cr,r, g, b, a);
+  debug_output (_f ("setrgbacolor r:%f g:%f b:%f a:%f", r, g, b, a));
+  return SCM_UNSPECIFIED;
+}
+
+
+
+LY_DEFINE (ly_cairo_draw_line, "ly:cairo-draw-line",
+           5, 0, 0, (SCM vardx, SCM vardy, SCM varx, SCM vary, SCM blotdiam),
+           "CAIRO equivalent of our postscript procedure draw_line"
+           " defined in music-drawing-routines.ps.")
+{
+  if (!from_scm<bool> (ly_get_option (ly_symbol2scm ("cairotest"))))
+    return SCM_UNSPECIFIED;
+  LY_ASSERT_TYPE (scm_is_real, vardx, 1);
+  LY_ASSERT_TYPE (scm_is_real, vardy, 2);
+  LY_ASSERT_TYPE (scm_is_real, varx, 3);
+  LY_ASSERT_TYPE (scm_is_real, vary, 4);
+  LY_ASSERT_TYPE (scm_is_real, blotdiam, 5);
+  double dx=from_scm<Real> (vardx);
+  double dy=from_scm<Real> (vardy);
+  double x=from_scm<Real> (varx);
+  double y=from_scm<Real> (vary);
+  double d=from_scm<Real> (blotdiam);
+  cairo_set_line_width(cr,d*sf);
+  cairo_set_line_cap(cr,CAIRO_LINE_CAP_ROUND);
+  cairo_rel_move_to(cr,x*sf,-y*sf);
+  cairo_rel_line_to(cr,dx*sf,-dy*sf);
+  cairo_stroke(cr);
+  debug_output (_f ("draw_line dx:%f dy:%f x:%f y:%f blotdiam:%f",
+                    from_scm<Real> (vardx), from_scm<Real> (vardy), from_scm<Real> (varx),
+                    from_scm<Real> (vary), from_scm<Real> (blotdiam)));
+  return SCM_UNSPECIFIED;
+}
+
+
+
+LY_DEFINE (ly_cairo_draw_round_box, "ly:cairo-draw-round-box",
+           5, 0, 0, (SCM width, SCM height, SCM varx, SCM vary, SCM blotdiam),
+           "CAIRO equivalent of our postscript procedure draw_round_box"
+           " defined in music-drawing-routines.ps.")
+{
+  if (!from_scm<bool> (ly_get_option (ly_symbol2scm ("cairotest"))))
+    return SCM_UNSPECIFIED;
+  LY_ASSERT_TYPE (scm_is_real, width, 1);
+  LY_ASSERT_TYPE (scm_is_real, height, 2);
+  LY_ASSERT_TYPE (scm_is_real, varx, 3);
+  LY_ASSERT_TYPE (scm_is_real, vary, 4);
+  LY_ASSERT_TYPE (scm_is_real, blotdiam, 5);
+  double w=from_scm<Real> (width);
+  double h=from_scm<Real> (height);
+  double x=from_scm<Real> (varx);
+  double y=from_scm<Real> (vary);
+  double d=from_scm<Real> (blotdiam);
+  double r = d / 2;
+  debug_output (_f ("draw_round_box width:%f height:%f x:%f y:%f blotdiam:%f", w, h, x, y, d));
+  // FIXME correct but inefficient code (pdfs are bigger than necessary)
+  //       possible optimizations: see ps code in music-drawing-routines.ps
+  if (r == 0) {
+    cairo_rel_move_to(cr,x*sf,-y*sf);
+    cairo_rel_line_to(cr,0,-h*sf);
+    cairo_rel_line_to(cr,w*sf,0);
+    cairo_rel_line_to(cr,0,h*sf);
+    cairo_rel_line_to(cr,-w*sf,0);
+    cairo_close_path(cr);
+    cairo_fill(cr);
+  } else {
+    double cx, cy;
+    cairo_rel_move_to(cr,x*sf, -y*sf);
+    cairo_get_current_point(cr,&cx, &cy);
+    cairo_new_sub_path(cr);
+    cairo_arc(cr,cx+w*sf,cy-h*sf,r*sf,-90*deg,0*deg);
+    cairo_arc(cr,cx+w*sf,cy,r*sf,0*deg,90*deg);
+    cairo_arc(cr,cx,cy,r*sf,90*deg,180*deg);
+    cairo_arc(cr,cx,cy-h*sf,r*sf,180*deg,270*deg);
+    cairo_close_path(cr);
+    cairo_fill(cr);
+  }
+  return SCM_UNSPECIFIED;
+}
+
+
+
+LY_DEFINE(ly_cairo_draw_polygon, "ly:cairo-draw-polygon",
+          4, 0, 0, (SCM count, SCM points, SCM linewidth, SCM filled),
+          "CAIRO: equivalent of our postscript procedure draw_polygon.")
+{
+  if (!from_scm<bool> (ly_get_option (ly_symbol2scm ("cairotest"))))
+    return SCM_UNSPECIFIED;
+  LY_ASSERT_TYPE (scm_is_integer, count, 1);
+  LY_ASSERT_TYPE (scm_is_real, linewidth, 3);
+  LY_ASSERT_TYPE (scm_is_bool, filled, 4);
+  int n = from_scm<int> (count);
+  double blot = from_scm<Real> (linewidth);
+  bool fill = from_scm<bool> (filled);
+  debug_output(_f ("draw_polygon: %s, linewidth %f, points: %d", fill?"filled":"outline", blot, n));
+  double cx, cy, x, y;
+  cairo_get_current_point(cr,&cx, &cy);
+  cairo_set_line_width(cr,blot*sf);
+  cairo_set_line_cap(cr,CAIRO_LINE_CAP_BUTT);
+  cairo_set_line_join(cr,CAIRO_LINE_JOIN_ROUND);
+  for (int i=0; i<n; i++) {
+    x = from_scm<Real> (scm_list_ref(points,to_scm(i*2)));
+    y = from_scm<Real> (scm_list_ref(points,to_scm(i*2+1)));
+    debug_output(_f("point %d: x=%f, y=%f", i+1, x, y));
+    if (i==0)
+      cairo_move_to(cr,x*sf+cx,-y*sf+cy);
+    else
+      cairo_line_to(cr,x*sf+cx,-y*sf+cy);
+  }
+  cairo_close_path(cr);
+  if (fill) {
+    cairo_stroke_preserve(cr);
+    cairo_fill(cr);
+  } else
+    cairo_stroke(cr);
+  return SCM_UNSPECIFIED;
+}
+
+
+
+LY_DEFINE(ly_cairo_draw_circle, "ly:cairo-draw-circle",
+          3, 0, 0, (SCM radius, SCM thickness, SCM filled),
+          "CAIRO: equivalent of our postscript procedure draw_circle.")
+{
+  if (!from_scm<bool> (ly_get_option (ly_symbol2scm ("cairotest"))))
+    return SCM_UNSPECIFIED;
+  LY_ASSERT_TYPE (scm_is_real, radius, 1);
+  LY_ASSERT_TYPE (scm_is_real, thickness, 2);
+  LY_ASSERT_TYPE (scm_is_bool, filled, 3);
+  bool fill = from_scm<bool> (filled);
+  double rad = from_scm<Real> (radius);
+  double blot = from_scm<Real> (thickness);
+  double cx, cy;
+  cairo_get_current_point(cr,&cx, &cy);
+  cairo_set_line_width(cr,blot*sf);
+  cairo_new_sub_path(cr);
+  cairo_arc (cr,cx,cy,rad*sf, 0.0, 2 * M_PI);
+  if (fill) {
+    cairo_stroke_preserve(cr);
+    cairo_fill(cr);
+  } else
+    cairo_stroke(cr);
+  return SCM_UNSPECIFIED;
+}
+
+
+
+LY_DEFINE(ly_cairo_draw_ellipse, "ly:cairo-draw-ellipse",
+          4, 0, 0, (SCM xradius, SCM yradius, SCM thickness, SCM filled),
+          "CAIRO: equivalent of our postscript procedure draw_circle.")
+{
+  if (!from_scm<bool> (ly_get_option (ly_symbol2scm ("cairotest"))))
+    return SCM_UNSPECIFIED;
+  LY_ASSERT_TYPE (scm_is_real, xradius, 1);
+  LY_ASSERT_TYPE (scm_is_real, yradius, 2);
+  LY_ASSERT_TYPE (scm_is_real, thickness, 3);
+  LY_ASSERT_TYPE (scm_is_bool, filled, 4);
+  bool fill = from_scm<bool> (filled);
+  double xrad = from_scm<Real> (xradius);
+  double yrad = from_scm<Real> (yradius);
+  double blot = from_scm<Real> (thickness);
+  double cx, cy;
+  cairo_matrix_t old_matrix;
+  cairo_get_matrix(cr, &old_matrix);
+  cairo_get_current_point(cr,&cx, &cy);
+  cairo_translate(cr,cx,cy);
+  cairo_scale(cr,1,yrad/xrad);
+  cairo_new_path(cr);
+  cairo_arc(cr,0,0,xrad*sf,0,2*M_PI);
+  cairo_set_matrix(cr,&old_matrix);
+  cairo_set_line_width(cr,blot*sf);
+  if (fill) {
+    cairo_stroke_preserve(cr);
+    cairo_fill(cr);
+  } else
+    cairo_stroke(cr);
+  return SCM_UNSPECIFIED;
+}
+
+
+
+LY_DEFINE(ly_cairo_at_eof, "ly:cairo-at-eof",
+          0, 0, 0, (),
+          "CAIRO: Inform cairo to finalize the pdf and to clean up.")
+{
+  if (!from_scm<bool> (ly_get_option (ly_symbol2scm ("cairotest"))))
+    return SCM_UNSPECIFIED;
+  cairo_surface_destroy(surface);
+  cairo_destroy(cr);
+  debug_output(_f("CAIRO: Finished Pdf, cairo surface and context destroyed."));
+  return SCM_UNSPECIFIED;
+}
+
+
+//
+//
+// still missing:  music-drawing-routines.ps: /draw_partial_ellipse % filled connect x-radius y-radius startangle endangle thickness draw_partial_ellipse
+//                 music-drawing-routines.ps: /mark_URI% llx lly urx ury URI
+//                 music-drawing-routines.ps: /mark_page_link % llx lly urx ury page
+//                 music-drawing-routines.ps: /draw_dashed_line % dx dy thickness dashpattern offset draw_dashed_line
+//
+//                 lots of other things ... rotation, transformations, ... transparency, ... etc, etc
+//
+//
diff --git a/lily/main.cc b/lily/main.cc
index 5564222b35..ddbeefe59f 100644
--- a/lily/main.cc
+++ b/lily/main.cc
@@ -145,6 +145,10 @@ static Long_option_init options_static[]
     0, "eps", 'E',
     _i ("generate Encapsulated PostScript files")
   },
+  {
+    0, "cairotest", 'c',
+    _i ("generate a *.cairo.pdf test file")
+  },
   {
     _i ("KEY"), "pspdfopt", 'O',
     _i ("set ps/pdf optimization to KEY, which is either\n"
@@ -679,6 +683,12 @@ parse_argv (int argc, char **argv)
           }
           break;
 
+        case 'c':
+          {
+            init_scheme_variables_global += "(cairotest . #t)\n";
+          }
+          break;
+
         case 'd':
           {
             string arg (option_parser->optional_argument_str0_);
diff --git a/scm/framework-ps.scm b/scm/framework-ps.scm
index 18dc6a7166..b8e91401f0 100644
--- a/scm/framework-ps.scm
+++ b/scm/framework-ps.scm
@@ -51,6 +51,7 @@
   "")
 
 (define (ps-define-font font font-name scaling)
+  (ly:cairo-def-scaled-font (ps-font-command font) font-name scaling)
   (if (ly:get-option 'music-font-encodings)
       (string-append
        "/" (ps-font-command font) "-N"
@@ -87,6 +88,11 @@
      "/" ps-key " "
      (value->string (ly:output-def-lookup layout ly-key)) " def\n"))
 
+  (ly:cairo-set-lily-output-units (/ (ly:bp 1)))
+  (ly:cairo-set-output-scale (ly:output-def-lookup layout 'output-scale))
+  (ly:cairo-set-page-height (ly:output-def-lookup layout 'paper-height))
+  (ly:cairo-set-page-width (ly:output-def-lookup layout 'paper-width))
+  (ly:cairo-set-staff-height (ly:output-def-lookup layout 'staff-height))
   (string-append
    "/lily-output-units "
    (number->string (/ (ly:bp 1))) " def %% millimeter\n"
@@ -123,6 +129,7 @@
     "gsave 0 paper-height translate set-ps-scale-to-lily-scale\n"))
   (ly:outputter-dump-stencil outputter page-stencil)
   (ly:outputter-dump-string outputter ".endtransparencygroup\n.poppdf14devicefilter\n")
+  (ly:cairo-showpage)
   (ly:outputter-dump-string outputter "stroke grestore\nshowpage\n"))
 
 (define (supplies-or-needs paper load-fonts?)
@@ -163,6 +170,8 @@
                 (ly:output-def-lookup paper 'output-scale))
                (ly:bp 1)))
          (landscape? (eq? (ly:output-def-lookup paper 'landscape) #t)))
+    (ly:cairo-set-paper-width (if landscape? h w))
+    (ly:cairo-set-paper-height (if landscape? w h))
     (format #f "%%DocumentMedia: ~a ~,2f ~,2f ~a ~a ~a\n"
                (ly:output-def-lookup paper 'papersizename)
                (if landscape? h w)
@@ -362,6 +371,8 @@
            (file-name (caddr font-name-filename))
            (font-index (cadddr font-name-filename))
            (bare-file-name (ly:find-file file-name)))
+      (if (not font)  (ly:cairo-use-font name file-name font-index)
+                      (ly:cairo-use-font name (ly:find-file (format #f "~a.otf" file-name)) font-index))
       (cond
        ((and (number? font-index)
              (!= font-index 0))
@@ -478,6 +489,8 @@
            (file-name (list-ref font-psname-filename-fontindex 2))
            (font-index (list-ref font-psname-filename-fontindex 3))
            (bare-file-name (ly:find-file file-name)))
+      (if (not font)  (ly:cairo-use-font name file-name font-index)
+                      (ly:cairo-use-font name (ly:find-file (format #f "~a.otf" file-name)) font-index))
       (cons name
             (cond ((mac-font? bare-file-name)
                    (handle-mac-font name bare-file-name))
@@ -765,6 +778,7 @@ mark {ly~a_stream} /CLOSE pdfmark
          (landscape? (eq? (ly:output-def-lookup paper 'landscape) #t))
          (page-number (1- (ly:output-def-lookup paper 'first-page-number)))
          (page-count (length page-stencils)))
+    (ly:cairo-set-basename basename)
     (cond-expand
      (guile-2 (set-port-encoding! port "Latin1"))
      (else))
@@ -790,6 +804,7 @@ mark {ly~a_stream} /CLOSE pdfmark
          (ly:output-def-lookup paper 'label-page-table)
          port))
     (display "%%Trailer\n%%EOF\n" port)
+    (ly:cairo-at-eof)
     (ly:outputter-close outputter)
     (postprocess-output book framework-ps-module (ly:output-formats)
                         basename tmp-name #f)))
diff --git a/scm/lily.scm b/scm/lily.scm
index 06760089f0..5b3f99f4ea 100644
--- a/scm/lily.scm
+++ b/scm/lily.scm
@@ -258,6 +258,8 @@ EPS backend.")
     (backend ps
              "Select backend.  Possible values: 'eps, 'null,
 'ps, 'scm, 'svg.")
+    (cairotest #f
+                          "Also generate a .cairo.pdf file.")
     (check-internal-types #f
                           "Check every property assignment for types.")
     (clip-systems #f
diff --git a/scm/output-ps.scm b/scm/output-ps.scm
index 3373108f8d..788af6141d 100644
--- a/scm/output-ps.scm
+++ b/scm/output-ps.scm
@@ -43,6 +43,7 @@
              i))
 
 (define (circle radius thick fill)
+  (ly:cairo-draw-circle radius thick fill)
   (ly:format
    "~a ~4f ~4f draw_circle\n"
    (if fill
@@ -60,6 +61,7 @@
              phase))
 
 (define (draw-line thick x1 y1 x2 y2)
+  (ly:cairo-draw-line (- x2 x1) (- y2 y1) x1 y1 thick)
   (ly:format "~4f ~4f ~4f ~4f ~4f draw_line\n"
              (- x2 x1) (- y2 y1)
              x1 y1 thick))
@@ -75,6 +77,7 @@
              thick))
 
 (define (ellipse x-radius y-radius thick fill)
+  (ly:cairo-draw-ellipse x-radius y-radius thick fill)
   (ly:format
    "~a ~4f ~4f ~4f draw_ellipse\n"
    (if fill
@@ -97,6 +100,11 @@
     (if (and (= x 0) (= y 0))
         (ly:format "currentpoint ~a moveto ~4f 0 rmoveto" g w)
         (ly:format "currentpoint ~4f ~4f rmoveto ~a moveto ~4f 0 rmoveto" x y g w)))
+  (define (cgs w h x y g) (list w x y g))
+  (ly:cairo-print-glyphs postscript-font-name size (length w-x-y-named-glyphs)
+                        (map (lambda (x)
+                                (apply cgs x))
+                                 w-x-y-named-glyphs))
   (if cid?
       (ly:format
        "/~a /CIDFont findresource ~a output-scale div scalefont setfont\n~a\n~a print_glyphs\n"
@@ -159,6 +167,7 @@
       ""))
 
 (define (named-glyph font glyph)
+  (ly:cairo-show-named-glyph (ps-font-command font) glyph)
   (if (and (ly:get-option 'music-font-encodings) (string-startswith (ly:font-file-name font) "emmentaler"))
       (if (string-endswith (ly:font-file-name font)"-brace")
           (if (or (string-startswith glyph "brace1") (string-startswith glyph "brace2"))
@@ -177,9 +186,11 @@
   "")
 
 (define (settranslation x y)
+  (ly:cairo-moveto x y)
   (ly:format " ~4f ~4f moveto\n" x y))
 
 (define (polygon points blot-diameter filled?)
+  (ly:cairo-draw-polygon (/ (length points) 2) points blot-diameter filled?)
   (ly:format "~a ~a ~a ~4f draw_polygon\n"
              (if filled? "true" "false")
              (string-join (map (lambda (p) (ly:format "~4f" p)) points) " ")
@@ -192,6 +203,7 @@
          (width (- right (+ halfblot x)))
          (y (- halfblot bottom))
          (height (- top (+ halfblot y))))
+    (ly:cairo-draw-round-box width height x y blotdiam)
     (ly:format "~4f ~4f ~4f ~4f ~4f draw_round_box\n"
                width height x y blotdiam)))
 
@@ -261,6 +273,7 @@
            (convert-path-exps (drop rest arity))))
         '()))
 
+  (ly:cairo-path thickness exps cap join fill?)
   (let ((cap-numeric (case cap ((butt) 0) ((round) 1) ((square) 2)
                            (else (begin
                                    (ly:warning (_ "unknown line-cap-style: ~S")
-- 
2.31.1

  • Cairo Knut Petersen
    • Re: Cairo Jonas Hahnfeld via Discussions on LilyPond development
      • Re: Cairo Jonas Hahnfeld via Discussions on LilyPond development
        • Re: Ca... Rene Brandenburger
        • Re: Ca... Knut Petersen
          • Re... David Kastrup
            • ... Knut Petersen
              • ... David Kastrup
                • ... Werner LEMBERG
                • ... Jean Abou Samra
                • ... David Kastrup
                • ... David Kastrup
              • ... Lukas-Fabian Moser
                • ... Knut Petersen
                • ... David Kastrup
                • ... Knut Petersen
                • ... Werner LEMBERG

Reply via email to