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