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