]> git.donarmstrong.com Git - lilypond.git/commitdiff
Merge branch 'master' into translation
authorJean-Charles Malahieude <lilyfan@orange.fr>
Sat, 9 Mar 2013 18:33:43 +0000 (19:33 +0100)
committerJean-Charles Malahieude <lilyfan@orange.fr>
Sat, 9 Mar 2013 18:33:43 +0000 (19:33 +0100)
73 files changed:
Documentation/changes.tely
Documentation/de/web/community.itexi
Documentation/de/web/download.itexi
Documentation/notation/ancient.itely
Documentation/notation/changing-defaults.itely
Documentation/web/news-front.itexi
Documentation/web/news.itexi
VERSION
input/regression/chord-dots.ly [new file with mode: 0644]
input/regression/scheme-text-spanner.ly
input/regression/test-output-distance.ly
lily/GNUmakefile
lily/align-interface.cc
lily/axis-group-interface.cc
lily/bar-check-iterator.cc
lily/beam-engraver.cc
lily/coherent-ligature-engraver.cc
lily/context-def.cc
lily/context.cc
lily/dimension-cache.cc
lily/dot-column.cc
lily/global-context.cc
lily/grob-closure.cc
lily/grob-property.cc
lily/grob-scheme.cc
lily/grob.cc
lily/include/context.hh
lily/include/dimension-cache.hh
lily/include/grob.hh
lily/include/kievan-ligature.hh [new file with mode: 0644]
lily/include/lily-proto.hh
lily/include/slur-proto-engraver.hh [new file with mode: 0644]
lily/include/translator-group.hh
lily/kievan-ligature-engraver.cc [new file with mode: 0644]
lily/kievan-ligature.cc [new file with mode: 0644]
lily/ligature-engraver.cc
lily/lily-guile.cc
lily/melody-engraver.cc
lily/multi-measure-rest.cc
lily/music-scheme.cc
lily/note-performer.cc
lily/parser.yy
lily/pdf-scheme.cc
lily/phrasing-slur-engraver.cc
lily/pure-from-neighbor-engraver.cc
lily/quote-iterator.cc
lily/rest-collision.cc
lily/semi-tie-column.cc
lily/separation-item.cc
lily/side-position-interface.cc
lily/simple-closure.cc
lily/skyline.cc
lily/slur-engraver.cc
lily/slur-proto-engraver.cc [new file with mode: 0644]
lily/slur.cc
lily/stencil-integral.cc
lily/system.cc
lily/translator-dispatch-list.cc
lily/unpure-pure-container.cc
ly/engraver-init.ly
ly/music-functions-init.ly
ly/performer-init.ly
po/lilypond.pot
scm/bar-line.scm
scm/define-context-properties.scm
scm/define-grob-properties.scm
scm/define-grobs.scm
scm/define-markup-commands.scm
scm/lily-library.scm
scm/lily.scm
scm/output-lib.scm
scm/paper-system.scm
scm/skyline.scm [new file with mode: 0644]

index d3eb33d83b09a258b0ede114ae0ded72b4034eef..dab40a311297339e0686d820f7704877dd16d10d 100644 (file)
@@ -61,6 +61,29 @@ which scares away people.
 
 @end ignore
 
+@item
+The meaning of @code{instrumentTransposition} has been reversed.
+After
+@example
+\set instrumentTransposition = #@{ b #@}
+@end example
+a written @code{c'} now sounds like @code{b}.  Previously, this
+would have been the other way round.  This and the following change
+should make dealing with transposing instruments more
+straightforward.
+
+@item
+The music generated by @code{\set} and @code{\override} commands
+is no longer affected by @code{\transpose}.  The main consequence
+is that @code{\transpose} will transpose audible/@/concert pitch and
+printed pitch by the same amount even when the transposed music
+contains @code{\transposition}.  Previously,
+@example
+\transpose c' f' \transposition bes'
+@end example
+was equivalent to @code{\transposition f'}.  Now it stays
+equivalent to @code{\transposition bes'}.
+
 @item
 Tuplets are now created with the @code{\tuplet} command, which
 takes a fraction @code{@var{t}/@var{n}} to specify that @var{t}
index f3fe6338812ad6c7653c64a913ddd1c9c7f4cbc1..8b68907ace7b0e1a08486c5c790307dc8ea9d459 100644 (file)
@@ -301,33 +301,37 @@ Betroffen einbezieht.
 @divClass{column-center-top}
 @subheading Was sind @qq{Minimalbeispiele}?
 
-Ein Minimalbeispiel ist ein Beispiel, von dem @strong{nichts} mehr entfernt
-werden kann.
+Ein Minimalbeispiel ist eine vollständige Quelldatei, die
+@strong{nicht} mehr weiter reduziert werden kann, ohne dass das
+illustrierte Problem verschwindet.  Es sollten keine Warnungen und
+Fehlermeldungen produziert werden, die nicht mit dem Problem im
+Zusammenhang stehen.
+
 @divEnd
 
 @divClass{column-left-bottom}
-@subheading Warum sollte ich so etwas tun?
+@subheading Warum sollte ich Minimalbeispiele erstellen?
 
 @divClass{keep-bullets}
 @itemize
 
 @item
 Je einfacher ein Beispiel ist, um so schneller können mögliche
-Hilfeleistende es verstehen und Ihnen helfen.
+Hilfeleistende das Beispiel untersuchen, das auftretende Problem
+einkreisen und Ihnen helfen.
 
 @item
-Ein kleines Beispiel zeigt, dass Sie sich zuerst Mühe gegeben
-haben, das Problem selber zu lösen.  Wenn Leute große Abschnitte
-an Code einschicken, sieht es so aus, dass sie sich auch nicht
-interessieren, ob ihnen geholfen wird oder nicht.
+Die effiziente Analyse eines Problems erfordert ohnehin eine
+Reduktion auf das wesentliche.  Kippen Sie umfangreiches Material
+in der Liste ab, so scheint Ihnen die Lösung Ihres Problems keine
+eigene Mühe wert.
 
 @item
-Ein Minimalbeispiel zu erstellen hilft Ihnen zu verstehen,
-was vorgeht.  Viele falsche Problemberichte können vermieden werden,
-wenn man versucht, erst einmal ein Minimalbeispiel zu erstellen.
-Wenn Sie einen @qq{Bug} in Ihrem Minimalbeispiel nicht reproduzieren
-können, was das Problem wohl eher zu geringes Verständnis von
-LilyPond, nicht jedoch ein Fehler.
+Ein Minimalbeispiel zu erstellen hilft Ihnen zu verstehen, was
+vorgeht.  Viele Problemberichte erübrigen sich schon während der
+Erstellung eines Minimalbeispiels.  Ist ein @qq{Bug} mit einem
+bestimmten Minimalbeispiel nicht reproduzierbar, ist es
+wahrscheinlich, daß er andere Ursachen als vermutet hat.
 
 @end itemize
 @divEnd
index 0cca1d5fba7da0a94975708ba5a6a8f90a808a25..f88f69d1da686924c5dce64cda3ebf7ec67aaf17 100644 (file)
@@ -302,8 +302,6 @@ Alle Logos und Produktabbildungen erkennen Copyright und Trademark an.
 @downloadStableDarwinNormal
 Für MacOS X 10.4 und höher auf Intel-Prozessoren (wenn Sie Zweifel haben, benutzen Sie diese Version).
 
-MacOS X 10.7 Lion wird noch nicht unterstützt.
-
 @item
 @sourceimage{logo-macosx,,,}
 @downloadStableDarwinPPC
index 6d122875f89150dab9d5c01540fa84b51b092ebd..0f3c9a7f70e7d4ea254b7cb3907aab785ca12c6d 100644 (file)
@@ -2416,6 +2416,7 @@ with head prefixes in arbitrary order.
 * Kievan notes::
 * Kievan accidentals::
 * Kievan bar line::
+* Kievan melismata::
 @end menu
 
 @node Kievan contexts
@@ -2569,6 +2570,63 @@ It can be invoked as @code{\bar "k"}.
 @ref{Bars},
 @ref{The Feta font}
 
+@node Kievan melismata
+@unnumberedsubsubsec Kievan melismata
+
+@cindex Ligatures
+
+Notes within a Kievan melisma are usually placed close to each other
+and the melismata separated by whitespace. This is done to allow
+the chanter to quickly identify the melodic structures of Znamenny
+chant. In LilyPond, melismata are treated as ligatures and the
+spacing is implemented by the @code{Kievan_ligature_engraver}.
+
+When the @code{KievanVoice} and @code{KievanStaff} contexts are used,
+the @code{Kievan_ligature_engraver} is enabled by default. In other
+contexts, it can be invoked by replacing the @code{Ligature_bracket_engraver}
+with the @code{Kievan_ligature_engraver} in the layout block:
+
+@example
+\layout @{
+  \context @{
+    \Voice
+    \remove "Ligature_bracket_engraver"
+    \consists "Kievan_ligature_engraver"
+  @}
+@}
+@end example
+
+The spacing between the notes within a Kievan ligature can be controlled
+by setting the @code{padding} property of the @code{KievanLigature}.
+
+The following example demonstrates the use of Kievan ligatures:
+
+@lilypond[quote,ragged-right,verbatim]
+\score {
+  <<
+    \new KievanVoice = "melody" \transpose c c' {
+      \cadenzaOn
+       e2 \[ e4( d4 ) \] \[ c4( d e  d ) \] e1 \bar "k"
+    }
+    \new Lyrics \lyricsto "melody" {
+      Га -- врі -- и -- лу
+    }
+  >>
+}
+@end lilypond
+
+@seealso
+Music Glossary:
+@rglos{ligature}.
+
+Notation Reference:
+@ref{White mensural ligatures},
+@ref{Gregorian square neume ligatures},
+@ref{Ligatures}.
+
+@knownissues
+Horizontal spacing of ligatures is poor.
+
 @node Working with ancient music---scenarios and solutions
 @subsection Working with ancient music---scenarios and solutions
 
index 25771a986c71c972e4add0075931ba8b6856b142..09cf63b5c020b30e65197d128adb9605595f621e 100644 (file)
@@ -195,8 +195,10 @@ a piece in mensural style.
 @unnumberedsubsubsec Bottom-level contexts - voices
 
 Voice-level contexts initialise certain properties and start
-appropriate engravers.  Being bottom-level contexts, they cannot
-contain other contexts.
+appropriate engravers.  A bottom-level context is one without
+@code{defaultchild}.  While it is possible to let it
+accept/@/contain subcontexts, they can only be created and entered
+explicitly.
 
 @strong{@emph{Voice}}
 
index 81d2ad686438c000579de66c3a0f25ebbc98b940..d3509436f3b899edf5bbad1e8ea6077e7af9a814 100644 (file)
@@ -9,9 +9,9 @@
 @c used for news about the upcoming release; see CG 10.2
 
 @newsItem
-@subsubheading LilyPond 2.17.12 released!  @emph{February 8, 2013}
+@subsubheading LilyPond 2.17.13 released!  @emph{February 23, 2013}
 
-We are happy to announce the release of LilyPond 2.17.12.  This
+We are happy to announce the release of LilyPond 2.17.13.  This
 release contains the usual number of bugfixes and enhancements, and contains
 some work in progress.  You will have access to the very latest features, but
 some may be incomplete, and you may encounter bugs and crashes.  If you require
index 20b9750c13d96a72601205c52c76a5bf33800c34..25daa24996eb8e33c4269fe21ea5d9bab9471152 100644 (file)
@@ -26,6 +26,17 @@ NOTE:
   * don't duplicate entries from news-front.itexi
 @end ignore
 
+@newsItem
+@subsubheading LilyPond 2.17.12 released!  @emph{February 8, 2013}
+
+We are happy to announce the release of LilyPond 2.17.12.  This
+release contains the usual number of bugfixes and enhancements, and contains
+some work in progress.  You will have access to the very latest features, but
+some may be incomplete, and you may encounter bugs and crashes.  If you require
+a stable version of Lilypond, we recommend using the 2.16 version.
+
+@newsEnd
+
 @newsItem
 @subsubheading LilyPond 2.17.11 released!  @emph{January 26, 2013}
 
diff --git a/VERSION b/VERSION
index b05a55cdf63a505b4244ea10bb5f9e03f3b504b9..51304f6f793ecea08804d5473844a34b4b7c783b 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1,7 +1,7 @@
 PACKAGE_NAME=LilyPond
 MAJOR_VERSION=2
 MINOR_VERSION=17
-PATCH_LEVEL=13
+PATCH_LEVEL=14
 MY_PATCH_LEVEL=
 VERSION_STABLE=2.16.2
-VERSION_DEVEL=2.17.12
+VERSION_DEVEL=2.17.13
diff --git a/input/regression/chord-dots.ly b/input/regression/chord-dots.ly
new file mode 100644 (file)
index 0000000..cc02f31
--- /dev/null
@@ -0,0 +1,21 @@
+\version "2.17.14"
+
+\header {
+  texidoc =
+"Property @code{chord-dots}: If set, remove dots which the
+@code{DotColumn} algorithm would vertically position too far away from
+note heads."
+}
+
+\layout{ ragged-right = ##t }
+
+
+\relative c'' {
+  \override Score.DotColumn.chord-dots = ##f
+  << { <d e f g a>4. } \\
+     { <a, b c d e>4. } >>
+
+  \override Score.DotColumn.chord-dots = ##t
+  << { <d' e f g a>4. } \\
+     { <a, b c d e>4. } >>
+}
index 1e7598b25b5089c8cbeca1427d025b98c98f80ed..6a26177850485c28644c927dbc2275638c4b600c 100644 (file)
@@ -126,7 +126,7 @@ start and stop.")
          grob
          (if (eq? axis X)
              ly:side-position-interface::x-aligned-side
-             ly:side-position-interface::y-aligned-side)
+             side-position-interface::y-aligned-side)
          (axis-offset-symbol axis)))))
 
 schemeTextSpannerEngraver =
index 6ea91213b7c606996dad291486c713fb3eefd0d7..ef10b57f9c629175c4c93db2c5ce05b14dc6924a 100644 (file)
@@ -18,5 +18,7 @@ it should always show up in the output-distance testing. "
   ragged-right = ##f
 }
 
-\relative c' { c4 d f8_\f[ g-.] }
+\new PianoStaff << \new Staff \relative c' { c4 d f8_\f[ g-.] r4 }
+                  \new Staff { \clef "bass" R1 }
+               >>
 
index e67a8836758a4a2f9e578bf0b7427218995ba6de..ba19ac9559e90cd2a4f16e668df11a482c7dcb59 100644 (file)
@@ -6,9 +6,6 @@ NAME = lilypond
 MODULE_LIBS=$(depth)/flower
 MODULE_INCLUDES= $(depth)/flower/include
 
-# need this to convert between function pointers and member function pointers.
-MODULE_CXXFLAGS= -Wno-pmf-conversions 
-
 
 HELP2MAN_EXECS = lilypond
 STEPMAKE_TEMPLATES=c c++ executable po help2man
index 8a2a8d9b819a4469f2b60c73f75f1d0899963d91..986599e3f93240b755ebca7826fe46a6ec0521af 100644 (file)
@@ -61,24 +61,24 @@ Align_interface::align_to_ideal_distances (SCM smob)
   return SCM_BOOL_T;
 }
 
