]> git.donarmstrong.com Git - lilypond.git/blob - lily/page-breaking.cc
Web: really read search-box HTML file in UTF-8
[lilypond.git] / lily / page-breaking.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 2006--2009 Joe Neeman <joeneeman@gmail.com>
5
6   LilyPond is free software: you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation, either version 3 of the License, or
9   (at your option) any later version.
10
11   LilyPond is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 /*
21   This is a utility class for page-breaking algorithms. There are some complex
22   parts of this class, some of which are useful to understand if you intend
23   to write a page breaking algorithm (ie. a subclass of Page_breaking). Most
24   of these complexities were introduced in order to break the problem of
25   page-breaking into simpler subproblems and to hide some of the bookkeeping
26   complexities of page breaking from the page breaking algorithms.
27
28   COMPRESSED LINES
29   There are several functions that actually distribute systems across pages
30   (for example, the space_systems_XXX and pack_systems_XXX functions). If
31   each of these functions had to handle \noPageBreak, it would be a mess.
32   Therefore, we handle \noPageBreak by "compressing" the list of systems
33   before doing any layout: we concatenate any two systems separated by a
34   \noPageBreak into a single system. The page-breaking functions can do their
35   magic without encountering a \noPageBreak; we then "uncompress" the systems
36   at the end. We almost always work with cached_line_details_, which are
37   "compressed."
38
39   CHUNKS
40   The basic operation of a page breaking algorithm is to repeatedly request
41   some systems from the line-breaker and place those systems on some pages.
42   With each repetition, the page breaking algorithm asks the line-breaker for
43   some systems that it thinks will help it achieve a better layout. The
44   Page_breaking class provides functionality to facilitate this in the case
45   that the page breaking algorithm only cares about the number of systems.
46
47   Even if a page breaking algorithm only cares number of systems, there may
48   be many ways to satisfy its request. For example, in a piece with 2 scores
49   and a request for 10 systems, we could return 5 systems from each score or
50   4 from the first and 6 from the second. Even within a score, we might
51   want to try several different line breaking configurations with a fixed
52   system count; if there is a forced \pageBreak, for example, we might wish
53   to tweak the number of systems on both sides of the \pageBreak independently.
54
55   The Page_breaking class takes care of finding these configurations. It
56   divides the piece into "chunks" and sets up the line-breaker in such a way
57   that the number of systems in each chunk can be modified independently.
58   Chunks never cross score boundaries; each title and markup is its own chunk.
59   When a page breaking algorithm requests a number of systems, the Page_breaker
60   stores an array of potential configurations, which the page breaking
61   algorithm can iterate over using current_configuration(vsize).
62
63   LINE_DIVISION
64   A Line_division is simply a way of storing the exact way in which the
65   total number of systems is distributed among chunks. Note that a
66   Line_division may not (in fact, usually will not) describe all of the chunks
67   in the entire book. Rather, it will describe the subset of chunks that lie
68   between some fixed starting and ending point. This subset of chunks changes
69   whenever a page breaking algorithm asks to consider a different pair of
70   starting and ending breakpoints. In particular, a Line_division should be
71   discarded after a call to set_current_breakpoints, since that Line_division
72   refers to a subset of chunks which might be different from the current
73   subset of chunks under consideration.
74 */
75
76 #include "page-breaking.hh"
77
78 #include "international.hh"
79 #include "item.hh"
80 #include "output-def.hh"
81 #include "page-layout-problem.hh"
82 #include "page-spacing.hh"
83 #include "paper-book.hh"
84 #include "paper-score.hh"
85 #include "paper-system.hh"
86 #include "system.hh"
87 #include "warn.hh"
88
89 /* for each forbidden page break, merge the systems around it into one
90    system. */
91 static vector<Line_details>
92 compress_lines (const vector<Line_details> &orig)
93 {
94   vector<Line_details> ret;
95
96   for (vsize i = 0; i < orig.size (); i++)
97     {
98       if (ret.size () && !scm_is_symbol (ret.back ().page_permission_))
99         {
100           Line_details const &old = ret.back ();
101           Line_details compressed = orig[i];
102           Real padding = orig[i].title_ ? old.title_padding_ : old.padding_;
103
104           compressed.extent_[DOWN] = old.extent_[DOWN];
105           compressed.extent_[UP] = old.extent_[UP] + orig[i].extent_.length () + padding;
106           compressed.space_ += old.space_;
107           compressed.inverse_hooke_ += old.inverse_hooke_;
108
109           compressed.compressed_lines_count_ = old.compressed_lines_count_ + 1;
110           compressed.compressed_nontitle_lines_count_ =
111             old.compressed_nontitle_lines_count_ + (compressed.title_ ? 0 : 1);
112
113           // compressed.title_ is true if and only if the first of its
114           // compressed lines was a title.
115           compressed.title_ = old.title_;
116           ret.back () = compressed;
117         }
118       else
119         {
120           ret.push_back (orig[i]);
121           ret.back ().force_ = 0;
122         }
123     }
124   return ret;
125 }
126
127 /* translate the number of systems-per-page into something meaningful for
128    the uncompressed lines.
129 */
130 static vector<vsize>
131 uncompress_solution (vector<vsize> const &systems_per_page,
132                      vector<Line_details> const &compressed)
133 {
134   vector<vsize> ret;
135   vsize start_sys = 0;
136
137   for (vsize i = 0; i < systems_per_page.size (); i++)
138     {
139       int compressed_count = 0;
140       for (vsize j = start_sys; j < start_sys + systems_per_page[i]; j++)
141         compressed_count += compressed[j].compressed_lines_count_ - 1;
142
143       ret.push_back (systems_per_page[i] + compressed_count);
144       start_sys += systems_per_page[i];
145     }
146   return ret;
147 }
148
149 /* for Page_breaking, the start index (when we are dealing with the stuff
150    between a pair of breakpoints) refers to the break_ index of the end of
151    the previous page. So the system index of the start of the current page
152    could either be the same as the end of the previous page or one more than
153    it. */
154
155 /* Turn a break index into the sys index that starts the next page */
156 vsize
157 Page_breaking::next_system (Break_position const &break_pos) const
158 {
159   vsize sys = break_pos.system_spec_index_;
160
161   if (sys == VPOS) /* beginning of the book */
162     return 0;
163   if (system_specs_[sys].pscore_ && !break_pos.score_ender_)
164     return sys; /* the score overflows the previous page */
165   return sys + 1; /* this page starts with a new System_spec */
166 }
167
168 Page_breaking::Page_breaking (Paper_book *pb, Break_predicate is_break)
169 {
170   book_ = pb;
171   system_count_ = 0;
172   ragged_ = to_boolean (pb->paper_->c_variable ("ragged-bottom"));
173   ragged_last_ = to_boolean (pb->paper_->c_variable ("ragged-last-bottom"));
174   systems_per_page_ = max (0, robust_scm2int (pb->paper_->c_variable ("systems-per-page"), 0));
175   max_systems_per_page_ = max (0, robust_scm2int (pb->paper_->c_variable ("max-systems-per-page"), 0));
176   min_systems_per_page_ = max (0, robust_scm2int (pb->paper_->c_variable ("min-systems-per-page"), 0));
177
178   if (systems_per_page_ && (max_systems_per_page_ || min_systems_per_page_))
179     {
180       warning (_f ("ignoring min-systems-per-page and max-systems-per-page because systems-per-page was set"));
181       min_systems_per_page_ = max_systems_per_page_ = 0;
182     }
183   if (max_systems_per_page_ && min_systems_per_page_ > max_systems_per_page_)
184     {
185       warning (_f ("min-systems-per-page is larger than max-systems-per-page, ignoring both values"));
186       min_systems_per_page_ = max_systems_per_page_ = 0;
187     }
188
189   create_system_list ();
190   find_chunks_and_breaks (is_break);
191 }
192
193 Page_breaking::~Page_breaking ()
194 {
195 }
196
197 bool
198 Page_breaking::ragged () const
199 {
200   return ragged_;
201 }
202
203 bool
204 Page_breaking::ragged_last () const
205 {
206   return ragged_last_;
207 }
208
209 int
210 Page_breaking::systems_per_page () const
211 {
212   return systems_per_page_;
213 }
214
215 int
216 Page_breaking::max_systems_per_page () const
217 {
218   return max_systems_per_page_;
219 }
220
221 int
222 Page_breaking::min_systems_per_page () const
223 {
224   return min_systems_per_page_;
225 }
226
227 vsize
228 Page_breaking::system_count () const
229 {
230   return system_count_;
231 }
232
233 bool
234 Page_breaking::too_many_lines (int line_count) const
235 {
236   return max_systems_per_page () > 0 && line_count > max_systems_per_page ();
237 }
238
239 bool
240 Page_breaking::too_few_lines (int line_count) const
241 {
242   return line_count < min_systems_per_page ();
243 }
244
245 Real
246 Page_breaking::line_count_penalty (int line_count) const
247 {
248   if (too_many_lines (line_count))
249     return (line_count - max_systems_per_page ()) * TERRIBLE_SPACING_PENALTY;
250   if (too_few_lines (line_count))
251     return (min_systems_per_page () - line_count) * TERRIBLE_SPACING_PENALTY;
252
253   return 0;
254 }
255
256 int
257 Page_breaking::line_count_status (int line_count) const
258 {
259   if (too_many_lines (line_count))
260     return SYSTEM_COUNT_TOO_MANY;
261   if (too_few_lines (line_count))
262     return SYSTEM_COUNT_TOO_FEW;
263
264   return SYSTEM_COUNT_OK;
265 }
266
267 /* translate indices into breaks_ into start-end parameters for the line breaker */
268 void
269 Page_breaking::line_breaker_args (vsize sys,
270                                   Break_position const &start,
271                                   Break_position const &end,
272                                   vsize *line_breaker_start,
273                                   vsize *line_breaker_end)
274 {
275   assert (system_specs_[sys].pscore_);
276   assert (next_system (start) <= sys && sys <= end.system_spec_index_);
277
278   if (start.system_spec_index_ == sys)
279     *line_breaker_start = start.score_break_;
280   else
281     *line_breaker_start = 0;
282
283   if (end.system_spec_index_ == sys)
284     *line_breaker_end = end.score_break_;
285   else
286     *line_breaker_end = VPOS;
287 }
288
289 void
290 Page_breaking::break_into_pieces (vsize start_break, vsize end_break,
291                                   Line_division const &div)
292 {
293   vector<Break_position> chunks = chunk_list (start_break, end_break);
294   bool ignore_div = false;
295   if (chunks.size () != div.size () + 1)
296     {
297       programming_error ("did not find a valid page breaking configuration");
298       ignore_div = true;
299     }
300
301   for (vsize i = 0; i + 1 < chunks.size (); i++)
302     {
303       vsize sys = next_system (chunks[i]);
304       if (system_specs_[sys].pscore_)
305         {
306           vsize start;
307           vsize end;
308           line_breaker_args (sys, chunks[i], chunks[i+1], &start, &end);
309
310           vector<Column_x_positions> pos = ignore_div
311             ? line_breaking_[sys].best_solution (start, end)
312             : line_breaking_[sys].solve (start, end, div[i]);
313           system_specs_[sys].pscore_->root_system ()->break_into_pieces (pos);
314         }
315     }
316 }
317
318 SCM
319 Page_breaking::systems ()
320 {
321   SCM ret = SCM_EOL;
322   for (vsize sys = 0; sys < system_specs_.size (); sys++)
323     {
324       if (system_specs_[sys].pscore_)
325         {
326           system_specs_[sys].pscore_->root_system ()
327             ->do_break_substitution_and_fixup_refpoints ();
328           SCM lines = system_specs_[sys].pscore_->root_system ()
329             ->get_broken_system_grobs ();
330           ret = scm_cons (lines, ret);
331         }
332       else
333         {
334           Prob *pb = system_specs_[sys].prob_;
335           ret = scm_cons (scm_list_1 (pb->self_scm ()), ret);
336           pb->unprotect ();
337         }
338     }
339   return scm_append (scm_reverse (ret));
340 }
341
342 SCM
343 Page_breaking::make_page (int page_num, bool last) const
344 {
345   bool last_part = ly_scm2bool (book_->paper_->c_variable ("is-last-bookpart"));
346   SCM mod = scm_c_resolve_module ("scm page");
347   SCM make_page_scm = scm_c_module_lookup (mod, "make-page");
348
349   make_page_scm = scm_variable_ref (make_page_scm);
350
351   return scm_apply_0 (make_page_scm,
352                       scm_list_n (book_->self_scm (),
353                                   ly_symbol2scm ("page-number"), scm_from_int (page_num),
354                                   ly_symbol2scm ("is-last-bookpart"), scm_from_bool (last_part),
355                                   ly_symbol2scm ("is-bookpart-last-page"), scm_from_bool (last),
356                                   SCM_UNDEFINED));
357 }
358
359 Real
360 Page_breaking::page_height (int page_num, bool last) const
361 {
362   SCM mod = scm_c_resolve_module ("scm page");
363   SCM page = make_page (page_num, last);
364   SCM calc_height = scm_c_module_lookup (mod, "calc-printable-height");
365   calc_height = scm_variable_ref (calc_height);
366
367   SCM height = scm_apply_1 (calc_height, page, SCM_EOL);
368   return scm_to_double (height);
369 }
370
371 SCM
372 Page_breaking::breakpoint_property (vsize breakpoint, char const *str)
373 {
374   Break_position const &pos = breaks_[breakpoint];
375
376   if (pos.system_spec_index_ == VPOS)
377     return SCM_EOL;
378   if (system_specs_[pos.system_spec_index_].pscore_)
379     return pos.col_->get_property (str);
380   return system_specs_[pos.system_spec_index_].prob_->get_property (str);
381 }
382
383 SCM
384 Page_breaking::get_page_configuration (SCM systems, int page_num, bool ragged, bool last)
385 {
386   SCM dummy_page = make_page (page_num, last);
387   Page_layout_problem layout (book_, dummy_page, systems);
388   return scm_is_pair (systems) ? layout.solution (ragged) : SCM_EOL;
389 }
390
391 SCM
392 Page_breaking::draw_page (SCM systems, SCM configuration, int page_num, bool last)
393 {
394   // Create a stencil for each system.
395   SCM paper_systems = SCM_EOL;
396   for (SCM s = scm_reverse (systems); scm_is_pair (s); s = scm_cdr (s))
397     {
398       SCM paper_system = scm_car (s);
399       if (Grob *g = unsmob_grob (scm_car (s)))
400         {
401           System *sys = dynamic_cast<System*> (g);
402           paper_system = sys->get_paper_system ();
403         }
404
405       paper_systems = scm_cons (paper_system, paper_systems);
406     }
407
408   // Create the page and draw it.
409   SCM page = make_page (page_num, last);
410   SCM page_module = scm_c_resolve_module ("scm page");
411   SCM page_stencil = scm_c_module_lookup (page_module, "page-stencil");
412   page_stencil = scm_variable_ref (page_stencil);
413
414   Prob *p = unsmob_prob (page);
415   p->set_property ("lines", paper_systems);
416   p->set_property ("configuration", configuration);
417   scm_apply_1 (page_stencil, page, SCM_EOL);
418
419   return page;
420 }
421
422 SCM
423 Page_breaking::make_pages (vector<vsize> lines_per_page, SCM systems)
424 {
425   int first_page_number
426     = robust_scm2int (book_->paper_->c_variable ("first-page-number"), 1);
427   SCM ret = SCM_EOL;
428   SCM label_page_table = book_->top_paper ()->c_variable ("label-page-table");
429   if (label_page_table == SCM_UNDEFINED)
430     label_page_table = SCM_EOL;
431
432   // Build a list of (systems . configuration) pairs. Note that we lay out
433   // the staves and find the configurations before drawing anything. Some
434   // grobs (like tuplet brackets) look at their neighbours while drawing
435   // themselves. If this happens before the neighbouring staves have
436   // been laid out, bad side-effects could happen (in particular,
437   // Align_interface::align_to_ideal_distances might be called).
438   SCM systems_and_configs = SCM_EOL;
439
440   for (vsize i = 0; i < lines_per_page.size (); i++)
441     {
442       int page_num = i + first_page_number;
443       bool bookpart_last_page = (i == lines_per_page.size () - 1);
444       bool rag = ragged () || (bookpart_last_page && ragged_last ());
445       SCM line_count = scm_from_int (lines_per_page[i]);
446       SCM lines = scm_list_head (systems, line_count);
447       SCM config = get_page_configuration (lines, page_num, rag, bookpart_last_page);
448
449       systems_and_configs = scm_cons (scm_cons (lines, config), systems_and_configs);
450       systems = scm_list_tail (systems, line_count);
451     }
452
453   // Now it's safe to make the pages.
454   int page_num = first_page_number + lines_per_page.size () - 1;
455   for (SCM s = systems_and_configs; scm_is_pair (s); s = scm_cdr (s))
456     {
457       SCM lines = scm_caar (s);
458       SCM config = scm_cdar (s);
459       bool bookpart_last_page = (s == systems_and_configs);
460       SCM page = draw_page (lines, config, page_num, bookpart_last_page);
461
462       /* collect labels */
463       SCM page_num_scm = scm_from_int (page_num);
464       for (SCM l = lines ; scm_is_pair (l)  ; l = scm_cdr (l))
465         {
466           SCM labels = SCM_EOL;
467           if (Grob * line = unsmob_grob (scm_car (l)))
468             {
469               System *system = dynamic_cast<System*> (line);
470               labels = system->get_property ("labels");
471             }
472           else if (Prob *prob = unsmob_prob (scm_car (l)))
473             labels = prob->get_property ("labels");
474
475           for (SCM lbls = labels ; scm_is_pair (lbls) ; lbls = scm_cdr (lbls))
476             label_page_table = scm_cons (scm_cons (scm_car (lbls), page_num_scm),
477                                          label_page_table);
478         }
479
480       ret = scm_cons (page, ret);
481       --page_num;
482     }
483   book_->top_paper ()->set_variable (ly_symbol2scm ("label-page-table"), label_page_table);
484   return ret;
485 }
486
487 /* The page-turn-page-breaker needs to have a line-breaker between any two
488    columns with non-NULL page-turn-permission.
489
490    The optimal-breaker needs to have a line-breaker between any two columns
491    with page-break-permission = 'force.
492
493    By using a grob predicate, we can accommodate both of these uses.
494 */
495 void
496 Page_breaking::create_system_list ()
497 {
498   SCM specs = book_->get_system_specs ();
499   for (SCM s = specs; scm_is_pair (s); s = scm_cdr (s))
500     {
501       if (Paper_score *ps = dynamic_cast<Paper_score*> (unsmob_music_output (scm_car (s))))
502         {
503           system_specs_.push_back (System_spec (ps));
504         }
505       else
506         {
507           Prob *pb = unsmob_prob (scm_car (s));
508           assert (pb);
509
510           pb->protect ();
511           system_specs_.push_back (System_spec (pb));
512         }
513     }
514 }
515
516 void
517 Page_breaking::find_chunks_and_breaks (Break_predicate is_break)
518 {
519   SCM force_sym = ly_symbol2scm ("force");
520
521   chunks_.push_back (Break_position ());
522   breaks_.push_back (Break_position ());
523
524   for (vsize i = 0; i < system_specs_.size (); i++)
525     {
526       if (system_specs_[i].pscore_)
527         {
528           vector<Grob*> cols;
529
530           SCM system_count = system_specs_[i].pscore_->layout ()->c_variable ("system-count");
531           if (scm_is_number (system_count))
532             {
533               // With system-count given, the line configuration for
534               // this score is fixed.  We need to ensure that chunk
535               // boundaries only occur at line breaks.
536               Constrained_breaking breaking (system_specs_[i].pscore_);
537               vector<Line_details> details = breaking.line_details (0, VPOS, scm_to_int (system_count));
538
539               cols.push_back (system_specs_[i].pscore_->root_system ()->used_columns ()[0]);
540               for (vsize j = 0; j < details.size (); j++)
541                 cols.push_back (details[j].last_column_);
542             }
543           else
544             cols = system_specs_[i].pscore_->root_system ()->used_columns ();
545
546           int last_chunk_idx = 0;
547           vector<vsize> line_breaker_columns;
548           line_breaker_columns.push_back (0);
549
550           for (vsize j = 1; j < cols.size (); j++)
551             {
552               bool last = (j == cols.size () - 1);
553               bool break_point = is_break (cols[j]);
554               bool chunk_end = cols[j]->get_property ("page-break-permission") == force_sym;
555               Break_position cur_pos = Break_position (i,
556                                                        line_breaker_columns.size (),
557                                                        cols[j],
558                                                        last);
559
560               // NOTE: even in the breaks_ list, forced_line_count_
561               // refers to the number of lines between a
562               // Break_position and the start of that /chunk/.  This
563               // is needed for system_count_bounds to work correctly,
564               // since it mixes Break_positions from breaks_ and
565               // chunks_.
566               if (scm_is_number (system_count))
567                 cur_pos.forced_line_count_ = j - last_chunk_idx;
568
569               if (break_point || (i == system_specs_.size () - 1 && last))
570                 breaks_.push_back (cur_pos);
571               if (chunk_end || last)
572                 {
573                   chunks_.push_back (cur_pos);
574                   last_chunk_idx = j;
575                 }
576
577               if ((break_point || chunk_end) && !last)
578                 line_breaker_columns.push_back (j);
579             }
580           line_breaking_.push_back (Constrained_breaking (system_specs_[i].pscore_, line_breaker_columns));
581         }
582       else
583         {
584           /* TODO: we want some way of applying Break_p to a prob? */
585           if (i == system_specs_.size () - 1)
586             breaks_.push_back (Break_position (i));
587
588           chunks_.push_back (Break_position (i));
589
590           /* FIXME: shouldn't we push a Null_breaker or similar dummy
591              class? --hwn */
592           line_breaking_.push_back (Constrained_breaking (NULL));
593         }
594     }
595 }
596
597 vector<Break_position>
598 Page_breaking::chunk_list (vsize start_index, vsize end_index)
599 {
600   Break_position start = breaks_[start_index];
601   Break_position end = breaks_[end_index];
602
603   vsize i = 0;
604   for (; i < chunks_.size () && chunks_[i] <= start; i++)
605     ;
606
607   vector<Break_position> ret;
608   ret.push_back (start);
609   for (; i < chunks_.size () && chunks_[i] < end; i++)
610     ret.push_back (chunks_[i]);
611   ret.push_back (end);
612   return ret;
613 }
614
615 vsize
616 Page_breaking::min_system_count (vsize start, vsize end)
617 {
618   vector<Break_position> chunks = chunk_list (start, end);
619   Line_division div = system_count_bounds (chunks, true);
620   vsize ret = 0;
621
622   for (vsize i = 0; i < div.size (); i++)
623     ret += div[i];
624   return ret;
625 }
626
627 vsize
628 Page_breaking::max_system_count (vsize start, vsize end)
629 {
630   vector<Break_position> chunks = chunk_list (start, end);
631   Line_division div = system_count_bounds (chunks, false);
632   vsize ret = 0;
633
634   for (vsize i = 0; i < div.size (); i++)
635     ret += div[i];
636   return ret;
637 }
638
639 Page_breaking::Line_division
640 Page_breaking::system_count_bounds (vector<Break_position> const &chunks,
641                                     bool min)
642 {
643   assert (chunks.size () >= 2);
644
645   Line_division ret;
646   ret.resize (chunks.size () - 1, 1);
647
648   for (vsize i = 0; i + 1 < chunks.size (); i++)
649     {
650       vsize sys = next_system (chunks[i]);
651
652       if (chunks[i+1].forced_line_count_)
653         ret[i] = chunks[i+1].forced_line_count_;
654       else if (system_specs_[sys].pscore_)
655         {
656           vsize start;
657           vsize end;
658           line_breaker_args (sys, chunks[i], chunks[i+1], &start, &end);
659           ret[i] = min
660             ? line_breaking_[sys].min_system_count (start, end)
661             : line_breaking_[sys].max_system_count (start, end);
662         }
663     }
664
665   return ret;
666 }
667
668 void
669 Page_breaking::set_current_breakpoints (vsize start,
670                                         vsize end,
671                                         vsize system_count,
672                                         Line_division lower_bound,
673                                         Line_division upper_bound)
674 {
675   system_count_ = system_count;
676   current_chunks_ = chunk_list (start, end);
677   current_start_breakpoint_ = start;
678   current_end_breakpoint_ = end;
679   clear_line_details_cache ();
680
681   if (!lower_bound.size ())
682     lower_bound = system_count_bounds (current_chunks_, true);
683   if (!upper_bound.size ())
684     upper_bound = system_count_bounds (current_chunks_, false);
685
686   assert (lower_bound.size () == current_chunks_.size () - 1);
687   assert (upper_bound.size () == current_chunks_.size () - 1);
688
689   Line_division work_in_progress;
690   current_configurations_.clear ();
691   line_divisions_rec (system_count,
692                       lower_bound,
693                       upper_bound,
694                       &work_in_progress);
695
696   /* we only consider a constant number of configurations. Otherwise,
697      this becomes slow when there are many small scores. The constant
698      5 is somewhat arbitrary. */
699   if (current_configurations_.size () > 5)
700     {
701       vector<pair<Real,vsize> > dems_and_indices;
702
703       for (vsize i = 0; i < current_configurations_.size (); i++)
704         {
705           cache_line_details (i);
706           Real dem = 0;
707           for (vsize j = 0; j < cached_line_details_.size (); j++)
708             dem += cached_line_details_[j].force_ * cached_line_details_[j].force_
709               + cached_line_details_[j].break_penalty_;
710
711           dems_and_indices.push_back (pair<Real,vsize> (dem, i));
712         }
713       vector_sort (dems_and_indices, less<pair<Real,vsize> > ());
714
715       vector<Line_division> best_5_configurations;
716       for (vsize i = 0; i < 5; i++)
717         best_5_configurations.push_back (current_configurations_[dems_and_indices[i].second]);
718
719       clear_line_details_cache ();
720       current_configurations_ = best_5_configurations;
721     }
722 }
723
724 void
725 Page_breaking::set_to_ideal_line_configuration (vsize start, vsize end)
726 {
727   current_chunks_ = chunk_list (start, end);
728   current_start_breakpoint_ = start;
729   current_end_breakpoint_ = end;
730   clear_line_details_cache ();
731   system_count_ = 0;
732
733   Line_division div;
734   for (vsize i = 0; i+1 < current_chunks_.size (); i++)
735     {
736       vsize sys = next_system (current_chunks_[i]);
737
738       if (current_chunks_[i+1].forced_line_count_)
739         div.push_back (current_chunks_[i+1].forced_line_count_);
740       else if (system_specs_[sys].pscore_)
741         {
742           line_breaker_args (sys, current_chunks_[i], current_chunks_[i+1], &start, &end);
743           div.push_back (line_breaking_[sys].best_solution (start, end).size ());
744         }
745       else
746         div.push_back (1);
747
748       system_count_ += div.back ();
749     }
750   current_configurations_.clear ();
751   current_configurations_.push_back (div);
752 }
753
754 vsize
755 Page_breaking::current_configuration_count () const
756 {
757   return current_configurations_.size ();
758 }
759
760 void
761 Page_breaking::cache_line_details (vsize configuration_index)
762 {
763   if (cached_configuration_index_ != configuration_index)
764     {
765       cached_configuration_index_ = configuration_index;
766
767       Line_division &div = current_configurations_[configuration_index];
768       uncompressed_line_details_.clear ();
769       for (vsize i = 0; i + 1 < current_chunks_.size (); i++)
770         {
771           vsize sys = next_system (current_chunks_[i]);
772           if (system_specs_[sys].pscore_)
773             {
774               vsize start;
775               vsize end;
776               line_breaker_args (sys, current_chunks_[i], current_chunks_[i+1], &start, &end);
777
778               vector<Line_details> details = line_breaking_[sys].line_details (start, end, div[i]);
779               uncompressed_line_details_.insert (uncompressed_line_details_.end (), details.begin (), details.end ());
780             }
781           else
782             {
783               assert (div[i] == 1);
784               uncompressed_line_details_.push_back (Line_details (system_specs_[sys].prob_, book_->paper_));
785             }
786         }
787       cached_line_details_ = compress_lines (uncompressed_line_details_);
788     }
789 }
790
791 void
792 Page_breaking::clear_line_details_cache ()
793 {
794   cached_configuration_index_ = VPOS;
795   cached_line_details_.clear ();
796   uncompressed_line_details_.clear ();
797 }
798
799 void
800 Page_breaking::line_divisions_rec (vsize system_count,
801                                    Line_division const &min_sys,
802                                    Line_division const &max_sys,
803                                    Line_division *cur_division)
804 {
805   vsize my_index = cur_division->size ();
806   vsize others_min = 0;
807   vsize others_max = 0;
808
809   for (vsize i = my_index + 1; i < min_sys.size (); i++)
810     {
811       others_min += min_sys[i];
812       others_max += max_sys[i];
813     }
814   others_max = min (others_max, system_count);
815   vsize real_min = max (min_sys[my_index], system_count - others_max);
816   vsize real_max = min (max_sys[my_index], system_count - others_min);
817
818   if (real_min > real_max || real_min <= 0)
819     {
820       /* this should never happen within a recursive call. If it happens
821          at all, it means that we were called with an unsolvable problem
822          and we should return an empty result */
823       assert (my_index == 0);
824       return;
825     }
826
827   for (vsize i = real_min; i <= real_max; i++)
828     {
829       cur_division->push_back (i);
830       if (my_index == min_sys.size () - 1)
831         current_configurations_.push_back (*cur_division);
832       else
833         line_divisions_rec (system_count - i, min_sys, max_sys, cur_division);
834       cur_division->pop_back ();
835     }
836 }
837
838 vsize
839 Page_breaking::min_page_count (vsize configuration, vsize first_page_num)
840 {
841   vsize ret = 1;
842   vsize page_starter = 0;
843   Real cur_rod_height = 0;
844   Real cur_spring_height = 0;
845   Real cur_page_height = page_height (first_page_num, false);
846   int line_count = 0;
847
848   cache_line_details (configuration);
849
850   if (cached_line_details_.size ())
851     cur_page_height -= min_whitespace_at_top_of_page (cached_line_details_[0]);
852
853   for (vsize i = 0; i < cached_line_details_.size (); i++)
854     {
855       Real ext_len = cached_line_details_[i].extent_.length ();
856       Real padding = 0;
857       if (cur_rod_height > 0)
858         padding = cached_line_details_[i].title_ ?
859           cached_line_details_[i-1].title_padding_ : cached_line_details_[i-1].padding_;
860
861       Real next_rod_height = cur_rod_height + ext_len + padding;
862       Real next_spring_height = cur_spring_height + cached_line_details_[i].space_;
863       Real next_height = next_rod_height + (ragged () ? next_spring_height : 0)
864         + min_whitespace_at_bottom_of_page (cached_line_details_[i]);
865       int next_line_count = line_count + cached_line_details_[i].compressed_nontitle_lines_count_;
866
867       if ((!too_few_lines (line_count) && (next_height > cur_page_height && cur_rod_height > 0))
868           || too_many_lines (next_line_count)
869           || (i > 0
870               && cached_line_details_[i-1].page_permission_ == ly_symbol2scm ("force")))
871         {
872           line_count = cached_line_details_[i].compressed_nontitle_lines_count_;
873           cur_rod_height = ext_len;
874           cur_spring_height = cached_line_details_[i].space_;
875           page_starter = i;
876
877           cur_page_height = page_height (first_page_num + ret, false);
878           cur_page_height -= min_whitespace_at_top_of_page (cached_line_details_[i]);
879
880           ret++;
881         }
882       else
883         {
884           cur_rod_height = next_rod_height;
885           cur_spring_height = next_spring_height;
886           line_count = next_line_count;
887         }
888     }
889
890   /* there are two potential problems with the last page (because we didn't know
891      it was the last page until after we managed to fit all the systems to it):
892      - we are ragged-last but the last page has a compressed spring
893      - the value returned by page_height (num, true) is smaller than the
894        value returned by page_height (num, false) and it causes the page not to
895        fit.
896
897      In either case, we just need to add one more page. This is because the last
898      line will always fit on the extra page and by adding one more page to the
899      end, the previous page is no longer the last page, so our previous
900      calculations that treated it as a non-last page were ok.
901   */
902
903   cur_page_height = page_height (first_page_num + ret - 1, true);
904   cur_page_height -= min_whitespace_at_top_of_page (cached_line_details_[page_starter]);
905   cur_page_height -= min_whitespace_at_bottom_of_page (cached_line_details_.back ());
906
907   Real cur_height = cur_rod_height + ((ragged_last () || ragged ()) ? cur_spring_height : 0);
908   if (!too_few_lines (line_count - cached_line_details_.back ().compressed_nontitle_lines_count_)
909       && cur_height > cur_page_height
910       /* don't increase the page count if the last page had only one system */
911       && cur_rod_height > cached_line_details_.back ().extent_.length ())
912     ret++;
913
914   assert (ret <= cached_line_details_.size ());
915   return ret;
916 }
917
918 // If systems_per_page_ is positive, we don't really try to space on N pages;
919 // we just put the requested number of systems on each page and penalize
920 // if the result doesn't have N pages.
921 Page_spacing_result
922 Page_breaking::space_systems_on_n_pages (vsize configuration, vsize n, vsize first_page_num)
923 {
924   Page_spacing_result ret;
925
926   if (systems_per_page_ > 0)
927     {
928       Page_spacing_result ret = space_systems_with_fixed_number_per_page (configuration, first_page_num);
929       ret.demerits_ += (ret.force_.size () == n) ? 0 : BAD_SPACING_PENALTY;
930       return ret;
931     }
932
933   cache_line_details (configuration);
934   bool valid_n = (n >= min_page_count (configuration, first_page_num)
935                   && n <= cached_line_details_.size ());
936
937   if (!valid_n)
938     programming_error ("number of pages is out of bounds");
939
940   if (n == 1 && valid_n)
941     ret = space_systems_on_1_page (cached_line_details_,
942                                    page_height (first_page_num, is_last ()),
943                                    ragged () || (is_last () && ragged_last ()));
944   else if (n == 2 && valid_n)
945     ret = space_systems_on_2_pages (configuration, first_page_num);
946   else
947     {
948       Page_spacer ps (cached_line_details_, first_page_num, this);
949       ret = ps.solve (n);
950     }
951
952   return finalize_spacing_result (configuration, ret);
953 }
954
955 Real
956 Page_breaking::blank_page_penalty () const
957 {
958   SCM penalty_sym;
959
960   if (is_last ())
961     penalty_sym = ly_symbol2scm ("blank-last-page-force");
962   else if (ends_score ())
963     penalty_sym = ly_symbol2scm ("blank-after-score-page-force");
964   else
965     penalty_sym = ly_symbol2scm ("blank-page-force");
966
967   Break_position const &pos = breaks_[current_end_breakpoint_];
968   if (Paper_score *ps = system_specs_[pos.system_spec_index_].pscore_)
969     return robust_scm2double (ps->layout ()->lookup_variable (penalty_sym), 0.0);
970
971   return robust_scm2double (book_->paper_->lookup_variable (penalty_sym), 0.0);
972 }
973
974 // If systems_per_page_ is positive, we don't really try to space on N
975 // or N+1 pages; see the comment to space_systems_on_n_pages.
976 Page_spacing_result
977 Page_breaking::space_systems_on_n_or_one_more_pages (vsize configuration, vsize n, vsize first_page_num,
978                                                      Real penalty_for_fewer_pages)
979 {
980   Page_spacing_result n_res;
981   Page_spacing_result m_res;
982
983   if (systems_per_page_ > 0)
984     {
985       Page_spacing_result ret = space_systems_with_fixed_number_per_page (configuration, first_page_num);
986       ret.demerits_ += (ret.force_.size () == n || ret.force_.size () == (n-1)) ? 0 : BAD_SPACING_PENALTY;
987       return ret;
988     }
989
990   cache_line_details (configuration);
991   vsize min_p_count = min_page_count (configuration, first_page_num);
992   bool valid_n = n >= min_p_count || n <= cached_line_details_.size ();
993
994   if (!valid_n)
995     programming_error ("both page counts are out of bounds");
996
997   if (n == 1 && valid_n)
998     {
999       bool rag = ragged () || (is_last () && ragged_last ());
1000       Real height = page_height (first_page_num, is_last ());
1001
1002       if (1 >= min_p_count)
1003         n_res = space_systems_on_1_page (cached_line_details_, height, rag);
1004       if (1 < cached_line_details_.size ())
1005         m_res = space_systems_on_2_pages (configuration, first_page_num);
1006     }
1007   else
1008     {
1009       Page_spacer ps (cached_line_details_, first_page_num, this);
1010       
1011       if (n >= min_p_count || !valid_n)
1012         n_res = ps.solve (n);
1013       if (n < cached_line_details_.size () || !valid_n)
1014         m_res = ps.solve (n+1);
1015     }
1016
1017   m_res = finalize_spacing_result (configuration, m_res);
1018   n_res = finalize_spacing_result (configuration, n_res);
1019
1020   Real page_spacing_weight = robust_scm2double (book_->paper_->c_variable ("page-spacing-weight"), 10);
1021   n_res.demerits_ += penalty_for_fewer_pages * page_spacing_weight;
1022
1023   if (n_res.force_.size ())
1024     n_res.force_.back () += penalty_for_fewer_pages;
1025
1026   return (m_res.demerits_ < n_res.demerits_) ? m_res : n_res;
1027 }
1028
1029 Page_spacing_result
1030 Page_breaking::space_systems_on_best_pages (vsize configuration, vsize first_page_num)
1031 {
1032   vsize min_p_count = min_page_count (configuration, first_page_num);
1033
1034   cache_line_details (configuration);
1035   Page_spacer ps (cached_line_details_, first_page_num, this);
1036   Page_spacing_result best = ps.solve (min_p_count);
1037
1038   for (vsize i = min_p_count+1; i <= cached_line_details_.size (); i++)
1039     {
1040       Page_spacing_result cur = ps.solve (i);
1041       if (cur.demerits_ < best.demerits_)
1042         best = cur;
1043     }
1044
1045   Page_spacing_result ret = finalize_spacing_result (configuration, best);
1046   return ret;
1047 }
1048
1049 Page_spacing_result
1050 Page_breaking::space_systems_with_fixed_number_per_page (vsize configuration,
1051                                                          vsize first_page_num)
1052 {
1053   Page_spacing_result res;
1054   Page_spacing space (page_height (first_page_num, false), this);
1055   vsize line = 0;
1056   vsize page = 0;
1057   vsize page_first_line = 0;
1058
1059   cache_line_details (configuration);
1060   while (line < cached_line_details_.size ())
1061     {
1062       page++;
1063       space.clear ();
1064       space.resize (page_height (first_page_num + page, false));
1065
1066       int system_count_on_this_page = 0;
1067       while (system_count_on_this_page < systems_per_page_
1068              && line < cached_line_details_.size ())
1069         {
1070           Line_details const &cur_line = cached_line_details_[line];
1071           space.append_system (cur_line);
1072           system_count_on_this_page += cur_line.compressed_nontitle_lines_count_;
1073           line++;
1074
1075           if (cur_line.page_permission_ == ly_symbol2scm ("force"))
1076             break;
1077         }
1078
1079       res.systems_per_page_.push_back (line - page_first_line);
1080
1081       res.force_.push_back (space.force_);
1082       res.penalty_ += cached_line_details_[line-1].page_penalty_;
1083       if (system_count_on_this_page != systems_per_page_)
1084         {
1085           res.penalty_ += TERRIBLE_SPACING_PENALTY;
1086           res.system_count_status_ |= ((system_count_on_this_page < systems_per_page_))
1087             ? SYSTEM_COUNT_TOO_FEW : SYSTEM_COUNT_TOO_MANY;
1088         }
1089
1090       page_first_line = line;
1091     }
1092
1093   /* Recalculate forces for the last page because we know now that is
1094      really the last page. */
1095   space.resize (page_height (first_page_num + page, true));
1096   res.force_.back () = space.force_;
1097   return finalize_spacing_result (configuration, res);
1098 }
1099
1100 Page_spacing_result
1101 Page_breaking::pack_systems_on_least_pages (vsize configuration, vsize first_page_num)
1102 {
1103   // TODO: add support for min/max-systems-per-page.
1104   Page_spacing_result res;
1105   vsize page = 0;
1106   vsize page_first_line = 0;
1107   Page_spacing space (page_height (first_page_num, false), this);
1108
1109   cache_line_details (configuration);
1110   for (vsize line = 0; line < cached_line_details_.size (); line++)
1111     {
1112       Real prev_force = space.force_;
1113       space.append_system (cached_line_details_[line]);
1114       if ((line > page_first_line)
1115           && (isinf (space.force_)
1116               || ((line > 0)
1117                   && (cached_line_details_[line-1].page_permission_ == ly_symbol2scm ("force")))))
1118         {
1119           res.systems_per_page_.push_back (line - page_first_line);
1120           res.force_.push_back (prev_force);
1121           res.penalty_ += cached_line_details_[line-1].page_penalty_;
1122           page++;
1123           space.resize (page_height (first_page_num + page, false));
1124           space.clear ();
1125           space.append_system (cached_line_details_[line]);
1126           page_first_line = line;
1127         }
1128
1129       if (line == cached_line_details_.size () - 1)
1130         {
1131           /* This is the last line */
1132           /* When the last page height was computed, we did not know yet that it
1133            * was the last one. If the systems put on it don't fit anymore, the last
1134            * system is moved to a new page */
1135           space.resize (page_height (first_page_num + page, true));
1136           if ((line > page_first_line) && (isinf (space.force_)))
1137             {
1138               res.systems_per_page_.push_back (line - page_first_line);
1139               res.force_.push_back (prev_force);
1140               /* the last page containing the last line */
1141               space.resize (page_height (first_page_num + page + 1, true));
1142               space.clear ();
1143               space.append_system (cached_line_details_[line]);
1144               res.systems_per_page_.push_back (1);
1145               res.force_.push_back (space.force_);
1146               res.penalty_ += cached_line_details_[line-1].page_penalty_;
1147               res.penalty_ += cached_line_details_[line].page_penalty_;
1148             }
1149           else
1150             {
1151               res.systems_per_page_.push_back (line + 1 - page_first_line);
1152               res.force_.push_back (space.force_);
1153               res.penalty_ += cached_line_details_[line].page_penalty_;
1154             }
1155         }
1156     }
1157   return finalize_spacing_result (configuration, res);
1158 }
1159
1160 /* Calculate demerits and fix res.systems_per_page_ so that
1161    it refers to the original line numbers, not the ones given by compress_lines (). */
1162 Page_spacing_result
1163 Page_breaking::finalize_spacing_result (vsize configuration, Page_spacing_result res)
1164 {
1165   if (res.force_.empty ())
1166     return res;
1167
1168   cache_line_details (configuration);
1169   res.systems_per_page_ = uncompress_solution (res.systems_per_page_, cached_line_details_);
1170
1171   Real line_force = 0;
1172   Real line_penalty = 0;
1173   Real page_demerits = res.penalty_;
1174   Real page_weighting = robust_scm2double (book_->paper_->c_variable ("page-spacing-weight"), 10);
1175
1176   for (vsize i = 0; i < uncompressed_line_details_.size (); i++)
1177     {
1178       line_force += uncompressed_line_details_[i].force_ * uncompressed_line_details_[i].force_;
1179       line_penalty += uncompressed_line_details_[i].break_penalty_;
1180     }
1181
1182   for (vsize i = 0; i < res.force_.size (); i++)
1183     {
1184       Real f = res.force_[i];
1185
1186       page_demerits += min(f*f, BAD_SPACING_PENALTY);
1187     }
1188
1189   /* for a while we tried averaging page and line forces across pages instead
1190      of summing them, but it caused a problem: if there is a single page
1191      with a very bad page force (for example because of a forced page break),
1192      the page breaker will put in a _lot_ of pages so that the bad force
1193      becomes averaged out over many pages. */
1194   res.demerits_ = line_force + line_penalty + page_demerits * page_weighting;
1195   return res;
1196
1197 }
1198
1199 /* the cases for page_count = 1 or 2 can be done in O (n) time. Since they
1200    are by far the most common cases, we have special functions for them.
1201
1202    space_systems_on_1_page has a different calling convention than most of the
1203    space_systems functions. This is because space_systems_on_1_page is (unlike
1204    the other space_systems functions) sometimes called on subsets of a full
1205    configuration. */
1206 Page_spacing_result
1207 Page_breaking::space_systems_on_1_page (vector<Line_details> const &lines, Real page_height, bool ragged)
1208 {
1209   Page_spacing space (page_height, this);
1210   Page_spacing_result ret;
1211   int line_count = 0;
1212
1213   for (vsize i = 0; i < lines.size (); i++)
1214     {
1215       space.append_system (lines[i]);
1216       line_count += lines[i].compressed_nontitle_lines_count_;
1217     }
1218
1219   ret.systems_per_page_.push_back (lines.size ());
1220   ret.force_.push_back (ragged ? min (space.force_, 0.0) : space.force_);
1221   ret.penalty_ = line_count_penalty (line_count) + lines.back ().page_penalty_ + lines.back ().turn_penalty_;
1222   ret.system_count_status_ |= line_count_status (line_count);
1223
1224   /* don't do finalize_spacing_result () because we are only an internal function */
1225   return ret;
1226 }
1227
1228 Page_spacing_result
1229 Page_breaking::space_systems_on_2_pages (vsize configuration, vsize first_page_num)
1230 {
1231   Real page1_height = page_height (first_page_num, false);
1232   Real page2_height = page_height (first_page_num + 1, is_last ());
1233   bool ragged1 = ragged ();
1234   bool ragged2 = ragged () || (is_last () && ragged_last ());
1235
1236   /* if there is a forced break, this reduces to 2 1-page problems */
1237   cache_line_details (configuration);
1238   for (vsize i = 0; i + 1 < cached_line_details_.size (); i++)
1239     if (cached_line_details_[i].page_permission_ == ly_symbol2scm ("force"))
1240       {
1241         vector<Line_details> lines1 (cached_line_details_.begin (), cached_line_details_.begin () + i + 1);
1242         vector<Line_details> lines2 (cached_line_details_.begin () + i + 1, cached_line_details_.end ());
1243         Page_spacing_result p1 = space_systems_on_1_page (lines1, page1_height, ragged1);
1244         Page_spacing_result p2 = space_systems_on_1_page (lines2, page2_height, ragged2);
1245
1246         p1.systems_per_page_.push_back (p2.systems_per_page_[0]);
1247         p1.force_.push_back (p2.force_[0]);
1248         p1.penalty_ += p2.penalty_ - cached_line_details_[i].turn_penalty_;
1249         return p1;
1250       }
1251
1252   vector<Real> page1_force;
1253   vector<Real> page2_force;
1254
1255   // page1_penalty and page2_penalty store the penalties based
1256   // on min-systems-per-page and max-systems-per-page.
1257   vector<Real> page1_penalty;
1258   vector<Real> page2_penalty;
1259
1260   // page1_status and page2_status keep track of whether the min-systems-per-page
1261   // and max-systems-per-page constraints are satisfied.
1262   vector<int> page1_status;
1263   vector<int> page2_status;
1264
1265   Page_spacing page1 (page1_height, this);
1266   Page_spacing page2 (page2_height, this);
1267   int page1_line_count = 0;
1268   int page2_line_count = 0;
1269
1270   page1_force.resize (cached_line_details_.size () - 1, infinity_f);
1271   page2_force.resize (cached_line_details_.size () - 1, infinity_f);
1272   page1_penalty.resize (cached_line_details_.size () - 1, infinity_f);
1273   page2_penalty.resize (cached_line_details_.size () - 1, infinity_f);
1274   page1_status.resize (cached_line_details_.size () - 1, 0);
1275   page2_status.resize (cached_line_details_.size () - 1, 0);
1276
1277   /* find the page 1 and page 2 forces for each page-breaking position */
1278   for (vsize i = 0; i < page1_force.size (); i++)
1279     {
1280       page1.append_system (cached_line_details_[i]);
1281       page2.prepend_system (cached_line_details_[cached_line_details_.size () - 1 - i]);
1282       page1_line_count += cached_line_details_[i].compressed_nontitle_lines_count_;
1283       page2_line_count += cached_line_details_[cached_line_details_.size () - 1 - i].compressed_nontitle_lines_count_;
1284
1285       page1_force[i] = (ragged1 && page1.force_ < 0 && i > 0) ? infinity_f : page1.force_;
1286       page1_penalty[i] = line_count_penalty (page1_line_count);
1287       page1_status[i] = line_count_status (page1_line_count);
1288
1289       if (ragged2)
1290         page2_force[page2_force.size () - 1 - i] =
1291           (page2.force_ < 0 && i + 1 < page1_force.size ()) ? infinity_f : 0;
1292       else
1293         page2_force[page2_force.size () - 1 - i] = page2.force_;
1294       page2_penalty[page2_penalty.size () - 1 - i] = line_count_penalty (page2_line_count);
1295       page2_status[page2_penalty.size () - 1 - i] = line_count_status (page2_line_count);
1296     }
1297
1298   /* find the position that minimises the sum of the page forces */
1299   vsize best_sys_count = 1;
1300   Real best_demerits = infinity_f;
1301   for (vsize i = 0; i < page1_force.size (); i++)
1302     {
1303       Real f = page1_force[i] * page1_force[i] + page2_force[i] * page2_force[i];
1304
1305       // NOTE: we treat max-systems-per-page and min-systems-per-page as soft
1306       // constraints. That is, we penalize harshly when they don't happen
1307       // but we don't completely reject.
1308       Real dem = f
1309         + page1_penalty[i] + page2_penalty[i]
1310         + cached_line_details_[i+1].page_penalty_
1311         + cached_line_details_.back ().page_penalty_ + cached_line_details_.back ().turn_penalty_;
1312       if (dem < best_demerits)
1313         {
1314           best_demerits = dem;
1315           best_sys_count = i+1;
1316         }
1317     }
1318
1319   Page_spacing_result ret;
1320   ret.systems_per_page_.push_back (best_sys_count);
1321   ret.systems_per_page_.push_back (cached_line_details_.size () - best_sys_count);
1322   ret.force_.push_back (page1_force[best_sys_count-1]);
1323   ret.force_.push_back (page2_force[best_sys_count-1]);
1324   ret.system_count_status_ = page1_status[best_sys_count-1] | page2_status[best_sys_count-1];
1325   ret.penalty_ = cached_line_details_[best_sys_count-1].page_penalty_
1326     + cached_line_details_.back ().page_penalty_
1327     + cached_line_details_.back ().turn_penalty_
1328     + page1_penalty[best_sys_count-1] + page2_penalty[best_sys_count-1];
1329
1330   /* don't do finalize_spacing_result () because we are only an internal function */
1331   return ret;
1332 }
1333
1334 bool
1335 Page_breaking::all_lines_stretched (vsize configuration)
1336 {
1337   cache_line_details (configuration);
1338   for (vsize i = 0; i < cached_line_details_.size (); i++)
1339     if (cached_line_details_[i].force_ < 0)
1340       return false;
1341
1342   return true;
1343 }
1344
1345 Page_breaking::Line_division
1346 Page_breaking::current_configuration (vsize configuration_index) const
1347 {
1348   return current_configurations_[configuration_index];
1349 }
1350
1351 bool
1352 Page_breaking::is_last () const
1353 {
1354   return current_end_breakpoint_ == last_break_position ();
1355 }
1356
1357 bool
1358 Page_breaking::ends_score () const
1359 {
1360   return breaks_[current_end_breakpoint_].score_ender_;
1361 }
1362
1363 vsize
1364 Page_breaking::last_break_position () const
1365 {
1366   return breaks_.size () - 1;  
1367 }
1368
1369 // This gives the minimum distance between the top of the
1370 // printable area (ie. the bottom of the top-margin) and
1371 // the extent box of the topmost system.
1372 Real
1373 Page_breaking::min_whitespace_at_top_of_page (Line_details const &line) const
1374 {
1375   SCM first_system_spacing = book_->paper_->c_variable ("top-system-spacing");
1376   if (line.title_)
1377     first_system_spacing = book_->paper_->c_variable ("top-title-spacing");
1378
1379   Real min_distance = -infinity_f;
1380   Real padding = 0;
1381
1382   Page_layout_problem::read_spacing_spec (first_system_spacing,
1383                                           &min_distance,
1384                                           ly_symbol2scm ("minimum-distance"));
1385   Page_layout_problem::read_spacing_spec (first_system_spacing,
1386                                           &padding,
1387                                           ly_symbol2scm ("padding"));
1388
1389   // FIXME: take into account the height of the header
1390   return max (0.0, max (padding, min_distance - line.extent_[UP]));
1391 }
1392
1393 Real
1394 Page_breaking::min_whitespace_at_bottom_of_page (Line_details const &line) const
1395 {
1396   SCM last_system_spacing = book_->paper_->c_variable ("bottom-system-spacing");
1397   Real min_distance = -infinity_f;
1398   Real padding = 0;
1399
1400   Page_layout_problem::read_spacing_spec (last_system_spacing,
1401                                           &min_distance,
1402                                           ly_symbol2scm ("minimum-distance"));
1403   Page_layout_problem::read_spacing_spec (last_system_spacing,
1404                                           &padding,
1405                                           ly_symbol2scm ("padding"));
1406
1407   // FIXME: take into account the height of the footer
1408   return max (0.0, max (padding, min_distance + line.extent_[DOWN]));
1409 }