From 74e4d219b24ec6d6f28d663c0285418e6c8e122e Mon Sep 17 00:00:00 2001
From: Mike Solomon <mike@apollinemike.com>
Date: Tue, 5 Mar 2013 21:03:55 +0100
Subject: [PATCH] Uses only unpure-pure containers to articulate unpure-pure
 relationships (issue 3199)

Previously, LilyPond used several different lists in define-grobs.scm
to define relationships between unpure and pure functions.  This patch
eliminates these lists, using unpure-pure containers to articulate
these relationships.

The modifications required to implement this change are described below:

-) axis-group-interface.cc
A Scheme function is no longer needed to determine pure relevant grobs.
All grobs can have their Y-extents meaningfully pure-evaluated now. The
worst-case scenario is that they evaluate to false. Dead grobs, on the
other hand, are never pure relevant. The calls to is_live are the only
holdovers from the old pure-relevant? scheme function.

-) grob-closure.cc
We allow unpure-pure containers in simple closures.

-) grob-property.cc
call_pure_function no longer looks up a Scheme module. Because there are
no hard-coded lists in Scheme any more, the function is smaller and
writing it in C++ gets slight efficiency gains.

-) grob.cc
pure_stencil_height used to be a Scheme function in define-grobs.scm.
Because it is much simpler (it no longer makes references to lists defined
in Scheme), it can be implemented in C++.

-) pure-from-neighbor-engraver.cc
Similar to axis-group-interface.cc, the pure-relevant distinction is
no longer important.

-) side-position-interface.cc
In order to avoid issues with alterBroken, we only check pure properties
before line breaking.

-) simple-closure.cc
Simple closures were incorrectly evaluated when containing unpure-pure
containers. This rectifies that.

-) stencil-integral.cc
Several pure equivalent functions needed to be written for skylines.

-) define-grobs.scm
Multiple overrides must be changed to unpure-pure containers. Previous
hard-coded lists are all deleted and several functions moved to C++ (see
above).

-) output-lib.scm
Several common unpure-pure containers used in define-grobs.scm are
defined here. Several functions from define-grobs.scm pertaining to
grob offsets are moved to this file.
---
 input/regression/scheme-text-spanner.ly |   2 +-
 lily/axis-group-interface.cc            |  23 +-
 lily/beam-engraver.cc                   |   6 +-
 lily/grob-closure.cc                    |   5 +-
 lily/grob-property.cc                   |  33 +-
 lily/grob-scheme.cc                     |   3 +-
 lily/grob.cc                            |  30 +-
 lily/include/grob.hh                    |   4 +
 lily/lily-guile.cc                      |   2 +
 lily/melody-engraver.cc                 |  12 +-
 lily/pure-from-neighbor-engraver.cc     |   4 +-
 lily/rest-collision.cc                  |   6 +-
 lily/semi-tie-column.cc                 |   1 +
 lily/separation-item.cc                 |  17 +-
 lily/side-position-interface.cc         |  26 +-
 lily/simple-closure.cc                  |  18 +-
 lily/slur.cc                            |   6 +-
 lily/stencil-integral.cc                |  36 +-
 lily/system.cc                          |   6 +-
 ly/music-functions-init.ly              |   4 +-
 scm/define-grobs.scm                    | 438 +++++++++---------------
 scm/output-lib.scm                      | 126 ++++++-
 22 files changed, 465 insertions(+), 343 deletions(-)

diff --git a/input/regression/scheme-text-spanner.ly b/input/regression/scheme-text-spanner.ly
index 1e7598b25b..6a26177850 100644
--- a/input/regression/scheme-text-spanner.ly
+++ b/input/regression/scheme-text-spanner.ly
@@ -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 =
diff --git a/lily/axis-group-interface.cc b/lily/axis-group-interface.cc
index 1ed1f7f8fc..0d786c3a29 100644
--- a/lily/axis-group-interface.cc
+++ b/lily/axis-group-interface.cc
@@ -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;
diff --git a/lily/beam-engraver.cc b/lily/beam-engraver.cc
index a89435de68..00b9081b3e 100644
--- a/lily/beam-engraver.cc
+++ b/lily/beam-engraver.cc
@@ -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
diff --git a/lily/grob-closure.cc b/lily/grob-closure.cc
index 4f6c0adc81..4c63fe3c0c 100644
--- a/lily/grob-closure.cc
+++ b/lily/grob-closure.cc
@@ -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);
diff --git a/lily/grob-property.cc b/lily/grob-property.cc
index 9120aefdf2..f9773e5ec5 100644
--- a/lily/grob-property.cc
+++ b/lily/grob-property.cc
@@ -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;
 }
 
