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