]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/page-breaking.cc
Run grand replace for 2015.
[lilypond.git] / lily / page-breaking.cc
index c46a04efa5c363b596da1fbf0ee83b91732cfa25..768cb79cc2150a88f81acdd04e7c09e719a9d64b 100644 (file)
@@ -1,7 +1,7 @@
 /*
   This file is part of LilyPond, the GNU music typesetter.
 
-  Copyright (C) 2006--2011 Joe Neeman <joeneeman@gmail.com>
+  Copyright (C) 2006--2015 Joe Neeman <joeneeman@gmail.com>
 
   LilyPond is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -183,15 +183,18 @@ compress_lines (const vector<Line_details> &orig)
           compressed.title_ = old.title_;
 
           // adds footnotes of one line to the footnotes of another
-          compressed.footnotes_.insert (compressed.footnotes_.begin (),
-                                        old.footnotes_.begin (), old.footnotes_.end ());
+          compressed.footnote_heights_.insert (compressed.footnote_heights_.begin (),
+                                               old.footnote_heights_.begin (),
+                                               old.footnote_heights_.end ());
+          compressed.in_note_heights_.insert (compressed.in_note_heights_.begin (),
+                                              old.in_note_heights_.begin (),
+                                              old.in_note_heights_.end ());
 
           ret.back () = compressed;
         }
       else
         {
           ret.push_back (orig[i]);
-          ret.back ().force_ = 0;
         }
     }
   return ret;
@@ -250,11 +253,11 @@ Page_breaking::Page_breaking (Paper_book *pb, Break_predicate is_break, Prob_bre
   min_systems_per_page_ = max (0, robust_scm2int (pb->paper_->c_variable ("min-systems-per-page"), 0));
   orphan_penalty_ = robust_scm2int (pb->paper_->c_variable ("orphan-penalty"), 100000);
 
-  Stencil *footnote_separator = Page_layout_problem::get_footnote_separator_stencil (pb->paper_);
+  Stencil footnote_separator = Page_layout_problem::get_footnote_separator_stencil (pb->paper_);
 
-  if (footnote_separator)
+  if (!footnote_separator.is_empty ())
     {
-      Interval separator_extent = footnote_separator->extent (Y_AXIS);
+      Interval separator_extent = footnote_separator.extent (Y_AXIS);
       Real separator_span = separator_extent.length ();
 
       footnote_separator_stencil_height_ = separator_span;
@@ -263,6 +266,7 @@ Page_breaking::Page_breaking (Paper_book *pb, Break_predicate is_break, Prob_bre
     footnote_separator_stencil_height_ = 0.0;
 
   footnote_padding_ = robust_scm2double (pb->paper_->c_variable ("footnote-padding"), 0.0);
+  in_note_padding_ = robust_scm2double (pb->paper_->c_variable ("in-note-padding"), 0.0);
   footnote_footer_padding_ = robust_scm2double (pb->paper_->c_variable ("footnote-footer-padding"), 0.0);
 
   footnote_number_raise_ = robust_scm2double (pb->paper_->c_variable ("footnote-number-raise"), 0.0);
@@ -332,6 +336,12 @@ Page_breaking::footnote_separator_stencil_height () const
   return footnote_separator_stencil_height_;
 }
 
+Real
+Page_breaking::in_note_padding () const
+{
+  return in_note_padding_;
+}
+
 Real
 Page_breaking::footnote_padding () const
 {
@@ -455,7 +465,7 @@ Page_breaking::systems ()
           pb->unprotect ();
         }
     }
-  return scm_append (scm_reverse (ret));
+  return scm_append (scm_reverse_x (ret, SCM_EOL));
 }
 
 SCM
@@ -493,7 +503,7 @@ Page_breaking::page_height (int page_num, bool last) const
   // This means that we won't cache properly if page_num is negative or
   // if calc_height returns a negative number.  But that's likely to
   // be rare, so it shouldn't affect performance.
-  vector<Real>cache = last ? last_page_height_cache_ : page_height_cache_;
+  vector<Real> &cache = last ? last_page_height_cache_ : page_height_cache_;
   if (page_num >= 0 && (int) cache.size () > page_num && cache[page_num] >= 0)
     return cache[page_num];
   else
@@ -529,22 +539,22 @@ Page_breaking::breakpoint_property (vsize breakpoint, char const *str)
 }
 
 SCM
-Page_breaking::get_page_configuration (SCM systems, int page_num, int footnote_count, bool ragged, bool last)
+Page_breaking::get_page_configuration (SCM systems, int page_num, bool ragged, bool last)
 {
   SCM dummy_page = make_page (page_num, last);
-  Page_layout_problem layout (book_, dummy_page, systems, footnote_count);
+  Page_layout_problem layout (book_, dummy_page, systems);
   return scm_is_pair (systems) ? layout.solution (ragged) : SCM_EOL;
 }
 
 SCM
-Page_breaking::draw_page (SCM systems, SCM configuration, int page_num, int footnote_num, bool last)
+Page_breaking::draw_page (SCM systems, SCM configuration, int page_num, bool last)
 {
   // Create a stencil for each system.
   SCM paper_systems = SCM_EOL;
-  for (SCM s = scm_reverse (systems); scm_is_pair (s); s = scm_cdr (s))
+  for (SCM s = systems; scm_is_pair (s); s = scm_cdr (s))
     {
       SCM paper_system = scm_car (s);
-      if (Grob *g = unsmob_grob (scm_car (s)))
+      if (Grob *g = Grob::unsmob (scm_car (s)))
         {
           System *sys = dynamic_cast<System *> (g);
           paper_system = sys->get_paper_system ();
@@ -552,32 +562,23 @@ Page_breaking::draw_page (SCM systems, SCM configuration, int page_num, int foot
 
       paper_systems = scm_cons (paper_system, paper_systems);
     }
+  paper_systems = scm_reverse_x (paper_systems, SCM_EOL);
 
   // Create the page and draw it.
   SCM page = make_page (page_num, last);
-  SCM page_module = scm_c_resolve_module ("scm page");
-  SCM page_stencil = scm_c_module_lookup (page_module, "page-stencil");
-  page_stencil = scm_variable_ref (page_stencil);
 
-  Prob *p = unsmob_prob (page);
+  Prob *p = Prob::unsmob (page);
   p->set_property ("lines", paper_systems);
   p->set_property ("configuration", configuration);
 
-  Stencil *foot = unsmob_stencil (p->get_property ("foot-stencil"));
-
-  footnote_num = (to_boolean (book_->paper_->c_variable ("reset-footnotes-on-new-page"))
-                  ? 0
-                  : footnote_num);
+  Stencil *foot_p = Stencil::unsmob (p->get_property ("foot-stencil"));
+  Stencil foot = foot_p ? *foot_p : Stencil ();
 
-  SCM footnotes = Page_layout_problem::get_footnotes_from_lines (systems,
-                  footnote_num,
-                  book_);
+  SCM footnotes = Page_layout_problem::get_footnotes_from_lines (systems);
 
-  Page_layout_problem::add_footnotes_to_footer (footnotes, foot, book_);
+  foot = Page_layout_problem::add_footnotes_to_footer (footnotes, foot, book_);
 
-  if (foot)
-    p->set_property ("foot-stencil", foot->smobbed_copy ());
-  scm_apply_1 (page_stencil, page, SCM_EOL);
+  p->set_property ("foot-stencil", foot.smobbed_copy ());
 
   return page;
 }
@@ -591,18 +592,22 @@ Page_breaking::make_pages (vector<vsize> lines_per_page, SCM systems)
   int first_page_number
     = robust_scm2int (book_->paper_->c_variable ("first-page-number"), 1);
   SCM ret = SCM_EOL;
+  bool reset_footnotes_on_new_page = to_boolean (book_->top_paper ()->c_variable ("reset-footnotes-on-new-page"));
   SCM label_page_table = book_->top_paper ()->c_variable ("label-page-table");
   if (label_page_table == SCM_UNDEFINED)
     label_page_table = SCM_EOL;
 
-  // Build a list of (systems . configuration) pairs. Note that we lay out
-  // the staves and find the configurations before drawing anything. Some
+  // Build a list of (systems configuration . footnote-count) triples.
+  // Note that we lay out the staves and find the configurations,
+  // but we do not draw anything in this function.  It is important
+  // that all staves are laid out vertically before any are drawn; some
   // grobs (like tuplet brackets) look at their neighbours while drawing
-  // themselves. If this happens before the neighbouring staves have
+  // themselves.  If this happens before the neighbouring staves have
   // been laid out, bad side-effects could happen (in particular,
   // Align_interface::align_to_ideal_distances might be called).
   SCM systems_configs_fncounts = SCM_EOL;
   vsize footnote_count = 0;
+  Real last_page_force = 0;
 
   for (vsize i = 0; i < lines_per_page.size (); i++)
     {
@@ -612,34 +617,53 @@ Page_breaking::make_pages (vector<vsize> lines_per_page, SCM systems)
       SCM line_count = scm_from_int (lines_per_page[i]);
       SCM lines = scm_list_head (systems, line_count);
       int fn_lines = Page_layout_problem::get_footnote_count (lines);
-      SCM config = get_page_configuration (lines, page_num, footnote_count, rag, bookpart_last_page);
+      Page_layout_problem::add_footnotes_to_lines (lines, reset_footnotes_on_new_page ? 0 : footnote_count, book_);
+
+      SCM config = SCM_EOL;
+      SCM dummy_page = make_page (page_num, bookpart_last_page);
+      Page_layout_problem layout (book_, dummy_page, lines);
+      if (!scm_is_pair (systems))
+        config = SCM_EOL;
+      else if (rag && !ragged ())
+        // If we're ragged-last but not ragged, make the last page
+        // have the same force as the previous page.
+        config = layout.fixed_force_solution (last_page_force);
+      else
+        config = layout.solution (rag);
 
-      systems_configs_fncounts = scm_cons (scm_list_3 (lines, config, scm_from_int ((int)footnote_count)), systems_configs_fncounts);
+      if ((ragged () && layout.force () < 0.0)
+          || isinf (layout.force ()))
+        warning (_f ("page %d has been compressed", page_num));
+      else
+        last_page_force = layout.force ();
+
+      systems_configs_fncounts = scm_cons (scm_cons (lines, config), systems_configs_fncounts);
       footnote_count += fn_lines;
       systems = scm_list_tail (systems, line_count);
     }
 
-  // Now it's safe to make the pages.
+  // TODO: previously, the following loop caused the systems to be
+  // drawn.  Now that we no longer draw anything in Page_breaking,
+  // it is safe to merge these two loops.
   int page_num = first_page_number + lines_per_page.size () - 1;
   for (SCM s = systems_configs_fncounts; scm_is_pair (s); s = scm_cdr (s))
     {
       SCM lines = scm_caar (s);
-      SCM config = scm_cadar (s);
-      int footnote_num = scm_to_int (scm_caddar (s));
+      SCM config = scm_cdar (s);
 
       bool bookpart_last_page = (s == systems_configs_fncounts);
-      SCM page = draw_page (lines, config, page_num, footnote_num, bookpart_last_page);
+      SCM page = draw_page (lines, config, page_num, bookpart_last_page);
       /* collect labels */
       SCM page_num_scm = scm_from_int (page_num);
       for (SCM l = lines; scm_is_pair (l); l = scm_cdr (l))
         {
           SCM labels = SCM_EOL;
-          if (Grob *line = unsmob_grob (scm_car (l)))
+          if (Grob *line = Grob::unsmob (scm_car (l)))
             {
               System *system = dynamic_cast<System *> (line);
               labels = system->get_property ("labels");
             }
-          else if (Prob *prob = unsmob_prob (scm_car (l)))
+          else if (Prob *prob = Prob::unsmob (scm_car (l)))
             labels = prob->get_property ("labels");
 
           for (SCM lbls = labels; scm_is_pair (lbls); lbls = scm_cdr (lbls))
@@ -659,27 +683,19 @@ Page_breaking::make_pages (vector<vsize> lines_per_page, SCM systems)
   return ret;
 }
 
