On Mon, 2006-05-22 at 20:58 +1000, Joe Neeman wrote:
> On Mon, 2006-05-22 at 10:57 +0200, Han-Wen Nienhuys wrote:
> > Joe Neeman schreef:
> > >> In that case, you could get the approximate height of one broken system 
> > >> in logarithmic time.
> > >>
> > > Here's a first attempt at doing this. It isn't complete or well-tested
> > > yet.
Here's my second attempt. I think it is feature-complete. It's also
reasonably fast. I have successfully used it to page-break the entire
Haydn Op 76 string quartets and it seems to be accurate enough. Web
makes successfully, although I haven't yet dug through the regression
tests to make sure they're OK.

Things still to do:
- remove the debugging messages
- remove the code that is commented out
- review the caching (I implemented caching little by little while
benchmarking, but I don't know if my later efforts made my earlier ones
obsolete)
- maybe move most of Grob::pure_height and
Grob::pure_relative_y_coordinate to Scheme (It was originally in scheme,
but I moved it to C++ for speed reasons that might not matter any more)

How does it look?
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	3 Jun 2006 02:10:06 -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,50 @@
   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);
+  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	3 Jun 2006 02:10:06 -0000
@@ -8,10 +8,17 @@
 
 #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 "item.hh"
+#include "paper-column.hh"
+#include "paper-score.hh"
+#include "system.hh"
 #include "warn.hh"
+#include "international.hh"
 
 void
 Axis_group_interface::add_element (Grob *me, Grob *e)
@@ -61,6 +68,92 @@
   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_brk = VPOS;
+  vsize end_brk = VPOS;
+
+  for (vsize i = 0; i < breaks.size (); i++)
+    {
+      int r = Paper_column::get_rank (cols[breaks[i]]);
+      if (start == r)
+	start_brk = i;
+      if (end == r)
+	end_brk = i;
+    }
+
+  if (start_brk == VPOS || end_brk == 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_brk; i < end_brk; 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 ())
+	    {
+	      message (_f ("%s %d-%d has child %s with extent (%f,%f)", me->name().c_str(), start, end, elts[i]->name().c_str(), dims[UP], dims[DOWN]));
+	      r.unite (dims);
+	    }
+	}
+    }
+  return r;
+}
+
 MAKE_SCHEME_CALLBACK (Axis_group_interface, width, 1);
 SCM
 Axis_group_interface::width (SCM smob)
@@ -76,6 +169,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 +193,41 @@
   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));
+
+  //  ly_display_scm (me->self_scm ());
+  //  message (_f ("has pure-extent (%f,%f)\n", r[UP], r[DOWN]));
+
+  return ly_interval2scm (r - my_coord);
+}
+
 void
 Axis_group_interface::get_children (Grob *me, vector<Grob*> *found)
 {
@@ -111,4 +250,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	3 Jun 2006 02:10:07 -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,13 @@
 					     ragged_right);
       for (vsize i = 0; i < breaks_.size () - 1; i++)
 	{
+	  //message (_f ("extents starting at %d", Paper_column::get_rank (all_[breaks_[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,16 +181,18 @@
 	      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_))
                 break;
             }
+	  //message (_f ("max extent was %f", max_ext));
 	}
 
       /* work out all the starting indices */
@@ -335,6 +342,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	3 Jun 2006 02:10:16 -0000
@@ -10,6 +10,7 @@
 
 #include <cstring>
 
+#include "align-interface.hh"
 #include "input-smob.hh"
 #include "international.hh"
 #include "item.hh"
@@ -278,6 +279,49 @@
   return off;
 }
 
