]> git.donarmstrong.com Git - lilypond.git/blob - lily/page-breaking.cc
bc9016ff6aef0bebdaed23bd0363f06a25777f74
[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   cache_line_details (configuration);
1141   Page_spacer ps (cached_line_details_, first_page_num, this);
1142
1143   return finalize_spacing_result (configuration, ps.solve ());
1144 }
1145
1146 Page_spacing_result
1147 Page_breaking::space_systems_with_fixed_number_per_page (vsize configuration,
1148                                                          vsize first_page_num)
1149 {
1150   Page_spacing_result res;
1151   Page_spacing space (page_height (first_page_num, false), this);
1152   vsize line = 0;
1153   vsize page = 0;
1154   vsize page_first_line = 0;
1155
1156   cache_line_details (configuration);
1157   while (line < cached_line_details_.size ())
1158     {
1159       page++;
1160       space.clear ();
1161       space.resize (page_height (first_page_num + page, false));
1162
1163       int system_count_on_this_page = 0;
1164       while (system_count_on_this_page < systems_per_page_
1165              && line < cached_line_details_.size ())
1166         {
1167           Line_details const &cur_line = cached_line_details_[line];
1168           space.append_system (cur_line);
1169           system_count_on_this_page += cur_line.compressed_nontitle_lines_count_;
1170           line++;
1171
1172           if (cur_line.page_permission_ == ly_symbol2scm ("force"))
1173             break;
1174         }
1175
1176       res.systems_per_page_.push_back (line - page_first_line);
1177
1178       res.force_.push_back (space.force_);
1179       res.penalty_ += cached_line_details_[line-1].page_penalty_;
1180       if (system_count_on_this_page != systems_per_page_)
1181         {
1182           res.penalty_ += TERRIBLE_SPACING_PENALTY;
1183           res.system_count_status_ |= ((system_count_on_this_page < systems_per_page_))
1184             ? SYSTEM_COUNT_TOO_FEW : SYSTEM_COUNT_TOO_MANY;
1185         }
1186
1187       page_first_line = line;
1188     }
1189
1190   /* Recalculate forces for the last page because we know now that is
1191      really the last page. */
1192   space.resize (page_height (first_page_num + page, true));
1193   res.force_.back () = space.force_;
1194   return finalize_spacing_result (configuration, res);
1195 }
1196
1197 Page_spacing_result
1198 Page_breaking::pack_systems_on_least_pages (vsize configuration, vsize first_page_num)
1199 {
1200   // TODO: add support for min/max-systems-per-page.
1201   Page_spacing_result res;
1202   vsize page = 0;
1203   vsize page_first_line = 0;
1204   Page_spacing space (page_height (first_page_num, false), this);
1205
1206   cache_line_details (configuration);
1207   for (vsize line = 0; line < cached_line_details_.size (); line++)
1208     {
1209       Real prev_force = space.force_;
1210       space.append_system (cached_line_details_[line]);
1211       if ((line > page_first_line)
1212           && (isinf (space.force_)
1213               || ((line > 0)
1214                   && (cached_line_details_[line-1].page_permission_ == ly_symbol2scm ("force")))))
1215         {
1216           res.systems_per_page_.push_back (line - page_first_line);
1217           res.force_.push_back (prev_force);
1218           res.penalty_ += cached_line_details_[line-1].page_penalty_;
1219           page++;
1220           space.resize (page_height (first_page_num + page, false));
1221           space.clear ();
1222           space.append_system (cached_line_details_[line]);
1223           page_first_line = line;
1224         }
1225
1226       if (line == cached_line_details_.size () - 1)
1227         {
1228           /* This is the last line */
1229           /* When the last page height was computed, we did not know yet that it
1230            * was the last one. If the systems put on it don't fit anymore, the last
1231            * system is moved to a new page */
1232           space.resize (page_height (first_page_num + page, true));
1233           if ((line > page_first_line) && (isinf (space.force_)))
1234             {
1235               res.systems_per_page_.push_back (line - page_first_line);
1236               res.force_.push_back (prev_force);
1237               /* the last page containing the last line */
1238               space.resize (page_height (first_page_num + page + 1, true));
1239               space.clear ();
1240               space.append_system (cached_line_details_[line]);
1241               res.systems_per_page_.push_back (1);
1242               res.force_.push_back (space.force_);
1243               res.penalty_ += cached_line_details_[line-1].page_penalty_;
1244               res.penalty_ += cached_line_details_[line].page_penalty_;
1245             }
1246           else
1247             {
1248               res.systems_per_page_.push_back (line + 1 - page_first_line);
1249               res.force_.push_back (space.force_);
1250               res.penalty_ += cached_line_details_[line].page_penalty_;
1251             }
1252         }
1253     }
1254   return finalize_spacing_result (configuration, res);
1255 }
1256
1257 /* Calculate demerits and fix res.systems_per_page_ so that
1258    it refers to the original line numbers, not the ones given by compress_lines (). */
1259 Page_spacing_result
1260 Page_breaking::finalize_spacing_result (vsize configuration, Page_spacing_result res)
1261 {
1262   if (res.force_.empty ())
1263     return res;
1264
1265   cache_line_details (configuration);
1266   res.systems_per_page_ = uncompress_solution (res.systems_per_page_, cached_line_details_);
1267
1268   Real line_force = 0;
1269   Real line_penalty = 0;
1270   Real page_demerits = res.penalty_;
1271   Real page_weighting = robust_scm2double (book_->paper_->c_variable ("page-spacing-weight"), 10);
1272
1273   for (vsize i = 0; i < uncompressed_line_details_.size (); i++)
1274     {
1275       line_force += uncompressed_line_details_[i].force_ * uncompressed_line_details_[i].force_;
1276       line_penalty += uncompressed_line_details_[i].break_penalty_;
1277     }
1278
1279   for (vsize i = 0; i < res.force_.size (); i++)
1280     {
1281       Real f = res.force_[i];
1282
1283       page_demerits += min(f*f, BAD_SPACING_PENALTY);
1284     }
1285
1286   /* for a while we tried averaging page and line forces across pages instead
1287      of summing them, but it caused a problem: if there is a single page
1288      with a very bad page force (for example because of a forced page break),
1289      the page breaker will put in a _lot_ of pages so that the bad force
1290      becomes averaged out over many pages. */
1291   res.demerits_ = line_force + line_penalty + page_demerits * page_weighting;
1292   return res;
1293
1294 }
1295
1296 /* the cases for page_count = 1 or 2 can be done in O (n) time. Since they
1297    are by far the most common cases, we have special functions for them.
1298
1299    space_systems_on_1_page has a different calling convention than most of the
1300    space_systems functions. This is because space_systems_on_1_page is (unlike
1301    the other space_systems functions) sometimes called on subsets of a full
1302    configuration. */
1303 Page_spacing_result
1304 Page_breaking::space_systems_on_1_page (vector<Line_details> const &lines, Real page_height, bool ragged)
1305 {
1306   Page_spacing space (page_height, this);
1307   Page_spacing_result ret;
1308   int line_count = 0;
1309
1310   for (vsize i = 0; i < lines.size (); i++)
1311     {
1312       space.append_system (lines[i]);
1313       line_count += lines[i].compressed_nontitle_lines_count_;
1314     }
1315
1316   ret.systems_per_page_.push_back (lines.size ());
1317   ret.force_.push_back (ragged ? min (space.force_, 0.0) : space.force_);
1318   ret.penalty_ = line_count_penalty (line_count) + lines.back ().page_penalty_ + lines.back ().turn_penalty_;
1319   ret.system_count_status_ |= line_count_status (line_count);
1320
1321   /* don't do finalize_spacing_result () because we are only an internal function */
1322   return ret;
1323 }
1324
1325 Page_spacing_result
1326 Page_breaking::space_systems_on_2_pages (vsize configuration, vsize first_page_num)
1327 {
1328   Real page1_height = page_height (first_page_num, false);
1329   Real page2_height = page_height (first_page_num + 1, is_last ());
1330   bool ragged1 = ragged ();
1331   bool ragged2 = ragged () || (is_last () && ragged_last ());
1332
1333   /* if there is a forced break, this reduces to 2 1-page problems */
1334   cache_line_details (configuration);
1335   for (vsize i = 0; i + 1 < cached_line_details_.size (); i++)
1336     if (cached_line_details_[i].page_permission_ == ly_symbol2scm ("force"))
1337       {
1338         vector<Line_details> lines1 (cached_line_details_.begin (), cached_line_details_.begin () + i + 1);
1339         vector<Line_details> lines2 (cached_line_details_.begin () + i + 1, cached_line_details_.end ());
1340         Page_spacing_result p1 = space_systems_on_1_page (lines1, page1_height, ragged1);
1341         Page_spacing_result p2 = space_systems_on_1_page (lines2, page2_height, ragged2);
1342
1343         p1.systems_per_page_.push_back (p2.systems_per_page_[0]);
1344         p1.force_.push_back (p2.force_[0]);
1345         p1.penalty_ += p2.penalty_ - cached_line_details_[i].turn_penalty_;
1346         p1.system_count_status_ |= p2.system_count_status_;
1347         return p1;
1348       }
1349
1350   vector<Real> page1_force;
1351   vector<Real> page2_force;
1352
1353   // page1_penalty and page2_penalty store the penalties based
1354   // on min-systems-per-page and max-systems-per-page.
1355   vector<Real> page1_penalty;
1356   vector<Real> page2_penalty;
1357
1358   // page1_status and page2_status keep track of whether the min-systems-per-page
1359   // and max-systems-per-page constraints are satisfied.
1360   vector<int> page1_status;
1361   vector<int> page2_status;
1362
1363   Page_spacing page1 (page1_height, this);
1364   Page_spacing page2 (page2_height, this);
1365   int page1_line_count = 0;
1366   int page2_line_count = 0;
1367
1368   page1_force.resize (cached_line_details_.size () - 1, infinity_f);
1369   page2_force.resize (cached_line_details_.size () - 1, infinity_f);
1370   page1_penalty.resize (cached_line_details_.size () - 1, infinity_f);
1371   page2_penalty.resize (cached_line_details_.size () - 1, infinity_f);
1372   page1_status.resize (cached_line_details_.size () - 1, 0);
1373   page2_status.resize (cached_line_details_.size () - 1, 0);
1374
1375   /* find the page 1 and page 2 forces for each page-breaking position */
1376   for (vsize i = 0; i < page1_force.size (); i++)
1377     {
1378       page1.append_system (cached_line_details_[i]);
1379       page2.prepend_system (cached_line_details_[cached_line_details_.size () - 1 - i]);
1380       page1_line_count += cached_line_details_[i].compressed_nontitle_lines_count_;
1381       page2_line_count += cached_line_details_[cached_line_details_.size () - 1 - i].compressed_nontitle_lines_count_;
1382
1383       page1_force[i] = (ragged1 && page1.force_ < 0 && i > 0) ? infinity_f : page1.force_;
1384       page1_penalty[i] = line_count_penalty (page1_line_count);
1385       page1_status[i] = line_count_status (page1_line_count);
1386
1387       if (ragged2)
1388         page2_force[page2_force.size () - 1 - i] =
1389           (page2.force_ < 0 && i + 1 < page1_force.size ()) ? infinity_f : 0;
1390       else
1391         page2_force[page2_force.size () - 1 - i] = page2.force_;
1392       page2_penalty[page2_penalty.size () - 1 - i] = line_count_penalty (page2_line_count);
1393       page2_status[page2_penalty.size () - 1 - i] = line_count_status (page2_line_count);
1394     }
1395
1396   /* find the position that minimises the sum of the page forces */
1397   vsize best_sys_count = 1;
1398   Real best_demerits = infinity_f;
1399   for (vsize i = 0; i < page1_force.size (); i++)
1400     {
1401       Real f = page1_force[i] * page1_force[i] + page2_force[i] * page2_force[i];
1402
1403       // NOTE: we treat max-systems-per-page and min-systems-per-page as soft
1404       // constraints. That is, we penalize harshly when they don't happen
1405       // but we don't completely reject.
1406       Real dem = f
1407         + page1_penalty[i] + page2_penalty[i]
1408         + cached_line_details_[i+1].page_penalty_
1409         + cached_line_details_.back ().page_penalty_ + cached_line_details_.back ().turn_penalty_;
1410       if (dem < best_demerits)
1411         {
1412           best_demerits = dem;
1413           best_sys_count = i+1;
1414         }
1415     }
1416
1417   Page_spacing_result ret;
1418   ret.systems_per_page_.push_back (best_sys_count);
1419   ret.systems_per_page_.push_back (cached_line_details_.size () - best_sys_count);
1420   ret.force_.push_back (page1_force[best_sys_count-1]);
1421   ret.force_.push_back (page2_force[best_sys_count-1]);
1422   ret.system_count_status_ = page1_status[best_sys_count-1] | page2_status[best_sys_count-1];
1423   ret.penalty_ = cached_line_details_[best_sys_count-1].page_penalty_
1424     + cached_line_details_.back ().page_penalty_
1425     + cached_line_details_.back ().turn_penalty_
1426     + page1_penalty[best_sys_count-1] + page2_penalty[best_sys_count-1];
1427
1428   /* don't do finalize_spacing_result () because we are only an internal function */
1429   return ret;
1430 }
1431
1432 bool
1433 Page_breaking::all_lines_stretched (vsize configuration)
1434 {
1435   cache_line_details (configuration);
1436   for (vsize i = 0; i < cached_line_details_.size (); i++)
1437     if (cached_line_details_[i].force_ < 0)
1438       return false;
1439
1440   return true;
1441 }
1442
1443 Page_breaking::Line_division
1444 Page_breaking::current_configuration (vsize configuration_index) const
1445 {
1446   return current_configurations_[configuration_index];
1447 }
1448
1449 bool
1450 Page_breaking::is_last () const
1451 {
1452   return current_end_breakpoint_ == last_break_position ();
1453 }
1454
1455 bool
1456 Page_breaking::ends_score () const
1457 {
1458   return breaks_[current_end_breakpoint_].score_ender_;
1459 }
1460
1461 vsize
1462 Page_breaking::last_break_position () const
1463 {
1464   return breaks_.size () - 1;  
1465 }
1466
1467 // This gives the minimum distance between the top of the
1468 // printable area (ie. the bottom of the top-margin) and
1469 // the extent box of the topmost system.
1470 Real
1471 Page_breaking::min_whitespace_at_top_of_page (Line_details const &line) const
1472 {
1473   SCM first_system_spacing = book_->paper_->c_variable ("top-system-spacing");
1474   if (line.title_)
1475     first_system_spacing = book_->paper_->c_variable ("top-markup-spacing");
1476
1477   Real min_distance = -infinity_f;
1478   Real padding = 0;
1479
1480   Page_layout_problem::read_spacing_spec (first_system_spacing,
1481                                           &min_distance,
1482                                           ly_symbol2scm ("minimum-distance"));
1483   Page_layout_problem::read_spacing_spec (first_system_spacing,
1484                                           &padding,
1485                                           ly_symbol2scm ("padding"));
1486
1487   // FIXME: take into account the height of the header
1488   Real translate = max (line.shape_.begin_[UP], line.shape_.rest_[UP]);
1489   return max (0.0, max (padding, min_distance - translate));
1490 }
1491
1492 Real
1493 Page_breaking::min_whitespace_at_bottom_of_page (Line_details const &line) const
1494 {
1495   SCM last_system_spacing = book_->paper_->c_variable ("last-bottom-spacing");
1496   Real min_distance = -infinity_f;
1497   Real padding = 0;
1498
1499   Page_layout_problem::read_spacing_spec (last_system_spacing,
1500                                           &min_distance,
1501                                           ly_symbol2scm ("minimum-distance"));
1502   Page_layout_problem::read_spacing_spec (last_system_spacing,
1503                                           &padding,
1504                                           ly_symbol2scm ("padding"));
1505
1506   // FIXME: take into account the height of the footer
1507   Real translate = min (line.shape_.begin_[DOWN], line.shape_.rest_[DOWN]);
1508   return max (0.0, max (padding, min_distance + translate));
1509 }
1510
1511 int
1512 Page_breaking::orphan_penalty () const
1513 {
1514   return orphan_penalty_;
1515 }