-/* The page-turn-page-breaker needs to have a line-breaker between any two
-   columns with non-NULL page-turn-permission.
-
-   The optimal-breaker needs to have a line-breaker between any two columns
-   with page-break-permission = 'force.
-
-   By using a grob predicate, we can accommodate both of these uses.
-*/
 void
 Page_breaking::create_system_list ()
 {
   SCM specs = book_->get_system_specs ();
   for (SCM s = specs; scm_is_pair (s); s = scm_cdr (s))
     {
-      if (Paper_score *ps = dynamic_cast<Paper_score *> (unsmob_music_output (scm_car (s))))
+      if (Paper_score *ps = dynamic_cast<Paper_score *> (Music_output::unsmob (scm_car (s))))
         {
           system_specs_.push_back (System_spec (ps));
         }
       else
         {
-          Prob *pb = unsmob_prob (scm_car (s));
+          Prob *pb = Prob::unsmob (scm_car (s));
           assert (pb);
 
           pb->protect ();
@@ -690,6 +706,14 @@ Page_breaking::create_system_list ()
     system_specs_.push_back (System_spec ());
 }
 
+/* The page-turn-page-breaker needs to have a line-breaker between any two
+   columns with non-NULL page-turn-permission.
+
+   The optimal-breaker needs to have a line-breaker between any two columns
+   with page-break-permission = 'force.
+
+   By using a grob predicate, we can accommodate both of these uses.
+*/
 void
 Page_breaking::find_chunks_and_breaks (Break_predicate is_break, Prob_break_predicate prob_is_break)
 {
@@ -723,7 +747,7 @@ Page_breaking::find_chunks_and_breaks (Break_predicate is_break, Prob_break_pred
           vector<vsize> line_breaker_columns;
           line_breaker_columns.push_back (0);
 
-          for (vsize j = 1; j < cols.size (); j++)
+          for (vsize j = 0; j < cols.size (); j++)
             {
               if (forced_line_break_cols.size ())
                 {
@@ -1148,9 +1172,8 @@ Page_breaking::min_page_count (vsize configuration, vsize first_page_num)
       cur_page_height -= min_whitespace_at_top_of_page (cached_line_details_[page_starter]);
       cur_page_height -= min_whitespace_at_bottom_of_page (cached_line_details_.back ());
 
-      Real cur_height = cur_rod_height + ((ragged_last () || ragged ()) ? cur_spring_height : 0);
       if (!too_few_lines (line_count - cached_line_details_.back ().compressed_nontitle_lines_count_)
-          && cur_height > cur_page_height
+          && cur_rod_height > cur_page_height
           /* don't increase the page count if the last page had only one system */
           && cur_rod_height > cached_line_details_.back ().full_height ())
         ret++;
@@ -1203,11 +1226,11 @@ Page_breaking::blank_page_penalty () const
   SCM penalty_sym;
 
   if (is_last ())
-    penalty_sym = ly_symbol2scm ("blank-last-page-force");
+    penalty_sym = ly_symbol2scm ("blank-last-page-penalty");
   else if (ends_score ())
-    penalty_sym = ly_symbol2scm ("blank-after-score-page-force");
+    penalty_sym = ly_symbol2scm ("blank-after-score-page-penalty");
   else
-    penalty_sym = ly_symbol2scm ("blank-page-force");
+    penalty_sym = ly_symbol2scm ("blank-page-penalty");
 
   Break_position const &pos = breaks_[current_end_breakpoint_];
   if (Paper_score *ps = system_specs_[pos.system_spec_index_].pscore_)
@@ -1416,7 +1439,9 @@ Page_breaking::finalize_spacing_result (vsize configuration, Page_spacing_result
       line_penalty += uncompressed_line_details_[i].break_penalty_;
     }
 
-  for (vsize i = 0; i < res.force_.size (); i++)
+  for (vsize i = ragged () ? res.force_.size () - 1 : 0;
+       i < res.force_.size () - (is_last () && ragged_last ());
+       i++)
     {
       Real f = res.force_[i];
 
@@ -1524,9 +1549,11 @@ Page_breaking::space_systems_on_2_pages (vsize configuration, vsize first_page_n
       page1_penalty[i] = line_count_penalty (page1_line_count);
       page1_status[i] = line_count_status (page1_line_count);
 
-      if (ragged2)
+      if (ragged1)
         page2_force[page2_force.size () - 1 - i]
           = (page2.force_ < 0 && i + 1 < page1_force.size ()) ? infinity_f : 0;
+      else if (ragged2 && page2.force_ > 0)
+        page2_force[page2_force.size () - 1 - i] = 0.0;
       else
         page2_force[page2_force.size () - 1 - i] = page2.force_;
       page2_penalty[page2_penalty.size () - 1 - i] = line_count_penalty (page2_line_count);