+Real
+Grob::pure_relative_y_coordinate (Grob const *refp, int start, int end)
+{
+  if (refp == this)
+    return 0.0;
+
+  SCM cached = get_property ("pure-Y-offset-cache");
+  Real off = 0;
+  if (scm_is_number (cached))
+    off = scm_to_double (cached);
+  else
+    {
+      SCM pure_offsets = ly_lily_module_constant ("pure-Y-offsets");
+      SCM conversions = ly_lily_module_constant ("Y-offset-conversions");
+      SCM y_offset = get_property_data (ly_symbol2scm ("Y-offset"));
+
+      if (scm_is_pair (scm_assq (y_offset, pure_offsets)))
+	off = scm_to_double (get_property ("Y-offset"));
+      else
+	{
+	  SCM conv = scm_assq (y_offset, conversions);
+	  if (scm_is_pair (conv))
+	    {
+	      SCM proc = scm_cdr (conv);
+	      set_property ("pure-Y-offset-cache", scm_from_double (0));
+	      SCM soff = scm_apply_3 (proc, self_scm (), scm_from_int (start), scm_from_int (end), SCM_EOL);
+	      off = scm_to_double (soff);
+	    }
+	}
+    }
+
+  /* pure-Y-offset is always cacheable? (pure Alignment is not included yet) */
+  set_property ("pure-Y-offset-cache", scm_from_double (off));
+
+  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 +349,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 (_f ("tried to get pure X-offset"));
+  return (pure && a == Y_AXIS) ? pure_relative_y_coordinate (refp, start, end)
+    : relative_coordinate (refp, a);
+}
 
 /****************************************************************
   extents
@@ -367,6 +419,58 @@
   return real_ext;
 }
 
+Interval
+Grob::pure_height (Grob *refp, int start, int end)
+{
+  SCM cached = get_property ("pure-Y-extent-cache");
+  Interval iv = robust_scm2interval (cached, Interval ());
+  if (!iv.is_empty ())
+    return iv;
+
+  SCM pure_extents = ly_lily_module_constant ("pure-Y-extents");
+  SCM conversions = ly_lily_module_constant ("Y-extent-conversions");
+  SCM y_extent = get_property_data (ly_symbol2scm ("Y-extent"));
+
+  if (scm_is_pair (y_extent))
+    iv = ly_scm2interval (y_extent);
+  else if (scm_is_pair (scm_assq (y_extent, pure_extents)))
+    iv = ly_scm2interval (get_property ("Y-extent"));
+  else
+    {
+      SCM conv = scm_assq (y_extent, conversions);
+      if (scm_is_pair (conv))
+	{
+	  SCM proc = scm_cdr (conv);
+	  set_property ("pure-Y-extent-cache", ly_interval2scm (Interval (0, 0)));
+	  SCM siv = scm_apply_3 (proc, self_scm (), scm_from_int (start), scm_from_int (end), SCM_EOL);
+	  if (to_boolean (get_property ("pure-cacheable")))
+	    set_property ("pure-Y-extent-cache", siv);
+	  else
+	    del_property (ly_symbol2scm ("pure-Y-extent-cache"));
+
+	  iv = ly_scm2interval (siv);
+	}
+    }
+  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 (_f ("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
 ****************************************************************/
@@ -535,6 +639,9 @@
 	       "staff-symbol "
 	       "stencil "
 	       "transparent "
+	       "pure-Y-extent-cache "
+	       "pure-Y-offset-cache "
+	       "pure-cacheable "
 	       );
 
 
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	3 Jun 2006 02:10:16 -0000
@@ -25,22 +25,77 @@
   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);
