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