]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/page-layout-problem.cc
Fix array over-run; issue 1723
[lilypond.git] / lily / page-layout-problem.cc
index c9301ff3843f6812c1c39a129df9511c01817aca..562f0aeb901c98e1eaa121af331ff0d8af45d9c5 100644 (file)
@@ -67,16 +67,52 @@ Page_layout_problem::get_footnote_count (SCM lines)
   return fn_count;
 }
 
+SCM
+Page_layout_problem::get_footnotes_from_lines (SCM lines)
+{
+  if (!scm_is_pair (lines))
+    return SCM_EOL;
+
+  bool footnotes_added;
+  if (Grob *g = unsmob_grob (scm_car (lines)))
+    footnotes_added = !scm_is_null (g->get_property ("footnote-stencil"));
+  else if (Prob *p = unsmob_prob (scm_car (lines)))
+    footnotes_added = !scm_is_null (p->get_property ("footnote-stencil"));
+  else
+    {
+      programming_error ("Systems on a page must be a prob or grob.");
+      return SCM_EOL;
+    }
+  if (!footnotes_added)
+    {
+      programming_error ("Footnotes must be added to lines before they are retrieved.");
+      return SCM_EOL;
+    }
+
+  SCM out = SCM_EOL;
+  for (SCM s = lines; scm_is_pair (s); s = scm_cdr (s))
+    {
+      if (Grob *g = unsmob_grob (scm_car (s)))
+        out = scm_cons (g->get_property ("footnote-stencil"), out);
+      else if (Prob *p = unsmob_prob (scm_car (s)))
+        out = scm_cons (p->get_property ("footnote-stencil"), out);
+      else
+        programming_error ("Systems on a page must be a prob or grob.");
+    }
+
+  return scm_reverse (out);
+}
+
 /*
-   Returns a stencil for the footnote of each system.  This stencil may
+   Adds a footnote stencil to each system.  This stencil may
    itself be comprised of several footnotes.
 
    This is a long function, but it seems better to keep it intact rather than
    splitting it into parts.
 */
 
