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