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