-SCM
-Page_layout_problem::get_footnotes_from_lines (SCM lines, int counter, Paper_book *pb)
+void
+Page_layout_problem::add_footnotes_to_lines (SCM lines, int counter, Paper_book *pb)
 {
   /*
     first, we have to see how many footnotes are on this page.
@@ -88,7 +124,7 @@ Page_layout_problem::get_footnotes_from_lines (SCM lines, int counter, Paper_boo
   if (!paper)
     {
       programming_error ("Cannot get footnotes because there is no valid paper block.");
-      return SCM_EOL;
+      return;
     }
 
   SCM number_footnote_table = pb->top_paper ()->c_variable ("number-footnote-table");
@@ -106,8 +142,6 @@ Page_layout_problem::get_footnotes_from_lines (SCM lines, int counter, Paper_boo
   // now, make the footnote stencils with the numbering function
   SCM numbers = SCM_EOL;
   SCM in_text_numbers = SCM_EOL;
-  bool do_numbering = to_boolean (paper->c_variable ("footnote-auto-numbering"));
-  // if there's no numbering, skip all this
   /*
     TODO: This recalculates numbering every time this function is called, including once
     after the balloon prints are called.  Although it is not a huge computational drain,
@@ -118,50 +152,47 @@ Page_layout_problem::get_footnotes_from_lines (SCM lines, int counter, Paper_boo
     in duplicated work, either by making this process less complicated or (preferably)
     by passing its results downstream.
   */
-  if (do_numbering)
+  vector<SCM> footnote_number_markups; // Holds the numbering markups.
+  vector<Stencil *> footnote_number_stencils; // Holds translated versions of the stencilized numbering markups.
+  for (vsize i = 0; i < fn_count; i++)
     {
-      vector<SCM> footnote_number_markups; // Holds the numbering markups.
-      vector<Stencil *> footnote_number_stencils; // Holds translated versions of the stencilized numbering markups.
-      for (vsize i = 0; i < fn_count; i++)
+      SCM markup = scm_call_1 (numbering_function, scm_from_int (counter));
+      Stencil *s = unsmob_stencil (Text_interface::interpret_markup (layout, props, markup));
+      if (!s)
         {
-          SCM markup = scm_call_1 (numbering_function, scm_from_int (counter));
-          Stencil *s = unsmob_stencil (Text_interface::interpret_markup (layout, props, markup));
-          if (!s)
-            {
-              programming_error ("Your numbering function needs to return a stencil.");
-              markup = SCM_EOL;
-              s = new Stencil (Box (Interval (0, 0), Interval (0, 0)), SCM_EOL);
-            }
-          footnote_number_markups.push_back (markup);
-          footnote_number_stencils.push_back (s);
-          counter++;
+          programming_error ("Your numbering function needs to return a stencil.");
+          markup = SCM_EOL;
+          s = new Stencil (Box (Interval (0, 0), Interval (0, 0)), SCM_EOL);
         }
+      footnote_number_markups.push_back (markup);
+      footnote_number_stencils.push_back (s);
+      counter++;
+    }
 
-      // find the maximum X_AXIS length
-      Real max_length = -infinity_f;
-      for (vsize i = 0; i < fn_count; i++)
-        max_length = max (max_length, footnote_number_stencils[i]->extent (X_AXIS).length ());
+  // find the maximum X_AXIS length
+  Real max_length = -infinity_f;
+  for (vsize i = 0; i < fn_count; i++)
+    max_length = max (max_length, footnote_number_stencils[i]->extent (X_AXIS).length ());
 
-      /*
-        translate each stencil such that it attains the correct maximum length and bundle the
-        footnotes into a scheme object.
-      */
-      SCM *tail = &numbers;
-      SCM *in_text_tail = &in_text_numbers;
+  /*
+    translate each stencil such that it attains the correct maximum length and bundle the
+    footnotes into a scheme object.
+  */
+  SCM *tail = &numbers;
+  SCM *in_text_tail = &in_text_numbers;
 
-      for (vsize i = 0; i < fn_count; i++)
-        {
-          *in_text_tail = scm_cons (footnote_number_markups[i], SCM_EOL);
-          in_text_tail = SCM_CDRLOC (*in_text_tail);
-          footnote_number_stencils[i]->translate_axis (max_length - footnote_number_stencils[i]->extent (X_AXIS).length (), X_AXIS);
-          *tail = scm_cons (footnote_number_stencils[i]->smobbed_copy (), SCM_EOL);
-          tail = SCM_CDRLOC (*tail);
-        }
+  for (vsize i = 0; i < fn_count; i++)
+    {
+      *in_text_tail = scm_cons (footnote_number_markups[i], SCM_EOL);
+      in_text_tail = SCM_CDRLOC (*in_text_tail);
+      footnote_number_stencils[i]->translate_axis ((max_length
+                                                    - footnote_number_stencils[i]->extent (X_AXIS).length ()),
+                                                   X_AXIS);
+      *tail = scm_cons (footnote_number_stencils[i]->smobbed_copy (), SCM_EOL);
+      tail = SCM_CDRLOC (*tail);
     }
   // build the footnotes
 
-  SCM footnotes = SCM_EOL;
-
   for (SCM s = lines; scm_is_pair (s); s = scm_cdr (s))
     {
       // Take care of musical systems.
@@ -174,7 +205,7 @@ Page_layout_problem::get_footnotes_from_lines (SCM lines, int counter, Paper_boo
               continue;
             }
           Stencil mol;
-
+          Stencil in_note_mol;
           for (vsize i = 0; i < sys->footnote_grobs ()->size (); i++)
             {
               Grob *footnote = sys->footnote_grobs ()->at (i);
@@ -183,9 +214,6 @@ Page_layout_problem::get_footnotes_from_lines (SCM lines, int counter, Paper_boo
                 if (orig->is_broken ())
                   footnote_markup = orig->broken_intos_[0]->get_property ("footnote-text");
 
-              if (!Text_interface::is_markup (footnote_markup))
-                continue;
-
               SCM props = scm_call_1 (ly_lily_module_constant ("layout-extract-page-properties"),
                                       paper->self_scm ());
 
@@ -193,6 +221,14 @@ Page_layout_problem::get_footnotes_from_lines (SCM lines, int counter, Paper_boo
                                                                    props, footnote_markup);
 
               Stencil *footnote_stencil = unsmob_stencil (footnote_stl);
+              bool do_numbering = to_boolean (footnote->get_property ("automatically-numbered"));
+              if (Spanner *orig = dynamic_cast<Spanner *>(footnote))
+                {
+                  if (orig->is_broken ())
+                    for (vsize i = 0; i < orig->broken_intos_.size (); i++)
+                      do_numbering = do_numbering
+                                    || to_boolean (orig->broken_intos_[i]->get_property ("automatically-numbered"));
+                }
               if (do_numbering)
                 {
                   SCM annotation_scm = scm_car (in_text_numbers);
@@ -206,53 +242,67 @@ Page_layout_problem::get_footnotes_from_lines (SCM lines, int counter, Paper_boo
                     }
 
                   Stencil *annotation = unsmob_stencil (scm_car (numbers));
-                  annotation->translate_axis (footnote_stencil->extent (Y_AXIS)[UP] + number_raise - annotation->extent (Y_AXIS)[UP], Y_AXIS);
+                  annotation->translate_axis ((footnote_stencil->extent (Y_AXIS)[UP]
+                                               + number_raise
+                                               - annotation->extent (Y_AXIS)[UP]),
+                                              Y_AXIS);
                   footnote_stencil->add_at_edge (X_AXIS, LEFT, *annotation, 0.0);
                   numbers = scm_cdr (numbers);
                   in_text_numbers = scm_cdr (in_text_numbers);
                 }
-              mol.add_at_edge (Y_AXIS, DOWN, *footnote_stencil, padding);
+              if (!footnote_stencil->is_empty ())
+                {
+                  if (to_boolean (footnote->get_property ("footnote")))
+                    mol.add_at_edge (Y_AXIS, DOWN, *footnote_stencil, padding);
+                  else
+                    in_note_mol.add_at_edge (Y_AXIS, DOWN, *footnote_stencil, padding);
+                }
             }
-          footnotes = scm_cons (mol.smobbed_copy (), footnotes);
+          sys->set_property ("in-note-stencil", in_note_mol.smobbed_copy ());
+          sys->set_property ("footnote-stencil", mol.smobbed_copy ());
         }
       // Take care of top-level markups
       else if (Prob *p = unsmob_prob (scm_car (s)))
         {
           SCM stencils = p->get_property ("footnotes");
-          if (stencils == SCM_EOL)
-            continue;
-          Stencil footnote_stencil;
+          Stencil mol;
 
           for (SCM st = stencils; scm_is_pair (st); st = scm_cdr (st))
             {
-              Stencil mol;
-              Stencil *footnote = unsmob_stencil (scm_cadar (st));
-              mol.add_stencil (*footnote);
+              Stencil footnote_stencil;
+              Stencil *footnote = unsmob_stencil (scm_caddar (st));
+              footnote_stencil.add_stencil (*footnote);
+              bool do_numbering = to_boolean (scm_cadar (st));
+              SCM in_text_stencil = Stencil ().smobbed_copy ();
               if (do_numbering)
                 {
                   Stencil *annotation = unsmob_stencil (scm_car (numbers));
                   SCM in_text_annotation = scm_car (in_text_numbers);
-                  SCM in_text_stencil = Text_interface::interpret_markup (layout, props, in_text_annotation);
+                  in_text_stencil = Text_interface::interpret_markup (layout,
+                                                                      props,
+                                                                      in_text_annotation);
                   if (!unsmob_stencil (in_text_stencil))
                     in_text_stencil = SCM_EOL;
-                  number_footnote_table = scm_cons (scm_cons (scm_caar (st), in_text_stencil), number_footnote_table);
-                  annotation->translate_axis (mol.extent (Y_AXIS)[UP] + number_raise - annotation->extent (Y_AXIS)[UP], Y_AXIS);
-                  mol.add_at_edge (X_AXIS, LEFT, *annotation, 0.0);
+                  annotation->translate_axis ((footnote_stencil.extent (Y_AXIS)[UP]
+                                               + number_raise
+                                               - annotation->extent (Y_AXIS)[UP]),
+                                              Y_AXIS);
+                  footnote_stencil.add_at_edge (X_AXIS, LEFT, *annotation, 0.0);
                   numbers = scm_cdr (numbers);
                   in_text_numbers = scm_cdr (in_text_numbers);
                 }
-              footnote_stencil.add_at_edge (Y_AXIS, DOWN, mol, padding);
+              number_footnote_table = scm_cons (scm_cons (scm_caar (st),
+                                                          in_text_stencil),
+                                                number_footnote_table);
+              if (!footnote_stencil.is_empty ())
+                mol.add_at_edge (Y_AXIS, DOWN, footnote_stencil, padding);
             }
-          footnotes = scm_cons (footnote_stencil.smobbed_copy (), footnotes);
+          p->set_property ("footnote-stencil", mol.smobbed_copy ());
         }
     }
 
   // note that this line of code doesn't do anything if numbering isn't turned on
   pb->top_paper ()->set_variable (ly_symbol2scm ("number-footnote-table"), number_footnote_table);
-  if (!scm_is_pair (footnotes))
-    return SCM_EOL;
-
-  return scm_reverse (footnotes);
 }
 
 Stencil *
