]> git.donarmstrong.com Git - lilypond.git/commitdiff
* scm/paper-system.scm (paper-system-annotate): also annotate the
authorJoe Neeman <joeneeman@gmail.com>
Fri, 9 Jun 2006 02:20:21 +0000 (02:20 +0000)
committerJoe Neeman <joeneeman@gmail.com>
Fri, 9 Jun 2006 02:20:21 +0000 (02:20 +0000)
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

25 files changed:
ChangeLog
lily/align-interface.cc
lily/axis-group-interface.cc
lily/constrained-breaking.cc
lily/grob.cc
lily/hara-kiri-group-spanner.cc
lily/include/align-interface.hh
lily/include/axis-group-interface.hh
lily/include/constrained-breaking.hh
lily/include/grob.hh
lily/include/hara-kiri-group-spanner.hh
lily/include/item.hh
lily/include/paper-score.hh
lily/include/side-position-interface.hh
lily/include/spanner.hh
lily/include/stem.hh
lily/item.cc
lily/paper-score.cc
lily/side-position-interface.cc
lily/staff-symbol-referencer.cc
lily/stem.cc
lily/system.cc
scm/define-grob-properties.scm
scm/define-grobs.scm
scm/paper-system.scm

index aee68cfa88ee7dad0ba9660769091bb7998d6687..fd266fe1fe9780e71c82ae066079a4119a64de8b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,39 @@
+2006-06-08  Joe Neeman  <joeneeman@gmail.com>
+
+       * 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-08  Han-Wen Nienhuys  <hanwen@lilypond.org>
 
        * lily/font-config.cc (init_fontconfig): do the init if
index c315e4ec32258ff19eec3acea76b8ed89f8c7738..410344dae2487a58065812212e920e9672820f5f 100644 (file)
@@ -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_interface::align_to_fixed_distance (Grob *me, Axis a)
   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 @@ Align_interface::align_elements_to_extents (Grob *me, Axis a)
     {
       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 @@ Align_interface::align_elements_to_extents (Grob *me, Axis a)
   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 @@ Align_interface::align_elements_to_extents (Grob *me, Axis a)
   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 d590813abf5cedab94f4b9dd1df4582341ad3ca0..1d509f04d1923b436c0f4866d2767e2b085fea32 100644 (file)
@@ -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 @@ Axis_group_interface::relative_group_extent (vector<Grob*> const &elts,
   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 @@ Axis_group_interface::height (SCM smob)
   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,51 @@ Axis_group_interface::generic_group_extent (Grob *me, Axis a)
   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]);
+
+         Item *it = dynamic_cast<Item*> (elts[i]);
+         Direction d = LEFT;
+         if (it)
+           do
+             {
+               Item *piece = it->find_prebroken_piece (d);
+               if (piece && to_boolean (scm_apply_1 (is_relevant, piece->self_scm (), SCM_EOL)))
+                 relevant_elts.push_back (piece);
+             }
+           while (flip (&d) != LEFT);
+       }
+
+      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 +257,8 @@ ADD_INTERFACE (Axis_group_interface, "axis-group-interface",
 
               /* properties */
               "axes "
-              "elements ");
+              "elements "
+              "common-refpoint-of-elements "
+              "pure-relevant-elements "
+              "cached-pure-extents "
+              );
index 3996856cbd4769d21d2aba9a66399d5550c3587a..c9753b1a0a750c5daa0a3903a217e384c72c0af0 100644 (file)
@@ -147,9 +147,9 @@ Constrained_breaking::resize (vsize systems)
   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 @@ Constrained_breaking::resize (vsize systems)
                                             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 @@ Constrained_breaking::resize (vsize systems)
              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 @@ Constrained_breaking::Constrained_breaking (vector<vsize> const &start)
 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 15eb1f9212b80da980ffbdcd8707e09de6a789e1..f79b266b08ee4e6f36f01cd5e22912d5b0bce838 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <cstring>
 
+#include "align-interface.hh"
 #include "input-smob.hh"
 #include "international.hh"
 #include "item.hh"
@@ -278,6 +279,37 @@ Grob::relative_coordinate (Grob const *refp, Axis a) const
   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 @@ Grob::get_offset (Axis a) const
     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 @@ Grob::extent (Grob *refp, Axis a) const
       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 @@ Grob::extent (Grob *refp, Axis a) const
   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 981639c237d81db41dc4f37ca5354a38a8f2bba9..4c9cc03963eb0753f65a39af9c3a0e5942be7129 100644 (file)
@@ -25,22 +25,84 @@ Hara_kiri_group_spanner::y_extent (SCM smob)
   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, 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 @@ ADD_INTERFACE (Hara_kiri_group_spanner, "hara-kiri-group-interface",
 
               /* properties */
               "items-worth-living "
+              "important-column-ranks "
               "remove-empty "
               "remove-first "
               );
index b01c744bffc63284b9374b2dc2afb74f0faab839..273dbc660ccb18dec8cd388c205f9c0298b4eeaa 100644 (file)
@@ -11,6 +11,7 @@
 
 #include "lily-proto.hh"
 #include "lily-guile.hh"
