Anyway, here's another try. Same ChangeLog as before
Index: ChangeLog
===================================================================
RCS file: /sources/lilypond/lilypond/ChangeLog,v
retrieving revision 1.5101
diff -u -r1.5101 ChangeLog
--- ChangeLog	7 Jun 2006 22:01:13 -0000	1.5101
+++ ChangeLog	7 Jun 2006 22:54:54 -0000
@@ -1,3 +1,39 @@
+2006-06-08  Joe Neeman  <[EMAIL PROTECTED]>
+
+	* scm/paper-system.scm (paper-system-annotate): also annotate the
+	estimated pure-Y-extent
+
+	* scm/define-grobs.scm: add pure-Y-extent and pure-Y-offset functions
+
+	* lily/system.cc (break_into_pieces): set the estimated height
+	of each child system
+
+	* lily/stem.cc (pure_height): new pure-Y-extent callback
+
+	* lily/staff-symbol-referencer.cc (callback): don't destroy
+	the staff-position property
+
+	* lily/hara-kiri-group-spanner.cc (request_suicide): split
+	consider_suicide into two functions
+
+	* lily/constrained-breaking.cc (resize): use the new pure
+	callbacks to estimate the height of a system
+
+	* lily/axis-group-interface.cc (pure_group_height): new
+	side-effect-free VerticalAxisGroup height-callback
+
+	* lily/align-interface.cc (get_extents_aligned_translates):
+	split align_elements_to_extents into two functions
+	(get_pure_child_y_translation): new function
+
+	* lily/grob.cc: new functions for pure-Y-extent and pure-Y-offset
+
+	* lily/item.cc: new functions pure_is_visible and spanned_rank_iv
+
+	* lily/paper-score.cc: cache break_indices and columns
+
+	* lily/side-position-interface.cc: new pure-Y-extent callbacks
+	
 2006-06-07  Graham Percival  <[EMAIL PROTECTED]>
 
 	* input/test/ add-staccato.ly, add-text-script.ly,
Index: lily/align-interface.cc
===================================================================
RCS file: /sources/lilypond/lilypond/lily/align-interface.cc,v
retrieving revision 1.97
diff -u -r1.97 align-interface.cc
--- lily/align-interface.cc	19 Feb 2006 00:14:59 -0000	1.97
+++ lily/align-interface.cc	7 Jun 2006 22:54:55 -0000
@@ -14,6 +14,7 @@
 #include "hara-kiri-group-spanner.hh"
 #include "grob-array.hh"
 #include "international.hh"
+#include "warn.hh"
 
 /*
   TODO: for vertical spacing, should also include a rod & spring
@@ -145,8 +146,11 @@
   align_to_fixed_distance ().
 */
 