-/* for each grob, find its upper and lower skylines. If the grob has
-   an empty extent, delete it from the list instead. If the extent is
+/* for each grob, find its upper and lower skylines. If the extent is
    non-empty but there is no skyline available (or pure is true), just
    create a flat skyline from the bounding box */
 // TODO(jneem): the pure and non-pure parts seem to share very little
 // code. Split them into 2 functions, perhaps?
 static void
 get_skylines (Grob *me,
-              vector<Grob *> *const elements,
+              vector<Grob *> const &elements,
               Axis a,
               bool pure, int start, int end,
-              vector<Skyline_pair> *const ret)
+              vector<Skyline_pair> *ret,
+              vector<bool> const *skip_elt)
 {
-  Grob *other_common = common_refpoint_of_array (*elements, me, other_axis (a));
+  Grob *other_common = common_refpoint_of_array (elements, me, other_axis (a));
 
-  for (vsize i = elements->size (); i--;)
+  for (vsize i = elements.size (); i--;)
     {
-      Grob *g = (*elements)[i];
+      Grob *g = elements[i];
       Skyline_pair skylines;
 
       if (!pure)
@@ -95,7 +95,7 @@ get_skylines (Grob *me,
           Real offset = g->relative_coordinate (other_common, other_axis (a));
           skylines.shift (offset);
         }
-      else
+      else if (!(*skip_elt)[i])
         {
           assert (a == Y_AXIS);
           Interval extent = g->pure_height (g, start, end);
@@ -111,8 +111,7 @@ get_skylines (Grob *me,
           // of the system. This way, the tall treble clefs are only compared with the treble
           // clefs of the other staff and they will be ignored if the staff above is, for example,
           // lyrics.
-          if (Axis_group_interface::has_interface (g)
-              && !Hara_kiri_group_spanner::request_suicide (g, start, end))
+          if (Axis_group_interface::has_interface (g))
             {
               extent = Axis_group_interface::rest_of_line_pure_height (g, start, end);
               Interval begin_of_line_extent = Axis_group_interface::begin_of_line_pure_height (g, start);
@@ -134,10 +133,10 @@ get_skylines (Grob *me,
             }
         }
 
-      if (skylines.is_empty ())
-        elements->erase (elements->begin () + i);
-      else
-        ret->push_back (skylines);
+      // even if the skyline is empty, we want to push it back
+      // the heap because we will use things like system-system-distance
+      // to account for its presence
+      ret->push_back (skylines);
     }
   reverse (*ret);
 }
@@ -177,7 +176,7 @@ Align_interface::get_minimum_translations_without_min_dist (Grob *me,
 //   else centered dynamics will break when there is a fixed alignment).
 vector<Real>
 Align_interface::internal_get_minimum_translations (Grob *me,
-                                                    vector<Grob *> const &all_grobs,
+                                                    vector<Grob *> const &elems,
                                                     Axis a,
                                                     bool include_fixed_spacing,
                                                     bool pure, int start, int end)
@@ -204,10 +203,18 @@ Align_interface::internal_get_minimum_translations (Grob *me,
 
   Direction stacking_dir = robust_scm2dir (me->get_property ("stacking-dir"),
                                            DOWN);
-  vector<Grob *> elems (all_grobs); // writable copy
   vector<Skyline_pair> skylines;
+  vector<bool> skip_elt;
+  // only add to skip elt if pure
+  // if not pure, no dead element should be in the list
+  for (vsize i = 0; i < elems.size (); i++)
+    {
+      if (!pure && !elems[i]->is_live ())
+        elems[i]->programming_error ("I should be dead by now...");
+      skip_elt.push_back (pure && Hara_kiri_group_spanner::request_suicide (elems[i], start, end));
+    }
 
-  get_skylines (me, &elems, a, pure, start, end, &skylines);
+  get_skylines (me, elems, a, pure, start, end, &skylines, &skip_elt);
 
   Real where = 0;
   Real default_padding = robust_scm2double (me->get_property ("padding"), 0.0);
@@ -219,6 +226,11 @@ Align_interface::internal_get_minimum_translations (Grob *me,
   int spaceable_count = 0;
   for (vsize j = 0; j < elems.size (); j++)
     {
+      // This means that it will be suicided later downstream, so we
+      // skip it so that its padding is not added in.
+      if (pure && skip_elt[j])
+        continue;
+
       Real dy = 0;
       Real padding = default_padding;
 
@@ -284,13 +296,18 @@ Align_interface::internal_get_minimum_translations (Grob *me,
   // So far, we've computed the translates for all the non-empty elements.
   // Here, we set the translates for the empty elements: an empty element
   // gets the same translation as the last non-empty element before it.
+  vector<Grob *> non_empty_elems;
+  for (vsize i = 0; i < elems.size (); i++)
+    if (!skip_elt[i])
+      non_empty_elems.push_back (elems[i]);
+
   vector<Real> all_translates;
   if (!translates.empty ())
     {
       Real w = translates[0];
-      for (vsize i = 0, j = 0; j < all_grobs.size (); j++)
+      for (vsize i = 0, j = 0; j < elems.size (); j++)
         {
-          if (i < elems.size () && all_grobs[j] == elems[i])
+          if (i < non_empty_elems.size () && elems[j] == non_empty_elems[i])
             w = translates[i++];
           all_translates.push_back (w);
         }
index 1ed1f7f8fcc109e3d65ea2ed83d556b3b936f217..0d786c3a2959aa201470f761c27ee3cd6a98645d 100644 (file)
@@ -258,6 +258,9 @@ Axis_group_interface::adjacent_pure_heights (SCM smob)
           && !has_interface (g))
         continue;
 
+      if (!g->is_live ())
+        continue;
+
       bool outside_staff = scm_is_number (g->get_property ("outside-staff-priority"));
       Real padding = robust_scm2double (g->get_property ("outside-staff-padding"), get_default_outside_staff_padding ());
 
@@ -493,20 +496,20 @@ Axis_group_interface::internal_calc_pure_relevant_grobs (Grob *me, string grob_s
   extract_grob_set (me, grob_set_name.c_str (), elts);
 
   vector<Grob *> relevant_grobs;
-  SCM pure_relevant_p = ly_lily_module_constant ("pure-relevant?");
 
   for (vsize i = 0; i < elts.size (); i++)
     {
-      if (to_boolean (scm_apply_1 (pure_relevant_p, elts[i]->self_scm (), SCM_EOL)))
-        relevant_grobs.push_back (elts[i]);
-
-      if (Item *it = dynamic_cast<Item *> (elts[i]))
+      if (elts[i] && elts[i]->is_live ())
         {
-          for (LEFT_and_RIGHT (d))
+          relevant_grobs.push_back (elts[i]);
+          if (Item *it = dynamic_cast<Item *> (elts[i]))
             {
-              Item *piece = it->find_prebroken_piece (d);
-              if (piece && to_boolean (scm_apply_1 (pure_relevant_p, piece->self_scm (), SCM_EOL)))
-                relevant_grobs.push_back (piece);
+              for (LEFT_and_RIGHT (d))
+                {
+                  Item *piece = it->find_prebroken_piece (d);
+                  if (piece && piece->is_live ())
+                    relevant_grobs.push_back (piece);
+                }
             }
         }
     }
@@ -573,7 +576,7 @@ Axis_group_interface::pure_group_height (Grob *me, int start, int end)
       programming_error ("no pure Y common refpoint");
       return Interval ();
     }
-  Real my_coord = me->relative_coordinate (common, Y_AXIS);
+  Real my_coord = me->pure_relative_y_coordinate (common, start, end);
   Interval r (relative_pure_height (me, start, end));
 
   return r - my_coord;
index a0fb8eaee17391231734a889ce2ec7e480615c98..ea4794897d3353f9fddae5c607ffe1f33fd78898 100644 (file)
@@ -27,7 +27,7 @@
   Check bar checks. We do this outside the engravers so that you can
   race through the score using skipTypesetting to correct durations.
 */
-class Bar_check_iterator : Simple_music_iterator
+class Bar_check_iterator : Music_iterator
 {
 public:
   virtual void process (Moment);
@@ -44,7 +44,7 @@ Bar_check_iterator::Bar_check_iterator ()
 void
 Bar_check_iterator::process (Moment m)
 {
-  Simple_music_iterator::process (m);
+  Music_iterator::process (m);
   if (!m.to_bool ())
     {
       Context *tr = get_outlet ();
index a89435de6871a6ff391ac34075cea7e3c3f44527..00b9081b3e34889ed1d6cf26323b7d6efe3e3e2a 100644 (file)
@@ -30,6 +30,7 @@
 #include "spanner.hh"
 #include "stream-event.hh"
 #include "stem.hh"
+#include "unpure-pure-container.hh"
 #include "warn.hh"
 
 #include "translator.icc"
@@ -243,7 +244,10 @@ Beam_engraver::acknowledge_rest (Grob_info info)
   if (beam_
       && !scm_is_number (info.grob ()->get_property_data ("staff-position")))
     chain_offset_callback (info.grob (),
-                           Beam::rest_collision_callback_proc, Y_AXIS);
+                           ly_make_unpure_pure_container
+                             (Beam::rest_collision_callback_proc,
+                              Beam::pure_rest_collision_callback_proc),
+                           Y_AXIS);
 }
 
 void
index 843c5208c0dfd78b570c9ebbe41d4427a16bee9f..3e2915e719674c28021273dad98233b09363c9b2 100644 (file)
@@ -40,9 +40,9 @@
  *
  * - delegate actual creation of ligature to concrete subclass,
  *
- * - collect all accidentals that occur within the ligature and put
- * them at the left side of the ligature (TODO; see function
- * collect_accidentals ()),
+ * - except in Kievan notation, collect all accidentals that occur
+ * within the ligature and put them at the left side of the ligature
+ * (TODO; see function collect_accidentals ()),
  *
  * - collapse superflous space after each ligature (TODO).
  *
@@ -135,6 +135,9 @@ Coherent_ligature_engraver::collect_accidentals (Spanner *,
                                                  vector<Grob_info> const &)
 {
   /* TODO */
+  /* NOTE: if implementing such a function, note that in Kievan notation,
+   * the B-flat accidental should not be "collected", but rather prints
+   * immediately before the note head as usual. */
 }
 
 void
index 1f823bf50368f747aff414b68bd6e8181c6b9b7c..9ef10bea966a6f631b2338138cfc46836342dfd1 100644 (file)
@@ -316,6 +316,7 @@ Context_def::instantiate (SCM ops)
   context->definition_mods_ = ops;
   context->aliases_ = context_aliases_;
   context->accepts_list_ = get_accepted (ops);
+  context->default_child_ = get_default_child (ops);
 
   return context;
 }
@@ -342,6 +343,10 @@ Context_def::to_alist () const
                             get_translator_names (SCM_EOL)), ell);
   ell = scm_cons (scm_cons (ly_symbol2scm ("description"), description_), ell);
   ell = scm_cons (scm_cons (ly_symbol2scm ("aliases"), context_aliases_), ell);
+  ell = scm_cons (scm_cons (ly_symbol2scm ("accepts"), get_accepted (SCM_EOL)),
+                  ell);
+  if (scm_is_symbol (default_child_))
+    ell = scm_acons (ly_symbol2scm ("default-child"), default_child_, ell);
   ell = scm_cons (scm_cons (ly_symbol2scm ("accepts"), get_accepted (SCM_EOL)),
                   ell);
   ell = scm_cons (scm_cons (ly_symbol2scm ("property-ops"), property_ops_),
@@ -381,7 +386,7 @@ bool
 Context_def::is_alias (SCM sym) const
 {
   if (scm_is_eq (sym, ly_symbol2scm ("Bottom")))
-    return !scm_is_pair (get_accepted (SCM_EOL));
+    return !scm_is_symbol (get_default_child (SCM_EOL));
 
   if (scm_is_eq (sym, get_context_name ()))
     return true;
index d2c93155a578964e5cf439400fe626236b611ca3..3da638fe557922cdee4817b22d98e937f6ba38a5 100644 (file)
@@ -86,6 +86,7 @@ Context::Context ()
   implementation_ = 0;
   properties_scm_ = SCM_EOL;
   accepts_list_ = SCM_EOL;
+  default_child_ = SCM_EOL;
   context_list_ = SCM_EOL;
   definition_ = SCM_EOL;
   definition_mods_ = SCM_EOL;
@@ -401,9 +402,7 @@ Context::create_context (Context_def *cdef,
 SCM
 Context::default_child_context_name () const
 {
-  return scm_is_pair (accepts_list_)
-         ? scm_car (accepts_list_)
-         : SCM_EOL;
+  return default_child_;
 }
 
 bool
@@ -492,10 +491,9 @@ Context::internal_send_stream_event (SCM type, Input *origin, SCM props[])
 bool
 Context::is_alias (SCM sym) const
 {
-  if (sym == ly_symbol2scm ("Bottom")
-      && !scm_is_pair (accepts_list_))
-    return true;
-  if (sym == unsmob_context_def (definition_)->get_context_name ())
+  if (scm_is_eq (sym, ly_symbol2scm ("Bottom")))
+    return is_bottom_context ();
+  if (scm_is_eq (sym, context_name_symbol ()))
     return true;
 
   return scm_c_memq (sym, aliases_) != SCM_BOOL_F;
@@ -687,6 +685,7 @@ Context::mark_smob (SCM sm)
   scm_gc_mark (me->definition_mods_);
   scm_gc_mark (me->properties_scm_);
   scm_gc_mark (me->accepts_list_);
+  scm_gc_mark (me->default_child_);
 
   if (me->implementation_)
     scm_gc_mark (me->implementation_->self_scm ());
index 2d2fce49f396d2c482c329916a9a7b4ba0b9ce30..4538f17bc11a22a2646741d5a14b67de299e7e7c 100644 (file)
@@ -30,6 +30,16 @@ Dimension_cache::Dimension_cache (Dimension_cache const &d)
   extent_ = d.extent_ ? new Interval (*d.extent_) : 0;
 }
 
+Dimension_cache &
+Dimension_cache::operator = (Dimension_cache const &d)
+{
+  clear ();
+  offset_ = d.offset_ ? new Real (*d.offset_) : 0;
+  parent_ = d.parent_;
+  extent_ = d.extent_ ? new Interval (*d.extent_) : 0;
+  return *this;
+}
+
 Dimension_cache::Dimension_cache ()
 {
   init ();
index 6cba432639deb7f8fd899a53a577987253787762..012808f289d27b8f1d4991e3b492bd59c060da72 100644 (file)
@@ -60,6 +60,7 @@ Dot_column::calc_positioning_done (SCM smob)
     = extract_grob_array (me, "dots");
 
   vector<Grob *> main_heads;
+  vector<Interval> allowed_y_positions;
   Real ss = 0;
 
   Grob *commonx = me;
@@ -73,7 +74,35 @@ Dot_column::calc_positioning_done (SCM smob)
           commonx = stem->common_refpoint (commonx, X_AXIS);
 
           if (Stem::first_head (stem) == n)
-            main_heads.push_back (n);
+            {
+              main_heads.push_back (n);
+
+              // Get vertical interval of the chord's notehead positions.
+              // We widen this interval since dots always sit between staff
+              // lines.  Be careful to make it work also for unusual
+              // overrides of `NoteHead.Y-offset'.
+              //
+              // Possible solutions to improve this code (namely, to handle
+              // the `staff-position' property also) -- in case there is
+              // ever the desire or necessity to do so -- can be found in
+              // the Rietveld comments at
+              //
+              //   https://codereview.appspot.com/7319049
+
+              Interval hp = Stem::head_positions (stem);
+
+              int top = int (ceil (hp[UP]));
+              if (Staff_symbol_referencer::on_line (stem, top))
+                top += 1;
+              hp[UP] = top;
+
+              int bottom = int (floor (hp[DOWN]));
+              if (Staff_symbol_referencer::on_line (stem, bottom))
+                bottom -= 1;
+              hp[DOWN] = bottom;
+
+              allowed_y_positions.push_back (hp);
+            }
         }
     }
 
@@ -194,6 +223,45 @@ Dot_column::calc_positioning_done (SCM smob)
 
   problem.register_configuration (cfg);
 
+  // If in a chord, remove dots which have vertical positions above or below
+  // the topmost or bottommost note, respectively ([Gould], p. 56).
+  // Note that a dot configuration can contain more than a single chord or
+  // rest (the latter gets ignored).
+  //
+  // The dot positioning algorithm vertically shifts dots; it thus can
+  // happen that, say, a dot of the upper voice's chord is positioned
+  // beneath a note head of the lower voice's chord, while the dots of the
+  // lower voice's chord are shifted down even more.  We thus check all
+  // vertical ranges for valid positions and not only the range of the dot's
+  // parent chord.
+  //
+  // Do nothing if there is either no staff line, or no note head, or the
+  // `chord-dots' property not set.
+  Grob *st = Staff_symbol_referencer::get_staff_symbol (me);
+  vsize num_positions = allowed_y_positions.size ();
+  bool chord_dots = to_boolean (me->get_property ("chord-dots"));
+
+  if (st && num_positions && chord_dots)
+    {
+      for (Dot_configuration::const_iterator i (cfg.begin ());
+           i != cfg.end (); i++)
+        {
+          vsize j;
+
+          for (j = 0; j < num_positions; j++)
+            if (allowed_y_positions[j].contains (i->first))
+              break;
+
+          if (j == num_positions)
+            {
+              Grob *dot = i->second.dot_;
+              Grob *n = dot->get_parent (Y_AXIS);
+              if (n && Note_head::has_interface (n))
+                dot->suicide ();
+            }
+        }
+    }
+
   for (Dot_configuration::const_iterator i (cfg.begin ());
        i != cfg.end (); i++)
     {
@@ -236,9 +304,10 @@ ADD_INTERFACE (Dot_column,
                " dots so they do not clash with staff lines.",
 
                /* properties */
-               "dots "
-               "positioning-done "
+               "chord-dots "
                "direction "
+               "dots "
                "note-collision "
+               "positioning-done "
               );
 
index 005c54b45e67b97b38e256e1d639eaea638c2e7b..8f22b943effe787d69033023ce8196d99486cafb 100644 (file)
@@ -58,7 +58,8 @@ Global_context::Global_context (Output_def *o)
   for (; scm_is_pair (p); p = scm_cdr (p))
     scm_hashq_set_x (ancestor_lookup_, scm_caar (p), scm_car (p));
 
-  accepts_list_ = scm_list_1 (ly_symbol2scm ("Score"));
+  default_child_ = ly_symbol2scm ("Score");
+  accepts_list_ = scm_list_1 (default_child_);
 }
 
 Output_def *
index 4f6c0adc81f5219836e20c2bb92754f347a20eab..4c63fe3c0c55436c4a608e0747582ff026c6ffd7 100644 (file)
@@ -1,5 +1,6 @@
 #include "grob.hh"
 #include "simple-closure.hh"
+#include "unpure-pure-container.hh"
 
 SCM
 axis_offset_symbol (Axis a)
@@ -38,7 +39,7 @@ add_offset_callback (Grob *g, SCM proc, Axis a)
       return;
     }
 
-  if (ly_is_procedure (data))
+  if (ly_is_procedure (data) || is_unpure_pure_container (data))
     data = ly_make_simple_closure (scm_list_1 (data));
   else if (is_simple_closure (data))
     data = simple_closure_expression (data);
@@ -66,7 +67,7 @@ chain_callback (Grob *g, SCM proc, SCM sym)
 {
   SCM data = g->get_property_data (sym);
 
-  if (ly_is_procedure (data))
+  if (ly_is_procedure (data) || is_unpure_pure_container (data))
     data = ly_make_simple_closure (scm_list_1 (data));
   else if (is_simple_closure (data))
     data = simple_closure_expression (data);
index 9120aefdf29939b5f16c6e60fb7218fdcafeba68..f9773e5ec5a4878b12f66f1535970a5696e6ff8a 100644 (file)
@@ -181,6 +181,7 @@ Grob::internal_get_property (SCM sym) const
 
   if (is_unpure_pure_container (val))
     val = unpure_pure_container_unpure_part (val);
+
   if (ly_is_procedure (val)
       || is_simple_closure (val))
     {
@@ -321,9 +322,35 @@ Grob::internal_has_interface (SCM k)
 SCM
 call_pure_function (SCM unpure, SCM args, int start, int end)
 {
-  SCM scm_call_pure_function = ly_lily_module_constant ("call-pure-function");
+  if (is_unpure_pure_container (unpure))
+    {
+      SCM pure = unpure_pure_container_pure_part (unpure);
+
+      if (is_simple_closure (pure))
+        {
+          SCM expr = simple_closure_expression (pure);
+          return evaluate_with_simple_closure (scm_car (args), expr, true, start, end);
+        }
+
+      if (ly_is_procedure (pure))
+        return scm_apply_0 (pure,
+                            scm_append (scm_list_2 (scm_list_3 (scm_car (args),
+                                                                scm_from_int (start),
+                                                                scm_from_int (end)),
+                                                    scm_cdr (args))));
+
+      return pure;
+    }
+
+  if (is_simple_closure (unpure))
+    {
+      SCM expr = simple_closure_expression (unpure);
+      return evaluate_with_simple_closure (scm_car (args), expr, true, start, end);
+    }
+
+  if (!ly_is_procedure (unpure))
+    return unpure;
 
-  return scm_apply_0 (scm_call_pure_function,
-                      scm_list_4 (unpure, args, scm_from_int (start), scm_from_int (end)));
+  return SCM_BOOL_F;
 }
 
index e5976a569b799b4db7a4fa6562afe6ee4953cb0f..9ae9c14fcbd3698a57adff41dfecf6edb80d5529 100644 (file)
@@ -25,6 +25,7 @@
 #include "paper-score.hh"
 #include "simple-closure.hh"
 #include "system.hh"
+#include "unpure-pure-container.hh"
 #include "warn.hh"              // error ()
 
 LY_DEFINE (ly_grob_property_data, "ly:grob-property-data",
@@ -450,7 +451,7 @@ LY_DEFINE (ly_grob_chain_callback, "ly:grob-chain-callback",
   Grob *gr = unsmob_grob (grob);
 
   LY_ASSERT_SMOB (Grob, grob, 1);
-  LY_ASSERT_TYPE (ly_is_procedure, proc, 2);
+  SCM_ASSERT_TYPE (ly_is_procedure (proc) || is_unpure_pure_container (proc), proc, SCM_ARG2, __FUNCTION__, "procedure or unpure pure container");
   LY_ASSERT_TYPE (ly_is_symbol, sym, 3);
 
   chain_callback (gr, proc, sym);
index 4c54cbc508a318938b50ef5258ce012ff2f381f2..a6b862e04eee586495fd6e1b3aff343e0340678b 100644 (file)
@@ -36,6 +36,7 @@
 #include "stencil.hh"
 #include "stream-event.hh"
 #include "system.hh"
+#include "unpure-pure-container.hh"
 #include "warn.hh"
 
 #include "ly-smobs.icc"
@@ -79,21 +80,30 @@ Grob::Grob (SCM basicprops)
   if (get_property_data ("X-extent") == SCM_EOL)
     set_property ("X-extent", Grob::stencil_width_proc);
   if (get_property_data ("Y-extent") == SCM_EOL)
-    set_property ("Y-extent", Grob::stencil_height_proc);
+    set_property ("Y-extent",
+                  ly_make_unpure_pure_container (Grob::stencil_height_proc,
+                                                 Grob::pure_stencil_height_proc));
   if (get_property_data ("vertical-skylines") == SCM_EOL)
-    set_property ("vertical-skylines", Grob::simple_vertical_skylines_from_extents_proc);
+    set_property ("vertical-skylines",
+                  ly_make_unpure_pure_container (Grob::simple_vertical_skylines_from_extents_proc,
+                                                 Grob::pure_simple_vertical_skylines_from_extents_proc));
   if (get_property_data ("horizontal-skylines") == SCM_EOL)
-    set_property ("horizontal-skylines", Grob::simple_horizontal_skylines_from_extents_proc);
+    set_property ("horizontal-skylines",
+                  ly_make_unpure_pure_container (Grob::simple_horizontal_skylines_from_extents_proc,
+                                                 Grob::pure_simple_horizontal_skylines_from_extents_proc));
 }
 
 Grob::Grob (Grob const &s)
-  : dim_cache_ (s.dim_cache_)
 {
   original_ = (Grob *) & s;
   self_scm_ = SCM_EOL;
 
   immutable_property_alist_ = s.immutable_property_alist_;
   mutable_property_alist_ = SCM_EOL;
+
+  for (Axis a = X_AXIS; a < NO_AXES; incr (a))
+      dim_cache_ [a] = s.dim_cache_ [a];
+
   interfaces_ = s.interfaces_;
   object_alist_ = SCM_EOL;
 
@@ -485,10 +495,7 @@ Interval
 Grob::pure_height (Grob *refp, int start, int end)
 {
   SCM iv_scm = get_pure_property ("Y-extent", start, end);
-  // TODO: Why is this Interval (0,0)
-  // Shouldn't it just be an empty interval?
-  // 0,0 puts an arbitrary point at 0,0 which will influence spacing
-  Interval iv = robust_scm2interval (iv_scm, Interval (0, 0));
+  Interval iv = robust_scm2interval (iv_scm, Interval ());
   Real offset = pure_relative_y_coordinate (refp, start, end);
 
   SCM min_ext = get_property ("minimum-Y-extent");
@@ -854,6 +861,18 @@ Grob::stencil_height (SCM smob)
   return grob_stencil_extent (me, Y_AXIS);
 }
 
+MAKE_SCHEME_CALLBACK (Grob, pure_stencil_height, 3);
+SCM
+Grob::pure_stencil_height (SCM smob, SCM /* beg */, SCM /* end */)
+{
+  Grob *me = unsmob_grob (smob);
+  if (unsmob_stencil (me->get_property_data ("stencil")))
+    return grob_stencil_extent (me, Y_AXIS);
+
+  return ly_interval2scm (Interval ());
+
+}
+
 MAKE_SCHEME_CALLBACK (Grob, y_parent_positioning, 1);
 SCM
 Grob::y_parent_positioning (SCM smob)
index 5543235c25d4b668d2140300697bcb2914a68799..794f275287e1f9fcbe404d22c44dfc731c782e6d 100644 (file)
@@ -55,6 +55,7 @@ protected:
   SCM properties_scm_;
   SCM context_list_;
   SCM accepts_list_;
+  SCM default_child_;
   SCM aliases_;
   Translator_group *implementation_;
   string id_string_;
index 581bcff8a99cc5109aa14171b01a34f7f7dabdd3..6210be1285130f886adab00c3a035d597a92b9e7 100644 (file)
@@ -36,6 +36,7 @@ class Dimension_cache
   friend class Grob;
 
   Dimension_cache (Dimension_cache const &);
+  Dimension_cache & operator = (Dimension_cache const &d);
   ~Dimension_cache ();
   Dimension_cache ();
 };
index a98b19a9f6ea4098041e3468eeaf270f6762d758..70c9c0a94e0a92ad2e9dfb3006473411b86da50f 100644 (file)
@@ -69,15 +69,18 @@ public:
   /* standard callbacks */
   DECLARE_SCHEME_CALLBACK (x_parent_positioning, (SCM));
   DECLARE_SCHEME_CALLBACK (y_parent_positioning, (SCM));
+  DECLARE_SCHEME_CALLBACK (pure_stencil_height, (SCM smob, SCM, SCM));
   DECLARE_SCHEME_CALLBACK (stencil_height, (SCM smob));
   DECLARE_SCHEME_CALLBACK (stencil_width, (SCM smob));
   DECLARE_SCHEME_CALLBACK (pure_simple_vertical_skylines_from_extents, (SCM smob, SCM, SCM));
   DECLARE_SCHEME_CALLBACK (simple_vertical_skylines_from_extents, (SCM smob));
   DECLARE_SCHEME_CALLBACK (vertical_skylines_from_stencil, (SCM smob));
+  DECLARE_SCHEME_CALLBACK (pure_vertical_skylines_from_element_stencils, (SCM smob, SCM, SCM));
   DECLARE_SCHEME_CALLBACK (vertical_skylines_from_element_stencils, (SCM smob));
   DECLARE_SCHEME_CALLBACK (pure_simple_horizontal_skylines_from_extents, (SCM smob, SCM, SCM));
   DECLARE_SCHEME_CALLBACK (simple_horizontal_skylines_from_extents, (SCM smob));
   DECLARE_SCHEME_CALLBACK (horizontal_skylines_from_stencil, (SCM smob));
+  DECLARE_SCHEME_CALLBACK (pure_horizontal_skylines_from_element_stencils, (SCM smob, SCM, SCM));
   DECLARE_SCHEME_CALLBACK (horizontal_skylines_from_element_stencils, (SCM smob));
 
   /* R/O access */
@@ -164,6 +167,7 @@ public:
   bool check_cross_staff (Grob *common);
   static bool less (Grob *g1, Grob *g2);
   static SCM maybe_pure_internal_simple_skylines_from_extents (Grob *, Axis, bool, int, int, bool, bool);
+  static SCM internal_skylines_from_element_stencils (Grob *me, Axis a, bool pure, int beg, int end);
   static SCM internal_skylines_from_element_stencils (SCM, Axis);
 };
 
diff --git a/lily/include/kievan-ligature.hh b/lily/include/kievan-ligature.hh
new file mode 100644 (file)
index 0000000..cb6494c
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+  This file is part of LilyPond, the GNU music typesetter.
+
+  Copyright (C) 2013 Aleksandr Andreev <aleksandr.andreev@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/>.
+*/
+
+#ifndef KIEVAN_LIGATURE_HH
+#define KIEVAN_LIGATURE_HH
+
+#include "lily-proto.hh"
+#include "grob-interface.hh"
+
+struct Kievan_ligature
+{
+  DECLARE_SCHEME_CALLBACK (print, (SCM));
+  DECLARE_GROB_INTERFACE ();
+};
+
+#endif /* KIEVAN_LIGATURE_HH */
index e726c4abe57d6796eb0c133ca5cecc56cc8140e2..53e863c2a9e9f9d32a3a8137dad8631c28448450 100644 (file)
@@ -198,8 +198,7 @@ class Translator_group;
 class Transposed_music;
 class yyFlexLexer;
 
-typedef void (*Engraver_void_function_engraver_grob_info) (Engraver *,
-                                                           Grob_info);
-typedef void (*Translator_void_method_ptr) (Translator *);
+typedef void (Engraver::*Engraver_void_function_engraver_grob_info) (Grob_info);
+typedef void (Translator::*Translator_void_method_ptr) ();
 
 #endif /* LILY_PROTO_HH */
diff --git a/lily/include/slur-proto-engraver.hh b/lily/include/slur-proto-engraver.hh
new file mode 100644 (file)
index 0000000..0b08617
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+  This file is part of LilyPond, the GNU music typesetter.
+
+  Copyright (C) 2013 Mike Solomon <mike@mikesolomon.org>
+
+  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/>.
+*/
+
+#ifndef SLUR_PROTO_ENGRAVER_HH
+#define SLUR_PROTO_ENGRAVER_HH
+
+#include "engraver.hh"
+#include "moment.hh"
+
+class Slur_proto_engraver : public Engraver
+{
+protected:
+  Slur_proto_engraver (const char* double_property_name,
+    const char* grob_name, const char* object_name, const char* event_name) :
+      double_property_name_ (double_property_name),
+      grob_name_ (grob_name), object_name_ (object_name),
+      event_name_ (event_name) {}
+
+  // protected so that subclasses can see them
+  vector<Stream_event *> start_events_;
+  vector<Stream_event *> stop_events_;
+  vector<Grob *> slurs_;
+  vector<Grob *> end_slurs_;
+  vector<Grob_info> objects_to_acknowledge_;
+  const char* double_property_name_;
+  const char* grob_name_;
+  const char* object_name_;
+  const char* event_name_;
+
+  DECLARE_ACKNOWLEDGER (inline_accidental);
+  DECLARE_ACKNOWLEDGER (fingering);
+  DECLARE_ACKNOWLEDGER (note_column);
+  DECLARE_ACKNOWLEDGER (script);
+  DECLARE_ACKNOWLEDGER (dots);
+  DECLARE_ACKNOWLEDGER (text_script);
+  DECLARE_END_ACKNOWLEDGER (tie);
+  DECLARE_ACKNOWLEDGER (tuplet_number);
+
+  void internal_listen_slur (Stream_event *ev);
+  void acknowledge_extra_object (Grob_info);
+  void stop_translation_timestep ();
+  void process_music ();
+
+  bool can_create_slur (string, vsize, vsize *, Stream_event *);
+  void create_slur (string spanner_id, Stream_event *ev_cause, Grob *g_cause, Direction dir, bool left_broken);
+  bool try_to_end (Stream_event *ev);
+
+  virtual void set_melisma (bool);
+  virtual void finalize ();
+  virtual void derived_mark () const;
+
+public:
+  // no TRANSLATOR_DECLARATIONS (Slur_proto_engraver) needed since this
+  // class is abstract
+};
+
+#endif // SLUR_PROTO_ENGRAVER_HH
index e5004c2925cd7cda2530b0b343977d2e9d1660d5..ad044de86075d6d9e9178d05a4ed11fd8d81335d 100644 (file)
@@ -43,7 +43,7 @@ struct Translator_method_binding
   void invoke ()
   {
     if (method_)
-      (*method_) (translator_);
+      (translator_->*method_) ();
   }
 };
 
diff --git a/lily/kievan-ligature-engraver.cc b/lily/kievan-ligature-engraver.cc
new file mode 100644 (file)
index 0000000..92b9848
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+  This file is part of LilyPond, the GNU music typesetter.
+
+  Copyright (C) 2013 Aleksandr Andreev <aleksandr.andreev@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 "coherent-ligature-engraver.hh"
+#include "font-interface.hh"
+#include "international.hh"
+#include "kievan-ligature.hh"
+#include "paper-column.hh"
+#include "rhythmic-head.hh"
+#include "spanner.hh"
+#include "stream-event.hh"
+#include "warn.hh"
+
+#include "translator.icc"
+
+class Kievan_ligature_engraver : public Coherent_ligature_engraver
+{
+
+protected:
+  virtual Spanner *create_ligature_spanner ();
+  virtual void build_ligature (Spanner *ligature,
+                               vector<Grob_info> const &primitives);
+  DECLARE_TRANSLATOR_LISTENER (ligature);
+
+public:
+  TRANSLATOR_DECLARATIONS (Kievan_ligature_engraver);
+
+private:
+  void fold_up_primitives (vector<Grob_info> const &primitives, Real padding, Real &min_length);
+};
+
+IMPLEMENT_TRANSLATOR_LISTENER (Kievan_ligature_engraver, ligature);
+void
+Kievan_ligature_engraver::listen_ligature (Stream_event *ev)
+{
+  Ligature_engraver::listen_ligature (ev);
+}
+
+Kievan_ligature_engraver::Kievan_ligature_engraver ()
+{
+
+}
+
+Spanner *
+Kievan_ligature_engraver::create_ligature_spanner ()
+{
+  return make_spanner ("KievanLigature", SCM_EOL);
+}
+
+void
+Kievan_ligature_engraver::fold_up_primitives (vector<Grob_info> const &primitives,
+                                               Real padding, Real &min_length)
+{
+  Item *first = 0;
+  Real accumul_acc_space = 0.0;
+  // start us off with some padding on the left
+  min_length = padding;
+
+  for (vsize i = 0; i < primitives.size (); i++)
+    {
+      Item *current = dynamic_cast<Item *> (primitives[i].grob ());
+      Interval my_ext = current->extent (current, X_AXIS);
+      Real head_width = my_ext.length ();
+      if (i == 0)
+         first = current;
+
+      // must keep track of accidentals in spacing problem
+      Grob *acc_gr = unsmob_grob (current->get_object ("accidental-grob"));
+      if (acc_gr && i > 0)
+        {
+           Interval acc_ext = acc_gr->extent (acc_gr, X_AXIS);
+           accumul_acc_space += acc_ext.length();
+        }
+
+      move_related_items_to_column (current, first->get_column (),
+                                    min_length);
+
+      // check if we have any dots
+      if (size_t const dot_count = Rhythmic_head::dot_count (current))
+        {
+          Grob *dot_gr = Rhythmic_head::get_dots (current);
+
+          head_width += Font_interface::get_default_font (current)->
+              find_by_name ("dots.dotkievan").extent (X_AXIS).length() -
+              0.5 * (padding - accumul_acc_space);
+
+          dot_gr->translate_axis (0.5 * (padding - accumul_acc_space), X_AXIS);
+        }
+
+      // add more padding if we have an accidental coming up
+      if (i < primitives.size () - 1)
+        {
+           Item *next = dynamic_cast<Item *> (primitives[i + 1].grob ());
+           Grob *acc_gr = unsmob_grob (next->get_object ("accidental-grob"));
+           if (acc_gr)
+             {
+                Interval acc_ext = acc_gr->extent (acc_gr, X_AXIS);
+                padding += acc_ext.length();
+             }
+        }
+
+      min_length += head_width + padding - accumul_acc_space;
+
+    }
+
+}
+
+void
+Kievan_ligature_engraver::build_ligature (Spanner *ligature,
+                                            vector<Grob_info> const &primitives)
+{
+  Real min_length;
+
+  Real padding = robust_scm2double (ligature->get_property ("padding"), 0.0);
+  fold_up_primitives (primitives, padding, min_length);
+  if (robust_scm2double (ligature->get_property ("minimum-length"), 0.0)
+      < min_length)
+    ligature->set_property ("minimum-length", scm_from_double (min_length));
+
+}
+
+ADD_ACKNOWLEDGER (Kievan_ligature_engraver, rest);
+ADD_ACKNOWLEDGER (Kievan_ligature_engraver, ligature_head);
+
+ADD_TRANSLATOR (Kievan_ligature_engraver,
+                /* doc */
+                "Handle @code{Kievan_ligature_events} by glueing Kievan"
+                " heads together.",
+
+                /* create */
+                "KievanLigature ",
+
+                /* read */
+                "",
+
+                /* write */
+                ""
+               );
diff --git a/lily/kievan-ligature.cc b/lily/kievan-ligature.cc
new file mode 100644 (file)
index 0000000..21ea23e
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+  This file is part of LilyPond, the GNU music typesetter.
+
+  Copyright (C) 2013 Aleksandr Andreev <aleksandr.andreev@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 "kievan-ligature.hh"
+
+#include "international.hh"
+#include "item.hh"
+#include "warn.hh"
+
+MAKE_SCHEME_CALLBACK (Kievan_ligature, print, 1);
+SCM
+Kievan_ligature::print (SCM)
+{
+  return SCM_EOL;
+}
+
+ADD_INTERFACE (Kievan_ligature,
+               "A kievan ligature.",
+
+               /* properties */
+               "primitive "
+               "padding "
+              );
index fb6f54c7064e97d6352d73a8417b599f58822c66..297337a976eb404c7b4096eb26307fb29c537578 100644 (file)
  * produce a single connected graphical object of fixed width,
  * consisting of noteheads and other primitives.  Space may be
  * inserted only after each ligature, if necessary, but in no case
- * between the primitives of the ligature.  Accidentals have to be put
+ * between the primitives of the ligature. The same approach is
+ * used for Kievan notation ligatures, or, rather melismas.
+ * Though these are not single connected objects, they behave much
+ * in the same way and have a fixed, small amount of space between
+ * noteheads. Except in Kievan "ligatures", accidentals have to be put
  * to the left of the ligature, and not to the left of individual
- * noteheads.  Class Coherent_ligature_engraver is the common
+ * noteheads. In Kievan ligatures, the B-flat may be part of the
+ * ligature itself. Class Coherent_ligature_engraver is the common
  * superclass for all of these engravers.
  *
  * The second category is for engravers that are relaxed in the sense
index ddda5185792522cc60afc155cc04a40fca0e8dcd..27909a6bc2a43bccca2bcce48fdb029099f3eb6d 100644 (file)
@@ -355,8 +355,23 @@ SCM
 ly_deep_copy (SCM src)
 {
   if (scm_is_pair (src))
-    return scm_cons (ly_deep_copy (scm_car (src)), ly_deep_copy (scm_cdr (src)));
-  else if (scm_is_vector (src))
+    {
+      SCM res = SCM_EOL;
+      do
+        {
+          res = scm_cons (ly_deep_copy (scm_car (src)), res);
+          src = scm_cdr (src);
+        }
+      while (scm_is_pair (src));
+      // Oh, come on, GUILE.  Why do you require the second argument
+      // of scm_reverse_x to be a proper list?  That makes no sense.
+      // return scm_reverse_x (res, ly_deep_copy (src));
+      SCM last_cons = res;
+      res = scm_reverse_x (res, SCM_EOL);
+      scm_set_cdr_x (last_cons, ly_deep_copy (src));
+      return res;
+    }
+  if (scm_is_vector (src))
     {
       int len = scm_c_vector_length (src);
       SCM nv = scm_c_make_vector (len, SCM_UNDEFINED);
@@ -365,6 +380,7 @@ ly_deep_copy (SCM src)
           SCM si = scm_from_int (i);
           scm_vector_set_x (nv, si, ly_deep_copy (scm_vector_ref (src, si)));
         }
+      return nv;
     }
   return src;
 }
@@ -394,6 +410,8 @@ type_check_assignment (SCM sym, SCM val, SCM type_symbol)
   if (val == SCM_EOL || val == SCM_BOOL_F)
     return ok;
 
+  // If undefined, some internal function caused it...should never happen.
+  assert (val != SCM_UNDEFINED);
   if (!scm_is_symbol (sym))
     return false;
 
index 0ebd1324506ebf7b404a3ab640ba57e746cf4f91..c6ab972c74994c27752d1881200a52c073651dea 100644 (file)
@@ -33,6 +33,7 @@ protected:
   DECLARE_ACKNOWLEDGER (slur);
   TRANSLATOR_DECLARATIONS (Melody_engraver);
   void stop_translation_timestep ();
+  void process_acknowledged ();
   void process_music ();
 };
 
@@ -49,8 +50,12 @@ Melody_engraver::process_music ()
     melody_item_ = 0;
 }
 
+/*
+  Used to be in stop_translation_timestep, but grobs can't
+  be created here.
+*/
 void
-Melody_engraver::stop_translation_timestep ()
+Melody_engraver::process_acknowledged ()
 {
   if (stem_
       && !is_direction (stem_->get_property_data ("neutral-direction")))
@@ -66,6 +71,11 @@ Melody_engraver::stop_translation_timestep ()
           Melody_spanner::add_stem (melody_item_, stem_);
         }
     }
+}
+
+void
+Melody_engraver::stop_translation_timestep ()
+{
   stem_ = 0;
 }
 
index df06f790dfb00e8f6201682fe3466c22ff0524ee..36e462653238fbfc62d4cb1db2fd4d808aa3efc8 100644 (file)
@@ -120,7 +120,6 @@ SCM
 Multi_measure_rest::height (SCM smob)
 {
   Grob *me = unsmob_grob (smob);
-  Spanner *sp = dynamic_cast<Spanner *> (me);
 
   Real space = 1000000; // something very large...
 
index ffa903b4ebedc5d6ead2b34eb08679747f3ab30e..3412e73b5642761765b09b971c5e585f14027229 100644 (file)
@@ -114,18 +114,30 @@ LY_DEFINE (ly_music_list_p, "ly:music-list?",
 
 LY_DEFINE (ly_music_deep_copy, "ly:music-deep-copy",
            1, 0, 0, (SCM m),
-           "Copy @var{m} and all sub expressions of@tie{}@var{m}.")
+           "Copy @var{m} and all sub expressions of@tie{}@var{m}."
+           " @var{m} may be an arbitrary type; cons cells and music"
+           " are copied recursively.")
 {
-  SCM copy = m;
   if (unsmob_music (m))
+      return unsmob_music (m)->clone ()->unprotect ();
+  if (scm_is_pair (m))
     {
-      Music *mcopy = unsmob_music (m)->clone ();
-      copy = mcopy->unprotect ();
+      SCM copy = SCM_EOL;
+      do
+        {
+          copy = scm_cons (ly_music_deep_copy (scm_car (m)), copy);
+          m = scm_cdr (m);
+        }
+      while (scm_is_pair (m));
+      // Oh, come on, GUILE.  Why do you require the second argument
+      // of scm_reverse_x to be a proper list?  That makes no sense.
+      // return scm_reverse_x (copy, ly_music_deep_copy (m));
+      SCM last_cons = copy;
+      copy = scm_reverse_x (copy, SCM_EOL);
+      scm_set_cdr_x (last_cons, ly_music_deep_copy (m));
+      return copy;
     }
-  else if (scm_is_pair (m))
-    copy = scm_cons (ly_music_deep_copy (scm_car (m)),
-                     ly_music_deep_copy (scm_cdr (m)));
-  return copy;
+  return m;
 }
 
 LY_DEFINE (ly_music_transpose, "ly:music-transpose",
index b0a81195c7185b953fa97c645d83d18eaebd4fc9..ddf9fe39213e0d74910ce75a268808ad254d424c 100644 (file)
@@ -80,7 +80,7 @@ Note_performer::process_music ()
           Moment len = get_event_length (n, now_mom ());
 
           Audio_note *p = new Audio_note (*pitp, len,
-                                          tie_event, transposing.negated ());
+                                          tie_event, transposing);
           Audio_element_info info (p, n);
           announce_element (info);
           notes_.push_back (p);
index 3f4faf5d7c06ceadc599fade3b9a08355ed3ee16..478d05377540e10033d55fb569792645d35e3612 100644 (file)
@@ -3236,7 +3236,7 @@ full_markup:
        ;
 
 markup_top:
-       markup_list {
+       simple_markup_list {
                $$ = scm_list_2 (ly_lily_module_constant ("line-markup"),  $1);
        }
        | markup_head_1_list simple_markup      {
@@ -3262,7 +3262,7 @@ markup_scm:
        ;
                        
 
-markup_list:
+simple_markup_list:
        markup_composed_list {
                $$ = $1;
        }
@@ -3278,6 +3278,24 @@ markup_list:
        }
        ;
 
+markup_list:
+       simple_markup_list
+       | markup_score
+       {
+               $$ = scm_list_1 (scm_list_2 (ly_lily_module_constant ("score-lines-markup-list"), $1));
+       }
+       ;
+
+markup_score:
+       SCORE {
+               SCM nn = parser->lexer_->lookup_identifier ("pitchnames");
+               parser->lexer_->push_note_state (nn);
+       } '{' score_body '}' {
+               $$ = $4;
+               parser->lexer_->pop_state ();
+       }
+       ;
+
 markup_composed_list:
        markup_head_1_list markup_braced_list {
                $$ = scm_call_2 (ly_lily_module_constant ("map-markup-command-list"), $1, $2);
@@ -3296,7 +3314,7 @@ markup_braced_list_body:
        | markup_braced_list_body markup {
                $$ = scm_cons ($2, $1);
        }
-       | markup_braced_list_body markup_list {
+       | markup_braced_list_body simple_markup_list {
                $$ = scm_reverse_x ($2, $1);
        }
        ;
@@ -3345,13 +3363,6 @@ simple_markup:
        STRING {
                $$ = make_simple_markup ($1);
        }
-       | SCORE {
-               SCM nn = parser->lexer_->lookup_identifier ("pitchnames");
-               parser->lexer_->push_note_state (nn);
-       } '{' score_body '}' {
-               $$ = scm_list_2 (ly_lily_module_constant ("score-markup"), $4);
-               parser->lexer_->pop_state ();
-       }
        | MARKUP_FUNCTION markup_command_basic_arguments {
                $$ = scm_cons ($1, scm_reverse_x ($2, SCM_EOL));
        }
@@ -3359,6 +3370,10 @@ simple_markup:
        {
                $$ = $2;
        }
+       | markup_score
+       {
+               $$ = scm_list_2 (ly_lily_module_constant ("score-markup"), $1);
+       }
        ;
 
 markup:
index 1801ae286d3fa8e9ae3e02611f9f09b6730eb411..544ce974614c253cf89d7952464171d20320c6c1 100644 (file)
@@ -36,10 +36,25 @@ LY_DEFINE (ly_encode_string_for_pdf, "ly:encode-string-for-pdf",
   char const *charset = "UTF-8"; // Input is ALWAYS UTF-8!
   gsize bytes_written = 0;
 
+#if 0
+
   /* First, try to convert to ISO-8859-1 (no encodings required). This will
    * fail, if the string contains accented characters, so we do not check
    * for errors. */
   g = g_convert (p, -1, "ISO-8859-1", charset, 0, &bytes_written, 0);
+
+#else
+
+  /* In contrast to the above comment, we do _not_ try full ISO-8859-1
+   * since a number of Ghostscript versions fail to properly convert
+   * this into PDF.  UTF-16BE, in contrast, works better with recent
+   * versions of Ghostscript.
+   */
+
+  g = g_convert (p, -1, "ASCII", charset, 0, &bytes_written, 0);
+
+#endif
+
   /* If that fails, we have to resolve to full UTF-16BE */
   if (!g)
     {
index 7e6c3c63fe3d8b0e026022e2ad555d767ca4dfda..6d9aac7af68d64fb5b7220acc2ebccb0f37435d0 100644 (file)
 #include "international.hh"
 #include "note-column.hh"
 #include "slur.hh"
+#include "slur-proto-engraver.hh"
 #include "spanner.hh"
 #include "stream-event.hh"
 #include "warn.hh"
 
 #include "translator.icc"
 
-/*
-  NOTE NOTE NOTE
-
-  This is largely similar to Slur_engraver. Check if fixes
-  apply there too.
-
-  (on principle, engravers don't use inheritance for code sharing)
-
- */
-
-/*
-  It is possible that a slur starts and ends on the same note.  At
-  least, it is for phrasing slurs: a note can be both beginning and
-  ending of a phrase.
-*/
-class Phrasing_slur_engraver : public Engraver
+class Phrasing_slur_engraver : public Slur_proto_engraver
 {
-  vector<Stream_event *> start_events_;
-  vector<Stream_event *> stop_events_;
-  vector<Grob *> slurs_;
-  vector<Grob *> end_slurs_;
-  vector<Grob_info> objects_to_acknowledge_;
-
 protected:
   DECLARE_TRANSLATOR_LISTENER (phrasing_slur);
-  DECLARE_ACKNOWLEDGER (inline_accidental);
-  DECLARE_ACKNOWLEDGER (fingering);
-  DECLARE_ACKNOWLEDGER (note_column);
   DECLARE_ACKNOWLEDGER (slur);
-  DECLARE_ACKNOWLEDGER (script);
-  DECLARE_ACKNOWLEDGER (dots);
-  DECLARE_ACKNOWLEDGER (text_script);
-  DECLARE_END_ACKNOWLEDGER (tie);
-  DECLARE_ACKNOWLEDGER (tuplet_number);
-
-  void acknowledge_extra_object (Grob_info);
-  void stop_translation_timestep ();
-  void process_music ();
-
-  virtual void finalize ();
-  virtual void derived_mark () const;
 
 public:
   TRANSLATOR_DECLARATIONS (Phrasing_slur_engraver);
 };
 
-Phrasing_slur_engraver::Phrasing_slur_engraver ()
+Phrasing_slur_engraver::Phrasing_slur_engraver () :
+  Slur_proto_engraver (0, "PhrasingSlur", "phrasing slur", "phrasing-slur-event")
 {
 }
 
-void
-Phrasing_slur_engraver::derived_mark () const
-{
-  for (vsize i = start_events_.size (); i--;)
-    scm_gc_mark (start_events_[i]->self_scm ());
-  for (vsize i = stop_events_.size (); i--;)
-    scm_gc_mark (stop_events_[i]->self_scm ());
-}
-
 IMPLEMENT_TRANSLATOR_LISTENER (Phrasing_slur_engraver, phrasing_slur);
 void
 Phrasing_slur_engraver::listen_phrasing_slur (Stream_event *ev)
 {
-  Direction d = to_dir (ev->get_property ("span-direction"));
-  if (d == START)
-    start_events_.push_back (ev);
-  else if (d == STOP)
-    stop_events_.push_back (ev);
-  else ev->origin ()->warning (_f ("direction of %s invalid: %d",
-                                     "phrasing-slur-event", int (d)));
-}
-
-void
-Phrasing_slur_engraver::acknowledge_note_column (Grob_info info)
-{
-  Grob *e = info.grob ();
-  for (vsize i = slurs_.size (); i--;)
-    Slur::add_column (slurs_[i], e);
-  for (vsize i = end_slurs_.size (); i--;)
-    Slur::add_column (end_slurs_[i], e);
-}
-
-void
-Phrasing_slur_engraver::acknowledge_extra_object (Grob_info info)
-{
-  objects_to_acknowledge_.push_back (info);
-}
-
-void
-Phrasing_slur_engraver::acknowledge_inline_accidental (Grob_info info)
-{
-  acknowledge_extra_object (info);
-}
-
-void
-Phrasing_slur_engraver::acknowledge_dots (Grob_info info)
-{
-  acknowledge_extra_object (info);
-}
-
-void
-Phrasing_slur_engraver::acknowledge_fingering (Grob_info info)
-{
-  acknowledge_extra_object (info);
-}
-
-void
-Phrasing_slur_engraver::acknowledge_tuplet_number (Grob_info info)
-{
-  acknowledge_extra_object (info);
-}
-
-void
-Phrasing_slur_engraver::acknowledge_script (Grob_info info)
-{
-  if (!info.grob ()->internal_has_interface (ly_symbol2scm ("dynamic-interface")))
-    acknowledge_extra_object (info);
-}
-
-void
-Phrasing_slur_engraver::acknowledge_text_script (Grob_info info)
-{
-  acknowledge_extra_object (info);
-}
-
-void
-Phrasing_slur_engraver::acknowledge_end_tie (Grob_info info)
-{
-  acknowledge_extra_object (info);
+  internal_listen_slur (ev);
 }
 
 void
@@ -167,146 +59,6 @@ Phrasing_slur_engraver::acknowledge_slur (Grob_info info)
   acknowledge_extra_object (info);
 }
 
-void
-Phrasing_slur_engraver::finalize ()
-{
-  for (vsize i = 0; i < slurs_.size (); i++)
-    {
-      slurs_[i]->warning (_ ("unterminated phrasing slur"));
-      slurs_[i]->suicide ();
-    }
-  slurs_.clear ();
-}
-
-void
-Phrasing_slur_engraver::process_music ()
-{
-  for (vsize i = 0; i < stop_events_.size (); i++)
-    {
-      Stream_event *ev = stop_events_[i];
-      string id = robust_scm2string (ev->get_property ("spanner-id"), "");
-
-      // Find the slurs that are ended with this event (by checking the spanner-id)
-      bool ended = false;
-      for (vsize j = slurs_.size (); j--;)
-        {
-          if (id == robust_scm2string (slurs_[j]->get_property ("spanner-id"), ""))
-            {
-              ended = true;
-              end_slurs_.push_back (slurs_[j]);
-              slurs_.erase (slurs_.begin () + j);
-            }
-        }
-      if (ended)
-        {
-          // Ignore redundant stop events for this id
-          for (vsize j = stop_events_.size (); --j > i;)
-            {
-              if (id == robust_scm2string (stop_events_[j]->get_property ("spanner-id"), ""))
-                stop_events_.erase (stop_events_.begin () + j);
-            }
-        }
-      else
-        ev->origin ()->warning (_ ("cannot end phrasing slur"));
-    }
-
-  vsize old_slurs = slurs_.size ();
-  for (vsize i = start_events_.size (); i--;)
-    {
-      Stream_event *ev = start_events_[i];
-      string id = robust_scm2string (ev->get_property ("spanner-id"), "");
-      Direction updown = to_dir (ev->get_property ("direction"));
-
-      bool completed;
-      for (vsize j = slurs_.size (); !(completed = (j-- == 0));)
-        {
-          // Check if we already have a slur with the same spanner-id.
-          if (id == robust_scm2string (slurs_[j]->get_property ("spanner-id"), ""))
-            {
-              if (j < old_slurs)
-                {
-                  // We already have an old slur, so give a warning
-                  // and completely ignore the new slur.
-                  ev->origin ()->warning (_ ("already have phrasing slur"));
-                  start_events_.erase (start_events_.begin () + i);
-                  break;
-                }
-
-              // If this slur event has no direction, it will not
-              // contribute anything new to the existing slur(s), so
-              // we can ignore it.
-
-              if (!updown)
-                break;
-
-              Stream_event *c = unsmob_stream_event (slurs_[j]->get_property ("cause"));
-
-              if (!c)
-                {
-                  slurs_[j]->programming_error ("phrasing slur without a cause");
-                  continue;
-                }
-
-              Direction slur_dir = to_dir (c->get_property ("direction"));
-
-              // If the existing slur does not have a direction yet,
-              // we'd rather take the new one.
-
-              if (!slur_dir)
-                {
-                  slurs_[j]->suicide ();
-                  slurs_.erase (slurs_.begin () + j);
-                  continue;
-                }
-
-              // If the existing slur has the same direction as ours, drop ours
-
-              if (slur_dir == updown)
-                break;
-            }
-        }
-      // If the loop completed, our slur is new
-      if (completed)
-        {
-          Grob *slur = make_spanner ("PhrasingSlur", ev->self_scm ());
-          slur->set_property ("spanner-id", ly_string2scm (id));
-          if (updown)
-            set_grob_direction (slur, updown);
-          slurs_.push_back (slur);
-        }
-    }
-}
-
-void
-Phrasing_slur_engraver::stop_translation_timestep ()
-{
-  if (Grob *g = unsmob_grob (get_property ("currentCommandColumn")))
-    {
-      for (vsize i = 0; i < end_slurs_.size (); i++)
-        Slur::add_extra_encompass (end_slurs_[i], g);
-
-      if (!start_events_.size ())
-        for (vsize i = 0; i < slurs_.size (); i++)
-          Slur::add_extra_encompass (slurs_[i], g);
-    }
-
-  for (vsize i = 0; i < end_slurs_.size (); i++)
-    {
-      Spanner *s = dynamic_cast<Spanner *> (end_slurs_[i]);
-      if (!s->get_bound (RIGHT))
-        s->set_bound (RIGHT, unsmob_grob (get_property ("currentMusicalColumn")));
-      announce_end_grob (s, SCM_EOL);
-    }
-
-  for (vsize i = 0; i < objects_to_acknowledge_.size (); i++)
-    Slur::auxiliary_acknowledge_extra_object (objects_to_acknowledge_[i], slurs_, end_slurs_);
-
-  objects_to_acknowledge_.clear ();
-  end_slurs_.clear ();
-  start_events_.clear ();
-  stop_events_.clear ();
-}
-
 ADD_ACKNOWLEDGER (Phrasing_slur_engraver, inline_accidental);
 ADD_ACKNOWLEDGER (Phrasing_slur_engraver, fingering)
 ADD_ACKNOWLEDGER (Phrasing_slur_engraver, note_column);
index bfb560925335d0ca70512e26ddcd6ef2c2fd974c..24925d29b8599b027703cc76cd0add07114f214b 100644 (file)
@@ -46,9 +46,7 @@ Pure_from_neighbor_engraver::Pure_from_neighbor_engraver ()
 void
 Pure_from_neighbor_engraver::acknowledge_item (Grob_info i)
 {
-  SCM pure_relevant_p = ly_lily_module_constant ("pure-relevant?");
-  if (!Pure_from_neighbor_interface::has_interface (i.item ())
-      && to_boolean (scm_call_1 (pure_relevant_p, i.item ()->self_scm ())))
+  if (!Pure_from_neighbor_interface::has_interface (i.item ()))
     pure_relevants_.push_back (i.item ());
 }
 
index 69c580f5d5484fc4e0c8717144e90ffce55a95f8..86d01304a878f28f8ffb1ad27658b3645b84a2b7 100644 (file)
@@ -237,11 +237,21 @@ Quote_iterator::process (Moment m)
       Pitch *quote_pitch = unsmob_pitch (scm_cdar (entry));
 
       /*
-        The pitch that sounds like central C
+        The pitch that sounds when written central C is played.
       */
+      Pitch temp_pitch;
       Pitch *me_pitch = unsmob_pitch (get_music ()->get_property ("quoted-transposition"));
       if (!me_pitch)
         me_pitch = unsmob_pitch (get_outlet ()->get_property ("instrumentTransposition"));
+      else
+        {
+          // We are not going to win a beauty contest with this one,
+          // but it is slated for replacement and touches little code.
+          // quoted-transposition currently has a different sign
+          // convention than instrumentTransposition
+          temp_pitch = me_pitch->negated ();
+          me_pitch = &temp_pitch;
+        }
       SCM cid = get_music ()->get_property ("quoted-context-id");
       bool is_cue = scm_is_string (cid) && (ly_scm2string (cid) == "cue");
 
@@ -263,7 +273,7 @@ Quote_iterator::process (Moment m)
                   if (me_pitch)
                     mp = *me_pitch;
 
-                  Pitch diff = pitch_interval (qp, mp);
+                  Pitch diff = pitch_interval (mp, qp);
                   ev = ev->clone ();
                   ev->make_transposable ();
 
index e2b0db5ef2352e6e6d002259d90386bb97579bee..46435b73ad5b26356e21ceb5ef369635eafe19df 100644 (file)
@@ -34,6 +34,7 @@ using namespace std;
 #include "staff-symbol-referencer.hh"
 #include "stem.hh"
 #include "grob.hh"
+#include "unpure-pure-container.hh"
 #include "warn.hh"
 
 MAKE_SCHEME_CALLBACK_WITH_OPTARGS (Rest_collision, force_shift_callback_rest, 2, 1, "");
@@ -72,7 +73,10 @@ Rest_collision::add_column (Grob *me, Grob *p)
   if (rest)
     {
       chain_offset_callback (rest,
-                             Rest_collision::force_shift_callback_rest_proc, Y_AXIS);
+                             ly_make_unpure_pure_container
+                               (Rest_collision::force_shift_callback_rest_proc,
+                                ly_lily_module_constant ("pure-chain-offset-callback")),
+                              Y_AXIS);
     }
 }
 
index f47171fb5a380ef8764a5abbc96e9f5c1135a24f..3dc8a2b0e6f97b3c2844155f9020c5ede6d64b8b 100644 (file)
@@ -34,6 +34,7 @@ ADD_INTERFACE (Semi_tie_column,
                "The interface for a column of l.v. (laissez vibrer) ties.",
 
                /* properties */
+               "direction "
                "positioning-done "
                "head-direction "
                "tie-configuration "
index 6ff2928072541611bda6db49d7cb64626d8ab4c3..8a32363eb4d2b0d8c6df9c321f429cbee8886e8d 100644 (file)
@@ -150,10 +150,19 @@ Separation_item::boxes (Grob *me, Grob *left)
       Interval extra_height = robust_scm2interval (elts[i]->get_property ("extra-spacing-height"),
                                                    Interval (0.0, 0.0));
 
-      x[LEFT] += extra_width[LEFT];
-      x[RIGHT] += extra_width[RIGHT];
-      y[DOWN] += extra_height[DOWN];
-      y[UP] += extra_height[UP];
+      // The conventional empty extent is (+inf.0 . -inf.0)
+      //  but (-inf.0 . +inf.0) is used as extra-spacing-height
+      //  on items that must not overlap other note-columns.
+      // If these two uses of inf combine, leave the empty extent.
+
+      if (!isinf (x[LEFT]))
+        x[LEFT] += extra_width[LEFT];
+      if (!isinf (x[RIGHT]))
+        x[RIGHT] += extra_width[RIGHT];
+      if (!isinf (y[DOWN]))
+        y[DOWN] += extra_height[DOWN];
+      if (!isinf (y[UP]))
+        y[UP] += extra_height[UP];
 
       if (!x.is_empty () && !y.is_empty ())
         out.push_back (Box (x, y));
index 49c6ece55a1c8853214e28965a7c253df284f5da..095b8b49c344db5566303b987dd890eea42136a4 100644 (file)
@@ -46,6 +46,7 @@ using namespace std;
 #include "string-convert.hh"
 #include "system.hh"
 #include "warn.hh"
+#include "unpure-pure-container.hh"
 
 void
 Side_position_interface::add_support (Grob *me, Grob *e)
@@ -184,7 +185,7 @@ Side_position_interface::calc_cross_staff (SCM smob)
 SCM
 Side_position_interface::aligned_side (Grob *me, Axis a, bool pure, int start, int end,
                                        Real *current_off)
-{//printf (" %s\n", me->name ().c_str ());
+{
   Direction dir = get_grob_direction (me);
 
   set<Grob *> support = get_support_set (me);
@@ -198,12 +199,13 @@ Side_position_interface::aligned_side (Grob *me, Axis a, bool pure, int start, i
                                            ax);
 
   Grob *staff_symbol = Staff_symbol_referencer::get_staff_symbol (me);
+  bool quantize_position = to_boolean (me->get_maybe_pure_property ("quantize-position", pure, start, end));
 
   bool include_staff
     = staff_symbol
       && a == Y_AXIS
-      && scm_is_number (me->get_property ("staff-padding"))
-      && !to_boolean (me->get_property ("quantize-position"));
+      && scm_is_number (me->get_maybe_pure_property ("staff-padding", pure, start, end))
+      && !quantize_position;
 
   if (include_staff)
     common[Y_AXIS] = staff_symbol->common_refpoint (common[Y_AXIS], Y_AXIS);
@@ -250,7 +252,7 @@ Side_position_interface::aligned_side (Grob *me, Axis a, bool pure, int start, i
   for (it = support.begin (); it != support.end (); it++)
     {
       Grob *e = *it;
-//printf ("    %s\n", e->name ().c_str ());
+
       // In the case of a stem, we will find a note head as well
       // ignoring the stem solves cyclic dependencies if the stem is
       // attached to a cross-staff beam.
@@ -286,7 +288,7 @@ Side_position_interface::aligned_side (Grob *me, Axis a, bool pure, int start, i
                Skyline_pair copy = Skyline_pair (*sp);
                if (a == Y_AXIS
                    && Stem::has_interface (e)
-                   && to_boolean (me->get_property ("add-stem-support")))
+                   && to_boolean (me->get_maybe_pure_property ("add-stem-support", pure, start, end)))
                  copy[dir].set_minimum_height (copy[dir].max_height ());
                copy.shift (a == X_AXIS ? yc : xc);
                copy.raise (a == X_AXIS ? xc : yc);
@@ -339,12 +341,12 @@ Side_position_interface::aligned_side (Grob *me, Axis a, bool pure, int start, i
     dim.set_minimum_height (dim.max_height ());
 
   Real ss = Staff_symbol_referencer::staff_space (me);
-  Real dist = dim.distance (my_dim, robust_scm2double (me->get_property ("horizon-padding"), 0.0));
+  Real dist = dim.distance (my_dim, robust_scm2double (me->get_maybe_pure_property ("horizon-padding", pure, start, end), 0.0));
   Real total_off = !isinf (dist) ? dir * dist : 0.0;
 
-  total_off += dir * ss * robust_scm2double (me->get_property ("padding"), 0.0);
+  total_off += dir * ss * robust_scm2double (me->get_maybe_pure_property ("padding", pure, start, end), 0.0);
 
-  Real minimum_space = ss * robust_scm2double (me->get_property ("minimum-space"), -1);
+  Real minimum_space = ss * robust_scm2double (me->get_maybe_pure_property ("minimum-space", pure, start, end), -1);
 
   if (minimum_space >= 0
       && dir
@@ -375,7 +377,7 @@ Side_position_interface::aligned_side (Grob *me, Axis a, bool pure, int start, i
   Grob *staff = Staff_symbol_referencer::get_staff_symbol (me);
   if (staff && a == Y_AXIS)
     {
-      if (to_boolean (me->get_property ("quantize-position")))
+      if (quantize_position)
         {
           Grob *common = me->common_refpoint (staff, Y_AXIS);
           Real my_off = me->get_parent (Y_AXIS)->maybe_pure_coordinate (common, Y_AXIS, pure, start, end);
@@ -398,13 +400,13 @@ Side_position_interface::aligned_side (Grob *me, Axis a, bool pure, int start, i
                 total_off += dir * 0.5 * ss;
             }
         }
-      else if (scm_is_number (me->get_property ("staff-padding")) && dir)
+      else if (scm_is_number (me->get_maybe_pure_property ("staff-padding", pure, start, end)) && dir)
         {
           Interval iv = me->maybe_pure_extent (me, a, pure, start, end);
 
           Real staff_padding
             = Staff_symbol_referencer::staff_space (me)
-              * scm_to_double (me->get_property ("staff-padding"));
+              * scm_to_double (me->get_maybe_pure_property ("staff-padding", pure, start, end));
 
           Grob *parent = me->get_parent (Y_AXIS);
           Grob *common = me->common_refpoint (staff, Y_AXIS);
@@ -429,7 +431,7 @@ Side_position_interface::set_axis (Grob *me, Axis a)
       chain_offset_callback (me,
                              (a == X_AXIS)
                              ? x_aligned_side_proc
-                             : y_aligned_side_proc,
+                             : ly_make_unpure_pure_container (y_aligned_side_proc, pure_y_aligned_side_proc),
                              a);
     }
 }
index 0c5dca8e95873af67d1d0433b50d8ae6950abfbb..59f9fd995b78c4f00a677db6c37cacb6e652129f 100644 (file)
@@ -18,6 +18,7 @@
   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
 */
 #include "simple-closure.hh"
+#include "unpure-pure-container.hh"
 
 #include "grob.hh"
 
@@ -64,27 +65,34 @@ evaluate_with_simple_closure (SCM delayed_argument,
   if (is_simple_closure (expr))
     {
       SCM inside = simple_closure_expression (expr);
+      SCM proc = is_unpure_pure_container (scm_car (inside))
+               ? (pure ? scm_car (inside) : unpure_pure_container_unpure_part (scm_car (inside)))
+               : scm_car (inside);
       SCM args = scm_cons (delayed_argument,
                            evaluate_args (delayed_argument, scm_cdr (inside),
                                           pure, start, end));
       if (scm_cdr (args) == SCM_UNSPECIFIED)
         return SCM_UNSPECIFIED;
       if (pure)
-        return call_pure_function (scm_car (inside), args, start, end);
-      return scm_apply_0 (scm_car (inside), args);
+        return call_pure_function (proc, args, start, end);
+      return scm_apply_0 (proc, args);
     }
   else if (!scm_is_pair (expr))
     return expr;
   else if (scm_car (expr) == ly_symbol2scm ("quote"))
     return scm_cadr (expr);
-  else if (ly_is_procedure (scm_car (expr)))
+  else if (is_unpure_pure_container (scm_car (expr))
+           || ly_is_procedure (scm_car (expr)))
     {
+      SCM proc = is_unpure_pure_container (scm_car (expr))
+               ? (pure ? scm_car (expr) : unpure_pure_container_unpure_part (scm_car (expr)))
+               : scm_car (expr);
       SCM args = evaluate_args (delayed_argument, scm_cdr (expr), pure, start, end);
       if (args == SCM_UNSPECIFIED)
         return SCM_UNSPECIFIED;
       if (pure)
-        return call_pure_function (scm_car (expr), args, start, end);
-      return scm_apply_0 (scm_car (expr), args);
+        return call_pure_function (proc, args, start, end);
+      return scm_apply_0 (proc, args);
     }
   else
     // ugh. deviation from standard. Should print error?
index ed5f390a017bbfdf59ad773c61d7f77fa0570c1b..bf95fe35418153ce65237a415a29c4d4553ecde0 100644 (file)
@@ -932,3 +932,12 @@ Skyline::get_height (SCM skyline_scm, SCM x_scm)
   Real x = robust_scm2double (x_scm, 0.0);
   return scm_from_double (Skyline::unsmob (skyline_scm)->height (x));
 }
+
+LY_DEFINE (ly_skyline_empty_p, "ly:skyline-empty?",
+           1, 0, 0, (SCM sky),
+           "Return whether @var{sky} is empty.")
+{
+  Skyline *s = Skyline::unsmob (sky);
+  LY_ASSERT_SMOB (Skyline, sky, 1);
+  return scm_from_bool (s->is_empty ());
+}
index 49f92ab0ed5a96b04e5bd5331fb1b49cf12f4e35..a8a54f535a1b4bdbd0edae79b25f3bdf4d51dafb 100644 (file)
 #include "international.hh"
 #include "note-column.hh"
 #include "slur.hh"
+#include "slur-proto-engraver.hh"
 #include "spanner.hh"
 #include "stream-event.hh"
 #include "warn.hh"
 
 #include "translator.icc"
 
-/*
-  NOTE NOTE NOTE
-
-  This is largely similar to Phrasing_slur_engraver. Check if fixes
-  apply there too.
-
-  (on principle, engravers don't use inheritance for code sharing)
-
- */
-
-/*
-  It is possible that a slur starts and ends on the same note.  At
-  least, it is for phrasing slurs: a note can be both beginning and
-  ending of a phrase.
-*/
-class Slur_engraver : public Engraver
+class Slur_engraver : public Slur_proto_engraver
 {
-  vector<Stream_event *> start_events_;
-  vector<Stream_event *> stop_events_;
-  vector<Grob *> slurs_;
-  vector<Grob *> end_slurs_;
-  vector<Grob_info> objects_to_acknowledge_;
-
-  void set_melisma (bool);
+  virtual void set_melisma (bool);
 
 protected:
   DECLARE_TRANSLATOR_LISTENER (slur);
-  DECLARE_ACKNOWLEDGER (inline_accidental);
-  DECLARE_ACKNOWLEDGER (fingering);
-  DECLARE_ACKNOWLEDGER (note_column);
-  DECLARE_ACKNOWLEDGER (script);
-  DECLARE_ACKNOWLEDGER (dots);
-  DECLARE_ACKNOWLEDGER (text_script);
-  DECLARE_END_ACKNOWLEDGER (tie);
-  DECLARE_ACKNOWLEDGER (tuplet_number);
-
-  void acknowledge_extra_object (Grob_info);
-  void stop_translation_timestep ();
-  void process_music ();
-
-  virtual void finalize ();
-  virtual void derived_mark () const;
 
 public:
   TRANSLATOR_DECLARATIONS (Slur_engraver);
 };
 
-Slur_engraver::Slur_engraver ()
+Slur_engraver::Slur_engraver () :
+  Slur_proto_engraver ("doubleSlurs", "Slur", "slur", "slur-event")
 {
 }
 
-void
-Slur_engraver::derived_mark () const
-{
-  for (vsize i = start_events_.size (); i--;)
-    scm_gc_mark (start_events_[i]->self_scm ());
-  for (vsize i = stop_events_.size (); i--;)
-    scm_gc_mark (stop_events_[i]->self_scm ());
-}
-
 IMPLEMENT_TRANSLATOR_LISTENER (Slur_engraver, slur);
 void
 Slur_engraver::listen_slur (Stream_event *ev)
 {
-  Direction d = to_dir (ev->get_property ("span-direction"));
-  if (d == START)
-    start_events_.push_back (ev);
-  else if (d == STOP)
-    stop_events_.push_back (ev);
-  else ev->origin ()->warning (_f ("direction of %s invalid: %d",
-                                     "slur-event", int (d)));
+  internal_listen_slur (ev);
 }
 
 void
 Slur_engraver::set_melisma (bool m)
 {
-  context ()->set_property ("slurMelismaBusy", m ? SCM_BOOL_T : SCM_BOOL_F);
-}
-
-void
-Slur_engraver::acknowledge_note_column (Grob_info info)
-{
-  Grob *e = info.grob ();
-  for (vsize i = slurs_.size (); i--;)
-    Slur::add_column (slurs_[i], e);
-  for (vsize i = end_slurs_.size (); i--;)
-    Slur::add_column (end_slurs_[i], e);
-}
-
-void
-Slur_engraver::acknowledge_extra_object (Grob_info info)
-{
-  objects_to_acknowledge_.push_back (info);
-}
-
-void
-Slur_engraver::acknowledge_inline_accidental (Grob_info info)
-{
-  acknowledge_extra_object (info);
-}
-
-void
-Slur_engraver::acknowledge_dots (Grob_info info)
-{
-  acknowledge_extra_object (info);
-}
-
-void
-Slur_engraver::acknowledge_fingering (Grob_info info)
-{
-  acknowledge_extra_object (info);
-}
-
-void
-Slur_engraver::acknowledge_tuplet_number (Grob_info info)
-{
-  acknowledge_extra_object (info);
-}
-
-void
-Slur_engraver::acknowledge_script (Grob_info info)
-{
-  if (!info.grob ()->internal_has_interface (ly_symbol2scm ("dynamic-interface")))
-    acknowledge_extra_object (info);
-}
-
-void
-Slur_engraver::acknowledge_text_script (Grob_info info)
-{
-  acknowledge_extra_object (info);
-}
-
-void
-Slur_engraver::acknowledge_end_tie (Grob_info info)
-{
-  acknowledge_extra_object (info);
-}
-
-void
-Slur_engraver::finalize ()
-{
-  for (vsize i = 0; i < slurs_.size (); i++)
-    {
-      slurs_[i]->warning (_ ("unterminated slur"));
-      slurs_[i]->suicide ();
-    }
-  slurs_.clear ();
-}
-
-void
-Slur_engraver::process_music ()
-{
-  for (vsize i = 0; i < stop_events_.size (); i++)
-    {
-      Stream_event *ev = stop_events_[i];
-      string id = robust_scm2string (ev->get_property ("spanner-id"), "");
-
-      // Find the slurs that are ended with this event (by checking the spanner-id)
-      bool ended = false;
-      for (vsize j = slurs_.size (); j--;)
-        {
-          if (id == robust_scm2string (slurs_[j]->get_property ("spanner-id"), ""))
-            {
-              ended = true;
-              end_slurs_.push_back (slurs_[j]);
-              slurs_.erase (slurs_.begin () + j);
-            }
-        }
-      if (ended)
-        {
-          // Ignore redundant stop events for this id
-          for (vsize j = stop_events_.size (); --j > i;)
-            {
-              if (id == robust_scm2string (stop_events_[j]->get_property ("spanner-id"), ""))
-                stop_events_.erase (stop_events_.begin () + j);
-            }
-        }
-      else
-        ev->origin ()->warning (_ ("cannot end slur"));
-    }
-
-  vsize old_slurs = slurs_.size ();
-  for (vsize i = start_events_.size (); i--;)
-    {
-      Stream_event *ev = start_events_[i];
-      string id = robust_scm2string (ev->get_property ("spanner-id"), "");
-      Direction updown = to_dir (ev->get_property ("direction"));
-
-      bool completed;
-      for (vsize j = slurs_.size (); !(completed = (j-- == 0));)
-        {
-          // Check if we already have a slur with the same spanner-id.
-          if (id == robust_scm2string (slurs_[j]->get_property ("spanner-id"), ""))
-            {
-              if (j < old_slurs)
-                {
-                  // We already have an old slur, so give a warning
-                  // and completely ignore the new slur.
-                  ev->origin ()->warning (_ ("already have slur"));
-                  start_events_.erase (start_events_.begin () + i);
-                  break;
-                }
-
-              // If this slur event has no direction, it will not
-              // contribute anything new to the existing slur(s), so
-              // we can ignore it.
-
-              if (!updown)
-                break;
-
-              Stream_event *c = unsmob_stream_event (slurs_[j]->get_property ("cause"));
-
-              if (!c)
-                {
-                  slurs_[j]->programming_error ("slur without a cause");
-                  continue;
-                }
-
-              Direction slur_dir = to_dir (c->get_property ("direction"));
-
-              // If the existing slur does not have a direction yet,
-              // we'd rather take the new one.
-
-              if (!slur_dir)
-                {
-                  slurs_[j]->suicide ();
-                  slurs_.erase (slurs_.begin () + j);
-                  continue;
-                }
-
-              // If the existing slur has the same direction as ours, drop ours
-
-              if (slur_dir == updown)
-                break;
-            }
-        }
-      // If the loop completed, our slur is new
-      if (completed)
-        {
-          Grob *slur = make_spanner ("Slur", ev->self_scm ());
-          slur->set_property ("spanner-id", ly_string2scm (id));
-          if (updown)
-            set_grob_direction (slur, updown);
-          slurs_.push_back (slur);
-
-          if (to_boolean (get_property ("doubleSlurs")))
-            {
-              set_grob_direction (slur, DOWN);
-              slur = make_spanner ("Slur", ev->self_scm ());
-              slur->set_property ("spanner-id", ly_string2scm (id));
-              set_grob_direction (slur, UP);
-              slurs_.push_back (slur);
-            }
-        }
-    }
-  set_melisma (slurs_.size ());
-}
-
-void
-Slur_engraver::stop_translation_timestep ()
-{
-  if (Grob *g = unsmob_grob (get_property ("currentCommandColumn")))
-    {
-      for (vsize i = 0; i < end_slurs_.size (); i++)
-        Slur::add_extra_encompass (end_slurs_[i], g);
-
-      if (!start_events_.size ())
-        for (vsize i = 0; i < slurs_.size (); i++)
-          Slur::add_extra_encompass (slurs_[i], g);
-    }
-
-  for (vsize i = 0; i < end_slurs_.size (); i++)
-    {
-      Spanner *s = dynamic_cast<Spanner *> (end_slurs_[i]);
-      if (!s->get_bound (RIGHT))
-        s->set_bound (RIGHT, unsmob_grob (get_property ("currentMusicalColumn")));
-      announce_end_grob (s, SCM_EOL);
-    }
-
-  for (vsize i = 0; i < objects_to_acknowledge_.size (); i++)
-    Slur::auxiliary_acknowledge_extra_object (objects_to_acknowledge_[i], slurs_, end_slurs_);
-
-  objects_to_acknowledge_.clear ();
-  end_slurs_.clear ();
-  start_events_.clear ();
-  stop_events_.clear ();
+  context ()->set_property ("slurMelismaBusy", ly_bool2scm (m));
 }
 
 ADD_ACKNOWLEDGER (Slur_engraver, inline_accidental);
diff --git a/lily/slur-proto-engraver.cc b/lily/slur-proto-engraver.cc
new file mode 100644 (file)
index 0000000..fbc5f00
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+  This file is part of LilyPond, the GNU music typesetter.
+
+  Copyright (C) 2013 Mike Solomon <mike@mikesolomon.org>
+
+  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 "engraver.hh"
+
+#include "context.hh"
+#include "directional-element-interface.hh"
+#include "international.hh"
+#include "note-column.hh"
+#include "slur.hh"
+#include "slur-proto-engraver.hh"
+#include "spanner.hh"
+#include "stream-event.hh"
+#include "warn.hh"
+
+#include "translator.icc"
+
+void
+Slur_proto_engraver::derived_mark () const
+{
+  for (vsize i = start_events_.size (); i--;)
+    scm_gc_mark (start_events_[i]->self_scm ());
+  for (vsize i = stop_events_.size (); i--;)
+    scm_gc_mark (stop_events_[i]->self_scm ());
+}
+
+void
+Slur_proto_engraver::internal_listen_slur (Stream_event *ev)
+{
+  Direction d = to_dir (ev->get_property ("span-direction"));
+  if (d == START)
+    start_events_.push_back (ev);
+  else if (d == STOP)
+    stop_events_.push_back (ev);
+  else ev->origin ()->warning (_f ("direction of %s invalid: %d",
+                                     event_name_, int (d)));
+}
+
+void
+Slur_proto_engraver::acknowledge_note_column (Grob_info info)
+{
+  Grob *e = info.grob ();
+  for (vsize i = slurs_.size (); i--;)
+    Slur::add_column (slurs_[i], e);
+  for (vsize i = end_slurs_.size (); i--;)
+    Slur::add_column (end_slurs_[i], e);
+}
+
+void
+Slur_proto_engraver::acknowledge_extra_object (Grob_info info)
+{
+  objects_to_acknowledge_.push_back (info);
+}
+
+void
+Slur_proto_engraver::acknowledge_inline_accidental (Grob_info info)
+{
+  acknowledge_extra_object (info);
+}
+
+void
+Slur_proto_engraver::acknowledge_dots (Grob_info info)
+{
+  acknowledge_extra_object (info);
+}
+
+void
+Slur_proto_engraver::acknowledge_fingering (Grob_info info)
+{
+  acknowledge_extra_object (info);
+}
+
+void
+Slur_proto_engraver::acknowledge_tuplet_number (Grob_info info)
+{
+  acknowledge_extra_object (info);
+}
+
+void
+Slur_proto_engraver::acknowledge_script (Grob_info info)
+{
+  if (!info.grob ()->internal_has_interface (ly_symbol2scm ("dynamic-interface")))
+    acknowledge_extra_object (info);
+}
+
+void
+Slur_proto_engraver::acknowledge_text_script (Grob_info info)
+{
+  acknowledge_extra_object (info);
+}
+
+void
+Slur_proto_engraver::acknowledge_end_tie (Grob_info info)
+{
+  acknowledge_extra_object (info);
+}
+
+void
+Slur_proto_engraver::finalize ()
+{
+  for (vsize i = 0; i < slurs_.size (); i++)
+    {
+      slurs_[i]->warning (_f ("unterminated %s", object_name_));
+      slurs_[i]->suicide ();
+    }
+  slurs_.clear ();
+}
+
+void
+Slur_proto_engraver::create_slur (string spanner_id, Stream_event *ev_cause, Grob *g_cause, Direction dir, bool left_broken)
+{
+  Grob *ccc = unsmob_grob (get_property ("currentCommandColumn"));
+  SCM cause = ev_cause ? ev_cause->self_scm () : g_cause->self_scm ();
+  Spanner *slur = make_spanner (grob_name_, cause);
+  slur->set_property ("spanner-id", ly_string2scm (spanner_id));
+  if (dir)
+    set_grob_direction (slur, dir);
+  if (left_broken)
+    slur->set_bound (LEFT, ccc);
+  slurs_.push_back (slur);
+  if (double_property_name_
+      && to_boolean (get_property (double_property_name_)))
+  {
+    set_grob_direction (slur, DOWN);
+    slur = make_spanner (grob_name_, cause);
+    slur->set_property ("spanner-id", ly_string2scm (spanner_id));
+    set_grob_direction (slur, UP);
+    if (left_broken)
+      slur->set_bound (LEFT, ccc);
+    slurs_.push_back (slur);
+  }
+
+}
+
+bool
+Slur_proto_engraver::can_create_slur (string id, vsize old_slurs, vsize *event_idx, Stream_event *ev)
+{
+  for (vsize j = slurs_.size (); j--;)
+    {
+      Grob *slur = slurs_[j];
+      Direction updown = to_dir (ev->get_property ("direction"));
+
+      // Check if we already have a slur with the same spanner-id.
+      if (id == robust_scm2string (slur->get_property ("spanner-id"), ""))
+        {
+          if (j < old_slurs)
+            {
+              // We already have an old slur, so give a warning
+              // and completely ignore the new slur.
+              ev->origin ()->warning (_f ("already have %s", object_name_));
+              if (event_idx)
+                start_events_.erase (start_events_.begin () + (*event_idx));
+              return false;
+            }
+
+          // If this slur event has no direction, it will not
+          // contribute anything new to the existing slur(s), so
+          // we can ignore it.
+
+          if (!updown)
+            return false;
+
+          Stream_event *c = unsmob_stream_event (slur->get_property ("cause"));
+
+          if (!c)
+            {
+              slur->programming_error (_f ("%s without a cause", object_name_));
+              return true;
+            }
+
+          Direction slur_dir = to_dir (c->get_property ("direction"));
+
+          // If the existing slur does not have a direction yet,
+          // we'd rather take the new one.
+
+          if (!slur_dir)
+            {
+              slur->suicide ();
+              slurs_.erase (slurs_.begin () + j);
+              return true;
+            }
+
+          // If the existing slur has the same direction as ours, drop ours
+
+          if (slur_dir == updown)
+            return false;
+        }
+    }
+  return true;
+}
+
+bool
+Slur_proto_engraver::try_to_end (Stream_event *ev)
+{
+  string id = robust_scm2string (ev->get_property ("spanner-id"), "");
+
+  // Find the slurs that are ended with this event (by checking the spanner-id)
+  bool ended = false;
+  for (vsize j = slurs_.size (); j--;)
+    {
+      if (id == robust_scm2string (slurs_[j]->get_property ("spanner-id"), ""))
+        {
+          ended = true;
+          end_slurs_.push_back (slurs_[j]);
+          slurs_.erase (slurs_.begin () + j);
+        }
+    }
+  return ended;
+}
+
+void
+Slur_proto_engraver::process_music ()
+{
+  for (vsize i = 0; i < stop_events_.size (); i++)
+    {
+      string id = robust_scm2string (stop_events_[i]->get_property ("spanner-id"), "");
+      bool ended = try_to_end (stop_events_[i]);
+      if (ended)
+        {
+          // Ignore redundant stop events for this id
+          for (vsize j = stop_events_.size (); --j > i;)
+            {
+              if (id == robust_scm2string (stop_events_[j]->get_property ("spanner-id"), ""))
+                stop_events_.erase (stop_events_.begin () + j);
+            }
+        }
+      else
+        stop_events_[i]->origin ()->warning (_f ("cannot end %s", object_name_));
+    }
+
+  vsize old_slurs = slurs_.size ();
+  for (vsize i = start_events_.size (); i--;)
+    {
+      Stream_event *ev = start_events_[i];
+      string id = robust_scm2string (ev->get_property ("spanner-id"), "");
+      Direction updown = to_dir (ev->get_property ("direction"));
+
+      if (can_create_slur (id, old_slurs, &i, ev))
+        create_slur (id, ev, 0, updown, false);
+    }
+
+  set_melisma (slurs_.size ());
+}
+
+void
+Slur_proto_engraver::set_melisma (bool)
+{
+}
+
+void
+Slur_proto_engraver::stop_translation_timestep ()
+{
+  if (Grob *g = unsmob_grob (get_property ("currentCommandColumn")))
+    {
+      for (vsize i = 0; i < end_slurs_.size (); i++)
+        Slur::add_extra_encompass (end_slurs_[i], g);
+
+      if (!start_events_.size ())
+        for (vsize i = 0; i < slurs_.size (); i++)
+          Slur::add_extra_encompass (slurs_[i], g);
+    }
+
+  for (vsize i = 0; i < end_slurs_.size (); i++)
+    {
+      Spanner *s = dynamic_cast<Spanner *> (end_slurs_[i]);
+      if (!s->get_bound (RIGHT))
+        s->set_bound (RIGHT, unsmob_grob (get_property ("currentMusicalColumn")));
+      announce_end_grob (s, SCM_EOL);
+    }
+
+  for (vsize i = 0; i < objects_to_acknowledge_.size (); i++)
+    Slur::auxiliary_acknowledge_extra_object (objects_to_acknowledge_[i], slurs_, end_slurs_);
+
+  objects_to_acknowledge_.clear ();
+  end_slurs_.clear ();
+  start_events_.clear ();
+  stop_events_.clear ();
+}
+
+// no ADD_ACKNOWLEDGER / ADD_TRANSLATOR macro calls
+// since this class is abstract
index eb9913dc160b94a6e8821f757d067832fb30c7aa..0aa96c787d1d7ba482ed0170e3990ee703258236 100644 (file)
@@ -40,6 +40,7 @@
 #include "warn.hh"
 #include "slur-scoring.hh"
 #include "separation-item.hh"
+#include "unpure-pure-container.hh"
 #include "international.hh"
 
 MAKE_SCHEME_CALLBACK (Slur, calc_direction, 1)
@@ -421,7 +422,10 @@ Slur::auxiliary_acknowledge_extra_object (Grob_info const &info,
     {
       if (slur)
         {
-          chain_offset_callback (e, outside_slur_callback_proc, Y_AXIS);
+          chain_offset_callback (e,
+                                 ly_make_unpure_pure_container (outside_slur_callback_proc,
+                                                                pure_outside_slur_callback_proc),
+                                 Y_AXIS);
           chain_callback (e, outside_slur_cross_staff_proc, ly_symbol2scm ("cross-staff"));
           e->set_object ("slur", slur->self_scm ());
         }
index 601893b5cb23913bbc5d925c31a29edde89aba23..58b2ff46ca55277930db2657c1d920a67485de77 100644 (file)
@@ -1088,9 +1088,8 @@ Grob::horizontal_skylines_from_stencil (SCM smob)
 }
 
 SCM
-Grob::internal_skylines_from_element_stencils (SCM smob, Axis a)
+Grob::internal_skylines_from_element_stencils (Grob *me, Axis a, bool pure, int beg, int end)
 {
-  Grob *me = unsmob_grob (smob);
 
   extract_grob_set (me, "elements", elts);
   vector<Real> x_pos;
@@ -1100,14 +1099,15 @@ Grob::internal_skylines_from_element_stencils (SCM smob, Axis a)
   for (vsize i = 0; i < elts.size (); i++)
     {
       x_pos.push_back (elts[i]->relative_coordinate (x_common, X_AXIS));
-      y_pos.push_back (elts[i]->relative_coordinate (y_common, Y_AXIS));
+      y_pos.push_back (elts[i]->maybe_pure_coordinate (y_common, Y_AXIS, pure, beg, end));
     }
   Real my_x = me->relative_coordinate (x_common, X_AXIS);
-  Real my_y = me->relative_coordinate (y_common, Y_AXIS);
+  Real my_y = me->maybe_pure_coordinate (y_common, Y_AXIS, pure, beg, end);
+
   Skyline_pair res;
   for (vsize i = 0; i < elts.size (); i++)
     {
-      Skyline_pair *skyp = Skyline_pair::unsmob (elts[i]->get_property (a == X_AXIS ? "vertical-skylines" : "horizontal-skylines"));
+      Skyline_pair *skyp = Skyline_pair::unsmob (elts[i]->get_maybe_pure_property (a == X_AXIS ? "vertical-skylines" : "horizontal-skylines", pure, beg, end));
       if (skyp)
         {
           /*
@@ -1141,12 +1141,34 @@ MAKE_SCHEME_CALLBACK (Grob, vertical_skylines_from_element_stencils, 1);
 SCM
 Grob::vertical_skylines_from_element_stencils (SCM smob)
 {
-  return internal_skylines_from_element_stencils (smob, X_AXIS);
+  Grob *me = unsmob_grob (smob);
+  return internal_skylines_from_element_stencils (me, X_AXIS, false, 0, INT_MAX);
 }
 
 MAKE_SCHEME_CALLBACK (Grob, horizontal_skylines_from_element_stencils, 1);
 SCM
 Grob::horizontal_skylines_from_element_stencils (SCM smob)
 {
-  return internal_skylines_from_element_stencils (smob, Y_AXIS);
+  Grob *me = unsmob_grob (smob);
+  return internal_skylines_from_element_stencils (me, Y_AXIS, false, 0, INT_MAX);
+}
+
+MAKE_SCHEME_CALLBACK (Grob, pure_vertical_skylines_from_element_stencils, 3);
+SCM
+Grob::pure_vertical_skylines_from_element_stencils (SCM smob, SCM beg_scm, SCM end_scm)
+{
+  Grob *me = unsmob_grob (smob);
+  int beg = robust_scm2int (beg_scm, 0);
+  int end = robust_scm2int (end_scm, 0);
+  return internal_skylines_from_element_stencils (me, X_AXIS, true, beg, end);
+}
+
+MAKE_SCHEME_CALLBACK (Grob, pure_horizontal_skylines_from_element_stencils, 3);
+SCM
+Grob::pure_horizontal_skylines_from_element_stencils (SCM smob, SCM beg_scm, SCM end_scm)
+{
+  Grob *me = unsmob_grob (smob);
+  int beg = robust_scm2int (beg_scm, 0);
+  int end = robust_scm2int (end_scm, 0);
+  return internal_skylines_from_element_stencils (me, Y_AXIS, true, beg, end);
 }
index e3da76687d9676704963b711c3a2e583236ccfa0..b2e0d53a880405a5037811a2f057a25e1bad2749 100644 (file)
@@ -914,21 +914,19 @@ System::calc_pure_relevant_grobs (SCM smob)
 
   extract_grob_set (me, "elements", elts);
   vector<Grob *> relevant_grobs;
-  SCM pure_relevant_p = ly_lily_module_constant ("pure-relevant?");
 
   for (vsize i = 0; i < elts.size (); ++i)
     {
       if (!Axis_group_interface::has_interface (elts[i]))
         {
-          if (to_boolean (scm_apply_1 (pure_relevant_p, elts[i]->self_scm (), SCM_EOL)))
-            relevant_grobs.push_back (elts[i]);
+          relevant_grobs.push_back (elts[i]);
 
           if (Item *it = dynamic_cast<Item *> (elts[i]))
             {
               for (LEFT_and_RIGHT (d))
                 {
                   Item *piece = it->find_prebroken_piece (d);
-                  if (piece && to_boolean (scm_apply_1 (pure_relevant_p, piece->self_scm (), SCM_EOL)))
+                  if (piece && piece->is_live ())
                     relevant_grobs.push_back (piece);
                 }
             }
index 6c74b259be4ab377aec8cd4117d9a757a9c36a2c..dffaa095f6013731855137d50469314901ec2792 100644 (file)
@@ -32,7 +32,7 @@ Engraver_dispatch_list::apply (Grob_info gi)
       if (e.engraver_ == origin)
         continue;
 
-      (*e.function_) (e.engraver_, gi);
+      (e.engraver_->*e.function_) (gi);
     }
 }
 
index 097cb9d80c46fc1f2baea71b6de1424a284265d9..05e9c4bcc8ea0d1f1f8db9dee1796f2789f297ba 100644 (file)
@@ -22,6 +22,9 @@
 #include "grob.hh"
 
 static scm_t_bits unpure_pure_container_tag;
+static scm_t_bits unpure_pure_call_tag;
+// Used for rerouting a function of (grob start end) to one of
+// (grob)
 
 bool
 is_unpure_pure_container (SCM s)
@@ -33,14 +36,21 @@ SCM
 unpure_pure_container_unpure_part (SCM smob)
 {
   LY_ASSERT_TYPE (is_unpure_pure_container, smob, 1);
-  return (SCM) SCM_CELL_WORD_1 (smob);
+  return SCM_SMOB_OBJECT (smob);
 }
 
 SCM
 unpure_pure_container_pure_part (SCM smob)
 {
   LY_ASSERT_TYPE (is_unpure_pure_container, smob, 1);
-  return (SCM) SCM_CELL_WORD_2 (smob);
+  SCM res = SCM_SMOB_OBJECT_2 (smob);
+
+  if (!SCM_UNBNDP (res))
+    return res;
+
+  SCM_NEWSMOB (res, unpure_pure_call_tag,
+               SCM_UNPACK (unpure_pure_container_unpure_part (smob)));
+  return res;
 }
 
 LY_DEFINE (ly_unpure_pure_container_p, "ly:unpure-pure-container?",
@@ -54,11 +64,13 @@ LY_DEFINE (ly_make_unpure_pure_container, "ly:make-unpure-pure-container",
            1, 1, 0, (SCM unpure, SCM pure),
            "Make an unpure-pure container.  @var{unpure} should be an unpure"
            " expression, and @var{pure} should be a pure expression.  If @var{pure}"
-           " is ommitted, the value of @var{unpure} will be used twice.")
+           " is omitted, the value of @var{unpure} will be used twice,"
+           " except that a callback is given two extra arguments"
+           " that are ignored for the sake of pure calculations.")
 {
   SCM z;
 
-  if (pure == SCM_UNDEFINED)
+  if (SCM_UNBNDP (pure) && !ly_is_procedure (unpure))
     pure = unpure;
 
   SCM_NEWSMOB2 (z, unpure_pure_container_tag, SCM_UNPACK (unpure), SCM_UNPACK (pure));
@@ -86,25 +98,46 @@ print_unpure_pure_container (SCM s, SCM port, scm_print_state *)
 {
   scm_puts ("#<unpure-pure-container ", port);
   scm_display (unpure_pure_container_unpure_part (s), port);
-  scm_puts (" ", port);
-  scm_display (unpure_pure_container_pure_part (s), port);
+  if (!SCM_UNBNDP (SCM_SMOB_OBJECT_2 (s)))
+    {
+      scm_puts (" ", port);
+      scm_display (unpure_pure_container_pure_part (s), port);
+    }
   scm_puts (" >", port);
   return 1;
 }
 
 SCM
-pure_mark (SCM pure)
+pure_mark (SCM smob)
 {
-  scm_gc_mark (unpure_pure_container_unpure_part (pure));
-  scm_gc_mark (unpure_pure_container_pure_part (pure));
-  return pure;
+  scm_gc_mark (SCM_SMOB_OBJECT (smob));
+  return SCM_SMOB_OBJECT_2 (smob);
+}
+
+// Function signature has two fixed arguments so that dropping two
+// will always work: if we have fewer to start with, it will trigger
+// wrong-number-of-args in a sensible location rather than making
+// drop-right barf.
+
+SCM
+apply_unpure_pure (SCM clo, SCM arg1, SCM arg2, SCM rest)
+{  
+  return scm_apply_0 (SCM_SMOB_OBJECT (clo),
+                      scm_call_2 (ly_lily_module_constant ("drop-right"),
+                                  scm_cons2 (arg1, arg2, rest),
+                                  scm_from_int (2)));
 }
+  
 
 void init_unpure_pure_container ()
 {
   unpure_pure_container_tag = scm_make_smob_type ("unpure-pure-container", 0);
   scm_set_smob_mark (unpure_pure_container_tag, pure_mark);
   scm_set_smob_print (unpure_pure_container_tag, print_unpure_pure_container);
+  unpure_pure_call_tag = scm_make_smob_type ("unpure-pure-call", 0);
+  scm_set_smob_mark (unpure_pure_call_tag, scm_markcdr);
+  scm_set_smob_apply (unpure_pure_call_tag,
+                      (SCM (*)()) apply_unpure_pure, 2, 0, 1);
 };
 
 ADD_SCM_INIT_FUNC (unpure_pure_container, init_unpure_pure_container);
index a7754ef67c54aa095ee6b3639c55c57b523a5142..58ee39a12304b4acf61aa4bbad4c76b683235829 100644 (file)
@@ -1139,6 +1139,9 @@ accommodated for typesetting a piece in Petrucci style."
  \description "Same as @code{Voice} context, except that it is
 accommodated for typesetting a piece in Kievan style."
 
+  \remove "Ligature_bracket_engraver"
+  \consists "Kievan_ligature_engraver"
+
  %% Set glyph styles.
  \override NoteHead.style = #'kievan
  \override Stem.X-offset = #stem::kievan-offset-callback
index 061e696d08f01f967924c674367e095cb245086a..379eb933ba192169821a9177991c19e52816ee96 100644 (file)
@@ -438,9 +438,7 @@ harmonics played on a fretted instrument by touching the strings at @var{fret}."
   #{
     \set harmonicDots = ##t
     \temporary \override TabNoteHead.stencil = #(tab-note-head::print-custom-fret-label (number->string fret))
-    \temporary \override NoteHead.Y-extent = #(ly:make-unpure-pure-container ly:grob::stencil-height
-                                       (lambda (grob start end)
-                                               (ly:grob::stencil-height grob)))
+    \temporary \override NoteHead.Y-extent = #grob::always-Y-extent-from-stencil
     \temporary \override NoteHead.stencil = #(lambda (grob) (ly:grob-set-property! grob 'style 'harmonic-mixed)
                                             (ly:note-head::print grob))
     #(make-harmonic
@@ -1339,6 +1337,8 @@ as a first or second voice.")
               'quoted-context-id "cue"
               'quoted-music-name what
               'quoted-voice-direction dir
+               ;; following is inverse of instrumentTransposition for
+               ;; historical reasons
               'quoted-transposition pitch))
 
 transposition =
@@ -1346,8 +1346,7 @@ transposition =
    (_i "Set instrument transposition")
 
    (context-spec-music
-    (make-property-set 'instrumentTransposition
-                       (ly:pitch-negate pitch))
+    (make-property-set 'instrumentTransposition pitch)
     'Staff))
 
 tuplet =
index e39bcf4c4840542101d3758dded226b195355bcd..b06587ce743b09428f77d90ab38c38b54c999064 100644 (file)
@@ -35,6 +35,7 @@
 \context {
   \name Global
   \accepts Score
+  \defaultchild Score
   \description "Hard coded entry point for LilyPond.  Cannot be tuned."
   EventClasses = #all-event-classes
 }
   \type "Performer_group"
   \consists "Staff_performer"
   \accepts ChordNameVoice
+  \defaultchild ChordNameVoice
   \name ChordNames
 }
 
index 90beab467017de47ed05113a2ecec142b22c0bb9..ae9a60f43727a2970594b7d4d8a480defd11cd7a 100644 (file)
@@ -6,10 +6,10 @@
 #, fuzzy
 msgid ""
 msgstr ""
-"Project-Id-Version: lilypond 2.17.12\n"
+"Project-Id-Version: lilypond 2.17.13\n"
 "Report-Msgid-Bugs-To: http://post.gmane.org/post.php?group=gmane.comp.gnu."
 "lilypond.bugs\n"
-"POT-Creation-Date: 2013-02-08 17:02+0000\n"
+"POT-Creation-Date: 2013-02-23 16:12+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -2041,31 +2041,31 @@ msgstr ""
 msgid "alteration not found"
 msgstr ""
 
-#: ligature-bracket-engraver.cc:72 ligature-engraver.cc:104
+#: ligature-bracket-engraver.cc:72 ligature-engraver.cc:109
 msgid "cannot find start of ligature"
 msgstr ""
 
-#: ligature-bracket-engraver.cc:85 ligature-engraver.cc:131
+#: ligature-bracket-engraver.cc:85 ligature-engraver.cc:136
 msgid "already have a ligature"
 msgstr ""
 
-#: ligature-engraver.cc:109
+#: ligature-engraver.cc:114
 msgid "no right bound"
 msgstr ""
 
-#: ligature-engraver.cc:140
+#: ligature-engraver.cc:145
 msgid "no left bound"
 msgstr ""
 
-#: ligature-engraver.cc:184
+#: ligature-engraver.cc:189
 msgid "unterminated ligature"
 msgstr ""
 
-#: ligature-engraver.cc:211
+#: ligature-engraver.cc:216
 msgid "ignoring rest: ligature may not contain rest"
 msgstr ""
 
-#: ligature-engraver.cc:212
+#: ligature-engraver.cc:217
 msgid "ligature was started here"
 msgstr ""
 
@@ -2092,16 +2092,16 @@ msgstr ""
 msgid "type check for `%s' failed; value `%s' must be of type `%s'"
 msgstr ""
 
-#: lily-lexer.cc:246
+#: lily-lexer.cc:249
 msgid "include files are not allowed in safe mode"
 msgstr ""
 
-#: lily-lexer.cc:273
+#: lily-lexer.cc:276
 #, c-format
 msgid "identifier name is a keyword: `%s'"
 msgstr ""
 
-#: lily-lexer.cc:294 lily-lexer.cc:307
+#: lily-lexer.cc:297 lily-lexer.cc:310
 #, c-format
 msgid "%s:EOF"
 msgstr ""
@@ -2126,19 +2126,19 @@ msgstr ""
 msgid "Processing `%s'"
 msgstr ""
 
-#: lily-parser-scheme.cc:208
+#: lily-parser-scheme.cc:209
 msgid ""
 "ly:parser-parse-string is only valid with a new parser.  Use ly:parser-"
 "include-string instead."
 msgstr ""
 
-#: lily-parser-scheme.cc:239
+#: lily-parser-scheme.cc:240
 msgid ""
 "ly:parse-string-expression is only valid with a new parser.  Use ly:parser-"
 "include-string instead."
 msgstr ""
 
-#: lily-parser.cc:108
+#: lily-parser.cc:107
 msgid "Parsing..."
 msgstr ""
 
@@ -2436,12 +2436,12 @@ msgstr ""
 msgid "Calculating page breaks..."
 msgstr ""
 
-#: multi-measure-rest.cc:153
+#: multi-measure-rest.cc:152
 msgid ""
 "usable-duration-logs must be a non-empty list.  Falling back to whole rests."
 msgstr ""
 
-#: multi-measure-rest.cc:343
+#: multi-measure-rest.cc:342
 msgid "Using naive multi measure rest spacing."
 msgstr ""
 
@@ -3121,92 +3121,92 @@ msgstr ""
 msgid "Too much lookahead"
 msgstr ""
 
-#: parser.yy:464 parser.yy:732 parser.yy:799
+#: parser.yy:466 parser.yy:734 parser.yy:801
 msgid "bad expression type"
 msgstr ""
 
-#: parser.yy:628 parser.yy:1113
+#: parser.yy:630 parser.yy:1115
 msgid "not a context mod"
 msgstr ""
 
-#: parser.yy:834
+#: parser.yy:836
 msgid "score expected"
 msgstr ""
 
-#: parser.yy:850
+#: parser.yy:852
 msgid "\\paper cannot be used in \\score, use \\layout instead"
 msgstr ""
 
-#: parser.yy:874
+#: parser.yy:876
 msgid "need \\paper for paper block"
 msgstr ""
 
-#: parser.yy:1022 parser.yy:1033
+#: parser.yy:1024 parser.yy:1035
 msgid "unexpected post-event"
 msgstr ""
 
-#: parser.yy:1038
+#: parser.yy:1040
 msgid "Ignoring non-music expression"
 msgstr ""
 
-#: parser.yy:1049 parser.yy:2304
+#: parser.yy:1051 parser.yy:2306
 msgid "music expected"
 msgstr ""
 
-#: parser.yy:1317
+#: parser.yy:1319
 msgid "not a symbol"
 msgstr ""
 
-#: parser.yy:2008 parser.yy:2119 parser.yy:2132 parser.yy:2141
+#: parser.yy:2010 parser.yy:2121 parser.yy:2134 parser.yy:2143
 msgid "bad grob property path"
 msgstr ""
 
-#: parser.yy:2099
+#: parser.yy:2101
 msgid "only \\consists and \\remove take non-string argument."
 msgstr ""
 
-#: parser.yy:2160
+#: parser.yy:2162
 msgid "bad context property path"
 msgstr ""
 
-#: parser.yy:2253 parser.yy:2257 parser.yy:2272
+#: parser.yy:2255 parser.yy:2259 parser.yy:2274
 msgid "simple string expected"
 msgstr ""
 
-#: parser.yy:2413
+#: parser.yy:2415
 msgid "not a rhythmic event"
 msgstr ""
 
-#: parser.yy:2509 parser.yy:2514 parser.yy:3057
+#: parser.yy:2511 parser.yy:2516 parser.yy:3059
 msgid "have to be in Lyric mode for lyrics"
 msgstr ""
 
-#: parser.yy:2629
+#: parser.yy:2631
 msgid "expecting string as script definition"
 msgstr ""
 
-#: parser.yy:2724
+#: parser.yy:2726
 msgid "not an articulation"
 msgstr ""
 
-#: parser.yy:2796 parser.yy:2842
+#: parser.yy:2798 parser.yy:2844
 #, c-format
 msgid "not a duration: %d"
 msgstr ""
 
-#: parser.yy:2859
+#: parser.yy:2861
 msgid "bass number expected"
 msgstr ""
 
-#: parser.yy:2973
+#: parser.yy:2975
 msgid "have to be in Note mode for notes"
 msgstr ""
 
-#: parser.yy:3032
+#: parser.yy:3034
 msgid "have to be in Chord mode for chords"
 msgstr ""
 
-#: parser.yy:3256
+#: parser.yy:3258
 msgid "not a markup"
 msgstr ""
 
@@ -3349,7 +3349,7 @@ msgid ""
 "add-bar-glyph-print-procedure: glyph '~a' has to be a single ASCII character."
 msgstr ""
 
-#: bar-line.scm:808
+#: bar-line.scm:802
 #, scheme-format
 msgid "No span bar glyph defined for bar glyph '~a'; ignoring."
 msgstr ""
@@ -3389,32 +3389,32 @@ msgstr ""
 msgid "defaulting to ~S pt"
 msgstr ""
 
-#: define-markup-commands.scm:3329
+#: define-markup-commands.scm:3420
 #, scheme-format
 msgid "not a valid duration string: ~a"
 msgstr ""
 
-#: define-markup-commands.scm:3540
+#: define-markup-commands.scm:3631
 #, scheme-format
 msgid "not a valid duration string: ~a - ignoring"
 msgstr ""
 
-#: define-music-types.scm:770
+#: define-music-types.scm:772
 #, scheme-format
 msgid "symbol expected: ~S"
 msgstr ""
 
-#: define-music-types.scm:773
+#: define-music-types.scm:775
 #, scheme-format
 msgid "cannot find music object: ~S"
 msgstr ""
 
-#: define-music-types.scm:792
+#: define-music-types.scm:794
 #, scheme-format
 msgid "unknown repeat type `~S'"
 msgstr ""
 
-#: define-music-types.scm:793
+#: define-music-types.scm:795
 msgid "See define-music-types.scm for supported repeats"
 msgstr ""
 
@@ -3533,37 +3533,37 @@ msgstr ""
 msgid "Error in beam quanting.  Expected ~S 0, found ~S."
 msgstr ""
 
-#: lily-library.scm:340
+#: lily-library.scm:331
 msgid "Music unsuitable for context-mod"
 msgstr ""
 
-#: lily-library.scm:395
+#: lily-library.scm:386
 #, scheme-format
 msgid "Cannot find context-def \\~a"
 msgstr ""
 
-#: lily-library.scm:411
+#: lily-library.scm:402
 msgid "Music unsuitable for output-def"
 msgstr ""
 
-#: lily-library.scm:927
+#: lily-library.scm:901
 msgid ""
 "Find the index between @var{start} and @var{end} (an integer)\n"
 "which produces the closest match to @var{target-val} if\n"
 "applied to function @var{getter}."
 msgstr ""
 
-#: lily-library.scm:1001
+#: lily-library.scm:975
 #, scheme-format
 msgid "unknown unit: ~S"
 msgstr ""
 
-#: lily-library.scm:1026
+#: lily-library.scm:1000
 #, scheme-format
 msgid "no \\version statement found, please add~afor future compatibility"
 msgstr ""
 
-#: lily-library.scm:1032
+#: lily-library.scm:1006
 msgid "old relative compatibility not used"
 msgstr ""
 
@@ -3584,37 +3584,37 @@ msgstr ""
 msgid "cannot find: ~A"
 msgstr ""
 
-#: lily.scm:794
+#: lily.scm:795
 msgid "Success: compilation successfully completed"
 msgstr ""
 
-#: lily.scm:795
+#: lily.scm:796
 msgid "Compilation completed with warnings or errors"
 msgstr ""
 
-#: lily.scm:857
+#: lily.scm:858
 #, scheme-format
 msgid "job ~a terminated with signal: ~a"
 msgstr ""
 
-#: lily.scm:860
+#: lily.scm:861
 #, scheme-format
 msgid ""
 "logfile ~a (exit ~a):\n"
 "~a"
 msgstr ""
 
-#: lily.scm:882 lily.scm:971
+#: lily.scm:883 lily.scm:972
 #, scheme-format
 msgid "failed files: ~S"
 msgstr ""
 
-#: lily.scm:962
+#: lily.scm:963
 #, scheme-format
 msgid "Redirecting output to ~a..."
 msgstr ""
 
-#: lily.scm:981 ps-to-png.scm:66
+#: lily.scm:982 ps-to-png.scm:66
 #, scheme-format
 msgid "Invoking `~a'...\n"
 msgstr ""
@@ -3629,7 +3629,7 @@ msgstr ""
 msgid "wrong type for argument ~a.  Expecting ~a, found ~s"
 msgstr ""
 
-#: ly-syntax-constructors.scm:188
+#: ly-syntax-constructors.scm:180
 #, scheme-format
 msgid "Invalid property operation ~a"
 msgstr ""
@@ -3768,17 +3768,17 @@ msgstr ""
 msgid "Must use #(set-paper-size .. ) within \\paper { ... }"
 msgstr ""
 
-#: parser-clef.scm:164 parser-clef.scm:215
+#: parser-clef.scm:164
 #, scheme-format
 msgid "unknown clef type `~a'"
 msgstr ""
 
-#: parser-clef.scm:165 parser-clef.scm:216
+#: parser-clef.scm:165
 #, scheme-format
 msgid "supported clefs: ~a"
 msgstr ""
 
-#: parser-ly-from-scheme.scm:73
+#: parser-ly-from-scheme.scm:74
 msgid "error in #{ ... #}"
 msgstr ""
 
@@ -3797,40 +3797,40 @@ msgstr ""
 msgid "assertion failed: ~S"
 msgstr ""
 
-#: translation-functions.scm:374
+#: translation-functions.scm:368
 #, scheme-format
 msgid "Negative fret for pitch ~a on string ~a"
 msgstr ""
 
-#: translation-functions.scm:377
+#: translation-functions.scm:371
 #, scheme-format
 msgid "Missing fret for pitch ~a on string ~a"
 msgstr ""
 
-#: translation-functions.scm:420
+#: translation-functions.scm:414
 #, scheme-format
 msgid "No open string for pitch ~a"
 msgstr ""
 
-#: translation-functions.scm:435 translation-functions.scm:447
+#: translation-functions.scm:429 translation-functions.scm:441
 #, scheme-format
 msgid "Requested string for pitch requires negative fret: string ~a pitch ~a"
 msgstr ""
 
-#: translation-functions.scm:438
+#: translation-functions.scm:432
 msgid "Ignoring string request and recalculating."
 msgstr ""
 
-#: translation-functions.scm:450
+#: translation-functions.scm:444
 msgid "Ignoring note in tablature."
 msgstr ""
 
-#: translation-functions.scm:473
+#: translation-functions.scm:467
 #, scheme-format
 msgid "No string for pitch ~a (given frets ~a)"
 msgstr ""
 
-#: translation-functions.scm:578
+#: translation-functions.scm:572
 #, scheme-format
 msgid ""
 "No label for fret ~a (on string ~a);\n"
index 8ac123e11e9f9d7bedfef87a7c3e2ed835e7c260..ce3288b205e18345c1b8ac4b81dbfbb6570e1714 100644 (file)
@@ -814,80 +814,76 @@ no elements."
   "The print routine for span bars."
   (let* ((elts-array (ly:grob-object grob 'elements))
          (refp (ly:grob-common-refpoint-of-array grob elts-array Y))
-         (elts (reverse (sort (ly:grob-array->list elts-array)
-                              ly:grob-vertical<?)))
+         (elts (sort (ly:grob-array->list elts-array)
+                     ly:grob-vertical<?))
          ;; Elements must be ordered according to their y coordinates
          ;; relative to their common axis group parent.
          ;; Otherwise, the computation goes mad.
-         (bar-glyph (ly:grob-property grob 'glyph-name))
-         (span-bar empty-stencil))
+         (bar-glyph (ly:grob-property grob 'glyph-name)))
 
         (if (string? bar-glyph)
-            (let ((extents '())
-                  (make-span-bars '())
-                  (model-bar #f))
-
-                 ;; we compute the extents of each system and store them
-                 ;; in a list; dito for the 'allow-span-bar property.
-                 ;; model-bar takes the bar grob, if given.
-                 (map (lambda (bar)
-                      (let ((ext (bar-line::bar-y-extent bar refp))
-                            (staff-symbol (ly:grob-object bar 'staff-symbol)))
-
-                           (if (ly:grob? staff-symbol)
-                               (let ((refp-extent (ly:grob-extent staff-symbol refp Y)))
-
-                                    (set! ext (interval-union ext refp-extent))
-
-                                    (if (> (interval-length ext) 0)
-                                        (begin
-                                          (set! extents (append extents (list ext)))
-                                          (set! model-bar bar)
-                                          (set! make-span-bars
-                                            (append make-span-bars
-                                                    (list (ly:grob-property
-                                                            bar
-                                                            'allow-span-bar
-                                                            #t))))))))))
-                     elts)
-                 ;; if there is no bar grob, we use the callback argument
-                 (if (not model-bar)
-                     (set! model-bar grob))
-                 ;; we discard the first entry in make-span-bars,
-                 ;; because its corresponding bar line is the
-                 ;; uppermost and therefore not connected to
-                 ;; another bar line
-                 (if (pair? make-span-bars)
-                     (set! make-span-bars (cdr make-span-bars)))
-                 ;; the span bar reaches from the lower end of the upper staff
-                 ;; to the upper end of the lower staff - when allow-span-bar is #t
-                 (reduce (lambda (curr prev)
-                                 (let ((span-extent (cons 0 0))
-                                       (allow-span-bar (car make-span-bars)))
-
-                                      (set! make-span-bars (cdr make-span-bars))
-                                      (if (> (interval-length prev) 0)
-                                          (begin
-                                            (set! span-extent (cons (cdr prev)
-                                                                    (car curr)))
-                                            ;; draw the span bar only when the staff lines
-                                            ;; don't overlap and allow-span-bar is #t:
-                                            (and (> (interval-length span-extent) 0)
-                                                 allow-span-bar
-                                                 (set! span-bar
-                                                       (ly:stencil-add
-                                                         span-bar
-                                                         (span-bar::compound-bar-line
-                                                           model-bar
-                                                           bar-glyph
-                                                           span-extent))))))
-                                      curr))
-                         "" extents)
-                 (set! span-bar (ly:stencil-translate-axis
-                                  span-bar
-                                  (- (ly:grob-relative-coordinate grob refp Y))
-                                  Y))))
-        span-bar))
+            (let loop ((extents '())
+                       (make-span-bars '())
+                       ;; if there is no bar grob, we use the callback
+                       ;; argument
+                       (model-bar grob)
+                       (bar-list elts))
+
+              ;; we compute the extents of each system and store them
+              ;; in a list; dito for the 'allow-span-bar property.
+              ;; model-bar takes the bar grob, if given.
+              (if (pair? bar-list)
+                  (let* ((bar (car bar-list))
+                         (ext (bar-line::bar-y-extent bar refp))
+                         (staff-symbol (ly:grob-object bar 'staff-symbol)))
+                    (if (ly:grob? staff-symbol)
+                        (if (positive? (interval-length ext))
+                            (loop (cons (interval-union
+                                         ext
+                                         (ly:grob-extent staff-symbol refp Y))
+                                        extents)
+                                  (cons (ly:grob-property
+                                         bar 'allow-span-bar #t)
+                                        make-span-bars)
+                                  bar
+                                  (cdr bar-list))
+                            (loop extents make-span-bars
+                                  model-bar (cdr bar-list)))))
+                  ;; end of loop
+                  ;; model-bar is the last bar found in the elts list
+                  ;; (former version had the first here).
+                  
+                  ;; the span bar reaches from the lower end of the upper staff
+                  ;; to the upper end of the lower staff - when
+                  ;; allow-span-bar is #t
+                  
+                  (if (pair? extents)
+                      (ly:stencil-translate-axis
+                       (fold
+                        (lambda (curr prev allow-span-bar span-bar)
+                          (if (and allow-span-bar
+                                   (positive? (interval-length prev)))
+                              (let ((span-extent (cons (cdr prev) (car curr))))
+                                ;; draw the span bar only when the staff lines
+                                ;; don't overlap and allow-span-bar is #t:
+                                (if (positive? (interval-length span-extent))
+                                    (ly:stencil-add
+                                     span-bar
+                                     (span-bar::compound-bar-line
+                                      model-bar
+                                      bar-glyph
+                                      span-extent))
+                                    span-bar))
+                              span-bar))
+                        empty-stencil
+                        ;; we discard the first entry in make-span-bars,
+                        ;; because its corresponding bar line is the
+                        ;; uppermost and therefore not connected to
+                        ;; another bar line
+                        (cdr extents) extents (cdr make-span-bars))
+                       (- (ly:grob-relative-coordinate grob refp Y)) Y)
+                      empty-stencil)))
+            empty-stencil)))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; volta bracket functions
index e9239fc65f8da1f07428c275270cbb99cd607edb..98f52aaa09bf89463d39d27032b0e8374ce8a3cc 100644 (file)
@@ -330,11 +330,10 @@ of numbers for the loudness range of the instrument.")
      (instrumentName ,markup? "The name to print left of a staff.  The
 @code{instrumentName} property labels the staff in the first system, and
 the @code{shortInstrumentName} property labels following lines.")
-     ;; the definition is reversed wrt traditional transposition
-     ;; otherwise \transpose { \transposition .. } won't work
      (instrumentTransposition ,ly:pitch? "Define the transposition of
-the instrument.  Its value is the pitch that sounds like middle@tie{}C.
-This is used to transpose the MIDI output, and @code{\\quote}s.")
+the instrument. Its value is the pitch that sounds when the instrument
+plays written middle C.  This is used to transpose the MIDI output,
+and @code{\\quote}s.")
      (internalBarNumber ,integer? "Contains the current barnumber.
 This property is used for internal timekeeping, among others by the
 @code{Accidental_engraver}.")
index c1a3a723cb89a601c2a65dd56719467a38088859..9afb49a0a32e4c3fb471df85f1ad3aea23f06ca4 100644 (file)
@@ -173,6 +173,9 @@ when a spanner is broken at a line break.")
 ;;
      (c0-position ,integer? "An integer indicating the position of
 middle@tie{}C.")
+     (chord-dots ,boolean? "If set, remove dots which the
+@code{DotColumn} algorithm would vertically position too far away from
+note heads.")
      (circled-tip ,boolean? "Put a circle at start/@/end of
 hairpins (al/@/del niente).")
      (clip-edges ,boolean? "Allow outward pointing beamlets at the
index cc4a9c76e935f7ba965f2904aedcfce460856724..effaf131faa22f1dce75d52d8738b4c4eeb71ae7 100644 (file)
@@ -24,6 +24,7 @@
 
 ;; TODO: junk the meta field in favor of something more compact?
 
+
 (define-public all-grob-descriptions
   `(
     (Accidental
        (glyph-name . ,accidental-interface::glyph-name)
        (glyph-name-alist . ,standard-alteration-glyph-name-alist)
        (stencil . ,ly:accidental-interface::print)
-       (horizontal-skylines . ,ly:accidental-interface::horizontal-skylines)
-       (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
+       (horizontal-skylines . ,(ly:make-unpure-pure-container ly:accidental-interface::horizontal-skylines))
+       (vertical-skylines . ,grob::unpure-vertical-skylines-from-stencil)
        (X-extent . ,ly:accidental-interface::width)
-       (Y-extent . ,ly:accidental-interface::height)
+       (Y-extent . ,accidental-interface::height)
        (meta . ((class . Item)
                 (interfaces . (accidental-interface
                                inline-accidental-interface
@@ -49,7 +50,7 @@
        (glyph-name-alist . ,standard-alteration-glyph-name-alist)
        (parenthesized . #t)
        (stencil . ,ly:accidental-interface::print)
-       (Y-extent . ,ly:accidental-interface::height)
+       (Y-extent . ,accidental-interface::height)
        (meta . ((class . Item)
                 (interfaces . (accidental-interface
                                inline-accidental-interface
@@ -90,8 +91,8 @@
                          (list ly:self-alignment-interface::centered-on-x-parent))
                        ,(ly:make-simple-closure
                          (list ly:self-alignment-interface::x-aligned-on-self)))))
-       (Y-extent . ,ly:accidental-interface::height)
-       (Y-offset . ,ly:side-position-interface::y-aligned-side)
+       (Y-extent . ,accidental-interface::height)
+       (Y-offset . ,side-position-interface::y-aligned-side)
        (meta . ((class . Item)
                 (interfaces . (accidental-interface
                                accidental-suggestion-interface
                        (time-signature . (extra-space . 0.0))
                        (first-note . (fixed-space . 0.0))))
        (X-extent . ,ly:axis-group-interface::width)
-       (Y-extent . ,ly:axis-group-interface::height)
+       (Y-extent . ,axis-group-interface::height)
        (meta . ((class . Item)
                 (object-callbacks . ((pure-Y-common . ,ly:axis-group-interface::calc-pure-y-common)
                                      (pure-relevant-grobs . ,ly:axis-group-interface::calc-pure-relevant-grobs)))
        (side-axis . ,X)
        (stencil . ,ly:accidental-interface::print)
        (X-offset . ,ly:side-position-interface::x-aligned-side)
-       (Y-extent . ,ly:accidental-interface::height)
+       (Y-extent . ,accidental-interface::height)
        (meta . ((class . Item)
                 (interfaces . (accidental-interface
                                break-aligned-interface
        (duration-log . 2)
        (glyph-name . ,note-head::calc-glyph-name)
        (stencil . ,ly:note-head::print)
-       (Y-offset . ,ly:staff-symbol-referencer::callback)
+       (Y-offset . ,staff-symbol-referencer::callback)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (meta . ((class . Item)
                 (interfaces . (ambitus-interface
                                font-interface
        (staff-position . 0.0)
        (stencil . ,ly:arpeggio::print)
        (X-extent . ,ly:arpeggio::width)
+       (Y-extent . ,(grob::unpure-Y-extent-from-stencil ly:arpeggio::pure-height))
        (X-offset . ,ly:side-position-interface::x-aligned-side)
-       (Y-offset . ,ly:staff-symbol-referencer::callback)
+       (Y-offset . ,staff-symbol-referencer::callback)
        (meta . ((class . Item)
                 (interfaces . (arpeggio-interface
                                font-interface
                        (next-note . (semi-fixed-space . 0.9))
                        (right-edge . (extra-space . 0.0))))
        (stencil . ,ly:bar-line::print)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (meta . ((class . Item)
                  (object-callbacks . ((pure-Y-common . ,ly:axis-group-interface::calc-pure-y-common)
                                       (pure-relevant-grobs . ,ly:pure-from-neighbor-interface::calc-pure-relevant-grobs)))
                          (list ly:break-alignable-interface::self-align-callback))
                        ,(ly:make-simple-closure
                          (list ly:self-alignment-interface::x-aligned-on-self)))))
-       (Y-offset . ,ly:side-position-interface::y-aligned-side)
+       (Y-offset . ,side-position-interface::y-aligned-side)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (meta .
              ((class . Item)
               (interfaces . (break-alignable-interface
     (BassFigure
      . (
        (stencil . ,ly:text-interface::print)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (meta . ((class . Item)
                 (interfaces . (bass-figure-interface
                                font-interface
        (padding . 0.2)
        (positioning-done . ,ly:align-interface::align-to-minimum-distances)
        (stacking-dir . ,DOWN)
-       (Y-extent . ,ly:axis-group-interface::height)
+       (Y-extent . ,axis-group-interface::height)
        (meta . ((class . Spanner)
                 (object-callbacks . ((pure-Y-common . ,ly:axis-group-interface::calc-pure-y-common)
                                      (pure-relevant-grobs . ,ly:axis-group-interface::calc-pure-relevant-grobs)))
        (padding . 0.5)
        (side-axis . ,Y)
        (staff-padding . 1.0)
-       (Y-extent . ,ly:axis-group-interface::height)
-       (Y-offset . ,ly:side-position-interface::y-aligned-side)
+       (Y-extent . ,axis-group-interface::height)
+       (Y-offset . ,side-position-interface::y-aligned-side)
        (meta . ((class . Spanner)
                 (object-callbacks . ((pure-Y-common . ,ly:axis-group-interface::calc-pure-y-common)
                                      (pure-relevant-grobs . ,ly:axis-group-interface::calc-pure-relevant-grobs)))
        (adjacent-pure-heights . ,ly:axis-group-interface::adjacent-pure-heights)
        (axes . (,Y))
        (vertical-skylines . ,ly:axis-group-interface::calc-skylines)
-       (Y-extent . ,ly:axis-group-interface::height)
+       (Y-extent . ,axis-group-interface::height)
        (meta . ((class . Spanner)
                 (object-callbacks . ((pure-Y-common . ,ly:axis-group-interface::calc-pure-y-common)
                                      (pure-relevant-grobs . ,ly:axis-group-interface::calc-pure-relevant-grobs)))
        (quantized-positions . ,ly:beam::set-stem-lengths)
 
        (shorten . ,ly:beam::calc-stem-shorten)
-       (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
+       (vertical-skylines . ,grob::unpure-vertical-skylines-from-stencil)
        (stencil . ,ly:beam::print)
 
        (meta . ((class . Spanner)
        (stencil . ,ly:text-interface::print)
        (text . ,(make-musicglyph-markup "scripts.rcomma"))
        (Y-offset . ,ly:breathing-sign::offset-callback)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (meta . ((class . Item)
                 (interfaces . (break-aligned-interface
                                breathing-sign-interface
        (extra-spacing-height . (0.2 . -0.2))
        (extra-spacing-width . (-0.5 . 0.5))
        (word-space . 0.0)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (meta . ((class . Item)
                 (interfaces . (chord-name-interface
                                font-interface
                        (next-note . (extra-space . 1.0))
                        (right-edge . (extra-space . 0.5))))
        (stencil . ,ly:clef::print)
-       (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
-       (Y-offset . ,ly:staff-symbol-referencer::callback)
+       (vertical-skylines . ,grob::always-vertical-skylines-from-stencil)
+       (Y-offset . ,staff-symbol-referencer::callback)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (meta . ((class . Item)
                  (object-callbacks . ((pure-Y-common . ,ly:axis-group-interface::calc-pure-y-common)
                                       (pure-relevant-grobs . ,ly:pure-from-neighbor-interface::calc-pure-relevant-grobs)))
        ;; todo: add X self alignment?
        (stencil . ,ly:text-interface::print)
        (X-offset . ,ly:self-alignment-interface::x-aligned-on-self)
-       (Y-offset . ,ly:side-position-interface::y-aligned-side)
+       (Y-offset . ,side-position-interface::y-aligned-side)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (meta . ((class . Item)
                 (interfaces . (font-interface
                                side-position-interface
                        (next-note . (extra-space . 1.0))
                        (right-edge . (extra-space . 0.5))))
        (stencil . ,ly:clef::print)
-       (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
-       (Y-offset . ,ly:staff-symbol-referencer::callback)
+       (vertical-skylines . ,grob::always-vertical-skylines-from-stencil)
+       (Y-offset . ,staff-symbol-referencer::callback)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (meta . ((class . Item)
                  (object-callbacks . ((pure-Y-common . ,ly:axis-group-interface::calc-pure-y-common)
                                       (pure-relevant-grobs . ,ly:pure-from-neighbor-interface::calc-pure-relevant-grobs)))
                        (next-note . (extra-space . 1.0))
                        (right-edge . (extra-space . 0.5))))
        (stencil . ,ly:clef::print)
-       (Y-offset . ,ly:staff-symbol-referencer::callback)
+       (Y-offset . ,staff-symbol-referencer::callback)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (meta . ((class . Item)
                  (object-callbacks . ((pure-Y-common . ,ly:axis-group-interface::calc-pure-y-common)
                                       (pure-relevant-grobs . ,ly:pure-from-neighbor-interface::calc-pure-relevant-grobs)))
                        (right-edge . (extra-space . 0.1))))
        (stencil . ,ly:custos::print)
        (style . vaticana)
-       (Y-offset . ,ly:staff-symbol-referencer::callback)
+       (Y-offset . ,staff-symbol-referencer::callback)
        (meta . ((class . Item)
                 (interfaces  . (break-aligned-interface
                                 custos-interface
     (DotColumn
      . (
        (axes . (,X))
+       (chord-dots . #t)
        (direction . ,RIGHT)
        (positioning-done . ,ly:dot-column::calc-positioning-done)
        (X-extent . ,ly:axis-group-interface::width)
        (dot-count . ,dots::calc-dot-count)
        (staff-position . ,dots::calc-staff-position)
        (stencil . ,ly:dots::print)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (extra-spacing-height . (-0.5 . 0.5))
        (meta . ((class . Item)
                 (interfaces . (dots-interface
        (slash-negative-kern . 1.6)
        (slope . 1.0)
        (stencil . ,ly:percent-repeat-item-interface::double-percent)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (thickness . 0.48)
        (meta . ((class . Item)
                 (interfaces . (break-aligned-interface
                          (list ly:self-alignment-interface::centered-on-y-parent))
                        ,(ly:make-simple-closure
                          (list ly:self-alignment-interface::x-aligned-on-self)))))
-       (Y-offset . ,ly:side-position-interface::y-aligned-side)
+       (Y-offset . ,side-position-interface::y-aligned-side)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (meta . ((class . Item)
                 (interfaces . (font-interface
                                percent-repeat-interface
        (slash-negative-kern . 1.6)
        (slope . 1.0)
        (stencil . ,ly:percent-repeat-item-interface::beat-slash)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (thickness . 0.48)
        (meta . ((class . Item)
                 (interfaces . (font-interface
        (side-axis . ,Y)
        (slur-padding . 0.3)
        (staff-padding . 0.1)
-       (vertical-skylines . ,ly:grob::vertical-skylines-from-element-stencils)
+       (vertical-skylines . ,grob::always-vertical-skylines-from-element-stencils)
        (X-extent . ,ly:axis-group-interface::width)
-       (Y-extent . ,ly:axis-group-interface::height)
-       (Y-offset . ,ly:side-position-interface::y-aligned-side)
+       (Y-extent . ,axis-group-interface::height)
+       (Y-offset . ,side-position-interface::y-aligned-side)
        (meta . ((class . Spanner)
                 (object-callbacks . ((pure-Y-common . ,ly:axis-group-interface::calc-pure-y-common)
                                      (pure-relevant-grobs . ,ly:axis-group-interface::calc-pure-relevant-grobs)))
        (self-alignment-X . ,CENTER)
        (self-alignment-Y . ,CENTER)
        (stencil . ,ly:text-interface::print)
-       (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
+       (vertical-skylines . ,grob::always-vertical-skylines-from-stencil)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (X-offset . ,ly:self-alignment-interface::x-aligned-on-self)
-       (Y-offset . ,ly:self-alignment-interface::y-aligned-on-self)
+       (Y-offset . ,self-alignment-interface::y-aligned-on-self)
        (meta . ((class . Item)
                 (interfaces . (dynamic-interface
                                dynamic-text-interface
        (springs-and-rods . ,ly:spanner::set-spacing-rods)
        (stencil . ,ly:line-spanner::print)
        (style . dashed-line)
-       (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
+       (vertical-skylines . ,grob::unpure-vertical-skylines-from-stencil)
        (meta . ((class . Spanner)
                 (interfaces . (dynamic-interface
                                dynamic-text-spanner-interface
        (side-axis . ,Y)
        (stencil . ,ly:line-spanner::print)
        (style . line)
-       (Y-offset . ,ly:side-position-interface::y-aligned-side)
+       (Y-offset . ,side-position-interface::y-aligned-side)
        (meta . ((class . Spanner)
                 (interfaces . (episema-interface
                                font-interface
        (staff-padding . 0.5)
        (stencil . ,ly:text-interface::print)
        (text . ,fingering::calc-text)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (meta . ((class . Item)
                 (interfaces . (finger-interface
                                font-interface
        (stencil . ,ly:flag::print)
        (X-extent . ,ly:flag::width)
        (X-offset . ,ly:flag::calc-x-offset)
-       (Y-offset . ,ly:flag::calc-y-offset)
-       (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
+       (Y-offset . ,(ly:make-unpure-pure-container ly:flag::calc-y-offset ly:flag::pure-calc-y-offset))
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
+       (vertical-skylines . ,grob::always-vertical-skylines-from-stencil)
        (meta . ((class . Item)
                 (interfaces . (flag-interface
                                 font-interface))))))
        (stencil . ,fret-board::calc-stencil)
        (extra-spacing-height . (0.2 . -0.2))
        (extra-spacing-width . (-0.5 . 0.5))
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (meta . ((class . Item)
                 (interfaces . (chord-name-interface
                                font-interface
        (simple-Y . #t)
        (stencil . ,ly:line-spanner::print)
        (style . line)
-       (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
+       (vertical-skylines . ,grob::unpure-vertical-skylines-from-stencil)
        (X-extent . #f)
        (Y-extent . #f)
        (zigzag-width . 0.75)
        (stencil . ,ly:hairpin::print)
        (thickness . 1.0)
        (to-barline . #t)
-       (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
-       (Y-offset . ,ly:self-alignment-interface::y-aligned-on-self)
+       (vertical-skylines . ,grob::unpure-vertical-skylines-from-stencil)
+       (Y-extent . ,(grob::unpure-Y-extent-from-stencil ly:hairpin::pure-height))
+       (Y-offset . ,self-alignment-interface::y-aligned-on-self)
        (meta . ((class . Spanner)
                 (interfaces . (dynamic-interface
                                hairpin-interface
        (staff-padding . 0.2)
        (stencil . ,ly:horizontal-bracket::print)
        (thickness . 1.0)
-       (Y-offset . ,ly:side-position-interface::y-aligned-side)
+       (Y-offset . ,side-position-interface::y-aligned-side)
        (meta . ((class . Spanner)
                 (interfaces . (horizontal-bracket-interface
                                line-interface
        (side-axis . ,Y)
        (staff-padding . 0.5)
        (stencil . ,ly:text-interface::print)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (X-offset . ,ly:self-alignment-interface::x-aligned-on-self)
-       (Y-offset . ,ly:side-position-interface::y-aligned-side)
+       (Y-offset . ,side-position-interface::y-aligned-side)
        (meta . ((class . Item)
                 (interfaces . (font-interface
                                self-alignment-interface
                        (right-edge . (extra-space . 0.5))
                        (first-note . (fixed-space . 2.5))))
        (stencil . ,ly:key-signature-interface::print)
-       (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
+       (vertical-skylines . ,grob::always-vertical-skylines-from-stencil)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (extra-spacing-width . (0.0 . 1.0))
        (extra-spacing-height . ,pure-from-neighbor-interface::extra-spacing-height-including-staff)
-       (Y-offset . ,ly:staff-symbol-referencer::callback)
+       (Y-offset . ,staff-symbol-referencer::callback)
        (meta . ((class . Item)
                  (object-callbacks . ((pure-Y-common . ,ly:axis-group-interface::calc-pure-y-common)
                                       (pure-relevant-grobs . ,ly:pure-from-neighbor-interface::calc-pure-relevant-grobs)))
                        (right-edge . (extra-space . 0.5))
                        (first-note . (fixed-space . 2.5))))
        (stencil . ,ly:key-signature-interface::print)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (extra-spacing-width . (0.0 . 1.0))
        (extra-spacing-height . ,pure-from-neighbor-interface::extra-spacing-height-including-staff)
-       (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
-       (Y-offset . ,ly:staff-symbol-referencer::callback)
+       (vertical-skylines . ,grob::always-vertical-skylines-from-stencil)
+       (Y-offset . ,staff-symbol-referencer::callback)
        (meta . ((class . Item)
                  (object-callbacks . ((pure-Y-common . ,ly:axis-group-interface::calc-pure-y-common)
                                       (pure-relevant-grobs . ,ly:pure-from-neighbor-interface::calc-pure-relevant-grobs)))
                                pure-from-neighbor-interface
                                staff-symbol-referencer-interface))))))
 
+    (KievanLigature
+     . (
+       (springs-and-rods . ,ly:spanner::set-spacing-rods)
+       (stencil . ,ly:kievan-ligature::print)
+       (padding . 0.5)
+       (meta . ((class . Spanner)
+                (interfaces . (font-interface
+                               kievan-ligature-interface))))))
 
    (LaissezVibrerTie
      . (
        (stencil  . ,laissez-vibrer::print)
        (thickness . 1.0)
        (extra-spacing-height . (-0.5 . 0.5))
-       (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
+       (vertical-skylines . ,grob::always-vertical-skylines-from-stencil)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (meta . ((class . Item)
                 (interfaces . (semi-tie-interface))))))
 
        (minimum-length-fraction . 0.25)
        (springs-and-rods . ,ly:ledger-line-spanner::set-spacing-rods)
        (stencil . ,ly:ledger-line-spanner::print)
-       (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
+       (vertical-skylines . ,grob::unpure-vertical-skylines-from-stencil)
        (X-extent . #f)
        (Y-extent . #f)
        (meta . ((class . Spanner)
        (padding . 0.07)
        (springs-and-rods . ,ly:lyric-hyphen::set-spacing-rods)
        (stencil . ,ly:lyric-hyphen::print)
-       (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
+       (vertical-skylines . ,grob::unpure-vertical-skylines-from-stencil)
        (thickness . 1.3)
        (Y-extent . (0 . 0))
        (meta . ((class . Spanner)
        (text . ,(grob::calc-property-by-copy 'text))
        (word-space . 0.6)
        (skyline-horizontal-padding . 0.1)
-       (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
+       (vertical-skylines . ,grob::always-vertical-skylines-from-stencil)
        (X-offset . ,ly:self-alignment-interface::aligned-on-x-parent)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (meta . ((class . Item)
                 (interfaces . (font-interface
                                lyric-syllable-interface
        (staff-padding . 3)
        (stencil . ,ly:measure-grouping::print)
        (thickness . 1)
-       (Y-offset . ,ly:side-position-interface::y-aligned-side)
+       (Y-offset . ,side-position-interface::y-aligned-side)
        (meta . ((class . Spanner)
                 (interfaces . (measure-grouping-interface
                                side-position-interface))))))
        (padding . 0.8)
        (side-axis . ,Y)
        (stencil . ,ly:text-interface::print)
-       (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
-       (Y-offset . ,ly:side-position-interface::y-aligned-side)
+       (vertical-skylines . ,grob::always-vertical-skylines-from-stencil)
+       (Y-offset . ,side-position-interface::y-aligned-side)
        (X-offset . ,(ly:make-simple-closure
                      `(,+
                        ,(ly:make-simple-closure
        (self-alignment-X . ,LEFT)
        (break-align-symbols . (time-signature))
        (non-break-align-symbols . (multi-measure-rest-interface))
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (meta . ((class . Item)
                 (interfaces . (break-alignable-interface
                                font-interface
        (thick-thickness . 6.6)
        ;; See Wanske pp. 125
        (usable-duration-logs . ,(iota 4 -3))
-       (Y-extent . ,ly:multi-measure-rest::height)
-       (Y-offset . ,ly:staff-symbol-referencer::callback)
+       (Y-extent . ,(ly:make-unpure-pure-container ly:multi-measure-rest::height))
+       (Y-offset . ,staff-symbol-referencer::callback)
        (meta . ((class . Spanner)
                 (interfaces . (font-interface
                                multi-measure-interface
                          (list ly:self-alignment-interface::x-aligned-on-self))
                        ,(ly:make-simple-closure
                          (list ly:self-alignment-interface::x-centered-on-y-parent)))))
-       (Y-offset . ,ly:side-position-interface::y-aligned-side)
-       (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
+       (Y-offset . ,side-position-interface::y-aligned-side)
+       (vertical-skylines . ,grob::unpure-vertical-skylines-from-stencil)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (meta . ((class . Spanner)
                 (interfaces . (font-interface
                                multi-measure-interface
                          (list ly:self-alignment-interface::x-centered-on-y-parent))
                        ,(ly:make-simple-closure
                          (list ly:self-alignment-interface::x-aligned-on-self)))))
-       (Y-offset . ,ly:side-position-interface::y-aligned-side)
-       (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
+       (Y-offset . ,side-position-interface::y-aligned-side)
+       (vertical-skylines . ,grob::unpure-vertical-skylines-from-stencil)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (meta . ((class . Spanner)
                 (interfaces . (font-interface
                                multi-measure-interface
        (positioning-done . ,ly:note-collision-interface::calc-positioning-done)
        (prefer-dotted-right . #t)
        (X-extent . ,ly:axis-group-interface::width)
-       (Y-extent . ,ly:axis-group-interface::height)
+       (Y-extent . ,axis-group-interface::height)
        (meta . ((class . Item)
                 (object-callbacks . ((pure-Y-common . ,ly:axis-group-interface::calc-pure-y-common)
                                      (pure-relevant-grobs . ,ly:axis-group-interface::calc-pure-relevant-grobs)))
        (horizontal-skylines . ,ly:separation-item::calc-skylines)
        (skyline-vertical-padding . 0.15)
        (X-extent . ,ly:axis-group-interface::width)
-       (Y-extent . ,ly:axis-group-interface::height)
+       (Y-extent . ,axis-group-interface::height)
        (meta . ((class . Item)
                 (object-callbacks . ((pure-Y-common . ,ly:axis-group-interface::calc-pure-y-common)
                                      (pure-relevant-grobs . ,ly:axis-group-interface::calc-pure-relevant-grobs)))
        (stem-attachment . ,ly:note-head::calc-stem-attachment)
        (stencil . ,ly:note-head::print)
        (X-offset . ,ly:note-head::stem-x-shift)
-       (Y-offset . ,ly:staff-symbol-referencer::callback)
+       (Y-offset . ,staff-symbol-referencer::callback)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (meta . ((class . Item)
                 (interfaces . (font-interface
                                gregorian-ligature-interface
     (NoteName
      . (
        (stencil . ,ly:text-interface::print)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (meta . ((class . Item)
                 (interfaces . (font-interface
                                note-name-interface
                          (list ly:self-alignment-interface::x-aligned-on-self))
                        ,(ly:make-simple-closure
                          (list ly:self-alignment-interface::centered-on-x-parent)))))
-       (Y-offset . ,ly:side-position-interface::y-aligned-side)
-       (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
+       (Y-offset . ,side-position-interface::y-aligned-side)
+       (vertical-skylines . ,grob::always-vertical-skylines-from-stencil)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (meta . ((class . Item)
                 (interfaces . (font-interface
                                octavate-eight-interface
        (staff-padding . 1.0)
        (stencil . ,ly:ottava-bracket::print)
        (style . dashed-line)
-       (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
-       (Y-offset . ,ly:side-position-interface::y-aligned-side)
+       (vertical-skylines . ,grob::unpure-vertical-skylines-from-stencil)
+       (Y-offset . ,side-position-interface::y-aligned-side)
        (meta . ((class . Spanner)
                 (interfaces . (font-interface
                                horizontal-bracket-interface
                          (list ly:self-alignment-interface::x-centered-on-y-parent))
                        ,(ly:make-simple-closure
                          (list ly:self-alignment-interface::x-aligned-on-self)))))
-       (Y-offset . ,ly:side-position-interface::y-aligned-side)
+       (Y-offset . ,side-position-interface::y-aligned-side)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (meta . ((class . Spanner)
                 (interfaces . (font-interface
                                percent-repeat-interface
        (springs-and-rods . ,ly:spanner::set-spacing-rods)
        (stencil . ,ly:slur::print)
        (thickness . 1.1)
-       (vertical-skylines . ,ly:slur::vertical-skylines)
-       (Y-extent . ,ly:slur::height)
+       (vertical-skylines . ,(ly:make-unpure-pure-container ly:slur::vertical-skylines ly:grob::pure-simple-vertical-skylines-from-extents))
+       (Y-extent . ,slur::height)
        (meta . ((class . Spanner)
                 (interfaces . (slur-interface))))))
 
        (stencil . ,ly:piano-pedal-bracket::print)
        (style . line)
        (thickness .  1.0)
-       (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
+       (vertical-skylines . ,grob::unpure-vertical-skylines-from-stencil)
        (meta . ((class . Spanner)
                 (interfaces . (line-interface
                                piano-pedal-bracket-interface
        (padding . 0.8)
        (self-alignment-X . ,CENTER)
        (stencil . ,ly:text-interface::print)
-       (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
+       (vertical-skylines . ,grob::always-vertical-skylines-from-stencil)
        (X-offset . ,(ly:make-simple-closure
                      `(,+
                        ,(ly:make-simple-closure
                          (list ly:break-alignable-interface::self-align-callback))
                        ,(ly:make-simple-closure
                          (list ly:self-alignment-interface::x-aligned-on-self)))))
-       (Y-offset . ,ly:side-position-interface::y-aligned-side)
+       (Y-offset . ,side-position-interface::y-aligned-side)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (meta . ((class . Item)
                 (interfaces . (break-alignable-interface
                                font-interface
        (slash-negative-kern . 0.85)
        (slope . 1.7)
        (stencil . ,ly:percent-repeat-item-interface::beat-slash)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (thickness . 0.48)
        (meta . ((class . Item)
                 (interfaces . (percent-repeat-interface
        (stencil  . ,ly:tie::print)
        (thickness . 1.0)
        (extra-spacing-height . (-0.5 . 0.5))
-       (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
+       (vertical-skylines . ,grob::always-vertical-skylines-from-stencil)
        (meta . ((class . Item)
                 (interfaces . (semi-tie-interface))))))
 
        (minimum-distance . 0.25)
        (stencil . ,ly:rest::print)
        (X-extent . ,ly:rest::width)
-       (Y-extent . ,ly:rest::height)
-       (Y-offset . ,ly:rest::y-offset-callback)
-       (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
+       (Y-extent . ,(ly:make-unpure-pure-container ly:rest::height ly:rest::pure-height))
+       (Y-offset . ,(ly:make-unpure-pure-container ly:rest::y-offset-callback))
+       (vertical-skylines . ,grob::unpure-vertical-skylines-from-stencil)
        (meta . ((class . Item)
                 (interfaces . (font-interface
                                rest-interface
        (staff-padding . 0.25)
 
        (stencil . ,ly:script-interface::print)
-       (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
+       (vertical-skylines . ,grob::always-vertical-skylines-from-stencil)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (X-offset . ,script-interface::calc-x-offset)
-       (Y-offset . ,ly:side-position-interface::y-aligned-side)
+       (Y-offset . ,side-position-interface::y-aligned-side)
        (meta . ((class . Item)
                 (interfaces . (font-interface
                                script-interface
        (springs-and-rods . ,ly:spanner::set-spacing-rods)
        (stencil . ,ly:slur::print)
        (thickness . 1.2)
-       (vertical-skylines . ,ly:slur::vertical-skylines)
-       (Y-extent . ,ly:slur::height)
+       (vertical-skylines . ,(ly:make-unpure-pure-container ly:slur::vertical-skylines ly:grob::pure-simple-vertical-skylines-from-extents))
+       (Y-extent . ,slur::height)
        (meta . ((class . Spanner)
                 (interfaces . (slur-interface))))))
 
        (padding . 0.0) ;; padding relative to SostenutoPedalLineSpanner
        (self-alignment-X . ,CENTER)
        (stencil . ,ly:text-interface::print)
-       (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
+       (vertical-skylines . ,grob::always-vertical-skylines-from-stencil)
        (X-offset . ,ly:self-alignment-interface::x-aligned-on-self)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (meta . ((class . Item)
                 (interfaces . (font-interface
                                piano-pedal-script-interface
        (padding . 1.2)
        (side-axis . ,Y)
        (staff-padding . 1.0)
-       (vertical-skylines . ,ly:grob::vertical-skylines-from-element-stencils)
+       (vertical-skylines . ,grob::always-vertical-skylines-from-element-stencils)
        (X-extent . ,ly:axis-group-interface::width)
-       (Y-extent . ,ly:axis-group-interface::height)
-       (Y-offset . ,ly:side-position-interface::y-aligned-side)
+       (Y-extent . ,axis-group-interface::height)
+       (Y-offset . ,side-position-interface::y-aligned-side)
        (meta . ((class . Spanner)
                 (object-callbacks . ((pure-Y-common . ,ly:axis-group-interface::calc-pure-y-common)
                                      (pure-relevant-grobs . ,ly:axis-group-interface::calc-pure-relevant-grobs)))
     (SpanBar
      . (
        (allow-span-bar . #t)
-       (bar-extent . ,ly:axis-group-interface::height)
+       (bar-extent . ,axis-group-interface::height)
        (before-line-breaking . ,ly:span-bar::before-line-breaking)
        (break-align-symbol . staff-bar)
        (cross-staff . #t)
      . (
         (X-extent . ,grob::x-parent-width)
        (extra-spacing-height . ,pure-from-neighbor-interface::extra-spacing-height)
-       (Y-extent . #f)
+       ; we want this to be ignored, so empty, but the extra spacing height
+       ; should preserve the span bar's presence for horizontal spacing
+       (Y-extent . ,pure-from-neighbor-interface::unobtrusive-height)
        (meta . ((class . Item)
                 (object-callbacks . ((pure-Y-common . ,ly:axis-group-interface::calc-pure-y-common)
                                      (pure-relevant-grobs . ,ly:pure-from-neighbor-interface::calc-pure-relevant-grobs)))
        (ledger-line-thickness . (1.0 . 0.1))
        (line-count . 5)
        (stencil . ,ly:staff-symbol::print)
-       (Y-extent . ,ly:staff-symbol::height)
+       (Y-extent . ,(ly:make-unpure-pure-container ly:staff-symbol::height))
        (meta . ((class . Spanner)
                 (interfaces . (staff-symbol-interface))))))
 
        (side-axis . ,X)
        (stencil . ,ly:text-interface::print)
        (X-offset . ,ly:side-position-interface::x-aligned-side)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (meta . ((class . Item)
                 (interfaces . (font-interface
                                side-position-interface
 
        (direction . ,ly:stem::calc-direction)
        (duration-log . ,stem::calc-duration-log)
-        (length . ,ly:stem::calc-length)
+        (length . ,(ly:make-unpure-pure-container ly:stem::calc-length ly:stem::pure-calc-length))
        (neutral-direction . ,DOWN)
        (positioning-done . ,ly:stem::calc-positioning-done)
        (stem-info . ,ly:stem::calc-stem-info)
-       (stem-begin-position . ,ly:stem::calc-stem-begin-position)
+       (stem-begin-position . ,(ly:make-unpure-pure-container ly:stem::calc-stem-begin-position ly:stem::pure-calc-stem-begin-position))
        (stencil . ,ly:stem::print)
        (thickness . 1.3)
        (X-extent . ,ly:stem::width)
        (X-offset . ,ly:stem::offset-callback)
-       (Y-extent . ,ly:stem::height)
-       (Y-offset . ,ly:staff-symbol-referencer::callback)
+       (Y-extent . ,(ly:make-unpure-pure-container ly:stem::height ly:stem::pure-height))
+       (Y-offset . ,staff-symbol-referencer::callback)
        (meta . ((class . Item)
                 (interfaces . (stem-interface))))))
 
        (stencil . ,ly:stem-tremolo::print)
        (style . ,ly:stem-tremolo::calc-style)
        (X-extent . ,ly:stem-tremolo::width)
+       (Y-extent . ,(grob::unpure-Y-extent-from-stencil ly:stem-tremolo::pure-height))
        (X-offset . ,(ly:make-simple-closure
                      `(,+
                        ,(ly:make-simple-closure
                          (list ly:self-alignment-interface::centered-on-x-parent))
                        ,(ly:make-simple-closure
                          (list ly:self-alignment-interface::x-aligned-on-self)))))
-       (Y-offset . ,ly:stem-tremolo::calc-y-offset)
+        (Y-offset . ,(ly:make-unpure-pure-container ly:stem-tremolo::calc-y-offset ly:stem-tremolo::pure-calc-y-offset))
        (meta . ((class . Item)
                 (interfaces . (self-alignment-interface
                                 stem-tremolo-interface))))))
        (staff-padding . 0.5)
        (stencil . ,print-circled-text-callback)
        (text . ,string-number::calc-text)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (meta . ((class . Item)
                 (interfaces . (font-interface
                                self-alignment-interface
        (staff-padding . 0.5)
        (stencil . ,ly:text-interface::print)
        (text . ,stroke-finger::calc-text)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (meta . ((class . Item)
                 (interfaces . (font-interface
                                self-alignment-interface
        (padding . 0.0)  ;; padding relative to SustainPedalLineSpanner
        (self-alignment-X . ,CENTER)
        (stencil . ,ly:sustain-pedal::print)
-       (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
+       (vertical-skylines . ,grob::always-vertical-skylines-from-stencil)
        (X-offset . ,ly:self-alignment-interface::x-aligned-on-self)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (meta . ((class . Item)
                 (interfaces . (font-interface
                                piano-pedal-interface
        (padding . 1.2)
        (side-axis . ,Y)
        (staff-padding . 1.2)
-       (vertical-skylines . ,ly:grob::vertical-skylines-from-element-stencils)
+       (vertical-skylines . ,grob::always-vertical-skylines-from-element-stencils)
        (X-extent . ,ly:axis-group-interface::width)
-       (Y-extent . ,ly:axis-group-interface::height)
-       (Y-offset . ,ly:side-position-interface::y-aligned-side)
+       (Y-extent . ,axis-group-interface::height)
+       (Y-offset . ,side-position-interface::y-aligned-side)
        (meta . ((class . Spanner)
                 (object-callbacks . ((pure-Y-common . ,ly:axis-group-interface::calc-pure-y-common)
                                      (pure-relevant-grobs . ,ly:axis-group-interface::calc-pure-relevant-grobs)))
        (skyline-horizontal-padding . 1.0)
        (vertical-skylines . ,ly:axis-group-interface::calc-skylines)
        (X-extent . ,ly:axis-group-interface::width)
-       (Y-extent . ,ly:system::height)
+       (Y-extent . ,(ly:make-unpure-pure-container ly:system::height ly:system::calc-pure-height))
        (meta . ((class . System)
                 (object-callbacks . ((footnotes-before-line-breaking . ,ly:system::footnotes-before-line-breaking)
                                      (footnotes-after-line-breaking . ,ly:system::footnotes-after-line-breaking)
        (stencil . ,tab-note-head::print)
        (whiteout . #t)
        (X-offset . ,ly:self-alignment-interface::x-aligned-on-self)
-       (Y-offset . ,ly:staff-symbol-referencer::callback)
+       (Y-offset . ,staff-symbol-referencer::callback)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (meta . ((class . Item)
                 (interfaces  . (font-interface
                                 note-head-interface
        (slur-padding . 0.5)
        (staff-padding . 0.5)
        (stencil . ,ly:text-interface::print)
-       (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
+       (vertical-skylines . ,grob::always-vertical-skylines-from-stencil)
        ;; todo: add X self alignment?
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (X-offset . ,ly:self-alignment-interface::x-aligned-on-self)
-       (Y-offset . ,ly:side-position-interface::y-aligned-side)
+       (Y-offset . ,side-position-interface::y-aligned-side)
        (meta . ((class . Item)
                 (interfaces . (font-interface
                                instrument-specific-markup-interface
        (staff-padding . 0.8)
        (stencil . ,ly:line-spanner::print)
        (style . dashed-line)
-       (Y-offset . ,ly:side-position-interface::y-aligned-side)
+       (Y-offset . ,side-position-interface::y-aligned-side)
 
        (meta . ((class . Spanner)
                 (interfaces . (font-interface
        (neutral-direction . ,UP)
        (springs-and-rods . ,ly:spanner::set-spacing-rods)
        (stencil . ,ly:tie::print)
-       (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
+       (vertical-skylines . ,grob::unpure-vertical-skylines-from-stencil)
        (thickness . 1.2)
        (meta . ((class . Spanner)
                 (interfaces . (tie-interface))))))
                        (right-edge . (extra-space . 0.5))
                        (staff-bar . (minimum-space . 2.0))))
        (stencil . ,ly:time-signature::print)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (style . C)
        (meta . ((class . Item)
                  (object-callbacks . ((pure-Y-common . ,ly:axis-group-interface::calc-pure-y-common)
        (side-axis . ,X)
        (stencil . ,ly:accidental-interface::print)
        (X-offset . ,ly:side-position-interface::x-aligned-side)
-       (Y-extent . ,ly:accidental-interface::height)
+       (Y-extent . ,accidental-interface::height)
        (meta . ((class . Item)
                 (interfaces . (accidental-interface
                                font-interface
        (stencil . ,parenthesize-elements)
        (stencils . ,parentheses-item::calc-parenthesis-stencils)
        (X-offset . ,ly:side-position-interface::x-aligned-side)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (meta . ((class . Item)
                 (interfaces . (axis-group-interface
                                font-interface
        (duration-log . 2)
        (font-size . -4)
        (stencil . ,ly:note-head::print)
-       (Y-offset . ,ly:staff-symbol-referencer::callback)
+       (Y-offset . ,staff-symbol-referencer::callback)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (meta . ((class . Item)
                 (interfaces . (font-interface
                                ledgered-interface
        (staff-padding . 1.0)
        (stencil . ,ly:line-spanner::print)
        (style . trill)
-       (Y-offset . ,ly:side-position-interface::y-aligned-side)
+       (Y-offset . ,side-position-interface::y-aligned-side)
        (meta . ((class . Spanner)
                 (interfaces . (font-interface
                                line-interface
        (staff-padding . 0.25)
        (stencil . ,ly:tuplet-bracket::print)
        (thickness . 1.6)
-       (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
+       (vertical-skylines . ,grob::unpure-vertical-skylines-from-stencil)
        (X-positions . ,ly:tuplet-bracket::calc-x-positions)
 
        (meta . ((class . Spanner)
        (padding . 0.0)  ;; padding relative to UnaCordaPedalLineSpanner
        (self-alignment-X . ,CENTER)
        (stencil . ,ly:text-interface::print)
-       (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
+       (vertical-skylines . ,grob::always-vertical-skylines-from-stencil)
+       (Y-extent . ,grob::always-Y-extent-from-stencil)
        (X-offset . ,ly:self-alignment-interface::x-aligned-on-self)
        (meta . ((class . Item)
                 (interfaces . (font-interface
        (padding . 1.2)
        (side-axis . ,Y)
        (staff-padding . 1.2)
-       (vertical-skylines . ,ly:grob::vertical-skylines-from-element-stencils)
+       (vertical-skylines . ,grob::always-vertical-skylines-from-element-stencils)
        (X-extent . ,ly:axis-group-interface::width)
-       (Y-extent . ,ly:axis-group-interface::height)
-       (Y-offset . ,ly:side-position-interface::y-aligned-side)
+       (Y-extent . ,axis-group-interface::height)
+       (Y-offset . ,side-position-interface::y-aligned-side)
        (meta . ((class . Spanner)
                 (object-callbacks . ((pure-Y-common . ,ly:axis-group-interface::calc-pure-y-common)
                                      (pure-relevant-grobs . ,ly:axis-group-interface::calc-pure-relevant-grobs)))
        (stacking-dir . -1)
        (vertical-skylines . ,ly:axis-group-interface::combine-skylines)
        (X-extent . ,ly:axis-group-interface::width)
-       (Y-extent . ,ly:axis-group-interface::height)
+       (Y-extent . ,axis-group-interface::height)
        (meta . ((class . Spanner)
                 (object-callbacks . ((Y-common . ,ly:axis-group-interface::calc-y-common)
                                      (pure-relevant-grobs . ,ly:axis-group-interface::calc-pure-relevant-grobs)
                                        (padding . 1)))
        (nonstaff-unrelatedstaff-spacing . ((padding . 0.5)))
        (outside-staff-placement-directive . left-to-right-polite)
-       (staff-staff-spacing . ,ly:axis-group-interface::calc-staff-staff-spacing)
+       (staff-staff-spacing . ,(ly:make-unpure-pure-container ly:axis-group-interface::calc-staff-staff-spacing ly:axis-group-interface::calc-pure-staff-staff-spacing))
        (stencil . ,ly:axis-group-interface::print)
        (skyline-horizontal-padding . 0.1)
        (vertical-skylines . ,ly:hara-kiri-group-spanner::calc-skylines)
        (X-extent . ,ly:axis-group-interface::width)
-       (Y-extent . ,ly:hara-kiri-group-spanner::y-extent)
+       (Y-extent . ,(ly:make-unpure-pure-container ly:hara-kiri-group-spanner::y-extent ly:hara-kiri-group-spanner::pure-height))
        (Y-offset . ,ly:hara-kiri-group-spanner::force-hara-kiri-callback)
        (meta . ((class . Spanner)
                 (object-callbacks . (
        (stencil . ,ly:volta-bracket-interface::print)
        (thickness . 1.6) ;; line-thickness
        (word-space . 0.6)
-       (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
+       (vertical-skylines . ,grob::unpure-vertical-skylines-from-stencil)
+       (Y-extent . ,(grob::unpure-Y-extent-from-stencil volta-bracket-interface::pure-height))
        (meta . ((class . Spanner)
                 (interfaces . (font-interface
                                horizontal-bracket-interface
        (outside-staff-priority . 600)
        (padding . 1)
        (side-axis . ,Y)
-       (vertical-skylines . ,ly:grob::vertical-skylines-from-element-stencils)
+       (vertical-skylines . ,grob::always-vertical-skylines-from-element-stencils)
        (X-extent . ,ly:axis-group-interface::width)
-       (Y-extent . ,ly:axis-group-interface::height)
-        (Y-offset . ,ly:side-position-interface::y-aligned-side)
+       (Y-extent . ,axis-group-interface::height)
+        (Y-offset . ,side-position-interface::y-aligned-side)
        (meta . ((class . Spanner)
                 (object-callbacks . ((pure-Y-common . ,ly:axis-group-interface::calc-pure-y-common)
                                      (pure-relevant-grobs . ,ly:axis-group-interface::calc-pure-relevant-grobs)))
      all-grob-descriptions)
 
 (set! all-grob-descriptions (sort all-grob-descriptions alist<?))
-
-(define (volta-bracket-interface::pure-height grob start end)
-  (let ((edge-height (ly:grob-property grob 'edge-height)))
-    (if (number-pair? edge-height)
-       (let ((smaller (min (car edge-height) (cdr edge-height)))
-             (larger (max (car edge-height) (cdr edge-height))))
-         (interval-union '(0 . 0) (cons smaller larger)))
-       '(0 . 0))))
-
-(define pure-print-callbacks
-  (list
-   fret-board::calc-stencil
-   note-head::brew-ez-stencil
-   print-circled-text-callback
-   laissez-vibrer::print
-   lyric-text::print
-   ly:bar-line::print
-   ly:mensural-ligature::brew-ligature-primitive
-   ly:note-head::print
-   ly:dots::print
-   ly:clef::print
-   ly:flag::print
-   ly:time-signature::print
-   default-flag
-   normal-flag
-   mensural-flag
-   no-flag
-   modern-straight-flag
-   old-straight-flag
-   ly:key-signature-interface::print
-   ly:percent-repeat-item-interface::beat-slash
-   ly:text-interface::print
-   ly:script-interface::print
-   ly:sustain-pedal::print))
-
-;; Sometimes we have grobs with (Y-extent . ,ly:grob::stencil-height)
-;; and the print function is not pure, but there is a easy way to
-;; figure out the Y-extent from the print function.
-(define pure-print-to-height-conversions
-  `(
-    (,ly:arpeggio::print . ,ly:arpeggio::pure-height)
-    (,ly:arpeggio::brew-chord-bracket . ,ly:arpeggio::pure-height)
-    (,ly:arpeggio::brew-chord-slur . ,ly:arpeggio::pure-height)
-    (,ly:hairpin::print . ,ly:hairpin::pure-height)
-    (,ly:stem-tremolo::print . ,ly:stem-tremolo::pure-height)
-    (,ly:volta-bracket-interface::print . ,volta-bracket-interface::pure-height)))
-
-;; ly:grob::stencil-extent is safe if the print callback is safe too
-(define (pure-stencil-height grob start stop)
-  (let* ((sten (ly:grob-property-data grob 'stencil))
-        (pure-height-callback (assoc-get sten pure-print-to-height-conversions)))
-    (cond ((or
-           (ly:stencil? sten)
-           (memq sten pure-print-callbacks))
-          (ly:grob::stencil-height grob))
-         ((procedure? pure-height-callback)
-          (pure-height-callback grob start stop))
-         (else
-          '(0 . 0)))))
-
-;; Sometimes, a pure callback will be chained to a non-pure callback via
-;; chain_offset_callback, in which case this provides a default by simply
-;; passing through the value from the pure callback.
-(define (pure-chain-offset-callback grob start end prev-offset) prev-offset)
-
-(define pure-conversions-alist
-  `(
-    (,ly:accidental-interface::height . ,ly:accidental-interface::pure-height)
-    (,ly:axis-group-interface::calc-staff-staff-spacing . ,ly:axis-group-interface::calc-pure-staff-staff-spacing)
-    (,ly:axis-group-interface::height . ,ly:axis-group-interface::pure-height)
-    (,ly:beam::rest-collision-callback . ,ly:beam::pure-rest-collision-callback)
-    (,ly:flag::calc-y-offset . ,ly:flag::pure-calc-y-offset)
-    (,ly:grob::horizontal-skylines-from-stencil . ,ly:grob::pure-simple-horizontal-skylines-from-extents)
-    (,ly:grob::horizontal-skylines-from-element-stencils . ,ly:grob::pure-simple-horizontal-skylines-from-extents)
-    (,ly:grob::simple-horizontal-skylines-from-extents . ,ly:grob::pure-simple-horizontal-skylines-from-extents)
-    (,ly:grob::simple-vertical-skylines-from-extents . ,ly:grob::pure-simple-vertical-skylines-from-extents)
-    (,ly:grob::stencil-height . ,pure-stencil-height)
-    (,ly:grob::vertical-skylines-from-stencil . ,ly:grob::pure-simple-vertical-skylines-from-extents)
-    (,ly:grob::vertical-skylines-from-element-stencils . ,ly:grob::pure-simple-vertical-skylines-from-extents)
-    (,ly:hara-kiri-group-spanner::y-extent . ,ly:hara-kiri-group-spanner::pure-height)
-    (,ly:rest-collision::force-shift-callback-rest . ,pure-chain-offset-callback)
-    (,ly:rest::height . ,ly:rest::pure-height)
-    (,ly:self-alignment-interface::y-aligned-on-self . ,ly:self-alignment-interface::pure-y-aligned-on-self)
-    (,ly:side-position-interface::y-aligned-side . ,ly:side-position-interface::pure-y-aligned-side)
-    (,ly:slur::height . ,ly:slur::pure-height)
-    (,ly:slur::outside-slur-callback . ,ly:slur::pure-outside-slur-callback)
-    (,ly:stem::calc-stem-begin-position . ,ly:stem::pure-calc-stem-begin-position)
-    (,ly:stem::calc-stem-end-position . ,ly:stem::pure-calc-stem-end-position)
-    (,ly:stem::calc-length . ,ly:stem::pure-calc-length)
-    (,ly:stem::height . ,ly:stem::pure-height)
-    (,ly:stem-tremolo::calc-y-offset . ,ly:stem-tremolo::pure-calc-y-offset)
-    (,ly:system::height . ,ly:system::calc-pure-height)))
-
-(define pure-functions
-  (list
-   ly:accidental-interface::horizontal-skylines
-   parenthesize-elements
-   laissez-vibrer::print
-   ly:multi-measure-rest::height
-   ly:rest::y-offset-callback
-   ly:staff-symbol-referencer::callback
-   ly:staff-symbol::height))
-
-(define-public (pure-relevant? grob)
-  (let ((extent-callback (ly:grob-property-data grob 'Y-extent)))
-    (not (eq? #f
-             (or
-               (ly:unpure-pure-container? extent-callback)
-              (pair? extent-callback)
-              (memq extent-callback pure-functions)
-              (and
-               (pair? (assq extent-callback pure-conversions-alist))
-               (let ((stencil (ly:grob-property-data grob 'stencil)))
-                 (or
-                  (not (eq? extent-callback ly:grob::stencil-height))
-                  (memq stencil pure-print-callbacks)
-                  (assq stencil pure-print-to-height-conversions)
-                  (ly:stencil? stencil)))))))))
-
-;; hideous code dup below - to be cleaned up when call pure functino
-;; is eliminated and lilypond works entirely from unpure-pure-containers
-
-(define-public (call-pure-function unpure args start end)
-  (if (ly:unpure-pure-container? unpure)
-      (let ((unpure (ly:unpure-pure-container-pure-part unpure)))
-        (if (ly:simple-closure? unpure)
-          (ly:eval-simple-closure (car args) unpure start end)
-          (if (not (procedure? unpure))
-              unpure
-              (apply unpure
-                     (append
-                       (list (car args) start end)
-                       (cdr args))))))
-      (if (ly:simple-closure? unpure)
-          (ly:eval-simple-closure (car args) unpure start end)
-          (if (not (procedure? unpure))
-              unpure
-              (if (memq unpure pure-functions)
-                  (apply unpure args)
-                  (let ((pure (assq unpure pure-conversions-alist)))
-                    (if pure
-                        (apply (cdr pure)
-                               (append
-                                (list (car args) start end)
-                                (cdr args))))))))))
index 92b4b704eb08d1778ba2b5794016799408d5a3da..251415d85b522a9cdaa7d78647be249c7290ebc4 100755 (executable)
@@ -961,6 +961,31 @@ samplePath =
       X-extent
       Y-extent)))
 
+(define-markup-list-command (score-lines layout props score)
+  (ly:score?)
+  "
+This is the same as the @code{\\score} markup but delivers its
+systems as a list of lines.  This is not usually called directly by
+the user.  Instead, it is called when the parser encounters
+@code{\\score} in a context where only markup lists are allowed.  When
+used as the argument of a toplevel @code{\\markuplist}, the result can
+be split across pages."
+  (let ((output (ly:score-embedded-format score layout)))
+
+    (if (ly:music-output? output)
+        (map
+         (lambda (paper-system)
+           ;; shift such that the refpoint of the bottom staff of
+           ;; the first system is the baseline of the score
+           (ly:stencil-translate-axis
+            (paper-system-stencil paper-system)
+            (- (car (paper-system-staff-extents paper-system)))
+            Y))
+         (vector->list (ly:paper-score-paper-systems output)))
+       (begin
+         (ly:warning (_"no systems found in \\score markup, does it have a \\layout block?"))
+          '()))))
+
 (define-markup-command (score layout props score)
   (ly:score?)
   #:category music
@@ -968,7 +993,9 @@ samplePath =
   "
 @cindex inserting music into text
 
-Inline an image of music.
+Inline an image of music.  The reference point (usually the middle
+staff line) of the lowest staff in the top system is placed on the
+baseline.
 
 @lilypond[verbatim,quote]
 \\markup {
@@ -1011,16 +1038,8 @@ Inline an image of music.
   }
 }
 @end lilypond"
-  (let ((output (ly:score-embedded-format score layout)))
-
-    (if (ly:music-output? output)
-       (stack-stencils Y DOWN baseline-skip
-                       (map paper-system-stencil
-                            (vector->list
-                             (ly:paper-score-paper-systems output))))
-       (begin
-         (ly:warning (_"no systems found in \\score markup, does it have a \\layout block?"))
-         empty-stencil))))
+  (stack-stencils Y DOWN baseline-skip
+                  (score-lines-markup-list layout props score)))
 
 (define-markup-command (null layout props)
   ()
index 5b39cc46ffdfc91255c64951a461bd974ecbf2e2..c6b8dd2a9ea3378e2794aa6931a9a2efd82ba38e 100644 (file)
@@ -144,27 +144,23 @@ duration (base note length and dot count), as a number of whole notes."
 
 (define-public (collect-music-aux score-handler parser music)
   (define (music-property symbol)
-    (let ((value (ly:music-property music symbol)))
-      (if (not (null? value))
-         value
-         #f)))
+    (ly:music-property music symbol #f))
   (cond ((music-property 'page-marker)
         ;; a page marker: set page break/turn permissions or label
-        (begin
-          (let ((label (music-property 'page-label)))
-            (if (symbol? label)
-                (score-handler (ly:make-page-label-marker label))))
-          (for-each (lambda (symbol)
-                      (let ((permission (music-property symbol)))
-                        (if (symbol? permission)
-                            (score-handler
-                             (ly:make-page-permission-marker symbol
-                                                             (if (eqv? 'forbid permission)
-                                                                 '()
-                                                                 permission))))))
-                    (list 'line-break-permission 'page-break-permission
-                          'page-turn-permission))))
-       ((not (music-property 'void))
+         (let ((label (music-property 'page-label)))
+           (if (symbol? label)
+               (score-handler (ly:make-page-label-marker label))))
+         (for-each (lambda (symbol)
+                     (let ((permission (music-property symbol)))
+                       (if (symbol? permission)
+                           (score-handler
+                            (ly:make-page-permission-marker symbol
+                                                            (if (eq? 'forbid permission)
+                                                                '()
+                                                                permission))))))
+                   '(line-break-permission page-break-permission
+                                           page-turn-permission)))
+        ((not (music-property 'void))
         ;; a regular music expression: make a score with this music
         ;; void music is discarded
         (score-handler (scorify-music music parser)))))
@@ -185,21 +181,16 @@ duration (base note length and dot count), as a number of whole notes."
 
 (define-public (scorify-music music parser)
   "Preprocess @var{music}."
-
-  (for-each (lambda (func)
-             (set! music (func music parser)))
-           toplevel-music-functions)
-
-  (ly:make-score music))
-
+  (ly:make-score
+   (fold (lambda (f m) (f m parser)) 
+         music
+         toplevel-music-functions)))
 
 (define (get-current-filename parser book)
   "return any suffix value for output filename allowing for settings by
 calls to bookOutputName function"
-  (let ((book-filename (paper-variable parser book 'output-filename)))
-    (if (not book-filename)
-       (ly:parser-output-name parser)
-       book-filename)))
+  (or (paper-variable parser book 'output-filename)
+      (ly:parser-output-name parser)))
 
 (define (get-current-suffix parser book)
   "return any suffix value for output filename allowing for settings by calls to
@@ -591,28 +582,27 @@ for comparisons."
   "Split LST into two lists at the first element that returns #f for
   (PRED previous_element element).  Return the two parts as a pair.
   Example: (split-at-predicate < '(1 2 3 2 1)) ==> ((1 2 3) . (2 1))"
-  (if (null? lst)
-      (list lst)
-      (let ((i (list-index (lambda (x y) (not (pred x y)))
-                          lst
-                          (cdr lst))))
-        (if i
-            (cons (take lst (1+ i)) (drop lst (1+ i)))
-            (list lst)))))
+  (let ((i (and (pair? lst)
+                (list-index (lambda (x y) (not (pred x y)))
+                            lst
+                            (cdr lst)))))
+    (if i
+        (call-with-values
+            (lambda () (split-at lst (1+ i)))
+          cons)
+        (list lst))))
 
 (define-public (split-list-by-separator lst pred)
   "Split @var{lst} at each element that satisfies @var{pred}, and return
 the parts (with the separators removed) as a list of lists.  For example,
 executing @samp{(split-list-by-separator '(a 0 b c 1 d) number?)} returns
 @samp{((a) (b c) (d))}."
-  (let loop ((result '()) (lst lst))
-    (if (and lst (not (null? lst)))
-        (loop
-          (append result
-                  (list (take-while (lambda (x) (not (pred x))) lst)))
-          (let ((tail (find-tail pred lst)))
-            (if tail (cdr tail) #f)))
-       result)))
+  (call-with-values (lambda () (break pred lst))
+    (lambda (head tail)
+      (cons head
+            (if (null? tail)
+                tail
+                (split-list-by-separator (cdr tail) pred))))))
 
 (define-public (offset-add a b)
   (cons (+ (car a) (car b))
@@ -706,15 +696,6 @@ right (@var{dir}=+1)."
 (define-public (reverse-interval iv)
   (cons (cdr iv) (car iv)))
 
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; boolean
-
-(define (lily-and a b)
-  (and a b))
-
-(define (lily-or a b)
-  (or a b))
-
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; coordinates
 
index e5e8cd93d67d871ef2be83499d2b572db9a5bee3..1c9353ff59a0750b9267424e39fc5be872ad419a 100644 (file)
@@ -458,6 +458,7 @@ messages into errors.")
     "define-note-names.scm"
     "c++.scm"
     "chord-entry.scm"
+    "skyline.scm"
     "stencil.scm"
     "define-markup-commands.scm"
     "markup.scm"
index bcb65588a4f576e89aafe33019940f3e4b998fa8..09f526b8af631dab96ac49bfff5ba4fcaf722278 100644 (file)
 
     (ly:text-interface::interpret-markup layout props text)))
 
+(define-public (grob::unpure-Y-extent-from-stencil pure-function)
+  "The unpure height will come from a stencil whereas the pure
+   height will come from @code{pure-function}."
+  (ly:make-unpure-pure-container ly:grob::stencil-height pure-function))
+
+(define-public grob::unpure-horizontal-skylines-from-stencil
+  (ly:make-unpure-pure-container
+    ly:grob::horizontal-skylines-from-stencil
+    ly:grob::pure-simple-horizontal-skylines-from-extents))
+
+(define-public grob::always-horizontal-skylines-from-stencil
+  (ly:make-unpure-pure-container
+    ly:grob::horizontal-skylines-from-stencil))
+
+(define-public grob::unpure-vertical-skylines-from-stencil
+  (ly:make-unpure-pure-container
+    ly:grob::vertical-skylines-from-stencil
+    ly:grob::pure-simple-vertical-skylines-from-extents))
+
+(define-public grob::always-vertical-skylines-from-stencil
+  (ly:make-unpure-pure-container
+    ly:grob::vertical-skylines-from-stencil))
+
+(define-public grob::always-vertical-skylines-from-element-stencils
+  (ly:make-unpure-pure-container
+    ly:grob::vertical-skylines-from-element-stencils
+    ly:grob::pure-vertical-skylines-from-element-stencils))
+
+(define-public grob::always-horizontal-skylines-from-element-stencils
+  (ly:make-unpure-pure-container
+    ly:grob::horizontal-skylines-from-element-stencils
+    ly:grob::pure-horizontal-skylines-from-element-stencils))
+
+;; Sometimes, in horizontal spacing, we want grobs to block other grobs.
+;; They thus need to have a non-empty height.  We give them a point height
+;; so that, minimally, they block grobs directly to the right of them.
+;; Often this is complimented by an extra-spacing-height.
+;; We don't, however, want these grobs to factor into vertical spacing
+;; decisions, so we make their unpure height #f.
+
+;; Using this as a callback for a grob's Y-extent promises
+;; that the grob's stencil does not depend on line-spacing.
+;; We use this promise to figure the space required by Clefs
+;; and such at the note-spacing stage.
+
+(define-public grob::always-Y-extent-from-stencil
+  (ly:make-unpure-pure-container ly:grob::stencil-height))
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; beam slope
 
 ;; side-position stuff
 
 (define-public (only-if-beamed g)
-  (reduce lily-or
-          #f
-          (map (lambda (x)
-                 (ly:grob? (ly:grob-object x 'beam)))
-               (ly:grob-array->list (ly:grob-object g
-                                                    'side-support-elements)))))
+  (any (lambda (x) (ly:grob? (ly:grob-object x 'beam)))
+       (ly:grob-array->list (ly:grob-object g 'side-support-elements))))
+
+(define-public side-position-interface::y-aligned-side
+  (ly:make-unpure-pure-container
+    ly:side-position-interface::y-aligned-side
+    ly:side-position-interface::pure-y-aligned-side))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; self-alignment stuff
+
+(define-public self-alignment-interface::y-aligned-on-self
+  (ly:make-unpure-pure-container
+    ly:self-alignment-interface::y-aligned-on-self
+    ly:self-alignment-interface::pure-y-aligned-on-self))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; staff symbol
+
+(define staff-symbol-referencer::callback
+  (ly:make-unpure-pure-container ly:staff-symbol-referencer::callback))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; note heads
@@ -451,6 +514,27 @@ and duration-log @var{log}."
                               10000000))))
     (coord-operation - from-neighbors height)))
 
+;; If there are neighbors, we place the height at their midpoint
+;; to avoid protrusion of this pure height out of the vertical
+;; axis group on either side.  This will minimize the impact of the
+;; grob on pure minimum translations.
+
+;; TODO - there is a double call to axis-group-interface::pure-height
+;; here and then in the extra-spacing-height function above. Can/should this
+;; be rolled into one?
+(define-public (pure-from-neighbor-interface::pure-height grob beg end)
+  (let* ((height (ly:axis-group-interface::pure-height
+                  grob
+                  0
+                  10000000))
+         (c (interval-center height)))
+    (if (interval-empty? height) empty-interval (cons c c))))
+
+;; Minimizes the impact of the height on vertical spacing while allowing
+;; it to appear in horizontal skylines of paper columns if necessary.
+(define-public pure-from-neighbor-interface::unobtrusive-height
+  (ly:make-unpure-pure-container #f pure-from-neighbor-interface::pure-height))
+
 (define-public (pure-from-neighbor-interface::account-for-span-bar grob)
   (let* ((esh (pure-from-neighbor-interface::extra-spacing-height grob))
          (hsb (ly:grob-property grob 'has-span-bar))
@@ -631,6 +715,11 @@ and duration-log @var{log}."
   (assoc-get (ly:grob-property grob 'alteration)
              standard-alteration-glyph-name-alist))
 
+(define-public accidental-interface::height
+  (ly:make-unpure-pure-container
+    ly:accidental-interface::height
+    ly:accidental-interface::pure-height))
+
 (define-public cancellation-glyph-name-alist
   '((0 . "accidentals.natural")))
 
@@ -768,6 +857,15 @@ and duration-log @var{log}."
       (- y-center (ly:grob-relative-coordinate me y-ref Y))))))
 
 
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; offset callbacks
+
+(define-public (pure-chain-offset-callback grob start end prev-offset)
+  "Sometimes, a chained offset callback is unpure and there is
+   no way to write a pure function that estimates its behavior.
+   In this case, we use a pure equivalent that will simply pass
+   the previous calculated offset value."
+  prev-offset)
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;
@@ -948,6 +1046,14 @@ between the two text elements."
     (ly:grob-property grob 'dot-placement-list))))
 
 
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; slurs
+
+(define-public slur::height
+  (ly:make-unpure-pure-container
+    ly:slur::height
+    ly:slur::pure-height))
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; scripts
 
@@ -1063,6 +1169,14 @@ between the two text elements."
      (interval-center extent))))
 
 
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; axis group interface
+
+(define-public axis-group-interface::height
+  (ly:make-unpure-pure-container
+    ly:axis-group-interface::height
+    ly:axis-group-interface::pure-height))
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; ambitus
 
@@ -1105,3 +1219,13 @@ between the two text elements."
 (define-public (laissez-vibrer::print grob)
  (ly:tie::print grob))
 
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; volta-bracket
+
+(define-public (volta-bracket-interface::pure-height grob start end)
+  (let ((edge-height (ly:grob-property grob 'edge-height)))
+    (if (number-pair? edge-height)
+       (let ((smaller (min (car edge-height) (cdr edge-height)))
+             (larger (max (car edge-height) (cdr edge-height))))
+         (interval-union '(0 . 0) (cons smaller larger)))
+       '(0 . 0))))
index 5a368dbe623b6bc772a623841ee88d4b4c91ae77..8269c77e1881e01cc6df806573ecaaa88ebe1226 100644 (file)
         (horizon-padding (and
                           (ly:grob? grob)
                           (ly:grob-property grob 'skyline-horizontal-padding 0)))
-        (padding-annotation (if next-system
+        (padding-annotation (if (skyline-pair-and-non-empty? next-system)
                                 (annotate-padding
                                   (- system-Y) system-X skyline (paper-system-extent system X)
                                   (- next-system-Y) next-system-X next-skyline (paper-system-extent next-system X)
diff --git a/scm/skyline.scm b/scm/skyline.scm
new file mode 100644 (file)
index 0000000..c4d1839
--- /dev/null
@@ -0,0 +1,25 @@
+;;;; This file is part of LilyPond, the GNU music typesetter.
+;;;;
+;;;; Copyright (C) 2013 Mike Solomon <mike@mikesolomon.org>
+;;;;
+;;;; 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/>.
+
+(define-public (skyline-pair::empty? skyp)
+  (and (ly:skyline-empty? (ly:skyline-pair::skyline skyp UP))
+       (ly:skyline-empty? (ly:skyline-pair::skyline skyp DOWN))))
+
+; checks if the pair is not null, and then if not empty
+(define-public (skyline-pair-and-non-empty? skyp)
+  (and (ly:skyline-pair? skyp)
+       (not (skyline-pair::empty? skyp))))