+#include "std-vector.hh"
 
 struct Align_interface
 {
@@ -18,12 +19,17 @@ struct Align_interface
   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 94e1a256d9dc0da75e9bb47e24bfb4372cbbce5b..767271ad34bfda475008db8f72b1f8cdd108d537 100644 (file)
 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 8f2a4de2effeea35c0e0fc030069d39d01e5cecf..ca662e854e6244d6e0ae18f7924ff5df73eed0e6 100644 (file)
@@ -17,7 +17,8 @@ struct Line_details {
   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 @@ struct Line_details {
     force_ = infinity_f;
     extent_ = 0;
     padding_ = 0;
+    bottom_padding_ = 0;
     space_ = 0;
     inverse_hooke_ = 1;
     break_permission_ = ly_symbol2scm ("allow");
index 6c3ef612bd7a81c3526592c0a50baf31bd246a91..e2bc0157cccbbff9902473e6234303af52bfb1cf 100644 (file)
@@ -109,16 +109,22 @@ public:
   /* 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 9533216be80da38173bc77c939b46eeb5868b3ac..0112b0864f081a1695acd7634845716feea8ac7c 100644 (file)
@@ -17,9 +17,11 @@ class Hara_kiri_group_spanner
 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 9d1f2e73f66aeb5d29347667d8f62e942e83516c..7c28a35240f5f212b6ee0c654b9acde45e8bbbe6 100644 (file)
@@ -30,6 +30,7 @@ public:
 
   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 @@ public:
   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 c165b9aacde45d3718cbe7c8877e9ac05adc7788..7f79aeb54873d172dc878c7cc053d750352bd0a4 100644 (file)
@@ -19,6 +19,9 @@ class Paper_score : public Music_output
   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 @@ public:
   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 6c6e48306681713c4b5de49be6c08708808aa92b..ea7655fa626f3cf03306e474a4467fc39429d61c 100644 (file)
@@ -22,12 +22,14 @@ struct Side_position_interface
 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 c64c61d6364a1f664b8a8fe334b1a32e1586636c..074c303036877afe40c8536479719eebb6b18f51 100644 (file)
@@ -45,8 +45,7 @@ public:
   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 da024edb351c87d0b0bdf75fc69c504637571c89..3d06bca6f6e08745fac2cf705ceba87ba7e9536d 100644 (file)
@@ -50,6 +50,7 @@ public:
   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 f4760eb2fd564bdb5d4555fa7592520a2e7fd679..ff00630b5f8a739cc7719caf5ee87d84c29781f0 100644 (file)
@@ -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,37 @@ Item::handle_prebroken_dependencies ()
   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 ();
     }
 }
 
+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 8dfbc38939b4f1c8a57ed4d1137d6adf88045a2f..ffad13c38b076c0b0b171f0abd24b096e1336f59 100644 (file)
@@ -75,9 +75,27 @@ Paper_score::find_break_indices () const
        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 4964c475727014e80f3795faaaa438ef1288786c..52e9ba5221f74ba043ab6109c72ff49c000d8a8f 100644 (file)
@@ -48,7 +48,8 @@ Side_position_interface::get_direction (Grob *me)
 /* 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 @@ Side_position_interface::general_side_position (Grob *me, Axis a, bool use_exten
   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 @@ Side_position_interface::general_side_position (Grob *me, Axis a, bool use_exten
       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 @@ Side_position_interface::general_side_position (Grob *me, Axis a, bool use_exten
 
   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 @@ Side_position_interface::general_side_position (Grob *me, Axis a, bool use_exten
 
 
 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 @@ MAKE_SCHEME_CALLBACK (Side_position_interface, x_aligned_side, 1);
 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 @@ Side_position_interface::aligned_side (Grob *me, Axis a)
       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 @@ Side_position_interface::aligned_side (Grob *me, Axis a)
 
          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 cfde343029a980f20dbf565ac060e20f9d26e4c7..87e83fadad1523842f0cddf291c30c0715f6726c 100644 (file)
@@ -110,7 +110,6 @@ Staff_symbol_referencer::callback (SCM smob)
     {
       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 a25c37f777211d6a77936decee08787fb8cf1016..05fc5e7417cfac2d95256cabd85a350ff5bd3522 100644 (file)
@@ -225,6 +225,28 @@ Stem::is_invisible (Grob *me)
           && 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 dda8fdf1321182e7c8d2dd56e934ac9eb44d6a46..a8a0ff5160f7ba0730c8ce20eee15796780cf5a5 100644 (file)
@@ -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)
@@ -185,6 +184,7 @@ System::get_paper_systems ()
        progress_indication ("[");
 
       System *system = dynamic_cast<System *> (broken_intos_[i]);
+
       system->post_processing ();
       scm_vector_set_x (lines, scm_from_int (i),
                        system->get_paper_system ());
@@ -206,6 +206,11 @@ System::break_into_pieces (vector<Column_x_positions> const &breaking)
       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 +509,6 @@ ADD_INTERFACE (System, "system-interface",
               /* properties */
               "all-elements "
               "columns "
+              "pure-Y-extent "
               "spaceable-staves "
               )
index 6303c2a6b22681e8a745eea14def67949824188a..2c84e2d822ff01d16af24fa86bc3215a038ad533 100644 (file)
@@ -484,6 +484,9 @@ sizes (like the dynamic @b{p} and @b{f}) on their baselines.")
      (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 @@ set, which grob to get the direction from .")
      (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 @@ columns.
      (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 02bc9cc8ad924c156ab73cf3cfde1ae2d024f3dd..440cc7162f765c3bdc785229c3f0c43448a26d85 100644 (file)
@@ -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))
        (meta . ((class . Spanner)
                 (interfaces . (slur-interface))))))
 
- (SostenutoPedal
   (SostenutoPedal
      . (
        (stencil . ,ly:text-interface::print)
        (direction . ,RIGHT)
 
 (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 pure-Y-extents
+  (list
+   `(,ly:staff-symbol::height . ())))
+
+(define 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 pure-Y-offsets
+  (list
+   `(,ly:staff-symbol-referencer::callback . ())))
+
+(define 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 2f22865b4830fed7e6a7b2c06611d27da78f3ad6..d3a140531fac845276815dc18dccb11426bbdac3 100644 (file)
                                        (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
                                 (+ 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