-void
-Align_interface::align_elements_to_extents (Grob *me, Axis a)
+vector<Real>
+Align_interface::get_extents_aligned_translates (Grob *me,
+						 vector<Grob*> const &all_grobs,
+						 Axis a,
+						 bool pure, int start, int end)
 {
   Spanner *me_spanner = dynamic_cast<Spanner *> (me);
 
@@ -156,7 +160,7 @@
     {
       line_break_details = me_spanner->get_bound (LEFT)->get_property ("line-break-system-details");
 
-      if (!me->get_system ())
+      if (!me->get_system () && !pure)
 	me->warning (_ ("vertical alignment called before line-breaking.\n"
 			"Only do cross-staff spanners with PianoStaff."));
 
@@ -171,10 +175,9 @@
   vector<Interval> dims;
   vector<Grob*> elems;
 
-  extract_grob_set (me, "elements", all_grobs);
   for (vsize i = 0; i < all_grobs.size (); i++)
     {
-      Interval y = all_grobs[i]->extent (me, a);
+      Interval y = all_grobs[i]->maybe_pure_extent (all_grobs[i], a, pure, start, end);
       if (!y.is_empty ())
 	{
 	  Grob *e = dynamic_cast<Grob *> (all_grobs[i]);
@@ -245,24 +248,68 @@
   if (translates.size ())
     {
       Real w = translates[0];
+
+      if (scm_is_number (align))
+	center_offset = total.linear_combination (scm_to_double (align));
+
       for  (vsize i = 0, j = 0; j < all_grobs.size (); j++)
 	{
 	  if (i < elems.size () && all_grobs[j] == elems[i])
 	    w = translates[i++];
-	  all_translates.push_back (w);
+	  all_translates.push_back (w - center_offset);
 	}
+    }
+  return all_translates;
+}
 
-      /*
-	FIXME: uncommenting freaks out the Y-alignment of
-	line-of-score.
-      */
-      if (scm_is_number (align))
-	center_offset = total.linear_combination (scm_to_double (align));
+void
+Align_interface::align_elements_to_extents (Grob *me, Axis a)
+{
+  extract_grob_set (me, "elements", all_grobs);
 
+  vector<Real> translates = get_extents_aligned_translates (me, all_grobs, a, false, 0, 0);
+  if (translates.size ())
       for (vsize j = 0; j < all_grobs.size (); j++)
-	all_grobs[j]->translate_axis (all_translates[j] - center_offset, a);
+	all_grobs[j]->translate_axis (translates[j], a);
+}
+
+Real
+Align_interface::get_pure_child_y_translation (Grob *me, Grob *ch, int start, int end)
+{
+  extract_grob_set (me, "elements", all_grobs);
+  SCM dy_scm = me->get_property ("forced-distance");
+
+  if (scm_is_number (dy_scm))
+    {
+      Real dy = scm_to_double (dy_scm) * robust_scm2dir (me->get_property ("stacking-dir"), DOWN);
+      Real pos = 0;
+      for (vsize i = 0; i < all_grobs.size (); i++)
+	{
+	  if (all_grobs[i] == ch)
+	    return pos;
+	  if (!Hara_kiri_group_spanner::has_interface (all_grobs[i])
+	      || !Hara_kiri_group_spanner::request_suicide (all_grobs[i], start, end))
+	    pos += dy;
+	}
     }
+  else
+    {
+      vector<Real> translates = get_extents_aligned_translates (me, all_grobs, Y_AXIS, true, start, end);
+
+      if (translates.size ())
+	{
+	  for (vsize i = 0; i < all_grobs.size (); i++)
+	    if (all_grobs[i] == ch)
+	      return translates[i];
+	}
+      else
+	return 0;
+    }
+
+  programming_error (_ ("tried to get a translation for something that isn't my child"));
+  return 0;
 }
+
 Axis
 Align_interface::axis (Grob *me)
 {
Index: lily/axis-group-interface.cc
===================================================================
RCS file: /sources/lilypond/lilypond/lily/axis-group-interface.cc,v
retrieving revision 1.76
diff -u -r1.76 axis-group-interface.cc
--- lily/axis-group-interface.cc	16 Mar 2006 14:39:46 -0000	1.76
+++ lily/axis-group-interface.cc	7 Jun 2006 22:54:55 -0000
@@ -8,9 +8,16 @@
 
 #include "axis-group-interface.hh"
 
+#include "align-interface.hh"
 #include "pointer-group-interface.hh"
 #include "grob.hh"
+#include "grob-array.hh"
 #include "hara-kiri-group-spanner.hh"
+#include "international.hh"
+#include "item.hh"
+#include "paper-column.hh"
+#include "paper-score.hh"
+#include "system.hh"
 #include "warn.hh"
 
 void
@@ -61,6 +68,89 @@
   return r;
 }
 
+Interval
+Axis_group_interface::cached_pure_height (Grob *me,
+					  vector<Grob*> const &elts,
+					  Grob *common,
+					  int start, int end)
+{
+  Paper_score *ps = get_root_system (me)->paper_score ();
+  vector<vsize> breaks = ps->get_break_indices ();
+  vector<Grob*> cols = ps->get_columns ();
+  vsize start_index = VPOS;
+  vsize end_index = VPOS;
+
+  for (vsize i = 0; i < breaks.size (); i++)
+    {
+      int r = Paper_column::get_rank (cols[breaks[i]]);
+      if (start == r)
+	start_index = i;
+      if (end == r)
+	end_index = i;
+    }
+
+  if (start_index == VPOS || end_index == VPOS)
+    {
+      programming_error (_ ("tried to calculate pure-height at a non-breakpoint"));
+      return Interval (0, 0);
+    }
+
+  SCM extents = me->get_property ("cached-pure-extents");
+  if (!scm_is_vector (extents))
+    {
+      extents = scm_c_make_vector (breaks.size () - 1, SCM_EOL);
+      for (vsize i = 0; i < breaks.size () - 1; i++)
+	{
+	  int st = Paper_column::get_rank (cols[breaks[i]]);
+	  int ed = Paper_column::get_rank (cols[breaks[i+1]]);
+	  Interval iv = relative_pure_height (me, elts, common, st, ed, false);
+	  scm_vector_set_x (extents, scm_from_int (i), ly_interval2scm (iv));
+	}
+      me->set_property ("cached-pure-extents", extents);
+    }
+
+  Interval ext (0, 0);
+  for (vsize i = start_index; i < end_index; i++)
+    ext.unite (ly_scm2interval (scm_c_vector_ref (extents, i)));
+  return ext;
+}
+
+Interval
+Axis_group_interface::relative_pure_height (Grob *me,
+					    vector<Grob*> const &elts,
+					    Grob *common,
+					    int start, int end,
+					    bool use_cache)
+{
+  /* It saves a _lot_ of time if we assume a VerticalAxisGroup is additive
+     (ie. height (i, k) = height (i, j) + height (j, k) for all i <= j <= k).
+     Unfortunately, it isn't always true, particularly if there is a
+     VerticalAlignment somewhere in the descendants.
+
+     Apart from PianoStaff, which has a fixed VerticalAlignment so it doesn't
+     count, the only VerticalAlignment comes from Score. This makes it
+     reasonably safe to assume that if our parent is a VerticalAlignment,
+     we can assume additivity and cache things nicely. */
+  Grob *p = me->get_parent (Y_AXIS);
+  if (use_cache && p && Align_interface::has_interface (p))
+    return Axis_group_interface::cached_pure_height (me, elts, common, start, end);
+
+  Interval r;
+
+  for (vsize i = 0; i < elts.size (); i++)
+    {
+      Interval_t<int> rank_span = elts[i]->spanned_rank_iv ();
+      Item *it = dynamic_cast<Item*> (elts[i]);
+      if (rank_span[LEFT] <= end && rank_span[RIGHT] >= start && (!it || it->pure_is_visible (start, end)))
+	{
+	  Interval dims = elts[i]->pure_height (common, start, end);
+	  if (!dims.is_empty ())
+	    r.unite (dims);
+	}
+    }
+  return r;
+}
+
 MAKE_SCHEME_CALLBACK (Axis_group_interface, width, 1);
 SCM
 Axis_group_interface::width (SCM smob)
@@ -76,6 +166,17 @@
   Grob *me = unsmob_grob (smob);
   return generic_group_extent (me, Y_AXIS);
 }
+
+MAKE_SCHEME_CALLBACK (Axis_group_interface, pure_height, 3);
+SCM
+Axis_group_interface::pure_height (SCM smob, SCM start_scm, SCM end_scm)
+{
+  int start = robust_scm2int (start_scm, 0);
+  int end = robust_scm2int (end_scm, INT_MAX);
+  Grob *me = unsmob_grob (smob);
+
+  return pure_group_height (me, start, end);
+}
   
 SCM
 Axis_group_interface::generic_group_extent (Grob *me, Axis a)
@@ -89,6 +190,38 @@
   return ly_interval2scm (r - my_coord);
 }
 
+SCM
+Axis_group_interface::pure_group_height (Grob *me, int start, int end)
+{
+  Grob *common = unsmob_grob (me->get_object ("common-refpoint-of-elements"));
+
+  if (!common)
+    {
+      extract_grob_set (me, "elements", elts);
+
+      vector<Grob*> relevant_elts;
+      SCM is_relevant = ly_lily_module_constant ("pure-relevant");
+
+      for (vsize i = 0; i < elts.size (); i++)
+	if (to_boolean (scm_apply_1 (is_relevant, elts[i]->self_scm (), SCM_EOL)))
+	  relevant_elts.push_back (elts[i]);
+
+      common = common_refpoint_of_array (relevant_elts, me, Y_AXIS);
+      me->set_object ("common-refpoint-of-elements", common->self_scm ());
+
+      SCM ga_scm = Grob_array::make_array ();
+      Grob_array *ga = unsmob_grob_array (ga_scm);
+      ga->set_array (relevant_elts);
+      me->set_object ("pure-relevant-elements", ga_scm);
+    }
+
+  extract_grob_set (me, "pure-relevant-elements", elts);
+  Real my_coord = me->relative_coordinate (common, Y_AXIS);
+  Interval r (relative_pure_height (me, elts, common, start, end, true));
+
+  return ly_interval2scm (r - my_coord);
+}
+
 void
 Axis_group_interface::get_children (Grob *me, vector<Grob*> *found)
 {
@@ -111,4 +244,8 @@
 
 	       /* properties */
 	       "axes "
-	       "elements ");
+	       "elements "
+	       "common-refpoint-of-elements "
+	       "pure-relevant-elements "
+	       "cached-pure-extents "
+	       );
Index: lily/constrained-breaking.cc
===================================================================
RCS file: /sources/lilypond/lilypond/lily/constrained-breaking.cc,v
retrieving revision 1.6
diff -u -r1.6 constrained-breaking.cc
--- lily/constrained-breaking.cc	9 May 2006 02:15:56 -0000	1.6
+++ lily/constrained-breaking.cc	7 Jun 2006 22:54:55 -0000
@@ -147,9 +147,9 @@
   if (!breaks_.size () && pscore_)
     {
       Output_def *l = pscore_->layout ();
-      Real extent = scm_to_double (l->c_variable ("system-height"));
-      Real padding = scm_to_double (l->c_variable ("between-system-padding"));
-      Real space = scm_to_double (l->c_variable ("between-system-space"));
+      System *sys = pscore_->root_system ();
+      Real padding = robust_scm2double (l->c_variable ("between-system-padding"), 0);
+      Real space = robust_scm2double (l->c_variable ("ideal-system-space"), 0);
       bool ragged_right = to_boolean (pscore_->layout ()->c_variable ("ragged-right"));
       bool ragged_last = to_boolean (pscore_->layout ()->c_variable ("ragged-last"));
 
@@ -167,8 +167,12 @@
 					     ragged_right);
       for (vsize i = 0; i < breaks_.size () - 1; i++)
 	{
+	  Real max_ext = 0;
           for (vsize j = i + 1; j < breaks_.size (); j++)
             {
+	      int start = Paper_column::get_rank (all_[breaks_[i]]);
+	      int end = Paper_column::get_rank (all_[breaks_[j]]);
+	      Interval extent = sys->pure_height (sys, start, end);
 	      bool last = j == breaks_.size () - 1;
 	      bool ragged = ragged_right || (last && ragged_last);
               int k = i*lines_rank_ + j;
@@ -176,11 +180,12 @@
 	      if (scm_is_number (pen))
 		lines_[k].break_penalty_ = scm_to_double (pen);
 
+	      max_ext = max (max_ext, extent.length ());
               lines_[k].force_ = forces[k];
-              lines_[k].extent_ = extent;
+              lines_[k].extent_ = extent.length ();
               lines_[k].padding_ = padding;
               lines_[k].space_ = space;
-              lines_[k].inverse_hooke_ = 3; // FIXME: somewhat arbitrary
+              lines_[k].inverse_hooke_ = 1;
 	      if (ragged && lines_[k].force_ < 0)
 		lines_[k].force_ = infinity_f;
               if (isinf (lines_[k].force_))
@@ -335,6 +340,6 @@
 Real
 Constrained_breaking::combine_demerits (Real force, Real prev_force)
 {
-  return force * force + fabs (prev_force - force);
+  return force * force + (prev_force - force) * (prev_force - force);
 }
 
Index: lily/grob.cc
===================================================================
RCS file: /sources/lilypond/lilypond/lily/grob.cc,v
retrieving revision 1.170
diff -u -r1.170 grob.cc
--- lily/grob.cc	28 May 2006 22:13:20 -0000	1.170
+++ lily/grob.cc	7 Jun 2006 22:54:56 -0000
@@ -10,6 +10,7 @@
 
 #include <cstring>
 
+#include "align-interface.hh"
 #include "input-smob.hh"
 #include "international.hh"
 #include "item.hh"
@@ -278,6 +279,37 @@
   return off;
 }
 
+Real
+Grob::pure_relative_y_coordinate (Grob const *refp, int start, int end)
+{
+  if (refp == this)
+    return 0.0;
+
+  SCM pure_off = ly_lily_module_constant ("pure-Y-offset");
+  Real off = 0;
+
+  if (dim_cache_[Y_AXIS].offset_)
+    off = *dim_cache_[Y_AXIS].offset_;
+  else if (ly_is_procedure (pure_off))
+    {
+      dim_cache_[Y_AXIS].offset_ = new Real (0.0);
+      off = scm_to_double (scm_apply_3 (pure_off, self_scm (),
+					scm_from_int (start), scm_from_int (end),
+					SCM_EOL));
+      delete dim_cache_[Y_AXIS].offset_;
+      dim_cache_[Y_AXIS].offset_ = 0;
+    }
+
+  /* we simulate positioning-done if we are the child of a VerticalAlignment */
+  Grob *p = get_parent (Y_AXIS);
+  Real trans = 0;
+  if (Align_interface::has_interface (p))
+    trans = Align_interface::get_pure_child_y_translation (p, this, start, end);
+
+  return off + trans
+    + dim_cache_[Y_AXIS].parent_->pure_relative_y_coordinate (refp, start, end);
+}
+
 /* Invoke callbacks to get offset relative to parent.  */
 Real
 Grob::get_offset (Axis a) const
@@ -305,6 +337,14 @@
     return 0.0;
 }
 