diff --git a/lily/grob-scheme.cc b/lily/grob-scheme.cc
index e5976a569b..9ae9c14fcb 100644
--- a/lily/grob-scheme.cc
+++ b/lily/grob-scheme.cc
@@ -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);
diff --git a/lily/grob.cc b/lily/grob.cc
index 8ece3cd6f9..a6b862e04e 100644
--- a/lily/grob.cc
+++ b/lily/grob.cc
@@ -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,11 +80,17 @@ 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)
@@ -488,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");
@@ -857,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)
diff --git a/lily/include/grob.hh b/lily/include/grob.hh
index a98b19a9f6..70c9c0a94e 100644
--- a/lily/include/grob.hh
+++ b/lily/include/grob.hh
@@ -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/lily-guile.cc b/lily/lily-guile.cc
index ddda518579..1ad0635d36 100644
--- a/lily/lily-guile.cc
+++ b/lily/lily-guile.cc
@@ -394,6 +394,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;
 
diff --git a/lily/melody-engraver.cc b/lily/melody-engraver.cc
index 0ebd132450..c6ab972c74 100644
--- a/lily/melody-engraver.cc
+++ b/lily/melody-engraver.cc
@@ -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;
 }
 
diff --git a/lily/pure-from-neighbor-engraver.cc b/lily/pure-from-neighbor-engraver.cc
index bfb5609253..24925d29b8 100644
--- a/lily/pure-from-neighbor-engraver.cc
+++ b/lily/pure-from-neighbor-engraver.cc
@@ -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 ());
 }
 
diff --git a/lily/rest-collision.cc b/lily/rest-collision.cc
index e2b0db5ef2..46435b73ad 100644
--- a/lily/rest-collision.cc
+++ b/lily/rest-collision.cc
@@ -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);
     }
 }
 
diff --git a/lily/semi-tie-column.cc b/lily/semi-tie-column.cc
index f47171fb5a..3dc8a2b0e6 100644
--- a/lily/semi-tie-column.cc
+++ b/lily/semi-tie-column.cc
@@ -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 "
diff --git a/lily/separation-item.cc b/lily/separation-item.cc
index 6ff2928072..8a32363eb4 100644
--- a/lily/separation-item.cc
+++ b/lily/separation-item.cc
@@ -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));
diff --git a/lily/side-position-interface.cc b/lily/side-position-interface.cc
index 49c6ece55a..095b8b49c3 100644
--- a/lily/side-position-interface.cc
+++ b/lily/side-position-interface.cc
@@ -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);
     }
 }
diff --git a/lily/simple-closure.cc b/lily/simple-closure.cc
index 0c5dca8e95..59f9fd995b 100644
--- a/lily/simple-closure.cc
+++ b/lily/simple-closure.cc
@@ -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?
diff --git a/lily/slur.cc b/lily/slur.cc
index eb9913dc16..0aa96c787d 100644
--- a/lily/slur.cc
+++ b/lily/slur.cc
@@ -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 ());
         }
diff --git a/lily/stencil-integral.cc b/lily/stencil-integral.cc
index 601893b5cb..58b2ff46ca 100644
--- a/lily/stencil-integral.cc
+++ b/lily/stencil-integral.cc
@@ -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);
 }
diff --git a/lily/system.cc b/lily/system.cc
index e3da76687d..b2e0d53a88 100644
--- a/lily/system.cc
+++ b/lily/system.cc
@@ -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);
                 }
             }
diff --git a/ly/music-functions-init.ly b/ly/music-functions-init.ly
index 2669cc6bfb..379eb933ba 100644
--- a/ly/music-functions-init.ly
+++ b/ly/music-functions-init.ly
@@ -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
diff --git a/scm/define-grobs.scm b/scm/define-grobs.scm
index ff02523046..effaf131fa 100644
--- a/scm/define-grobs.scm
+++ b/scm/define-grobs.scm
@@ -24,6 +24,7 @@
 
 ;; TODO: junk the meta field in favor of something more compact?
 