+}
+
+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-columns");
+  vsize ustart = (vsize) max (start, 0);
+  vsize uend = (end >= 0) ? end : VPOS;
+  if (scm_is_vector (important))
+    {
+      vsize imp_size = scm_c_vector_length (important);
+      for (vsize i = ustart; i <= uend; i++)
+	{
+	  if (i >= imp_size)
+	    break;
+	  if (to_boolean (scm_c_vector_ref (important, i)))
+	    return false;
+	}
+    }
+  else /* build the important-columns-cache */
+    {
+      extract_grob_set (me, "items-worth-living", worth);
+      vector<bool> important_cols;
+
+      for (vsize i = 0; i < worth.size (); i++)
+	{
+	  Item *it = dynamic_cast<Item*> (worth[i]);
+	  if (it)
+	    {
+	      vsize col = Paper_column::get_rank (it->get_column ());
+	      important_cols.resize (max (important_cols.size (), col+1));
+	      important_cols[col] = 1;
+	    }
+	}
+
+      SCM scm_vec = scm_c_make_vector (important_cols.size (), SCM_EOL);
+      for (vsize i = 0; i < important_cols.size (); i++)
+	scm_vector_set_x (scm_vec, scm_from_int (i), scm_from_bool (important_cols[i]));
+      me->set_property ("important-columns", 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 +154,7 @@
 
 	       /* properties */
 	       "items-worth-living "
+	       "important-columns "
 	       "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	3 Jun 2006 02:10:16 -0000
@@ -8,6 +8,7 @@
 
 #include "item.hh"
 
+#include "axis-group-interface.hh"
 #include "paper-score.hh"
 #include "warn.hh"
 #include "paper-column.hh"
@@ -72,6 +73,12 @@
       Item *item = dynamic_cast<Item *> (dolly);
       get_root_system (this)->typeset_grob (item);
       new_copies[i] = item;
+
+      /* if we end up suiciding, our Y-axis-parent won't get the correct
+	 Y-extent unless we add our child to it */
+      Grob *p = unsmob_grob (get_object ("axis-group-parent-Y"));
+      if (p)
+	Axis_group_interface::add_element (p, dolly);
     }
   while (flip (&i) != LEFT);
 
@@ -156,6 +163,30 @@
     }
 }
 
+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	3 Jun 2006 02:10:16 -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/pointer-group-interface.cc
===================================================================
RCS file: /sources/lilypond/lilypond/lily/pointer-group-interface.cc,v
retrieving revision 1.17
diff -u -r1.17 pointer-group-interface.cc
--- lily/pointer-group-interface.cc	16 Mar 2006 14:39:46 -0000	1.17
+++ lily/pointer-group-interface.cc	3 Jun 2006 02:10:16 -0000
@@ -12,6 +12,8 @@
 #include "item.hh"
 #include "grob-array.hh"
 #include "grob.hh"
+#include "warn.hh"
+#include "international.hh"
 
 int
 Pointer_group_interface::count (Grob *me, SCM sym)
@@ -52,6 +54,10 @@
 {
   Grob_array *arr = get_grob_array (me, sym);
   arr->add (p);
+
+  //  message ( _f("grob %s adds grob %s", me->name ().c_str (), p->name ().c_str ()));
+  //  if (me->name() == "System")
+  //    message ("hi");
 }
 
 void
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	3 Jun 2006 02:10:16 -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->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/simple-spacer.cc
===================================================================
RCS file: /sources/lilypond/lilypond/lily/simple-spacer.cc,v
retrieving revision 1.98
diff -u -r1.98 simple-spacer.cc
--- lily/simple-spacer.cc	9 May 2006 02:15:56 -0000	1.98
+++ lily/simple-spacer.cc	3 Jun 2006 02:10:17 -0000
@@ -305,6 +305,7 @@
   Real inverse_hooke_;
   Real end_ideal_;
   Real end_inverse_hooke_;
+  SCM break_permission_;
   Interval keep_inside_line_;
 };
 
@@ -401,6 +402,7 @@
     }
   if (!line_starter && to_boolean (col->get_property ("keep-inside-line")))
     desc.keep_inside_line_ = col->extent (col, X_AXIS);
+  desc.break_permission_ = col->get_property ("line-break-permission");
   return desc;
 }
 
@@ -409,10 +411,12 @@
 		 Real line_len, Real indent, bool ragged)
 {
   vector<Real> force;
-  force.resize (breaks.size () * breaks.size ());
+  force.resize (breaks.size () * breaks.size (), infinity_f);
 
   vector<Column_desc> cols;
   vsize b = 1;
+  SCM force_break = ly_symbol2scm ("force");
+
   cols.push_back (Column_desc ());
   for (vsize i = 1; i < icols.size () - 1; i++)
     {
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	3 Jun 2006 02:10:17 -0000
@@ -110,7 +110,7 @@
     {
       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));
+      //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	3 Jun 2006 02:10:17 -0000
@@ -225,6 +225,29 @@
 	   && 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);