+Real
+Grob::maybe_pure_coordinate (Grob const *refp, Axis a, bool pure, int start, int end)
+{
+  if (pure && a != Y_AXIS)
+    programming_error ("tried to get pure X-offset");
+  return (pure && a == Y_AXIS) ? pure_relative_y_coordinate (refp, start, end)
+    : relative_coordinate (refp, a);
+}
 
 /****************************************************************
   extents
@@ -358,7 +398,6 @@
       SCM min_ext = internal_get_property (min_ext_sym);
       if (is_number_pair (min_ext))
 	real_ext.unite (ly_scm2interval (min_ext));
-      ((Grob*)this)->del_property (ext_sym);
       ((Grob*)this)->dim_cache_[a].extent_ = new Interval (real_ext);  
     }
   
@@ -367,6 +406,36 @@
   return real_ext;
 }
 
+Interval
+Grob::pure_height (Grob *refp, int start, int end)
+{
+  SCM pure_height = ly_lily_module_constant ("pure-Y-extent");
+  Interval iv (0, 0);
+
+  if (ly_is_procedure (pure_height))
+    iv = ly_scm2interval (scm_apply_3 (pure_height, self_scm (),
+				       scm_from_int (start), scm_from_int (end),
+				       SCM_EOL));
+  Real offset = pure_relative_y_coordinate (refp, start, end);
+
+  iv.translate (offset);
+  return iv;
+}
+
+Interval
+Grob::maybe_pure_extent (Grob *refp, Axis a, bool pure, int start, int end)
+{
+  if (pure && a != Y_AXIS)
+    programming_error ("tried to get pure width");
+  return (pure && a == Y_AXIS) ? pure_height (refp, start, end) : extent (refp, a);
+}
+
+Interval_t<int>
+Grob::spanned_rank_iv ()
+{
+  return Interval_t<int> (INT_MIN, INT_MAX);
+}
+
 /****************************************************************
   REFPOINTS
 ****************************************************************/
Index: lily/hara-kiri-group-spanner.cc
===================================================================
RCS file: /sources/lilypond/lilypond/lily/hara-kiri-group-spanner.cc,v
retrieving revision 1.54
diff -u -r1.54 hara-kiri-group-spanner.cc
--- lily/hara-kiri-group-spanner.cc	16 Mar 2006 14:39:46 -0000	1.54
+++ lily/hara-kiri-group-spanner.cc	7 Jun 2006 22:54:56 -0000
@@ -25,22 +25,84 @@
   return Axis_group_interface::generic_group_extent (me, Y_AXIS);
 }
 
