]> git.donarmstrong.com Git - lilypond.git/blob - lily/page-breaking.cc
22fe336da513e5c49cb969cd86bb67b5e4185f9a
[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   cur_page_height = page_height (first_page_num + ret - 1, true);
1003   cur_page_height -= min_whitespace_at_top_of_page (cached_line_details_[page_starter]);
1004   cur_page_height -= min_whitespace_at_bottom_of_page (cached_line_details_.back ());
1005
1006   Real cur_height = cur_rod_height + ((ragged_last () || ragged ()) ? cur_spring_height : 0);
1007   if (!too_few_lines (line_count - cached_line_details_.back ().compressed_nontitle_lines_count_)
1008       && cur_height > cur_page_height
1009       /* don't increase the page count if the last page had only one system */
1010       && cur_rod_height > cached_line_details_.back ().full_height ())
1011     ret++;
1012
1013   assert (ret <= cached_line_details_.size ());
1014   return ret;
1015 }
1016
1017 // If systems_per_page_ is positive, we don't really try to space on N pages;
1018 // we just put the requested number of systems on each page and penalize
1019 // if the result doesn't have N pages.
1020 Page_spacing_result
1021 Page_breaking::space_systems_on_n_pages (vsize configuration, vsize n, vsize first_page_num)
1022 {
1023   Page_spacing_result ret;
1024
1025   if (systems_per_page_ > 0)
1026     {
1027       Page_spacing_result ret = space_systems_with_fixed_number_per_page (configuration, first_page_num);
1028       ret.demerits_ += (ret.force_.size () == n) ? 0 : BAD_SPACING_PENALTY;
1029       return ret;
1030     }
1031
1032   cache_line_details (configuration);
1033   bool valid_n = (n >= min_page_count (configuration, first_page_num)
1034                   && n <= cached_line_details_.size ());
1035
1036   if (!valid_n)
1037     programming_error ("number of pages is out of bounds");
1038
1039   if (n == 1 && valid_n)
1040     ret = space_systems_on_1_page (cached_line_details_,
1041                                    page_height (first_page_num, is_last ()),
1042                                    ragged () || (is_last () && ragged_last ()));
1043   else if (n == 2 && valid_n)
1044     ret = space_systems_on_2_pages (configuration, first_page_num);
1045   else
1046     {
1047       Page_spacer ps (cached_line_details_, first_page_num, this);
1048       ret = ps.solve (n);
1049     }
1050
1051   return finalize_spacing_result (configuration, ret);
1052 }
1053
1054 Real
1055 Page_breaking::blank_page_penalty () const
1056 {
1057   SCM penalty_sym;
1058
1059   if (is_last ())
1060     penalty_sym = ly_symbol2scm ("blank-last-page-force");
1061   else if (ends_score ())
1062     penalty_sym = ly_symbol2scm ("blank-after-score-page-force");
1063   else
1064     penalty_sym = ly_symbol2scm ("blank-page-force");
1065
1066   Break_position const &pos = breaks_[current_end_breakpoint_];
1067   if (Paper_score *ps = system_specs_[pos.system_spec_index_].pscore_)
1068     return robust_scm2double (ps->layout ()->lookup_variable (penalty_sym), 0.0);
1069
1070   return robust_scm2double (book_->paper_->lookup_variable (penalty_sym), 0.0);
1071 }
1072
1073 // If systems_per_page_ is positive, we don't really try to space on N
1074 // or N+1 pages; see the comment to space_systems_on_n_pages.
1075 Page_spacing_result
1076 Page_breaking::space_systems_on_n_or_one_more_pages (vsize configuration, vsize n, vsize first_page_num,
1077                                                      Real penalty_for_fewer_pages)
1078 {
1079   Page_spacing_result n_res;
1080   Page_spacing_result m_res;
1081
1082   if (systems_per_page_ > 0)
1083     {
1084       Page_spacing_result ret = space_systems_with_fixed_number_per_page (configuration, first_page_num);
1085       ret.demerits_ += (ret.force_.size () == n || ret.force_.size () == (n-1)) ? 0 : BAD_SPACING_PENALTY;
1086       return ret;
1087     }
1088
1089   cache_line_details (configuration);
1090   vsize min_p_count = min_page_count (configuration, first_page_num);
1091   bool valid_n = n >= min_p_count || n <= cached_line_details_.size ();
1092
1093   if (!valid_n)
1094     programming_error ("both page counts are out of bounds");
1095
1096   if (n == 1 && valid_n)
1097     {
1098       bool rag = ragged () || (is_last () && ragged_last ());
1099       Real height = page_height (first_page_num, is_last ());
1100
1101       if (1 >= min_p_count)
1102         n_res = space_systems_on_1_page (cached_line_details_, height, rag);
1103       if (1 < cached_line_details_.size ())
1104         m_res = space_systems_on_2_pages (configuration, first_page_num);
1105     }
1106   else
1107     {
1108       Page_spacer ps (cached_line_details_, first_page_num, this);
1109       
1110       if (n >= min_p_count || !valid_n)
1111         n_res = ps.solve (n);
1112       if (n < cached_line_details_.size () || !valid_n)
1113         m_res = ps.solve (n+1);
1114     }
1115
1116   m_res = finalize_spacing_result (configuration, m_res);
1117   n_res = finalize_spacing_result (configuration, n_res);
1118
1119   Real page_spacing_weight = robust_scm2double (book_->paper_->c_variable ("page-spacing-weight"), 10);
1120   n_res.demerits_ += penalty_for_fewer_pages * page_spacing_weight;
1121
1122   if (n_res.force_.size ())
1123     n_res.force_.back () += penalty_for_fewer_pages;
1124
1125   return (m_res.demerits_ < n_res.demerits_) ? m_res : n_res;
1126 }
1127
1128 Page_spacing_result
1129 Page_breaking::space_systems_on_best_pages (vsize configuration, vsize first_page_num)
1130 {
1131   cache_line_details (configuration);
1132   Page_spacer ps (cached_line_details_, first_page_num, this);
1133
1134   return finalize_spacing_result (configuration, ps.solve ());
1135 }
1136
1137 Page_spacing_result
1138 Page_breaking::space_systems_with_fixed_number_per_page (vsize configuration,
1139                                                          vsize first_page_num)
1140 {
1141   Page_spacing_result res;
1142   Page_spacing space (page_height (first_page_num, false), this);
1143   vsize line = 0;
1144   vsize page = 0;
1145   vsize page_first_line = 0;
1146
1147   cache_line_details (configuration);
1148   while (line < cached_line_details_.size ())
1149     {
1150       page++;
1151       space.clear ();
1152       space.resize (page_height (first_page_num + page, false));
1153
1154       int system_count_on_this_page = 0;
1155       while (system_count_on_this_page < systems_per_page_
1156              && line < cached_line_details_.size ())
1157         {
1158           Line_details const &cur_line = cached_line_details_[line];
1159           space.append_system (cur_line);
1160           system_count_on_this_page += cur_line.compressed_nontitle_lines_count_;
1161           line++;
1162
1163           if (cur_line.page_permission_ == ly_symbol2scm ("force"))
1164             break;
1165         }
1166
1167       res.systems_per_page_.push_back (line - page_first_line);
1168
1169       res.force_.push_back (space.force_);
1170       res.penalty_ += cached_line_details_[line-1].page_penalty_;
1171       if (system_count_on_this_page != systems_per_page_)
1172         {
1173           res.penalty_ += TERRIBLE_SPACING_PENALTY;
1174           res.system_count_status_ |= ((system_count_on_this_page < systems_per_page_))
1175             ? SYSTEM_COUNT_TOO_FEW : SYSTEM_COUNT_TOO_MANY;
1176         }
1177
1178       page_first_line = line;
1179     }
1180
1181   /* Recalculate forces for the last page because we know now that is
1182      really the last page. */
1183   space.resize (page_height (first_page_num + page, true));
1184   res.force_.back () = space.force_;
1185   return finalize_spacing_result (configuration, res);
1186 }
1187
1188 Page_spacing_result
1189 Page_breaking::pack_systems_on_least_pages (vsize configuration, vsize first_page_num)
1190 {
1191   // TODO: add support for min/max-systems-per-page.
1192   Page_spacing_result res;
1193   vsize page = 0;
1194   vsize page_first_line = 0;
1195   Page_spacing space (page_height (first_page_num, false), this);
1196
1197   cache_line_details (configuration);
1198   for (vsize line = 0; line < cached_line_details_.size (); line++)
1199     {
1200       Real prev_force = space.force_;
1201       space.append_system (cached_line_details_[line]);
1202       if ((line > page_first_line)
1203           && (isinf (space.force_)
1204               || ((line > 0)
1205                   && (cached_line_details_[line-1].page_permission_ == ly_symbol2scm ("force")))))
1206         {
1207           res.systems_per_page_.push_back (line - page_first_line);
1208           res.force_.push_back (prev_force);
1209           res.penalty_ += cached_line_details_[line-1].page_penalty_;
1210           page++;
1211           space.resize (page_height (first_page_num + page, false));
1212           space.clear ();
1213           space.append_system (cached_line_details_[line]);
1214           page_first_line = line;
1215         }
1216
1217       if (line == cached_line_details_.size () - 1)
1218         {
1219           /* This is the last line */
1220           /* When the last page height was computed, we did not know yet that it
1221            * was the last one. If the systems put on it don't fit anymore, the last
1222            * system is moved to a new page */
1223           space.resize (page_height (first_page_num + page, true));
1224           if ((line > page_first_line) && (isinf (space.force_)))
1225             {
1226               res.systems_per_page_.push_back (line - page_first_line);
1227               res.force_.push_back (prev_force);
1228               /* the last page containing the last line */
1229               space.resize (page_height (first_page_num + page + 1, true));
1230               space.clear ();
1231               space.append_system (cached_line_details_[line]);
1232               res.systems_per_page_.push_back (1);
1233               res.force_.push_back (space.force_);
1234               res.penalty_ += cached_line_details_[line-1].page_penalty_;
1235               res.penalty_ += cached_line_details_[line].page_penalty_;
1236             }
1237           else
1238             {
1239               res.systems_per_page_.push_back (line + 1 - page_first_line);
1240               res.force_.push_back (space.force_);
1241               res.penalty_ += cached_line_details_[line].page_penalty_;
1242             }
1243         }
1244     }
1245   return finalize_spacing_result (configuration, res);
1246 }
1247
1248 /* Calculate demerits and fix res.systems_per_page_ so that
1249    it refers to the original line numbers, not the ones given by compress_lines (). */
1250 Page_spacing_result
1251 Page_breaking::finalize_spacing_result (vsize configuration, Page_spacing_result res)
1252 {
1253   if (res.force_.empty ())
1254     return res;
1255
1256   cache_line_details (configuration);
1257   res.systems_per_page_ = uncompress_solution (res.systems_per_page_, cached_line_details_);
1258
1259   Real line_force = 0;
1260   Real line_penalty = 0;
1261   Real page_demerits = res.penalty_;
1262   Real page_weighting = robust_scm2double (book_->paper_->c_variable ("page-spacing-weight"), 10);
1263
1264   for (vsize i = 0; i < uncompressed_line_details_.size (); i++)
1265     {
1266       line_force += uncompressed_line_details_[i].force_ * uncompressed_line_details_[i].force_;
1267       line_penalty += uncompressed_line_details_[i].break_penalty_;
1268     }
1269
1270   for (vsize i = 0; i < res.force_.size (); i++)
1271     {
1272       Real f = res.force_[i];
1273
1274       page_demerits += min(f*f, BAD_SPACING_PENALTY);
1275     }
1276
1277   /* for a while we tried averaging page and line forces across pages instead
1278      of summing them, but it caused a problem: if there is a single page
1279      with a very bad page force (for example because of a forced page break),
1280      the page breaker will put in a _lot_ of pages so that the bad force
1281      becomes averaged out over many pages. */
1282   res.demerits_ = line_force + line_penalty + page_demerits * page_weighting;
1283   return res;
1284
1285 }
1286
1287 /* the cases for page_count = 1 or 2 can be done in O (n) time. Since they
1288    are by far the most common cases, we have special functions for them.
1289
1290    space_systems_on_1_page has a different calling convention than most of the
1291    space_systems functions. This is because space_systems_on_1_page is (unlike
1292    the other space_systems functions) sometimes called on subsets of a full
1293    configuration. */
1294 Page_spacing_result
1295 Page_breaking::space_systems_on_1_page (vector<Line_details> const &lines, Real page_height, bool ragged)
1296 {
1297   Page_spacing space (page_height, this);
1298   Page_spacing_result ret;
1299   int line_count = 0;
1300
1301   for (vsize i = 0; i < lines.size (); i++)
1302     {
1303       space.append_system (lines[i]);
1304       line_count += lines[i].compressed_nontitle_lines_count_;
1305     }
1306
1307   ret.systems_per_page_.push_back (lines.size ());
1308   ret.force_.push_back (ragged ? min (space.force_, 0.0) : space.force_);
1309   ret.penalty_ = line_count_penalty (line_count) + lines.back ().page_penalty_ + lines.back ().turn_penalty_;
1310   ret.system_count_status_ |= line_count_status (line_count);
1311
1312   /* don't do finalize_spacing_result () because we are only an internal function */
1313   return ret;
1314 }
1315
1316 Page_spacing_result
1317 Page_breaking::space_systems_on_2_pages (vsize configuration, vsize first_page_num)
1318 {
1319   Real page1_height = page_height (first_page_num, false);
1320   Real page2_height = page_height (first_page_num + 1, is_last ());
1321   bool ragged1 = ragged ();
1322   bool ragged2 = ragged () || (is_last () && ragged_last ());
1323
1324   /* if there is a forced break, this reduces to 2 1-page problems */
1325   cache_line_details (configuration);
1326   for (vsize i = 0; i + 1 < cached_line_details_.size (); i++)
1327     if (cached_line_details_[i].page_permission_ == ly_symbol2scm ("force"))
1328       {
1329         vector<Line_details> lines1 (cached_line_details_.begin (), cached_line_details_.begin () + i + 1);
1330         vector<Line_details> lines2 (cached_line_details_.begin () + i + 1, cached_line_details_.end ());
1331         Page_spacing_result p1 = space_systems_on_1_page (lines1, page1_height, ragged1);
1332         Page_spacing_result p2 = space_systems_on_1_page (lines2, page2_height, ragged2);
1333
1334         p1.systems_per_page_.push_back (p2.systems_per_page_[0]);
1335         p1.force_.push_back (p2.force_[0]);
1336         p1.penalty_ += p2.penalty_ - cached_line_details_[i].turn_penalty_;
1337         p1.system_count_status_ |= p2.system_count_status_;
1338         return p1;
1339       }
1340
1341   vector<Real> page1_force;
1342   vector<Real> page2_force;
1343
1344   // page1_penalty and page2_penalty store the penalties based
1345   // on min-systems-per-page and max-systems-per-page.
1346   vector<Real> page1_penalty;
1347   vector<Real> page2_penalty;
1348
1349   // page1_status and page2_status keep track of whether the min-systems-per-page
1350   // and max-systems-per-page constraints are satisfied.
1351   vector<int> page1_status;
1352   vector<int> page2_status;
1353
1354   Page_spacing page1 (page1_height, this);
1355   Page_spacing page2 (page2_height, this);
1356   int page1_line_count = 0;
1357   int page2_line_count = 0;
1358
1359   page1_force.resize (cached_line_details_.size () - 1, infinity_f);
1360   page2_force.resize (cached_line_details_.size () - 1, infinity_f);
1361   page1_penalty.resize (cached_line_details_.size () - 1, infinity_f);
1362   page2_penalty.resize (cached_line_details_.size () - 1, infinity_f);
1363   page1_status.resize (cached_line_details_.size () - 1, 0);
1364   page2_status.resize (cached_line_details_.size () - 1, 0);
1365
1366   /* find the page 1 and page 2 forces for each page-breaking position */
1367   for (vsize i = 0; i < page1_force.size (); i++)
1368     {
1369       page1.append_system (cached_line_details_[i]);
1370       page2.prepend_system (cached_line_details_[cached_line_details_.size () - 1 - i]);
1371       page1_line_count += cached_line_details_[i].compressed_nontitle_lines_count_;
1372       page2_line_count += cached_line_details_[cached_line_details_.size () - 1 - i].compressed_nontitle_lines_count_;
1373
1374       page1_force[i] = (ragged1 && page1.force_ < 0 && i > 0) ? infinity_f : page1.force_;
1375       page1_penalty[i] = line_count_penalty (page1_line_count);
1376       page1_status[i] = line_count_status (page1_line_count);
1377
1378       if (ragged2)
1379         page2_force[page2_force.size () - 1 - i] =
1380           (page2.force_ < 0 && i + 1 < page1_force.size ()) ? infinity_f : 0;
1381       else
1382         page2_force[page2_force.size () - 1 - i] = page2.force_;
1383       page2_penalty[page2_penalty.size () - 1 - i] = line_count_penalty (page2_line_count);
1384       page2_status[page2_penalty.size () - 1 - i] = line_count_status (page2_line_count);
1385     }
1386
1387   /* find the position that minimises the sum of the page forces */
1388   vsize best_sys_count = 1;
1389   Real best_demerits = infinity_f;
1390   for (vsize i = 0; i < page1_force.size (); i++)
1391     {
1392       Real f = page1_force[i] * page1_force[i] + page2_force[i] * page2_force[i];
1393
1394       // NOTE: we treat max-systems-per-page and min-systems-per-page as soft
1395       // constraints. That is, we penalize harshly when they don't happen
1396       // but we don't completely reject.
1397       Real dem = f
1398         + page1_penalty[i] + page2_penalty[i]
1399         + cached_line_details_[i+1].page_penalty_
1400         + cached_line_details_.back ().page_penalty_ + cached_line_details_.back ().turn_penalty_;
1401       if (dem < best_demerits)
1402         {
1403           best_demerits = dem;
1404           best_sys_count = i+1;
1405         }
1406     }
1407
1408   Page_spacing_result ret;
1409   ret.systems_per_page_.push_back (best_sys_count);
1410   ret.systems_per_page_.push_back (cached_line_details_.size () - best_sys_count);
1411   ret.force_.push_back (page1_force[best_sys_count-1]);
1412   ret.force_.push_back (page2_force[best_sys_count-1]);
1413   ret.system_count_status_ = page1_status[best_sys_count-1] | page2_status[best_sys_count-1];
1414   ret.penalty_ = cached_line_details_[best_sys_count-1].page_penalty_
1415     + cached_line_details_.back ().page_penalty_
1416     + cached_line_details_.back ().turn_penalty_
1417     + page1_penalty[best_sys_count-1] + page2_penalty[best_sys_count-1];
1418
1419   /* don't do finalize_spacing_result () because we are only an internal function */
1420   return ret;
1421 }
1422
1423 bool
1424 Page_breaking::all_lines_stretched (vsize configuration)
1425 {
1426   cache_line_details (configuration);
1427   for (vsize i = 0; i < cached_line_details_.size (); i++)
1428     if (cached_line_details_[i].force_ < 0)
1429       return false;
1430
1431   return true;
1432 }
1433
1434 Page_breaking::Line_division
1435 Page_breaking::current_configuration (vsize configuration_index) const
1436 {
1437   return current_configurations_[configuration_index];
1438 }
1439
1440 bool
1441 Page_breaking::is_last () const
1442 {
1443   return current_end_breakpoint_ == last_break_position ();
1444 }
1445
1446 bool
1447 Page_breaking::ends_score () const
1448 {
1449   return breaks_[current_end_breakpoint_].score_ender_;
1450 }
1451
1452 vsize
1453 Page_breaking::last_break_position () const
1454 {
1455   return breaks_.size () - 1;  
1456 }
1457
1458 // This gives the minimum distance between the top of the
1459 // printable area (ie. the bottom of the top-margin) and
1460 // the extent box of the topmost system.
1461 Real
1462 Page_breaking::min_whitespace_at_top_of_page (Line_details const &line) const
1463 {
1464   SCM first_system_spacing = book_->paper_->c_variable ("top-system-spacing");
1465   if (line.title_)
1466     first_system_spacing = book_->paper_->c_variable ("top-markup-spacing");
1467
1468   Real min_distance = -infinity_f;
1469   Real padding = 0;
1470
1471   Page_layout_problem::read_spacing_spec (first_system_spacing,
1472                                           &min_distance,
1473                                           ly_symbol2scm ("minimum-distance"));
1474   Page_layout_problem::read_spacing_spec (first_system_spacing,
1475                                           &padding,
1476                                           ly_symbol2scm ("padding"));
1477
1478   // FIXME: take into account the height of the header
1479   Real translate = max (line.shape_.begin_[UP], line.shape_.rest_[UP]);
1480   return max (0.0, max (padding, min_distance - translate));
1481 }
1482
1483 Real
1484 Page_breaking::min_whitespace_at_bottom_of_page (Line_details const &line) const
1485 {
1486   SCM last_system_spacing = book_->paper_->c_variable ("last-bottom-spacing");
1487   Real min_distance = -infinity_f;
1488   Real padding = 0;
1489
1490   Page_layout_problem::read_spacing_spec (last_system_spacing,
1491                                           &min_distance,
1492                                           ly_symbol2scm ("minimum-distance"));
1493   Page_layout_problem::read_spacing_spec (last_system_spacing,
1494                                           &padding,
1495                                           ly_symbol2scm ("padding"));
1496
1497   // FIXME: take into account the height of the footer
1498   Real translate = min (line.shape_.begin_[DOWN], line.shape_.rest_[DOWN]);
1499   return max (0.0, max (padding, min_distance + translate));
1500 }
1501
1502 int
1503 Page_breaking::orphan_penalty () const
1504 {
1505   return orphan_penalty_;
1506 }