+
 (define-public all-grob-descriptions
   `(
     (Accidental
@@ -33,10 +34,10 @@
 	(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
@@ -115,7 +116,7 @@
 			(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)))
@@ -131,7 +132,7 @@
 	(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
@@ -153,8 +154,8 @@
 	(duration-log . 2)
 	(glyph-name . ,note-head::calc-glyph-name)
 	(stencil . ,ly:note-head::print)
-	(Y-offset . ,ly:staff-symbol-referencer::callback)
-	(Y-extent . ,grob::all-heights-from-stencil)
+	(Y-offset . ,staff-symbol-referencer::callback)
+	(Y-extent . ,grob::always-Y-extent-from-stencil)
 	(meta . ((class . Item)
 		 (interfaces . (ambitus-interface
 				font-interface
@@ -173,8 +174,9 @@
 	(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
@@ -229,7 +231,7 @@
 			(next-note . (semi-fixed-space . 0.9))
 			(right-edge . (extra-space . 0.0))))
 	(stencil . ,ly:bar-line::print)
-	(Y-extent . ,grob::all-heights-from-stencil)
+	(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)))
@@ -264,8 +266,8 @@
 			  (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-extent . ,grob::all-heights-from-stencil)
+	(Y-offset . ,side-position-interface::y-aligned-side)
+	(Y-extent . ,grob::always-Y-extent-from-stencil)
 	(meta .
 	      ((class . Item)
 	       (interfaces . (break-alignable-interface
@@ -277,7 +279,7 @@
     (BassFigure
      . (
 	(stencil . ,ly:text-interface::print)
-	(Y-extent . ,grob::all-heights-from-stencil)
+	(Y-extent . ,grob::always-Y-extent-from-stencil)
 	(meta . ((class . Item)
 		 (interfaces . (bass-figure-interface
 				font-interface
@@ -290,7 +292,7 @@
 	(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)))
@@ -305,8 +307,8 @@
 	(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)))
@@ -333,7 +335,7 @@
 	(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)))
@@ -408,7 +410,7 @@
 	(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)
@@ -507,7 +509,7 @@
 	(stencil . ,ly:text-interface::print)
 	(text . ,(make-musicglyph-markup "scripts.rcomma"))
 	(Y-offset . ,ly:breathing-sign::offset-callback)
-	(Y-extent . ,grob::all-heights-from-stencil)
+	(Y-extent . ,grob::always-Y-extent-from-stencil)
 	(meta . ((class . Item)
 		 (interfaces . (break-aligned-interface
 				breathing-sign-interface
@@ -523,7 +525,7 @@
 	(extra-spacing-height . (0.2 . -0.2))
 	(extra-spacing-width . (-0.5 . 0.5))
 	(word-space . 0.0)
-	(Y-extent . ,grob::all-heights-from-stencil)
+	(Y-extent . ,grob::always-Y-extent-from-stencil)
 	(meta . ((class . Item)
 		 (interfaces . (chord-name-interface
 				font-interface
@@ -548,9 +550,9 @@
 			(next-note . (extra-space . 1.0))
 			(right-edge . (extra-space . 0.5))))
 	(stencil . ,ly:clef::print)
-	(Y-extent . ,grob::all-heights-from-stencil)
-	(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)))
@@ -593,8 +595,8 @@
 	;; 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-extent . ,grob::all-heights-from-stencil)
+	(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
@@ -621,9 +623,9 @@
 			(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-extent . ,grob::all-heights-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)))
@@ -654,8 +656,8 @@
 			(next-note . (extra-space . 1.0))
 			(right-edge . (extra-space . 0.5))))
 	(stencil . ,ly:clef::print)
-	(Y-extent . ,grob::all-heights-from-stencil)
-	(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)))
@@ -676,7 +678,7 @@
 			(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
@@ -700,7 +702,7 @@
 	(dot-count . ,dots::calc-dot-count)
 	(staff-position . ,dots::calc-staff-position)
 	(stencil . ,ly:dots::print)
-	(Y-extent . ,grob::all-heights-from-stencil)
+	(Y-extent . ,grob::always-Y-extent-from-stencil)
 	(extra-spacing-height . (-0.5 . 0.5))
 	(meta . ((class . Item)
 		 (interfaces . (dots-interface
@@ -717,7 +719,7 @@
 	(slash-negative-kern . 1.6)
 	(slope . 1.0)
 	(stencil . ,ly:percent-repeat-item-interface::double-percent)
-	(Y-extent . ,grob::all-heights-from-stencil)
+	(Y-extent . ,grob::always-Y-extent-from-stencil)
 	(thickness . 0.48)
 	(meta . ((class . Item)
 		 (interfaces . (break-aligned-interface
@@ -741,8 +743,8 @@
 			  (list ly:self-alignment-interface::centered-on-y-parent))
 			,(ly:make-simple-closure
 			  (list ly:self-alignment-interface::x-aligned-on-self)))))
-	(Y-extent . ,grob::all-heights-from-stencil)
-	(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
@@ -758,7 +760,7 @@
 	(slash-negative-kern . 1.6)
 	(slope . 1.0)
 	(stencil . ,ly:percent-repeat-item-interface::beat-slash)
-	(Y-extent . ,grob::all-heights-from-stencil)
+	(Y-extent . ,grob::always-Y-extent-from-stencil)
 	(thickness . 0.48)
 	(meta . ((class . Item)
 		 (interfaces . (font-interface
@@ -777,10 +779,10 @@
 	(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)))
@@ -806,10 +808,10 @@
 	(self-alignment-X . ,CENTER)
 	(self-alignment-Y . ,CENTER)
 	(stencil . ,ly:text-interface::print)
-	(vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
-	(Y-extent . ,grob::all-heights-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
@@ -857,7 +859,7 @@
 	(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
@@ -886,7 +888,7 @@
 	(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
@@ -914,7 +916,7 @@
 	(staff-padding . 0.5)
 	(stencil . ,ly:text-interface::print)
 	(text . ,fingering::calc-text)
-	(Y-extent . ,grob::all-heights-from-stencil)
+	(Y-extent . ,grob::always-Y-extent-from-stencil)
 	(meta . ((class . Item)
 		 (interfaces . (finger-interface
 				font-interface
@@ -936,9 +938,9 @@
 	(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-extent . ,grob::all-heights-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))))))
@@ -991,7 +993,7 @@
 	(stencil . ,fret-board::calc-stencil)
 	(extra-spacing-height . (0.2 . -0.2))
 	(extra-spacing-width . (-0.5 . 0.5))
-	(Y-extent . ,grob::all-heights-from-stencil)
+	(Y-extent . ,grob::always-Y-extent-from-stencil)
 	(meta . ((class . Item)
 		 (interfaces . (chord-name-interface
 				font-interface
@@ -1018,7 +1020,7 @@
 	(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)
@@ -1076,8 +1078,9 @@
 	(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
@@ -1095,7 +1098,7 @@
 	(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
@@ -1128,9 +1131,9 @@
 	(side-axis . ,Y)
 	(staff-padding . 0.5)
 	(stencil . ,ly:text-interface::print)
-	(Y-extent . ,grob::all-heights-from-stencil)
+	(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
@@ -1154,11 +1157,11 @@
 			(right-edge . (extra-space . 0.5))
 			(first-note . (fixed-space . 2.5))))
 	(stencil . ,ly:key-signature-interface::print)
-	(Y-extent . ,grob::all-heights-from-stencil)
-	(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)))
@@ -1186,11 +1189,11 @@
 			(right-edge . (extra-space . 0.5))
 			(first-note . (fixed-space . 2.5))))
 	(stencil . ,ly:key-signature-interface::print)
-	(Y-extent . ,grob::all-heights-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)
-	(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)))
@@ -1219,8 +1222,8 @@
 	(stencil  . ,laissez-vibrer::print)
 	(thickness . 1.0)
 	(extra-spacing-height . (-0.5 . 0.5))
-	(vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
-	(Y-extent . ,grob::all-heights-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))))))
 
@@ -1240,7 +1243,7 @@
 	(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)
@@ -1312,7 +1315,7 @@
 	(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)
@@ -1345,9 +1348,9 @@
 	(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::all-heights-from-stencil)
+	(Y-extent . ,grob::always-Y-extent-from-stencil)
 	(meta . ((class . Item)
 		 (interfaces . (font-interface
 				lyric-syllable-interface
@@ -1384,7 +1387,7 @@
 	(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))))))
@@ -1415,8 +1418,8 @@
 	(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
@@ -1426,7 +1429,7 @@
 	(self-alignment-X . ,LEFT)
 	(break-align-symbols . (time-signature))
 	(non-break-align-symbols . (multi-measure-rest-interface))
-	(Y-extent . ,grob::all-heights-from-stencil)
+	(Y-extent . ,grob::always-Y-extent-from-stencil)
 	(meta . ((class . Item)
 		 (interfaces . (break-alignable-interface
 				font-interface
@@ -1447,8 +1450,8 @@
 	(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
@@ -1473,9 +1476,9 @@
 			  (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-extent . ,grob::all-heights-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
@@ -1497,9 +1500,9 @@
 			  (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-extent . ,grob::all-heights-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
@@ -1542,7 +1545,7 @@
 	(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)))
@@ -1557,7 +1560,7 @@
 	(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)))
@@ -1575,8 +1578,8 @@
 	(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-extent . ,grob::all-heights-from-stencil)
+	(Y-offset . ,staff-symbol-referencer::callback)
+	(Y-extent . ,grob::always-Y-extent-from-stencil)
 	(meta . ((class . Item)
 		 (interfaces . (font-interface
 				gregorian-ligature-interface
@@ -1592,7 +1595,7 @@
     (NoteName
      . (
 	(stencil . ,ly:text-interface::print)
-	(Y-extent . ,grob::all-heights-from-stencil)
+	(Y-extent . ,grob::always-Y-extent-from-stencil)
 	(meta . ((class . Item)
 		 (interfaces . (font-interface
 				note-name-interface
@@ -1625,9 +1628,9 @@
 			  (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-extent . ,grob::all-heights-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
@@ -1648,8 +1651,8 @@
 	(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
@@ -1723,8 +1726,8 @@
 			  (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-extent . ,grob::all-heights-from-stencil)
+	(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
@@ -1745,8 +1748,8 @@
 	(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))))))
 
@@ -1761,7 +1764,7 @@
 	(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
@@ -1783,15 +1786,15 @@
 	(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-extent . ,grob::all-heights-from-stencil)
+	(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
@@ -1805,7 +1808,7 @@
 	(slash-negative-kern . 0.85)
 	(slope . 1.7)
 	(stencil . ,ly:percent-repeat-item-interface::beat-slash)
-	(Y-extent . ,grob::all-heights-from-stencil)
+	(Y-extent . ,grob::always-Y-extent-from-stencil)
 	(thickness . 0.48)
 	(meta . ((class . Item)
 		 (interfaces . (percent-repeat-interface
@@ -1822,7 +1825,8 @@
 	(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))))))
 
@@ -1843,9 +1847,9 @@
 	(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
@@ -1875,10 +1879,10 @@
 	(staff-padding . 0.25)
 
 	(stencil . ,ly:script-interface::print)
-	(vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
-	(Y-extent . ,grob::all-heights-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
@@ -1911,8 +1915,8 @@
 	(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))))))
 
@@ -1924,9 +1928,9 @@
 	(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::all-heights-from-stencil)
+	(Y-extent . ,grob::always-Y-extent-from-stencil)
 	(meta . ((class . Item)
 		 (interfaces . (font-interface
 				piano-pedal-script-interface
@@ -1943,10 +1947,10 @@
 	(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)))
@@ -1969,7 +1973,7 @@
     (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)
@@ -1988,7 +1992,9 @@
      . (
         (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)))
@@ -2021,7 +2027,7 @@
 	(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))))))
 
@@ -2033,7 +2039,7 @@
 	(side-axis . ,X)
 	(stencil . ,ly:text-interface::print)
 	(X-offset . ,ly:side-position-interface::x-aligned-side)
-	(Y-extent . ,grob::all-heights-from-stencil)
+	(Y-extent . ,grob::always-Y-extent-from-stencil)
 	(meta . ((class . Item)
 		 (interfaces . (font-interface
 				side-position-interface
@@ -2079,17 +2085,17 @@
 
 	(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))))))
 
@@ -2110,13 +2116,14 @@
 	(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))))))
@@ -2134,7 +2141,7 @@
 	(staff-padding . 0.5)
 	(stencil . ,print-circled-text-callback)
 	(text . ,string-number::calc-text)
-	(Y-extent . ,grob::all-heights-from-stencil)
+	(Y-extent . ,grob::always-Y-extent-from-stencil)
 	(meta . ((class . Item)
 		 (interfaces . (font-interface
 				self-alignment-interface
@@ -2155,7 +2162,7 @@
 	(staff-padding . 0.5)
 	(stencil . ,ly:text-interface::print)
 	(text . ,stroke-finger::calc-text)
-	(Y-extent . ,grob::all-heights-from-stencil)
+	(Y-extent . ,grob::always-Y-extent-from-stencil)
 	(meta . ((class . Item)
 		 (interfaces . (font-interface
 				self-alignment-interface
@@ -2171,9 +2178,9 @@
 	(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::all-heights-from-stencil)
+	(Y-extent . ,grob::always-Y-extent-from-stencil)
 	(meta . ((class . Item)
 		 (interfaces . (font-interface
 				piano-pedal-interface
@@ -2191,10 +2198,10 @@
 	(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)))
@@ -2210,7 +2217,7 @@
 	(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)
@@ -2307,8 +2314,8 @@
 	(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-extent . ,grob::all-heights-from-stencil)
+	(Y-offset . ,staff-symbol-referencer::callback)
+	(Y-extent . ,grob::always-Y-extent-from-stencil)
 	(meta . ((class . Item)
 		 (interfaces  . (font-interface
 				 note-head-interface
@@ -2335,11 +2342,11 @@
 	(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::all-heights-from-stencil)
+	(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
@@ -2370,7 +2377,7 @@
 	(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
@@ -2410,7 +2417,7 @@
 	(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))))))
@@ -2441,7 +2448,7 @@
 			(right-edge . (extra-space . 0.5))
 			(staff-bar . (minimum-space . 2.0))))
 	(stencil . ,ly:time-signature::print)
-	(Y-extent . ,grob::all-heights-from-stencil)
+	(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)
@@ -2460,7 +2467,7 @@
 	(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
@@ -2478,7 +2485,7 @@
 	(stencil . ,parenthesize-elements)
 	(stencils . ,parentheses-item::calc-parenthesis-stencils)
 	(X-offset . ,ly:side-position-interface::x-aligned-side)
-	(Y-extent . ,grob::all-heights-from-stencil)
+	(Y-extent . ,grob::always-Y-extent-from-stencil)
 	(meta . ((class . Item)
 		 (interfaces . (axis-group-interface
 				font-interface
@@ -2491,8 +2498,8 @@
 	(duration-log . 2)
 	(font-size . -4)
 	(stencil . ,ly:note-head::print)
-	(Y-offset . ,ly:staff-symbol-referencer::callback)
-	(Y-extent . ,grob::all-heights-from-stencil)
+	(Y-offset . ,staff-symbol-referencer::callback)
+	(Y-extent . ,grob::always-Y-extent-from-stencil)
 	(meta . ((class . Item)
 		 (interfaces . (font-interface
 				ledgered-interface
@@ -2521,7 +2528,7 @@
 	(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
@@ -2543,7 +2550,7 @@
 	(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)
@@ -2575,8 +2582,8 @@
 	(padding . 0.0)  ;; padding relative to UnaCordaPedalLineSpanner
 	(self-alignment-X . ,CENTER)
 	(stencil . ,ly:text-interface::print)
-	(vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
-	(Y-extent . ,grob::all-heights-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
@@ -2594,10 +2601,10 @@
 	(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)))
@@ -2622,7 +2629,7 @@
 	(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)
@@ -2639,12 +2646,12 @@
 					(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 . (
@@ -2688,7 +2695,8 @@
 	(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
@@ -2707,10 +2715,10 @@
 	(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)))
@@ -2769,119 +2777,3 @@
      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))))
-
-;; 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 ((ly:stencil? sten)
-	   (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))
-		   (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))))))))))
diff --git a/scm/output-lib.scm b/scm/output-lib.scm
index 6c43b0aab1..09f526b8af 100644
--- a/scm/output-lib.scm
+++ b/scm/output-lib.scm
@@ -58,15 +58,53 @@
 
     (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::all-heights-from-stencil
-  (ly:make-unpure-pure-container
-    ly:grob::stencil-height
-    (lambda (grob start end) (ly:grob::stencil-height grob))))
+(define-public grob::always-Y-extent-from-stencil
+  (ly:make-unpure-pure-container ly:grob::stencil-height))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; beam slope
@@ -201,6 +239,25 @@
   (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
 
@@ -457,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))
@@ -637,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")))
 
@@ -774,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)
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;
@@ -954,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
 
@@ -1069,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
 
@@ -1111,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))))
-- 
2.39.5