-void
-Hara_kiri_group_spanner::consider_suicide (Grob *me)
+MAKE_SCHEME_CALLBACK (Hara_kiri_group_spanner, pure_height, 3);
+SCM
+Hara_kiri_group_spanner::pure_height (SCM smob, SCM start_scm, SCM end_scm)
 {
-  Spanner *sp = dynamic_cast<Spanner *> (me);
-  if (!to_boolean (me->get_property ("remove-empty")))
-    return ;
+  Grob *me = unsmob_grob (smob);
+  int start = robust_scm2int (start_scm, 0);
+  int end = robust_scm2int (end_scm, INT_MAX);
 
-  extract_grob_set (me, "items-worth-living", worth);
-  if (worth.size ())
-    return;
+  if (request_suicide (me, start, end))
+    return ly_interval2scm (Interval ());
+  return Axis_group_interface::pure_group_height (me, start, end);
+}
+
+/* there is probably a way that doesn't involve re-implementing a binary
+   search (I would love some proper closures right now) */
+bool find_in_range (SCM vector, int low, int hi, int min, int max)
+{
+  if (low >= hi)
+    return false;
+
+  int mid = low + (hi - low) / 2;
+  int val = scm_to_int (scm_c_vector_ref (vector, mid));
+  if (val >= min && val <= max)
+    return true;
+  else if (val < min)
+    return find_in_range (vector, mid+1, hi, min, max);
+  return find_in_range (vector, low, mid, min, max);
+}
+
+bool
+Hara_kiri_group_spanner::request_suicide (Grob *me, int start, int end)
+{
+  if (!to_boolean (me->get_property ("remove-empty")))
+    return false;
 
   bool remove_first = to_boolean (me->get_property ("remove-first"));
-  if (!remove_first
-       && ((sp->original () && broken_spanner_index (sp) == 0)
-	   || Paper_column::get_rank (sp->get_bound (LEFT)->get_column ())
-	   == 0)) 
+  if (!remove_first && start <= 0)
+    return false;
+
+  SCM important = me->get_property ("important-column-ranks");
+  if (scm_is_vector (important))
+    {
+      int len = scm_c_vector_length (important);
+      if (find_in_range (important, 0, len-1, start, end))
+	return false;
+    }
+  else /* build the important-columns-cache */
+    {
+      extract_grob_set (me, "items-worth-living", worth);
+      vector<int> ranks;
+
+      for (vsize i = 0; i < worth.size (); i++)
+	{
+	  Item *it = dynamic_cast<Item*> (worth[i]);
+	  if (it)
+	    ranks.push_back (Paper_column::get_rank (it->get_column ()));
+	}
+      vector_sort (ranks, default_compare);
+      uniq (ranks);
+
+      SCM scm_vec = scm_c_make_vector (ranks.size (), SCM_EOL);
+      for (vsize i = 0; i < ranks.size (); i++)
+	scm_vector_set_x (scm_vec, scm_from_int (i), scm_from_int (ranks[i]));
+      me->set_property ("important-column-ranks", scm_vec);
+
+      return request_suicide (me, start, end);
+    }
+
+  return true;
+}
+
+void
+Hara_kiri_group_spanner::consider_suicide (Grob *me)
+{
+  Spanner *sp = dynamic_cast<Spanner*> (me);
+  int left = sp->get_bound (LEFT)->get_column ()->get_rank ();
+  int right = sp->get_bound (RIGHT)->get_column ()->get_rank ();
+  if (!request_suicide (me, left, right))
     return;
 
   vector<Grob*> childs;
@@ -99,6 +161,7 @@
 
 	       /* properties */
 	       "items-worth-living "
+	       "important-column-ranks "
 	       "remove-empty "
 	       "remove-first "
 	       );
Index: lily/item.cc
===================================================================
RCS file: /sources/lilypond/lilypond/lily/item.cc,v
retrieving revision 1.124
diff -u -r1.124 item.cc
--- lily/item.cc	9 May 2006 02:15:56 -0000	1.124
+++ lily/item.cc	7 Jun 2006 22:54:56 -0000
@@ -8,6 +8,7 @@
 
 #include "item.hh"
 
+#include "axis-group-interface.hh"
 #include "paper-score.hh"
 #include "warn.hh"
 #include "paper-column.hh"
@@ -149,13 +150,47 @@
   SCM vis = get_property ("break-visibility");
   if (scm_is_vector (vis))
     {
-      bool visible = to_boolean (scm_vector_ref (vis, scm_from_int (break_status_dir () + 1)));
+      bool visible = to_boolean (scm_c_vector_ref (vis, break_status_dir () + 1));
 
       if (!visible)
-	suicide ();
+	{
+	  Grob *p = unsmob_grob (get_object ("axis-group-parent-Y"));
+	  if (!original () && p)
+	    {
+	      if (to_boolean (scm_c_vector_ref (vis, LEFT + 1)))
+		Axis_group_interface::add_element (p, broken_to_drul_[LEFT]);
+	      else if (to_boolean (scm_c_vector_ref (vis, RIGHT + 1)))
+		Axis_group_interface::add_element (p, broken_to_drul_[RIGHT]);
+	    }
+	  suicide ();
+	}
     }
 }
 
+bool
+Item::pure_is_visible (int start, int end) const
+{
+  SCM vis = get_property ("break-visibility");
+  if (scm_is_vector (vis))
+    {
+      int pos = 1;
+      int pc_rank = Paper_column::get_rank (get_column ());
+      if (pc_rank == start)
+	pos = 2;
+      else if (pc_rank == end)
+	pos = 0;
+      return to_boolean (scm_vector_ref (vis, scm_from_int (pos)));
+    }
+  return true;
+}
+
+Interval_t<int>
+Item::spanned_rank_iv ()
+{
+  int c = get_column ()->get_rank ();
+  return Interval_t<int> (c, c);
+}
+
 void
 Item::derived_mark () const
 {
Index: lily/paper-score.cc
===================================================================
RCS file: /sources/lilypond/lilypond/lily/paper-score.cc,v
retrieving revision 1.102
diff -u -r1.102 paper-score.cc
--- lily/paper-score.cc	9 May 2006 02:15:56 -0000	1.102
+++ lily/paper-score.cc	7 Jun 2006 22:54:56 -0000
@@ -75,9 +75,27 @@
 	retval.push_back (i);
     }
 
+  cols_ = all;
+  break_indices_ = retval;
+
   return retval;
 }
 
+vector<vsize>
+Paper_score::get_break_indices () const
+{
+  if (break_indices_.empty ())
+    find_break_indices ();
+  return break_indices_;
+}
+
+vector<Grob*>
+Paper_score::get_columns () const
+{
+  if (cols_.empty ())
+    find_break_indices ();
+  return cols_;
+}
 
 vector<Column_x_positions>
 Paper_score::calc_breaking ()