+  iv = Interval (-len, 0);
+
+  if (!hp.is_empty ())
+    iv.translate (hp[dir] * ss / 2);
+
+  SCM scm_iv = ly_interval2scm (iv);
+  me->set_property ("pure-Y-extent-cache", scm_iv);
+  return scm_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	3 Jun 2006 02:10:17 -0000
@@ -206,6 +206,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));
+      message ( _f("system from %d to %d has extent (%f,%f)", st, end, iv[UP], iv[DOWN]));
+
       system->set_bound (LEFT, c[0]);
       system->set_bound (RIGHT, c.back ());
       for (vsize j = 0; j < c.size (); j++)
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	3 Jun 2006 02:10:17 -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	3 Jun 2006 02:10:17 -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	3 Jun 2006 02:10:17 -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	3 Jun 2006 02:10:17 -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	3 Jun 2006 02:10:17 -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	3 Jun 2006 02:10:17 -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	3 Jun 2006 02:10:17 -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	3 Jun 2006 02:10:17 -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	3 Jun 2006 02:10:17 -0000
@@ -46,7 +46,7 @@
   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	3 Jun 2006 02:10:17 -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	3 Jun 2006 02:10:27 -0000
@@ -484,6 +484,12 @@
      (apply define-internal-grob-property x))
    
    `(
+     (pure-Y-offset-cache ,number? "Caches a pure-Y-offset")
+     (pure-Y-extent-cache ,pair? "Caches a pure Y-extent")
+     (pure-cacheable ,boolean? "Whether the pure Y-extent and offset are cacheable (ie. they don't depend on the start and end of the line)")
+     (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 +504,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-columns ,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.")
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	3 Jun 2006 02:10:27 -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))
@@ -994,6 +994,7 @@
 	(axes . (0 1))
 	(X-extent . ,ly:axis-group-interface::width)
 	(Y-extent . ,ly:axis-group-interface::height)
+	(pure-cacheable . #t)
 	(meta . ((class . Item)
 		 (interfaces . (axis-group-interface
 				note-column-interface))))))
@@ -1314,7 +1315,7 @@
 	(meta . ((class . Spanner)
 		 (interfaces . (slur-interface))))))
 
- (SostenutoPedal
+    (SostenutoPedal
      . (
 	(stencil . ,ly:text-interface::print)
 	(direction . ,RIGHT)
@@ -1938,3 +1939,54 @@
 
 (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)))
+	(begin
+;	  (display (list "matched " (ly:grob-property-data grob 'stencil) "\n"))
+	  (ly:grob::stencil-height grob))
+	(begin
+;	  (display (list "failed " (ly:grob-property-data grob 'stencil) "\n"))
+	  '(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))
+	 (offset-callback (ly:grob-property-data grob 'Y-offset)))
+     (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)))))))
Index: scm/page.scm
===================================================================
RCS file: /sources/lilypond/lilypond/scm/page.scm,v
retrieving revision 1.334 -- not really, I fucked this up when I edited the diff
diff -u -r1.334 page.scm
+++ scm/page.scm	3 Jun 2006 02:10:27 -0000
@@ -320,8 +320,10 @@
        (foot (prop 'foot-stencil))
        )
 
-    (if (or (annotate? layout)
-	    (ly:output-def-lookup layout 'annotatesystems #f))
+    (if (and
+	 (or (annotate? layout)
+	     (ly:output-def-lookup layout 'annotatesystems #f))
+	 (pair? lines))
 
 	(begin
 	  (for-each (lambda (sys) (paper-system-annotate sys layout))
@@ -390,9 +392,6 @@
   (let*
       ((p-book (page-property page 'paper-book))
        (layout (ly:paper-book-paper p-book))
-       (scopes (ly:paper-book-scopes p-book))
-       (number (page-page-number page))
-       (last? (page-property page 'is-last))
        (h (- (ly:output-def-lookup layout 'paper-height)
 	       (ly:output-def-lookup layout 'top-margin)
 	       (ly:output-def-lookup layout 'bottom-margin)))
_______________________________________________
lilypond-devel mailing list
lilypond-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/lilypond-devel

Reply via email to