@@ -277,6 +327,11 @@ Page_layout_problem::get_footnote_separator_stencil (Output_def *paper)
 void
 Page_layout_problem::add_footnotes_to_footer (SCM footnotes, Stencil *foot, Paper_book *pb)
 {
+  if (!foot && scm_is_pair (footnotes))
+    {
+      warning ("Must have a footer to add footnotes.");
+      return;
+    }
   bool footnotes_found = false;
   Real footnote_padding = robust_scm2double (pb->paper_->c_variable ("footnote-padding"), 0.0);
   Real footnote_footer_padding = robust_scm2double (pb->paper_->c_variable ("footnote-footer-padding"), 0.0);
@@ -305,7 +360,7 @@ Page_layout_problem::add_footnotes_to_footer (SCM footnotes, Stencil *foot, Pape
     }
 }
 
-Page_layout_problem::Page_layout_problem (Paper_book *pb, SCM page_scm, SCM systems, int footnote_count)
+Page_layout_problem::Page_layout_problem (Paper_book *pb, SCM page_scm, SCM systems)
   : bottom_skyline_ (DOWN)
 {
   Prob *page = unsmob_prob (page_scm);
@@ -322,9 +377,7 @@ Page_layout_problem::Page_layout_problem (Paper_book *pb, SCM page_scm, SCM syst
 
       if (pb && pb->paper_)
         {
-          if (to_boolean (pb->paper_->c_variable ("reset-footnotes-on-new-page")))
-            footnote_count = 0;
-          SCM footnotes = get_footnotes_from_lines (systems, footnote_count, pb);
+          SCM footnotes = get_footnotes_from_lines (systems);
           add_footnotes_to_footer (footnotes, foot, pb);
         }
       else
@@ -373,6 +426,8 @@ Page_layout_problem::Page_layout_problem (Paper_book *pb, SCM page_scm, SCM syst
 
       read_spacing_spec (top_system_spacing, &header_padding_, ly_symbol2scm ("padding"));
       read_spacing_spec (last_bottom_spacing, &footer_padding_, ly_symbol2scm ("padding"));
+      in_note_padding_ = robust_scm2double (paper->c_variable ("in-note-padding"), 0.5);
+      in_note_direction_ = robust_scm2dir (paper->c_variable ("in-note-direction"), UP);
     }
   bool last_system_was_title = false;
 
@@ -481,6 +536,18 @@ Page_layout_problem::append_system (System *sys, Spring const &spring, Real inde
   build_system_skyline (elts, minimum_offsets_with_min_dist, &up_skyline, &down_skyline);
   up_skyline.shift (indent);
   down_skyline.shift (indent);
+  Stencil *in_note_stencil = unsmob_stencil (sys->get_property ("in-note-stencil"));
+
+  if (in_note_stencil && in_note_stencil->extent (Y_AXIS).length () > 0)
+    {
+      sys->set_property ("in-note-padding", scm_from_double (in_note_padding_));
+      sys->set_property ("in-note-direction", scm_from_int (in_note_direction_));
+      Skyline *sky = in_note_direction_ == UP ? &up_skyline : &down_skyline;
+      sky->set_minimum_height (sky->max_height ()
+                               + in_note_direction_
+                                 * (in_note_padding_
+                                    + in_note_stencil->extent (Y_AXIS).length ()));
+    }
 
   /*
     We need to call distance with skyline-horizontal-padding because
@@ -488,7 +555,10 @@ Page_layout_problem::append_system (System *sys, Spring const &spring, Real inde
     of an individual staff.  So we add the padding for the distance check
     at the time of adding in the system.
   */
-  Real minimum_distance = up_skyline.distance (bottom_skyline_, robust_scm2double (sys->get_property ("skyline-horizontal-padding"), 0)) + padding;
+  Real minimum_distance = up_skyline.distance (bottom_skyline_,
+                                               robust_scm2double (sys->get_property ("skyline-horizontal-padding"),
+                                                                  0))
+                          + padding;
 
   Spring spring_copy = spring;
   spring_copy.ensure_min_distance (minimum_distance);