Index: lily/side-position-interface.cc
===================================================================
RCS file: /sources/lilypond/lilypond/lily/side-position-interface.cc,v
retrieving revision 1.124
diff -u -r1.124 side-position-interface.cc
--- lily/side-position-interface.cc	16 Mar 2006 14:39:46 -0000	1.124
+++ lily/side-position-interface.cc	7 Jun 2006 22:54:56 -0000
@@ -48,7 +48,8 @@
 /* Put the element next to the support, optionally taking in
    account the extent of the support.  */
 SCM
-Side_position_interface::general_side_position (Grob *me, Axis a, bool use_extents)
+Side_position_interface::general_side_position (Grob *me, Axis a, bool use_extents,
+						bool pure, int start, int end)
 {
   Real ss = Staff_symbol_referencer::staff_space (me);
 
@@ -67,7 +68,7 @@
   if (include_staff)
     {
       common = staff_symbol->common_refpoint (common, Y_AXIS);
-      staff_extents = staff_symbol->extent (common, Y_AXIS);
+      staff_extents = staff_symbol->maybe_pure_extent (common, Y_AXIS, pure, start, end);
 
       if (include_staff)
 	dim.unite (staff_extents);
@@ -78,10 +79,10 @@
       Grob *e = support[i];
       if (e)
 	if (use_extents)
-	  dim.unite (e->extent (common, a));
+	  dim.unite (e->maybe_pure_extent (common, a, pure, start, end));
 	else
 	  {
-	    Real x = e->relative_coordinate (common, a);
+	    Real x = e->maybe_pure_coordinate (common, a, pure, start, end);
 	    dim.unite (Interval (x, x));
 	  }
     }
@@ -91,7 +92,7 @@
 
   Direction dir = get_grob_direction (me);
 
-  Real off = me->get_parent (a)->relative_coordinate (common, a);
+  Real off = me->get_parent (a)->maybe_pure_coordinate (common, a, pure, start, end);
   Real minimum_space = ss * robust_scm2double (me->get_property ("minimum-space"), -1);
 
   Real total_off = dim.linear_combination (dir) - off;
@@ -118,13 +119,19 @@
 
 
 MAKE_SCHEME_CALLBACK (Side_position_interface, y_aligned_on_support_refpoints, 1);
-
 SCM
 Side_position_interface::y_aligned_on_support_refpoints (SCM smob)
 {
-  return general_side_position (unsmob_grob (smob), Y_AXIS, false); 
+  return general_side_position (unsmob_grob (smob), Y_AXIS, false, false, 0, 0); 
 }
 
+MAKE_SCHEME_CALLBACK (Side_position_interface, pure_y_aligned_on_support_refpoints, 3);
+SCM
+Side_position_interface::pure_y_aligned_on_support_refpoints (SCM smob, SCM start, SCM end)
+{
+  return general_side_position (unsmob_grob (smob), Y_AXIS, false,
+				true, scm_to_int (start), scm_to_int (end)); 
+}
 
 
 /*
@@ -135,23 +142,30 @@
 SCM
 Side_position_interface::x_aligned_side (SCM smob)
 {
-  return aligned_side (unsmob_grob (smob), X_AXIS);
+  return aligned_side (unsmob_grob (smob), X_AXIS, false, 0, 0);
 }
 
 MAKE_SCHEME_CALLBACK (Side_position_interface, y_aligned_side, 1);
 SCM
 Side_position_interface::y_aligned_side (SCM smob)
 {
-  return aligned_side (unsmob_grob (smob), Y_AXIS);
+  return aligned_side (unsmob_grob (smob), Y_AXIS, false, 0, 0);
+}
+
+MAKE_SCHEME_CALLBACK (Side_position_interface, pure_y_aligned_side, 3);
+SCM
+Side_position_interface::pure_y_aligned_side (SCM smob, SCM start, SCM end)
+{
+  return aligned_side (unsmob_grob (smob), Y_AXIS, true, scm_to_int (start), scm_to_int (end));
 }
 
 SCM
-Side_position_interface::aligned_side (Grob *me, Axis a)
+Side_position_interface::aligned_side (Grob *me, Axis a, bool pure, int start, int end)
 {
   Direction dir = get_grob_direction (me);
 
-  Real o = scm_to_double (general_side_position (me, a, true));
-  Interval iv = me->extent (me, a);
+  Real o = scm_to_double (general_side_position (me, a, true, pure, start, end));
+  Interval iv = me->maybe_pure_extent (me, a, pure, start, end);
 
   if (!iv.is_empty ())
     {
@@ -174,8 +188,8 @@
       if (to_boolean (me->get_property ("quantize-position")))
 	{
 	  Grob *common = me->common_refpoint (staff, Y_AXIS);
-	  Real my_off = me->relative_coordinate (common, Y_AXIS);
-	  Real staff_off = staff->relative_coordinate (common, Y_AXIS);
+	  Real my_off = me->get_parent (Y_AXIS)->maybe_pure_coordinate (common, Y_AXIS, pure, start, end);
+	  Real staff_off = staff->maybe_pure_coordinate (common, Y_AXIS, pure, start, end);
 	  Real ss = Staff_symbol::staff_space (staff);
 	  Real position = 2 * (my_off + o - staff_off) / ss;
 	  Real rounded = directed_round (position, dir);
@@ -198,7 +212,7 @@
 
 	  Grob *common = me->common_refpoint (staff, Y_AXIS);
 
-	  Interval staff_size = staff->extent (common, Y_AXIS);
+	  Interval staff_size = staff->maybe_pure_extent (common, Y_AXIS, pure, start, end);
 	  Real diff = dir*staff_size[dir] + padding - dir * (o + iv[-dir]);
 	  o += dir * max (diff, 0.0);
 	}
Index: lily/staff-symbol-referencer.cc
===================================================================
RCS file: /sources/lilypond/lilypond/lily/staff-symbol-referencer.cc,v
retrieving revision 1.87
diff -u -r1.87 staff-symbol-referencer.cc
--- lily/staff-symbol-referencer.cc	6 Feb 2006 01:13:58 -0000	1.87
+++ lily/staff-symbol-referencer.cc	7 Jun 2006 22:54:56 -0000
@@ -110,7 +110,6 @@
     {
       Real space = Staff_symbol_referencer::staff_space (me);
       off = scm_to_double (pos) * space / 2.0;
-      me->set_property ("staff-position", scm_from_int (0));
     }
 
   return scm_from_double (off);
Index: lily/stem.cc
===================================================================
RCS file: /sources/lilypond/lilypond/lily/stem.cc,v
retrieving revision 1.307
diff -u -r1.307 stem.cc
--- lily/stem.cc	22 May 2006 17:45:40 -0000	1.307
+++ lily/stem.cc	7 Jun 2006 22:54:58 -0000
@@ -225,6 +225,28 @@
 	   && scm_to_int (me->get_property ("duration-log")) >= 1);
 }
 
+MAKE_SCHEME_CALLBACK (Stem, pure_height, 3)
+SCM
+Stem::pure_height (SCM smob, SCM start, SCM end)
+{
+  Grob *me = unsmob_grob (smob);
+  Real ss = Staff_symbol_referencer::staff_space (me);
+  Real len = scm_to_double (calc_length (smob)) * ss / 2;
+  Direction dir = get_grob_direction (me);
+
+  Interval iv;
+  Interval hp = head_positions (me);
+  if (dir == UP)
+    iv = Interval (0, len);
+  else
+    iv = Interval (-len, 0);
+
+  if (!hp.is_empty ())
+    iv.translate (hp[dir] * ss / 2);
+
+  return ly_interval2scm (iv);
+}
+
 MAKE_SCHEME_CALLBACK (Stem, calc_stem_end_position, 1)
 SCM
 Stem::calc_stem_end_position (SCM smob)
Index: lily/system.cc
===================================================================
RCS file: /sources/lilypond/lilypond/lily/system.cc,v
retrieving revision 1.143
diff -u -r1.143 system.cc
--- lily/system.cc	28 May 2006 18:03:49 -0000	1.143
+++ lily/system.cc	7 Jun 2006 22:54:58 -0000
@@ -23,7 +23,6 @@
 #include "staff-symbol-referencer.hh"
 #include "tweak-registration.hh"
 #include "warn.hh"
-#include "warn.hh"
 
 System::System (System const &src, int count)
   : Spanner (src, count)
@@ -206,6 +205,11 @@
       vector<Grob*> c (breaking[i].cols_);
       pscore_->typeset_system (system);
 
+      int st = Paper_column::get_rank (c[0]);
+      int end = Paper_column::get_rank (c.back ());
+      Interval iv (pure_height (this, st, end));
+      system->set_property ("pure-Y-extent", ly_interval2scm (iv));
+
       system->set_bound (LEFT, c[0]);
       system->set_bound (RIGHT, c.back ());
       for (vsize j = 0; j < c.size (); j++)
@@ -504,5 +508,6 @@
 	       /* properties */
 	       "all-elements "
 	       "columns "
+	       "pure-Y-extent "
 	       "spaceable-staves "
 	       )
Index: lily/include/align-interface.hh
===================================================================
RCS file: /sources/lilypond/lilypond/lily/include/align-interface.hh,v
retrieving revision 1.29
diff -u -r1.29 align-interface.hh
--- lily/include/align-interface.hh	6 Jan 2006 09:13:24 -0000	1.29
+++ lily/include/align-interface.hh	7 Jun 2006 22:54:58 -0000
@@ -11,6 +11,7 @@
 
 #include "lily-proto.hh"
 #include "lily-guile.hh"
+#include "std-vector.hh"
 
 struct Align_interface
 {
@@ -18,12 +19,17 @@
   DECLARE_SCHEME_CALLBACK (stretch_after_break, (SCM element));
   static void align_to_fixed_distance (Grob *, Axis a);
   static void align_elements_to_extents (Grob *, Axis a);
+  static vector<Real> get_extents_aligned_translates (Grob *, vector<Grob*> const&,
+						      Axis a,
+						      bool safe, int start, int end);
   static void set_ordered (Grob *);
   static Axis axis (Grob *);
   static void add_element (Grob *, Grob *);
   static int get_count (Grob *, Grob *);
 
   static bool has_interface (Grob *);
+
+  static Real get_pure_child_y_translation (Grob *, Grob *child, int start, int end);
 };
 
 Grob *find_fixed_alignment_parent (Grob *g);
Index: lily/include/axis-group-interface.hh
===================================================================
RCS file: /sources/lilypond/lilypond/lily/include/axis-group-interface.hh,v
retrieving revision 1.30
diff -u -r1.30 axis-group-interface.hh
--- lily/include/axis-group-interface.hh	16 Feb 2006 11:54:21 -0000	1.30
+++ lily/include/axis-group-interface.hh	7 Jun 2006 22:54:58 -0000
@@ -18,10 +18,17 @@
 struct Axis_group_interface
 {
   static SCM generic_group_extent (Grob *me, Axis a);
+  static SCM pure_group_height (Grob *me, int start, int end);
   DECLARE_SCHEME_CALLBACK (width, (SCM smob));
   DECLARE_SCHEME_CALLBACK (height, (SCM smob));
+  DECLARE_SCHEME_CALLBACK (pure_height, (SCM smob, SCM start, SCM end));
   static Interval relative_group_extent (vector<Grob*> const &list,
 					 Grob *common, Axis);
+  static Interval relative_pure_height (Grob *me, vector<Grob*> const &list,
+					Grob *common, int start, int end,
+					bool use_cache);
+  static Interval cached_pure_height (Grob *me, vector<Grob*> const &list,
+				      Grob *common, int, int);
 
   static void add_element (Grob *me, Grob *);
   static void set_axes (Grob *, Axis, Axis);
Index: lily/include/constrained-breaking.hh
===================================================================
RCS file: /sources/lilypond/lilypond/lily/include/constrained-breaking.hh,v
retrieving revision 1.7
diff -u -r1.7 constrained-breaking.hh
--- lily/include/constrained-breaking.hh	9 May 2006 02:15:56 -0000	1.7
+++ lily/include/constrained-breaking.hh	7 Jun 2006 22:54:58 -0000
@@ -17,7 +17,8 @@
   Real force_;
   Real extent_;   /* Y-extent of the system */
   Real padding_;  /* compulsory space after this system (if we're not last on a page) */
-  Real space_;    /* spring length (stretches over extent_ but not over padding_) */
+  Real bottom_padding_;
+  Real space_;    /* spring length */
   Real inverse_hooke_;
 
   SCM break_permission_;
@@ -32,6 +33,7 @@
     force_ = infinity_f;
     extent_ = 0;
     padding_ = 0;
+    bottom_padding_ = 0;
     space_ = 0;
     inverse_hooke_ = 1;
     break_permission_ = ly_symbol2scm ("allow");
Index: lily/include/grob.hh
===================================================================
RCS file: /sources/lilypond/lilypond/lily/include/grob.hh,v
retrieving revision 1.80
diff -u -r1.80 grob.hh
--- lily/include/grob.hh	11 Feb 2006 11:35:16 -0000	1.80
+++ lily/include/grob.hh	7 Jun 2006 22:54:58 -0000
@@ -109,16 +109,22 @@
   /* offsets */
   void translate_axis (Real, Axis);
   Real relative_coordinate (Grob const *refp, Axis) const;
+  Real pure_relative_y_coordinate (Grob const *refp, int start, int end);
+  Real maybe_pure_coordinate (Grob const *refp, Axis a, bool pure, int start, int end);
 
   /* extents */
   Interval extent (Grob *refpoint, Axis) const;
   void flush_extent_cache (Axis);
+  Interval pure_height (Grob *refpoint, int start_col, int end_col);
+  Interval maybe_pure_extent (Grob *refpoint, Axis, bool pure, int start, int end);
 
   /* refpoints */
   Grob *common_refpoint (Grob const *s, Axis a) const;
   void set_parent (Grob *e, Axis);
   Grob *get_parent (Axis a) const;
   void fixup_refpoint ();
+
+  virtual Interval_t<int> spanned_rank_iv ();
 };
 
 /* smob utilities */
Index: lily/include/hara-kiri-group-spanner.hh
===================================================================
RCS file: /sources/lilypond/lilypond/lily/include/hara-kiri-group-spanner.hh,v
retrieving revision 1.21
diff -u -r1.21 hara-kiri-group-spanner.hh
--- lily/include/hara-kiri-group-spanner.hh	5 Feb 2006 00:23:21 -0000	1.21
+++ lily/include/hara-kiri-group-spanner.hh	7 Jun 2006 22:54:58 -0000
@@ -17,9 +17,11 @@
 public:
   DECLARE_SCHEME_CALLBACK (force_hara_kiri_callback, (SCM));
   DECLARE_SCHEME_CALLBACK (y_extent, (SCM smob));
+  DECLARE_SCHEME_CALLBACK (pure_height, (SCM smob, SCM start, SCM end));
   DECLARE_SCHEME_CALLBACK (force_hara_kiri_in_y_parent_callback, (SCM));
   DECLARE_SCHEME_CALLBACK (after_line_breaking, (SCM));
   static bool has_interface (Grob *);
+  static bool request_suicide (Grob *me, int start, int end);
   static void consider_suicide (Grob *me);
   static void add_interesting_item (Grob *me, Grob *n);
 };
Index: lily/include/item.hh
===================================================================
RCS file: /sources/lilypond/lilypond/lily/include/item.hh,v
retrieving revision 1.62
diff -u -r1.62 item.hh
--- lily/include/item.hh	9 May 2006 02:15:56 -0000	1.62
+++ lily/include/item.hh	7 Jun 2006 22:54:58 -0000
@@ -30,6 +30,7 @@
 
   static bool is_non_musical (Grob *);
   bool is_broken () const;
+  bool pure_is_visible (int start, int end) const;
 
   Direction break_status_dir () const;
 
@@ -38,6 +39,7 @@
   virtual System *get_system () const;
   virtual Paper_column *get_column () const;
   virtual void handle_prebroken_dependencies ();
+  virtual Interval_t<int> spanned_rank_iv ();
   static bool has_interface (Grob *);
 protected:
   virtual void discretionary_processing ();
Index: lily/include/paper-score.hh
===================================================================
RCS file: /sources/lilypond/lilypond/lily/include/paper-score.hh,v
retrieving revision 1.41
diff -u -r1.41 paper-score.hh
--- lily/include/paper-score.hh	4 May 2006 09:49:38 -0000	1.41
+++ lily/include/paper-score.hh	7 Jun 2006 22:54:58 -0000
@@ -19,6 +19,9 @@
   System *system_;
   SCM systems_;
   SCM paper_systems_;
+
+  mutable vector<Grob*> cols_;
+  mutable vector<vsize> break_indices_;
 public:
   Paper_score (Output_def *);
   
@@ -30,6 +33,8 @@
   void typeset_system (System *);
   vector<Column_x_positions> calc_breaking ();
   vector<vsize> find_break_indices () const;
+  vector<vsize> get_break_indices () const;
+  vector<Grob*> get_columns () const;
   SCM get_paper_systems ();
 protected:
   virtual void process ();
Index: lily/include/side-position-interface.hh
===================================================================
RCS file: /sources/lilypond/lilypond/lily/include/side-position-interface.hh,v
retrieving revision 1.33
diff -u -r1.33 side-position-interface.hh
--- lily/include/side-position-interface.hh	18 Jan 2006 13:41:06 -0000	1.33
+++ lily/include/side-position-interface.hh	7 Jun 2006 22:54:58 -0000
@@ -22,12 +22,14 @@
 public:
 
   DECLARE_SCHEME_CALLBACK (y_aligned_on_support_refpoints, (SCM element));
+  DECLARE_SCHEME_CALLBACK (pure_y_aligned_on_support_refpoints, (SCM element, SCM start, SCM end));
   DECLARE_SCHEME_CALLBACK (x_aligned_side, (SCM element));
   DECLARE_SCHEME_CALLBACK (y_aligned_side, (SCM element));
+  DECLARE_SCHEME_CALLBACK (pure_y_aligned_side, (SCM element, SCM start, SCM end));
 
-  static SCM aligned_side (Grob*me, Axis a);
+  static SCM aligned_side (Grob*me, Axis a, bool pure, int start, int end);
 
-  static SCM general_side_position (Grob *, Axis, bool);
+  static SCM general_side_position (Grob *, Axis, bool, bool pure, int start, int end);
   static Axis get_axis (Grob *);
   static void set_axis (Grob *, Axis);
   static bool has_interface (Grob *);
Index: lily/include/spanner.hh
===================================================================
RCS file: /sources/lilypond/lilypond/lily/include/spanner.hh,v
retrieving revision 1.81
diff -u -r1.81 spanner.hh
--- lily/include/spanner.hh	11 Feb 2006 11:35:16 -0000	1.81
+++ lily/include/spanner.hh	7 Jun 2006 22:54:58 -0000
@@ -45,8 +45,7 @@
   void substitute_one_mutable_property (SCM sym, SCM val);
   bool fast_substitute_grob_array (SCM sym, Grob_array *);
 
-  // TODO: make virtual and do this for Items as well.
-  Interval_t<int> spanned_rank_iv ();
+  virtual Interval_t<int> spanned_rank_iv ();
   void set_bound (Direction d, Grob *);
   Item *get_bound (Direction d) const;
 
Index: lily/include/stem.hh
===================================================================
RCS file: /sources/lilypond/lilypond/lily/include/stem.hh,v
retrieving revision 1.103
diff -u -r1.103 stem.hh
--- lily/include/stem.hh	16 Feb 2006 11:54:21 -0000	1.103
+++ lily/include/stem.hh	7 Jun 2006 22:54:58 -0000
@@ -50,6 +50,7 @@
   DECLARE_SCHEME_CALLBACK (calc_stem_info, (SCM));
   DECLARE_SCHEME_CALLBACK (calc_positioning_done, (SCM));
   DECLARE_SCHEME_CALLBACK (width, (SCM smob));
+  DECLARE_SCHEME_CALLBACK (pure_height, (SCM, SCM, SCM));
   DECLARE_SCHEME_CALLBACK (height, (SCM));
 };
 #endif
Index: scm/define-grob-properties.scm
===================================================================
RCS file: /sources/lilypond/lilypond/scm/define-grob-properties.scm,v
retrieving revision 1.167
diff -u -r1.167 define-grob-properties.scm
--- scm/define-grob-properties.scm	2 Jun 2006 00:34:28 -0000	1.167
+++ scm/define-grob-properties.scm	7 Jun 2006 22:54:59 -0000
@@ -484,6 +484,9 @@
      (apply define-internal-grob-property x))
    
    `(
+     (pure-relevant-elements ,ly:grob-array? "The subset of elements that are relevant for finding the pure-Y-extent.")
+     (cached-pure-extents ,vector? "Used by a VerticalAxisGroup to cache the Y-extents of different column ranges.")
+     (common-refpoint-of-elements ,ly:grob? "Caches the common_refpoint_of_array of the elements grob-set")
      (axis-group-parent-X ,ly:grob? "Containing X axis group")
      (axis-group-parent-Y ,ly:grob? "Containing Y axis group")
      (accidental-grobs ,list? "Alist with (NOTENAME . GROBLIST) entries")
@@ -498,6 +501,7 @@
      (dot ,ly:grob? "reference to Dots object.")
      (dots ,ly:grob-array? "multiple Dots objects.")
      (figures ,ly:grob-array? "Figured bass objects for continuation line.")
+     (important-column-ranks ,vector? "Cache of columns that contain items-worth-living.")
      (glyph-name ,string? "a name of character within font.")
      (pedal-text ,ly:grob? "Pointer to the text of a mixed-style piano pedal.")
      (stem ,ly:grob? "pointer to Stem object.")
@@ -555,6 +559,7 @@
      (positioning-done ,boolean?
 		       "Used to signal that a positioning element
 did its job. This ensures that a positioning is only done once.")
+     (pure-Y-extent ,number-pair? "The estimated height of a system")
 
 
      (script-stencil ,pair? "Pair (@code{type} . @code{arg}), which
Index: scm/define-grobs.scm
===================================================================
RCS file: /sources/lilypond/lilypond/scm/define-grobs.scm,v
retrieving revision 1.334
diff -u -r1.334 define-grobs.scm
--- scm/define-grobs.scm	30 May 2006 15:47:16 -0000	1.334
+++ scm/define-grobs.scm	7 Jun 2006 22:55:00 -0000
@@ -67,7 +67,7 @@
      . (
 	(axes . (0 1))
 	(X-extent . ,ly:axis-group-interface::width)
-	(X-extent . ,ly:axis-group-interface::height)
+	(Y-extent . ,ly:axis-group-interface::height)
 	(space-alist . (
 			(clef . (extra-space . 0.5))
 			(key-signature . (extra-space . 0.0))
@@ -1314,7 +1314,7 @@
 	(meta . ((class . Spanner)
 		 (interfaces . (slur-interface))))))
 
- (SostenutoPedal
+    (SostenutoPedal
      . (
 	(stencil . ,ly:text-interface::print)
 	(direction . ,RIGHT)
@@ -1938,3 +1938,68 @@
 
 (set! all-grob-descriptions (sort all-grob-descriptions alist<?))
 
+
+(define pure-print-callbacks
+  (list
+   `(,ly:note-head::print . '())
+   `(,ly:clef::print . '())
+   `(,ly:text-interface::print . '())))
+
+;; ly:grob::stencil-extent is safe iff the print callback is safe too
+(define (pure-stencil-height grob start stop)
+  (let ((sten (ly:grob-property-data grob 'stencil)))
+    (if (or
+	 (ly:stencil? sten)
+	 (pair? (assq sten pure-print-callbacks)))
+	(ly:grob::stencil-height grob)
+	'(0 . 0))))
+
+(define-public pure-Y-extents
+  (list
+   `(,ly:staff-symbol::height . ())))
+
+(define-public Y-extent-conversions
+  (list
+   `(,ly:stem::height . ,ly:stem::pure-height)
+   `(,ly:grob::stencil-height . ,pure-stencil-height)
+   `(,ly:side-position-interface::y-aligned-side . ,ly:side-position-interface::pure-y-aligned-side)
+   `(,ly:axis-group-interface::height . ,ly:axis-group-interface::pure-height)
+   `(,ly:hara-kiri-group-spanner::y-extent . ,ly:hara-kiri-group-spanner::pure-height)))
+
+(define-public pure-Y-offsets
+  (list
+   `(,ly:staff-symbol-referencer::callback . ())))
+
+(define-public Y-offset-conversions
+  (list
+   `(,ly:side-position-interface::y-aligned-side . ,ly:side-position-interface::pure-y-aligned-side)))
+
+(define-public (pure-relevant grob)
+  (let ((extent-callback (ly:grob-property-data grob 'Y-extent)))
+    (or
+     (pair? (assq extent-callback pure-Y-extents))
+     (and
+      (pair? (assq extent-callback Y-extent-conversions))
+      (or
+       (not (eq? extent-callback ly:grob::stencil-height))
+       (pair? (assq (ly:grob-property-data grob 'stencil) pure-print-callbacks))
+       (ly:stencil? (ly:grob-property-data grob 'stencil)))))))
+
+(define (pure-conversion pures conversions defsymbol defreturn rettype? grob start stop)
+  (let* ((normal-callback (ly:grob-property-data grob defsymbol))
+	 (pure-callback (assq normal-callback conversions)))
+    (if (rettype? normal-callback)
+	normal-callback
+	(if (pair? (assq normal-callback pures))
+	    (normal-callback grob)
+	    (if (pair? pure-callback)
+		((cdr pure-callback) grob start stop)
+		defreturn)))))
+
+(define-public (pure-Y-extent grob start stop)
+  (pure-conversion pure-Y-extents Y-extent-conversions
+		   'Y-extent '(0 . 0) pair? grob start stop))
+
+(define-public (pure-Y-offset grob start stop)
+  (pure-conversion pure-Y-offsets Y-offset-conversions
+		   'Y-offset 0 number? grob start stop))
Index: scm/paper-system.scm
===================================================================
RCS file: /sources/lilypond/lilypond/scm/paper-system.scm,v
retrieving revision 1.6
diff -u -r1.6 paper-system.scm
--- scm/paper-system.scm	4 Jun 2006 16:36:26 -0000	1.6
+++ scm/paper-system.scm	7 Jun 2006 22:55:00 -0000
@@ -103,7 +103,15 @@
 					(list annotations
 					      (ly:make-stencil '() (cons 0 1) (cons 0 0))
 					      (apply ly:stencil-add
-						     extent-annotations)))))))))
+						     extent-annotations))))))))
+
+	 (grob (ly:prob-property system 'system-grob))
+	 (estimate-extent (if (ly:grob? grob)
+			      (annotate-y-interval layout
+						   "extent-estimate"
+						   (ly:grob-property grob 'pure-Y-extent)
+						   #f)
+			      #f)))
     (let ((next-space (ly:prob-property
 		       system 'next-space
 		       (cond ((and next-system
@@ -128,6 +136,12 @@
 				 (+ next-space next-padding)
 				 "refpoint-Y-extent" "next-space+padding"
 				 "space after next-space+padding"))
+    (if estimate-extent
+	(set! annotations
+	      (stack-stencils X RIGHT 0.5
+			      (list annotations
+				    estimate-extent))))
+				
     (if (not (null? annotations))
 	(set! (ly:prob-property system 'stencil)
 	      (ly:stencil-add
_______________________________________________
lilypond-devel mailing list
lilypond-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/lilypond-devel

Reply via email to