Fixes Issue 1504, allowing feather beam line breaking.
[lilypond/patrick.git] / lily / page-breaking.cc
blob80702f59ba2e3517aa8afd8fd1f3acb9d790a9af
1 /*
2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 2006--2011 Joe Neeman <joeneeman@gmail.com>
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.
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.
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/>.
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.
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."
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.
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.
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).
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.
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.
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.
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.
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.
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.
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.
130 #include "page-breaking.hh"
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-score.hh"
140 #include "paper-system.hh"
141 #include "text-interface.hh"
142 #include "system.hh"
143 #include "warn.hh"
145 /* for each forbidden page break, merge the systems around it into one
146 system. */
147 static vector<Line_details>
148 compress_lines (const vector<Line_details> &orig)
150 vector<Line_details> ret;
152 for (vsize i = 0; i < orig.size (); i++)
154 if (ret.size () && !scm_is_symbol (ret.back ().page_permission_))
156 Line_details const &old = ret.back ();
157 Line_details compressed = orig[i];
159 We must account for the padding between the lines that we are compressing.
160 The padding values come from "old," which is the upper system here. Note
161 the meaning of tight-spacing: if a system has tight-spacing, then the padding
162 _before_ it is ignored.
164 Real padding = 0;
165 if (!orig[i].tight_spacing_)
166 padding = orig[i].title_ ? old.title_padding_ : old.padding_;
168 // FIXME: double check these. Doesn't foo.piggyback (bar) mean
169 // that foo goes on top?
170 // TODO: break out a Line_details::piggyback from here?
171 compressed.shape_ = old.shape_.piggyback (orig[i].shape_, padding);
172 compressed.refpoint_extent_[UP] = old.refpoint_extent_[UP];
173 compressed.refpoint_extent_[DOWN] += compressed.shape_.rest_[UP] - old.shape_.rest_[UP];
174 compressed.space_ += old.space_;
175 compressed.inverse_hooke_ += old.inverse_hooke_;
177 compressed.compressed_lines_count_ = old.compressed_lines_count_ + 1;
178 compressed.compressed_nontitle_lines_count_ =
179 old.compressed_nontitle_lines_count_ + (compressed.title_ ? 0 : 1);
181 // compressed.title_ is true if and only if the first of its
182 // compressed lines was a title.
183 compressed.title_ = old.title_;
185 // adds footnotes of one line to the footnotes of another
186 compressed.footnotes_.insert (compressed.footnotes_.begin (),
187 old.footnotes_.begin (), old.footnotes_.end ());
189 ret.back () = compressed;
191 else
193 ret.push_back (orig[i]);
194 ret.back ().force_ = 0;
197 return ret;
200 /* translate the number of systems-per-page into something meaningful for
201 the uncompressed lines.
203 static vector<vsize>
204 uncompress_solution (vector<vsize> const &systems_per_page,
205 vector<Line_details> const &compressed)
207 vector<vsize> ret;
208 vsize start_sys = 0;
210 for (vsize i = 0; i < systems_per_page.size (); i++)
212 int compressed_count = 0;
213 for (vsize j = start_sys; j < start_sys + systems_per_page[i]; j++)
214 compressed_count += compressed[j].compressed_lines_count_ - 1;
216 ret.push_back (systems_per_page[i] + compressed_count);
217 start_sys += systems_per_page[i];
219 return ret;
222 /* for Page_breaking, the start index (when we are dealing with the stuff
223 between a pair of breakpoints) refers to the break_ index of the end of
224 the previous page. So the system index of the start of the current page
225 could either be the same as the end of the previous page or one more than
226 it. */
228 /* Turn a break index into the sys index that starts the next page */
229 vsize
230 Page_breaking::next_system (Break_position const &break_pos) const
232 vsize sys = break_pos.system_spec_index_;
234 if (sys == VPOS) /* beginning of the book */
235 return 0;
236 if (system_specs_[sys].pscore_ && !break_pos.score_ender_)
237 return sys; /* the score overflows the previous page */
238 return sys + 1; /* this page starts with a new System_spec */
241 Page_breaking::Page_breaking (Paper_book *pb, Break_predicate is_break, Prob_break_predicate prob_break)
243 book_ = pb;
244 system_count_ = 0;
245 paper_height_ = robust_scm2double (pb->paper_->c_variable ("paper-height"), 1.0);
246 ragged_ = to_boolean (pb->paper_->c_variable ("ragged-bottom"));
247 ragged_last_ = to_boolean (pb->paper_->c_variable ("ragged-last-bottom"));
248 systems_per_page_ = max (0, robust_scm2int (pb->paper_->c_variable ("systems-per-page"), 0));
249 max_systems_per_page_ = max (0, robust_scm2int (pb->paper_->c_variable ("max-systems-per-page"), 0));
250 min_systems_per_page_ = max (0, robust_scm2int (pb->paper_->c_variable ("min-systems-per-page"), 0));
251 orphan_penalty_ = robust_scm2int (pb->paper_->c_variable ("orphan-penalty"), 100000);
253 Stencil *footnote_separator = Page_layout_problem::get_footnote_separator_stencil (pb->paper_);
255 if (footnote_separator)
257 Interval separator_extent = footnote_separator->extent (Y_AXIS);
258 Real separator_span = separator_extent.length ();
260 footnote_separator_stencil_height_ = separator_span;
262 else
263 footnote_separator_stencil_height_ = 0.0;
265 footnote_padding_ = robust_scm2double (pb->paper_->c_variable ("footnote-padding"), 0.0);
267 if (systems_per_page_ && (max_systems_per_page_ || min_systems_per_page_))
269 warning (_f ("ignoring min-systems-per-page and max-systems-per-page because systems-per-page was set"));
270 min_systems_per_page_ = max_systems_per_page_ = 0;
272 if (max_systems_per_page_ && min_systems_per_page_ > max_systems_per_page_)
274 warning (_f ("min-systems-per-page is larger than max-systems-per-page, ignoring both values"));
275 min_systems_per_page_ = max_systems_per_page_ = 0;
278 create_system_list ();
279 find_chunks_and_breaks (is_break, prob_break);
282 Page_breaking::~Page_breaking ()
286 bool
287 Page_breaking::ragged () const
289 return ragged_;
292 bool
293 Page_breaking::ragged_last () const
295 return ragged_last_;
299 Page_breaking::systems_per_page () const
301 return systems_per_page_;
305 Page_breaking::max_systems_per_page () const
307 if (systems_per_page_)
308 return systems_per_page_;
309 return max_systems_per_page_;
313 Page_breaking::min_systems_per_page () const
315 if (systems_per_page_)
316 return systems_per_page_;
317 return min_systems_per_page_;
320 vsize
321 Page_breaking::system_count () const
323 return system_count_;
326 Real
327 Page_breaking::footnote_separator_stencil_height () const
329 return footnote_separator_stencil_height_;
332 Real
333 Page_breaking::footnote_padding () const
335 return footnote_padding_;
338 bool
339 Page_breaking::too_many_lines (int line_count) const
341 return max_systems_per_page () > 0 && line_count > max_systems_per_page ();
344 bool
345 Page_breaking::too_few_lines (int line_count) const
347 return line_count < min_systems_per_page ();
350 Real
351 Page_breaking::line_count_penalty (int line_count) const
353 if (too_many_lines (line_count))
354 return (line_count - max_systems_per_page ()) * TERRIBLE_SPACING_PENALTY;
355 if (too_few_lines (line_count))
356 return (min_systems_per_page () - line_count) * TERRIBLE_SPACING_PENALTY;
358 return 0;
362 Page_breaking::line_count_status (int line_count) const
364 if (too_many_lines (line_count))
365 return SYSTEM_COUNT_TOO_MANY;
366 if (too_few_lines (line_count))
367 return SYSTEM_COUNT_TOO_FEW;
369 return SYSTEM_COUNT_OK;
372 /* translate indices into breaks_ into start-end parameters for the line breaker */
373 void
374 Page_breaking::line_breaker_args (vsize sys,
375 Break_position const &start,
376 Break_position const &end,
377 vsize *line_breaker_start,
378 vsize *line_breaker_end)
380 assert (system_specs_[sys].pscore_);
381 assert (next_system (start) <= sys && sys <= end.system_spec_index_);
383 if (start.system_spec_index_ == sys)
384 *line_breaker_start = start.score_break_;
385 else
386 *line_breaker_start = 0;
388 if (end.system_spec_index_ == sys)
389 *line_breaker_end = end.score_break_;
390 else
391 *line_breaker_end = VPOS;
394 void
395 Page_breaking::break_into_pieces (vsize start_break, vsize end_break,
396 Line_division const &div)
398 vector<Break_position> chunks = chunk_list (start_break, end_break);
399 bool ignore_div = false;
400 if (chunks.size () != div.size () + 1)
402 programming_error ("did not find a valid page breaking configuration");
403 ignore_div = true;
406 for (vsize i = 0; i + 1 < chunks.size (); i++)
408 vsize sys = next_system (chunks[i]);
409 if (system_specs_[sys].pscore_)
411 vsize start;
412 vsize end;
413 line_breaker_args (sys, chunks[i], chunks[i+1], &start, &end);
415 vector<Column_x_positions> pos = ignore_div
416 ? line_breaking_[sys].best_solution (start, end)
417 : line_breaking_[sys].solve (start, end, div[i]);
418 system_specs_[sys].pscore_->root_system ()->break_into_pieces (pos);
424 Page_breaking::systems ()
426 SCM ret = SCM_EOL;
427 for (vsize sys = 0; sys < system_specs_.size (); sys++)
429 if (system_specs_[sys].pscore_)
431 system_specs_[sys].pscore_->root_system ()
432 ->do_break_substitution_and_fixup_refpoints ();
433 SCM lines = system_specs_[sys].pscore_->root_system ()
434 ->get_broken_system_grobs ();
435 ret = scm_cons (lines, ret);
437 else if (Prob *pb = system_specs_[sys].prob_)
439 ret = scm_cons (scm_list_1 (pb->self_scm ()), ret);
440 pb->unprotect ();
443 return scm_append (scm_reverse (ret));
447 Page_breaking::make_page (int page_num, bool last) const
449 bool last_part = ly_scm2bool (book_->paper_->c_variable ("is-last-bookpart"));
450 SCM mod = scm_c_resolve_module ("scm page");
451 SCM make_page_scm = scm_c_module_lookup (mod, "make-page");
453 make_page_scm = scm_variable_ref (make_page_scm);
455 return scm_apply_0 (make_page_scm,
456 scm_list_n (book_->self_scm (),
457 ly_symbol2scm ("page-number"), scm_from_int (page_num),
458 ly_symbol2scm ("is-last-bookpart"), scm_from_bool (last_part),
459 ly_symbol2scm ("is-bookpart-last-page"), scm_from_bool (last),
460 SCM_UNDEFINED));
463 // Returns the total height of the paper, including margins and
464 // space for the header/footer. This is an upper bound on
465 // page_height, and it doesn't depend on the current page.
466 Real
467 Page_breaking::paper_height () const
469 return paper_height_;
472 Real
473 Page_breaking::page_height (int page_num, bool last) const
475 // The caches allow us to store the page heights for any
476 // non-negative page numbers. We use a negative value in the
477 // cache to signal that that position has not yet been initialized.
478 // This means that we won't cache properly if page_num is negative or
479 // if calc_height returns a negative number. But that's likely to
480 // be rare, so it shouldn't affect performance.
481 vector<Real>& cache = last ? last_page_height_cache_ : page_height_cache_;
482 if (page_num >= 0 && (int) cache.size () > page_num && cache[page_num] >= 0)
483 return cache[page_num];
484 else
486 SCM mod = scm_c_resolve_module ("scm page");
487 SCM page = make_page (page_num, last);
488 SCM calc_height = scm_c_module_lookup (mod, "calc-printable-height");
489 calc_height = scm_variable_ref (calc_height);
491 SCM height_scm = scm_apply_1 (calc_height, page, SCM_EOL);
492 Real height = scm_to_double (height_scm);
494 if (page_num >= 0)
496 if ((int) cache.size () <= page_num)
497 cache.resize (page_num + 1, -1);
498 cache[page_num] = height;
500 return height;
505 Page_breaking::breakpoint_property (vsize breakpoint, char const *str)
507 Break_position const &pos = breaks_[breakpoint];
509 if (pos.system_spec_index_ == VPOS)
510 return SCM_EOL;
511 if (system_specs_[pos.system_spec_index_].pscore_)
512 return pos.col_->get_property (str);
513 return system_specs_[pos.system_spec_index_].prob_->get_property (str);
517 Page_breaking::get_page_configuration (SCM systems, int page_num, bool ragged, bool last)
519 SCM dummy_page = make_page (page_num, last);
520 Page_layout_problem layout (book_, dummy_page, systems);
521 return scm_is_pair (systems) ? layout.solution (ragged) : SCM_EOL;
525 Page_breaking::draw_page (SCM systems, SCM configuration, int page_num, bool last)
527 // Create a stencil for each system.
528 SCM paper_systems = SCM_EOL;
529 for (SCM s = scm_reverse (systems); scm_is_pair (s); s = scm_cdr (s))
531 SCM paper_system = scm_car (s);
532 if (Grob *g = unsmob_grob (scm_car (s)))
534 System *sys = dynamic_cast<System*> (g);
535 paper_system = sys->get_paper_system ();
538 paper_systems = scm_cons (paper_system, paper_systems);
541 // Create the page and draw it.
542 SCM page = make_page (page_num, last);
543 SCM page_module = scm_c_resolve_module ("scm page");
544 SCM page_stencil = scm_c_module_lookup (page_module, "page-stencil");
545 page_stencil = scm_variable_ref (page_stencil);
547 Prob *p = unsmob_prob (page);
548 p->set_property ("lines", paper_systems);
549 p->set_property ("configuration", configuration);
551 Stencil *foot = unsmob_stencil (p->get_property ("foot-stencil"));
552 SCM footnotes = Page_layout_problem::get_footnotes_from_lines (systems, footnote_padding ());
553 Page_layout_problem::add_footnotes_to_footer (footnotes, foot, unsmob_paper_book (p->get_property ("paper-book")));
555 p->set_property ("foot-stencil", foot->smobbed_copy ());
556 scm_apply_1 (page_stencil, page, SCM_EOL);
558 return page;
562 Page_breaking::make_pages (vector<vsize> lines_per_page, SCM systems)
564 if (scm_is_null (systems))
565 return SCM_EOL;
567 int first_page_number
568 = robust_scm2int (book_->paper_->c_variable ("first-page-number"), 1);
569 SCM ret = SCM_EOL;
570 SCM label_page_table = book_->top_paper ()->c_variable ("label-page-table");
571 if (label_page_table == SCM_UNDEFINED)
572 label_page_table = SCM_EOL;
574 // Build a list of (systems . configuration) pairs. Note that we lay out
575 // the staves and find the configurations before drawing anything. Some
576 // grobs (like tuplet brackets) look at their neighbours while drawing
577 // themselves. If this happens before the neighbouring staves have
578 // been laid out, bad side-effects could happen (in particular,
579 // Align_interface::align_to_ideal_distances might be called).
580 SCM systems_and_configs = SCM_EOL;
582 for (vsize i = 0; i < lines_per_page.size (); i++)
584 int page_num = i + first_page_number;
585 bool bookpart_last_page = (i == lines_per_page.size () - 1);
586 bool rag = ragged () || (bookpart_last_page && ragged_last ());
587 SCM line_count = scm_from_int (lines_per_page[i]);
588 SCM lines = scm_list_head (systems, line_count);
589 SCM config = get_page_configuration (lines, page_num, rag, bookpart_last_page);
591 systems_and_configs = scm_cons (scm_cons (lines, config), systems_and_configs);
592 systems = scm_list_tail (systems, line_count);
595 // Now it's safe to make the pages.
596 int page_num = first_page_number + lines_per_page.size () - 1;
597 for (SCM s = systems_and_configs; scm_is_pair (s); s = scm_cdr (s))
599 SCM lines = scm_caar (s);
600 SCM config = scm_cdar (s);
602 bool bookpart_last_page = (s == systems_and_configs);
603 SCM page = draw_page (lines, config, page_num, bookpart_last_page);
605 /* collect labels */
606 SCM page_num_scm = scm_from_int (page_num);
607 for (SCM l = lines ; scm_is_pair (l) ; l = scm_cdr (l))
609 SCM labels = SCM_EOL;
610 if (Grob * line = unsmob_grob (scm_car (l)))
612 System *system = dynamic_cast<System*> (line);
613 labels = system->get_property ("labels");
615 else if (Prob *prob = unsmob_prob (scm_car (l)))
616 labels = prob->get_property ("labels");
618 for (SCM lbls = labels ; scm_is_pair (lbls) ; lbls = scm_cdr (lbls))
619 label_page_table = scm_cons (scm_cons (scm_car (lbls), page_num_scm),
620 label_page_table);
623 ret = scm_cons (page, ret);
624 --page_num;
627 // By reversing the table, we ensure that duplicated labels (eg. those
628 // straddling a page turn) will appear in the table with their last
629 // occurence first.
630 label_page_table = scm_reverse_x (label_page_table, SCM_EOL);
631 book_->top_paper ()->set_variable (ly_symbol2scm ("label-page-table"), label_page_table);
632 return ret;
635 /* The page-turn-page-breaker needs to have a line-breaker between any two
636 columns with non-NULL page-turn-permission.
638 The optimal-breaker needs to have a line-breaker between any two columns
639 with page-break-permission = 'force.
641 By using a grob predicate, we can accommodate both of these uses.
643 void
644 Page_breaking::create_system_list ()
646 SCM specs = book_->get_system_specs ();
647 for (SCM s = specs; scm_is_pair (s); s = scm_cdr (s))
649 if (Paper_score *ps = dynamic_cast<Paper_score*> (unsmob_music_output (scm_car (s))))
651 system_specs_.push_back (System_spec (ps));
653 else
655 Prob *pb = unsmob_prob (scm_car (s));
656 assert (pb);
658 pb->protect ();
659 system_specs_.push_back (System_spec (pb));
662 if (!system_specs_.size ())
663 system_specs_.push_back (System_spec ());
666 void
667 Page_breaking::find_chunks_and_breaks (Break_predicate is_break, Prob_break_predicate prob_is_break)
669 SCM force_sym = ly_symbol2scm ("force");
671 chunks_.push_back (Break_position ());
672 breaks_.push_back (Break_position ());
674 for (vsize i = 0; i < system_specs_.size (); i++)
676 if (system_specs_[i].pscore_)
678 vector<Grob*> cols = system_specs_[i].pscore_->root_system ()->used_columns ();
679 vector<Grob*> forced_line_break_cols;
681 SCM system_count = system_specs_[i].pscore_->layout ()->c_variable ("system-count");
682 if (scm_is_number (system_count))
684 // With system-count given, the line configuration for
685 // this score is fixed. We need to ensure that chunk
686 // boundaries only occur at line breaks.
687 Constrained_breaking breaking (system_specs_[i].pscore_);
688 vector<Line_details> details = breaking.line_details (0, VPOS, scm_to_int (system_count));
690 for (vsize j = 0; j < details.size (); j++)
691 forced_line_break_cols.push_back (details[j].last_column_);
694 int last_forced_line_break_idx = 0;
695 vsize forced_line_break_idx = 0;
696 vector<vsize> line_breaker_columns;
697 line_breaker_columns.push_back (0);
699 for (vsize j = 1; j < cols.size (); j++)
701 if (forced_line_break_cols.size ())
703 if (forced_line_break_idx >= forced_line_break_cols.size ()
704 || forced_line_break_cols[forced_line_break_idx] != cols[j])
705 continue;
706 else
707 forced_line_break_idx++;
710 bool last = (j == cols.size () - 1);
711 bool break_point = is_break && is_break (cols[j]);
712 bool chunk_end = cols[j]->get_property ("page-break-permission") == force_sym;
713 Break_position cur_pos = Break_position (i,
714 line_breaker_columns.size (),
715 cols[j],
716 last);
718 // NOTE: even in the breaks_ list, forced_line_count_
719 // refers to the number of lines between a
720 // Break_position and the start of that /chunk/. This
721 // is needed for system_count_bounds to work correctly,
722 // since it mixes Break_positions from breaks_ and
723 // chunks_.
724 if (scm_is_number (system_count))
725 cur_pos.forced_line_count_ = forced_line_break_idx - last_forced_line_break_idx;
727 if (break_point || (i == system_specs_.size () - 1 && last))
728 breaks_.push_back (cur_pos);
729 if (chunk_end || last)
731 chunks_.push_back (cur_pos);
732 last_forced_line_break_idx = forced_line_break_idx;
735 if ((break_point || chunk_end) && !last)
736 line_breaker_columns.push_back (j);
738 line_breaking_.push_back (Constrained_breaking (system_specs_[i].pscore_, line_breaker_columns));
740 else if (system_specs_[i].prob_)
742 bool break_point = prob_is_break && prob_is_break (system_specs_[i].prob_);
743 if (break_point || i == system_specs_.size () - 1)
744 breaks_.push_back (Break_position (i));
746 chunks_.push_back (Break_position (i));
748 /* FIXME: shouldn't we push a Null_breaker or similar dummy
749 class? --hwn */
750 line_breaking_.push_back (Constrained_breaking (NULL));
755 vector<Break_position>
756 Page_breaking::chunk_list (vsize start_index, vsize end_index)
758 Break_position start = breaks_[start_index];
759 Break_position end = breaks_[end_index];
761 vsize i = 0;
762 for (; i < chunks_.size () && chunks_[i] <= start; i++)
765 vector<Break_position> ret;
766 ret.push_back (start);
767 for (; i < chunks_.size () && chunks_[i] < end; i++)
768 ret.push_back (chunks_[i]);
769 ret.push_back (end);
770 return ret;
773 // Returns the minimum number of _non-title_ lines.
774 vsize
775 Page_breaking::min_system_count (vsize start, vsize end)
777 vector<Break_position> chunks = chunk_list (start, end);
778 Line_division div = system_count_bounds (chunks, true);
779 vsize ret = 0;
781 for (vsize i = 0; i < div.size (); i++)
782 ret += div[i];
783 return ret;
786 // Returns the maximum number of _non-title_ lines.
787 vsize
788 Page_breaking::max_system_count (vsize start, vsize end)
790 vector<Break_position> chunks = chunk_list (start, end);
791 Line_division div = system_count_bounds (chunks, false);
792 vsize ret = 0;
794 for (vsize i = 0; i < div.size (); i++)
795 ret += div[i];
796 return ret;
799 // The numbers returned by this function represent either
800 // the maximum or minimum number of _non-title_ lines
801 // per chunk.
802 Page_breaking::Line_division
803 Page_breaking::system_count_bounds (vector<Break_position> const &chunks,
804 bool min)
806 assert (chunks.size () >= 2);
808 Line_division ret;
809 ret.resize (chunks.size () - 1, 0);
811 for (vsize i = 0; i + 1 < chunks.size (); i++)
813 vsize sys = next_system (chunks[i]);
815 if (chunks[i+1].forced_line_count_)
816 ret[i] = chunks[i+1].forced_line_count_;
817 else if (system_specs_[sys].pscore_)
819 vsize start;
820 vsize end;
821 line_breaker_args (sys, chunks[i], chunks[i+1], &start, &end);
822 ret[i] = min
823 ? line_breaking_[sys].min_system_count (start, end)
824 : line_breaking_[sys].max_system_count (start, end);
828 return ret;
831 void
832 Page_breaking::set_current_breakpoints (vsize start,
833 vsize end,
834 vsize system_count,
835 Line_division lower_bound,
836 Line_division upper_bound)
838 system_count_ = system_count;
839 current_chunks_ = chunk_list (start, end);
840 current_start_breakpoint_ = start;
841 current_end_breakpoint_ = end;
842 clear_line_details_cache ();
844 if (!lower_bound.size ())
845 lower_bound = system_count_bounds (current_chunks_, true);
846 if (!upper_bound.size ())
847 upper_bound = system_count_bounds (current_chunks_, false);
849 assert (lower_bound.size () == current_chunks_.size () - 1);
850 assert (upper_bound.size () == current_chunks_.size () - 1);
852 Line_division work_in_progress;
853 current_configurations_.clear ();
854 line_divisions_rec (system_count,
855 lower_bound,
856 upper_bound,
857 &work_in_progress);
859 /* we only consider a constant number of configurations. Otherwise,
860 this becomes slow when there are many small scores. The constant
861 5 is somewhat arbitrary. */
862 if (current_configurations_.size () > 5)
864 vector<pair<Real,vsize> > dems_and_indices;
866 for (vsize i = 0; i < current_configurations_.size (); i++)
868 cache_line_details (i);
869 Real dem = 0;
870 for (vsize j = 0; j < cached_line_details_.size (); j++)
871 dem += cached_line_details_[j].force_ * cached_line_details_[j].force_
872 + cached_line_details_[j].break_penalty_;
874 dems_and_indices.push_back (pair<Real,vsize> (dem, i));
876 vector_sort (dems_and_indices, less<pair<Real,vsize> > ());
878 vector<Line_division> best_5_configurations;
879 for (vsize i = 0; i < 5; i++)
880 best_5_configurations.push_back (current_configurations_[dems_and_indices[i].second]);
882 clear_line_details_cache ();
883 current_configurations_ = best_5_configurations;
887 void
888 Page_breaking::set_to_ideal_line_configuration (vsize start, vsize end)
890 current_chunks_ = chunk_list (start, end);
891 current_start_breakpoint_ = start;
892 current_end_breakpoint_ = end;
893 clear_line_details_cache ();
894 system_count_ = 0;
896 Line_division div;
897 for (vsize i = 0; i+1 < current_chunks_.size (); i++)
899 vsize sys = next_system (current_chunks_[i]);
901 if (current_chunks_[i+1].forced_line_count_)
902 div.push_back (current_chunks_[i+1].forced_line_count_);
903 else if (system_specs_[sys].pscore_)
905 line_breaker_args (sys, current_chunks_[i], current_chunks_[i+1], &start, &end);
906 div.push_back (line_breaking_[sys].best_solution (start, end).size ());
908 else
909 div.push_back (0);
911 system_count_ += div.back ();
913 current_configurations_.clear ();
914 current_configurations_.push_back (div);
917 vsize
918 Page_breaking::current_configuration_count () const
920 return current_configurations_.size ();
923 void
924 Page_breaking::cache_line_details (vsize configuration_index)
926 if (cached_configuration_index_ != configuration_index)
928 cached_configuration_index_ = configuration_index;
930 Line_division &div = current_configurations_[configuration_index];
931 uncompressed_line_details_.clear ();
932 for (vsize i = 0; i + 1 < current_chunks_.size (); i++)
934 vsize sys = next_system (current_chunks_[i]);
935 if (system_specs_[sys].pscore_)
937 vsize start;
938 vsize end;
939 line_breaker_args (sys, current_chunks_[i], current_chunks_[i+1], &start, &end);
941 vector<Line_details> details = line_breaking_[sys].line_details (start, end, div[i]);
942 uncompressed_line_details_.insert (uncompressed_line_details_.end (), details.begin (), details.end ());
944 else
946 assert (div[i] == 0);
947 uncompressed_line_details_.push_back (system_specs_[sys].prob_
948 ? Line_details (system_specs_[sys].prob_, book_->paper_)
949 : Line_details ());
952 cached_line_details_ = compress_lines (uncompressed_line_details_);
953 compute_line_heights ();
957 void
958 Page_breaking::clear_line_details_cache ()
960 cached_configuration_index_ = VPOS;
961 cached_line_details_.clear ();
962 uncompressed_line_details_.clear ();
965 void
966 Page_breaking::line_divisions_rec (vsize system_count,
967 Line_division const &min_sys,
968 Line_division const &max_sys,
969 Line_division *cur_division)
971 vsize my_index = cur_division->size ();
972 int others_min = 0;
973 int others_max = 0;
975 for (vsize i = my_index + 1; i < min_sys.size (); i++)
977 others_min += min_sys[i];
978 others_max += max_sys[i];
980 others_max = min (others_max, (int) system_count);
981 int real_min = max ((int) min_sys[my_index], (int) system_count - others_max);
982 int real_max = min ((int) max_sys[my_index], (int) system_count - others_min);
984 if (real_min > real_max || real_min < 0)
986 /* this should never happen within a recursive call. If it happens
987 at all, it means that we were called with an unsolvable problem
988 and we should return an empty result */
989 assert (my_index == 0);
990 return;
993 for (int i = real_min; i <= real_max; i++)
995 cur_division->push_back (i);
996 if (my_index == min_sys.size () - 1)
997 current_configurations_.push_back (*cur_division);
998 else
999 line_divisions_rec (system_count - i, min_sys, max_sys, cur_division);
1000 cur_division->pop_back ();
1004 void
1005 Page_breaking::compute_line_heights ()
1007 Real prev_hanging = 0;
1008 Real prev_hanging_begin = 0;
1009 Real prev_hanging_rest = 0;
1011 // refpoint_hanging is the y coordinate of the origin of this system.
1012 // It may not be the same as refpoint_extent[UP], which is the
1013 // refpoint of the first spaceable staff in this system.
1014 Real prev_refpoint_hanging = 0;
1015 for (vsize i = 0; i < cached_line_details_.size (); i++)
1017 Line_details& cur = cached_line_details_[i];
1018 Line_shape shape = cur.shape_;
1019 Real a = shape.begin_[UP];
1020 Real b = shape.rest_[UP];
1021 bool title = cur.title_;
1022 Real refpoint_hanging = max (prev_hanging_begin + a, prev_hanging_rest + b);
1024 if (i > 0)
1026 Real padding = 0;
1027 Line_details const& prev = cached_line_details_[i-1];
1028 if (!cur.tight_spacing_)
1029 padding = title
1030 ? prev.title_padding_
1031 : prev.padding_;
1032 Real min_dist = title
1033 ? prev.title_min_distance_
1034 : prev.min_distance_;
1035 refpoint_hanging = max (refpoint_hanging + padding,
1036 prev_refpoint_hanging - prev.refpoint_extent_[DOWN]
1037 + cur.refpoint_extent_[UP] + min_dist);
1040 Real hanging_begin = refpoint_hanging - shape.begin_[DOWN];
1041 Real hanging_rest = refpoint_hanging - shape.rest_[DOWN];
1042 Real hanging = max (hanging_begin, hanging_rest);
1043 cur.tallness_ = hanging - prev_hanging;
1044 prev_hanging = hanging;
1045 prev_hanging_begin = hanging_begin;
1046 prev_hanging_rest = hanging_rest;
1047 prev_refpoint_hanging = refpoint_hanging;
1051 vsize
1052 Page_breaking::min_page_count (vsize configuration, vsize first_page_num)
1054 vsize ret = 1;
1055 vsize page_starter = 0;
1056 Real cur_rod_height = 0;
1057 Real cur_spring_height = 0;
1058 Real cur_page_height = page_height (first_page_num, false);
1059 int line_count = 0;
1061 cache_line_details (configuration);
1063 if (cached_line_details_.size ())
1064 cur_page_height -= min_whitespace_at_top_of_page (cached_line_details_[0]);
1066 for (vsize i = 0; i < cached_line_details_.size (); i++)
1068 Line_details const &cur = cached_line_details_[i];
1069 Line_details const *const prev = (i > 0) ? &cached_line_details_[i-1] : 0;
1070 Real ext_len;
1071 if (cur_rod_height > 0)
1072 ext_len = cur.tallness_;
1073 else
1074 ext_len = cur.full_height();
1076 Real spring_len = (i > 0) ? prev->spring_length (cur) : 0;
1077 Real next_rod_height = cur_rod_height + ext_len;
1078 Real next_spring_height = cur_spring_height + spring_len;
1079 Real next_height = next_rod_height + (ragged () ? next_spring_height : 0)
1080 + min_whitespace_at_bottom_of_page (cur);
1081 int next_line_count = line_count + cur.compressed_nontitle_lines_count_;
1083 if ((!too_few_lines (line_count) && (next_height > cur_page_height && cur_rod_height > 0))
1084 || too_many_lines (next_line_count)
1085 || (prev && prev->page_permission_ == ly_symbol2scm ("force")))
1087 line_count = cur.compressed_nontitle_lines_count_;
1088 cur_rod_height = cur.full_height();
1089 cur_spring_height = 0;
1090 page_starter = i;
1092 cur_page_height = page_height (first_page_num + ret, false);
1093 cur_page_height -= min_whitespace_at_top_of_page (cur);
1095 ret++;
1097 else
1099 cur_rod_height = next_rod_height;
1100 cur_spring_height = next_spring_height;
1101 line_count = next_line_count;
1105 /* there are two potential problems with the last page (because we didn't know
1106 it was the last page until after we managed to fit all the systems to it):
1107 - we are ragged-last but the last page has a compressed spring
1108 - the value returned by page_height (num, true) is smaller than the
1109 value returned by page_height (num, false) and it causes the page not to
1110 fit.
1112 In either case, we just need to add one more page. This is because the last
1113 line will always fit on the extra page and by adding one more page to the
1114 end, the previous page is no longer the last page, so our previous
1115 calculations that treated it as a non-last page were ok.
1118 if (is_last ())
1120 cur_page_height = page_height (first_page_num + ret - 1, true);
1121 cur_page_height -= min_whitespace_at_top_of_page (cached_line_details_[page_starter]);
1122 cur_page_height -= min_whitespace_at_bottom_of_page (cached_line_details_.back ());
1124 Real cur_height = cur_rod_height + ((ragged_last () || ragged ()) ? cur_spring_height : 0);
1125 if (!too_few_lines (line_count - cached_line_details_.back ().compressed_nontitle_lines_count_)
1126 && cur_height > cur_page_height
1127 /* don't increase the page count if the last page had only one system */
1128 && cur_rod_height > cached_line_details_.back ().full_height ())
1129 ret++;
1130 assert (ret <= cached_line_details_.size ());
1133 return ret;
1136 // If systems_per_page_ is positive, we don't really try to space on N pages;
1137 // we just put the requested number of systems on each page and penalize
1138 // if the result doesn't have N pages.
1139 Page_spacing_result
1140 Page_breaking::space_systems_on_n_pages (vsize configuration, vsize n, vsize first_page_num)
1142 Page_spacing_result ret;
1144 if (systems_per_page_ > 0)
1146 Page_spacing_result ret = space_systems_with_fixed_number_per_page (configuration, first_page_num);
1147 ret.demerits_ += (ret.force_.size () == n) ? 0 : BAD_SPACING_PENALTY;
1148 return ret;
1151 cache_line_details (configuration);
1152 bool valid_n = (n >= min_page_count (configuration, first_page_num)
1153 && n <= cached_line_details_.size ());
1155 if (!valid_n)
1156 programming_error ("number of pages is out of bounds");
1158 if (n == 1 && valid_n)
1159 ret = space_systems_on_1_page (cached_line_details_,
1160 page_height (first_page_num, is_last ()),
1161 ragged () || (is_last () && ragged_last ()));
1162 else if (n == 2 && valid_n)
1163 ret = space_systems_on_2_pages (configuration, first_page_num);
1164 else
1166 Page_spacer ps (cached_line_details_, first_page_num, this);
1167 ret = ps.solve (n);
1170 return finalize_spacing_result (configuration, ret);
1173 Real
1174 Page_breaking::blank_page_penalty () const
1176 SCM penalty_sym;
1178 if (is_last ())
1179 penalty_sym = ly_symbol2scm ("blank-last-page-force");
1180 else if (ends_score ())
1181 penalty_sym = ly_symbol2scm ("blank-after-score-page-force");
1182 else
1183 penalty_sym = ly_symbol2scm ("blank-page-force");
1185 Break_position const &pos = breaks_[current_end_breakpoint_];
1186 if (Paper_score *ps = system_specs_[pos.system_spec_index_].pscore_)
1187 return robust_scm2double (ps->layout ()->lookup_variable (penalty_sym), 0.0);
1189 return robust_scm2double (book_->paper_->lookup_variable (penalty_sym), 0.0);
1192 // If systems_per_page_ is positive, we don't really try to space on N
1193 // or N+1 pages; see the comment to space_systems_on_n_pages.
1194 Page_spacing_result
1195 Page_breaking::space_systems_on_n_or_one_more_pages (vsize configuration, vsize n, vsize first_page_num,
1196 Real penalty_for_fewer_pages)
1198 Page_spacing_result n_res;
1199 Page_spacing_result m_res;
1201 if (systems_per_page_ > 0)
1203 Page_spacing_result ret = space_systems_with_fixed_number_per_page (configuration, first_page_num);
1204 ret.demerits_ += (ret.force_.size () == n || ret.force_.size () == (n-1)) ? 0 : BAD_SPACING_PENALTY;
1205 return ret;
1208 cache_line_details (configuration);
1209 vsize min_p_count = min_page_count (configuration, first_page_num);
1210 bool valid_n = n >= min_p_count || n <= cached_line_details_.size ();
1212 if (!valid_n)
1213 programming_error ("both page counts are out of bounds");
1215 if (n == 1 && valid_n)
1217 bool rag = ragged () || (is_last () && ragged_last ());
1218 Real height = page_height (first_page_num, is_last ());
1220 if (1 >= min_p_count)
1221 n_res = space_systems_on_1_page (cached_line_details_, height, rag);
1222 if (1 < cached_line_details_.size ())
1223 m_res = space_systems_on_2_pages (configuration, first_page_num);
1225 else
1227 Page_spacer ps (cached_line_details_, first_page_num, this);
1229 if (n >= min_p_count || !valid_n)
1230 n_res = ps.solve (n);
1231 if (n < cached_line_details_.size () || !valid_n)
1232 m_res = ps.solve (n+1);
1235 m_res = finalize_spacing_result (configuration, m_res);
1236 n_res = finalize_spacing_result (configuration, n_res);
1238 Real page_spacing_weight = robust_scm2double (book_->paper_->c_variable ("page-spacing-weight"), 10);
1239 n_res.demerits_ += penalty_for_fewer_pages * page_spacing_weight;
1241 if (n_res.force_.size ())
1242 n_res.force_.back () += penalty_for_fewer_pages;
1244 return (m_res.demerits_ < n_res.demerits_) ? m_res : n_res;
1247 Page_spacing_result
1248 Page_breaking::space_systems_on_best_pages (vsize configuration, vsize first_page_num)
1250 if (systems_per_page_ > 0)
1251 return space_systems_with_fixed_number_per_page (configuration, first_page_num);
1253 cache_line_details (configuration);
1254 Page_spacer ps (cached_line_details_, first_page_num, this);
1256 return finalize_spacing_result (configuration, ps.solve ());
1259 Page_spacing_result
1260 Page_breaking::space_systems_with_fixed_number_per_page (vsize configuration,
1261 vsize first_page_num)
1263 Page_spacing_result res;
1264 Page_spacing space (page_height (first_page_num, false), this);
1265 vsize line = 0;
1266 vsize page = 0;
1267 vsize page_first_line = 0;
1269 cache_line_details (configuration);
1270 while (line < cached_line_details_.size ())
1272 page++;
1273 space.clear ();
1274 space.resize (page_height (first_page_num + page, false));
1276 int system_count_on_this_page = 0;
1277 while (system_count_on_this_page < systems_per_page_
1278 && line < cached_line_details_.size ())
1280 Line_details const &cur_line = cached_line_details_[line];
1281 space.append_system (cur_line);
1282 system_count_on_this_page += cur_line.compressed_nontitle_lines_count_;
1283 line++;
1285 if (cur_line.page_permission_ == ly_symbol2scm ("force"))
1286 break;
1289 res.systems_per_page_.push_back (line - page_first_line);
1291 res.force_.push_back (space.force_);
1292 res.penalty_ += cached_line_details_[line-1].page_penalty_;
1293 if (system_count_on_this_page != systems_per_page_)
1295 res.penalty_ += abs (system_count_on_this_page - systems_per_page_) * TERRIBLE_SPACING_PENALTY;
1296 res.system_count_status_ |= ((system_count_on_this_page < systems_per_page_))
1297 ? SYSTEM_COUNT_TOO_FEW : SYSTEM_COUNT_TOO_MANY;
1300 page_first_line = line;
1303 /* Recalculate forces for the last page because we know now that is
1304 really the last page. */
1305 space.resize (page_height (first_page_num + page, true));
1306 res.force_.back () = space.force_;
1307 return finalize_spacing_result (configuration, res);
1310 Page_spacing_result
1311 Page_breaking::pack_systems_on_least_pages (vsize configuration, vsize first_page_num)
1313 // TODO: add support for min/max-systems-per-page.
1314 Page_spacing_result res;
1315 vsize page = 0;
1316 vsize page_first_line = 0;
1317 Page_spacing space (page_height (first_page_num, false), this);
1319 cache_line_details (configuration);
1320 for (vsize line = 0; line < cached_line_details_.size (); line++)
1322 Real prev_force = space.force_;
1323 space.append_system (cached_line_details_[line]);
1324 if ((line > page_first_line)
1325 && (isinf (space.force_)
1326 || ((line > 0)
1327 && (cached_line_details_[line-1].page_permission_ == ly_symbol2scm ("force")))))
1329 res.systems_per_page_.push_back (line - page_first_line);
1330 res.force_.push_back (prev_force);
1331 res.penalty_ += cached_line_details_[line-1].page_penalty_;
1332 page++;
1333 space.resize (page_height (first_page_num + page, false));
1334 space.clear ();
1335 space.append_system (cached_line_details_[line]);
1336 page_first_line = line;
1339 if (line == cached_line_details_.size () - 1)
1341 /* This is the last line */
1342 /* When the last page height was computed, we did not know yet that it
1343 * was the last one. If the systems put on it don't fit anymore, the last
1344 * system is moved to a new page */
1345 space.resize (page_height (first_page_num + page, true));
1346 if ((line > page_first_line) && (isinf (space.force_)))
1348 res.systems_per_page_.push_back (line - page_first_line);
1349 res.force_.push_back (prev_force);
1350 /* the last page containing the last line */
1351 space.resize (page_height (first_page_num + page + 1, true));
1352 space.clear ();
1353 space.append_system (cached_line_details_[line]);
1354 res.systems_per_page_.push_back (1);
1355 res.force_.push_back (space.force_);
1356 res.penalty_ += cached_line_details_[line-1].page_penalty_;
1357 res.penalty_ += cached_line_details_[line].page_penalty_;
1359 else
1361 res.systems_per_page_.push_back (line + 1 - page_first_line);
1362 res.force_.push_back (space.force_);
1363 res.penalty_ += cached_line_details_[line].page_penalty_;
1367 return finalize_spacing_result (configuration, res);
1370 /* Calculate demerits and fix res.systems_per_page_ so that
1371 it refers to the original line numbers, not the ones given by compress_lines (). */
1372 Page_spacing_result
1373 Page_breaking::finalize_spacing_result (vsize configuration, Page_spacing_result res)
1375 if (res.force_.empty ())
1376 return res;
1378 cache_line_details (configuration);
1379 res.systems_per_page_ = uncompress_solution (res.systems_per_page_, cached_line_details_);
1381 Real line_force = 0;
1382 Real line_penalty = 0;
1383 Real page_demerits = res.penalty_;
1384 Real page_weighting = robust_scm2double (book_->paper_->c_variable ("page-spacing-weight"), 10);
1386 for (vsize i = 0; i < uncompressed_line_details_.size (); i++)
1388 line_force += uncompressed_line_details_[i].force_ * uncompressed_line_details_[i].force_;
1389 line_penalty += uncompressed_line_details_[i].break_penalty_;
1392 for (vsize i = 0; i < res.force_.size (); i++)
1394 Real f = res.force_[i];
1396 page_demerits += min(f*f, BAD_SPACING_PENALTY);
1399 /* for a while we tried averaging page and line forces across pages instead
1400 of summing them, but it caused a problem: if there is a single page
1401 with a very bad page force (for example because of a forced page break),
1402 the page breaker will put in a _lot_ of pages so that the bad force
1403 becomes averaged out over many pages. */
1404 res.demerits_ = line_force + line_penalty + page_demerits * page_weighting;
1405 return res;
1409 /* the cases for page_count = 1 or 2 can be done in O (n) time. Since they
1410 are by far the most common cases, we have special functions for them.
1412 space_systems_on_1_page has a different calling convention than most of the
1413 space_systems functions. This is because space_systems_on_1_page is (unlike
1414 the other space_systems functions) sometimes called on subsets of a full
1415 configuration. */
1416 Page_spacing_result
1417 Page_breaking::space_systems_on_1_page (vector<Line_details> const &lines, Real page_height, bool ragged)
1419 Page_spacing space (page_height, this);
1420 Page_spacing_result ret;
1421 int line_count = 0;
1423 for (vsize i = 0; i < lines.size (); i++)
1425 space.append_system (lines[i]);
1426 line_count += lines[i].compressed_nontitle_lines_count_;
1429 ret.systems_per_page_.push_back (lines.size ());
1430 ret.force_.push_back (ragged ? min (space.force_, 0.0) : space.force_);
1431 ret.penalty_ = line_count_penalty (line_count) + lines.back ().page_penalty_ + lines.back ().turn_penalty_;
1432 ret.system_count_status_ |= line_count_status (line_count);
1434 /* don't do finalize_spacing_result () because we are only an internal function */
1435 return ret;
1438 Page_spacing_result
1439 Page_breaking::space_systems_on_2_pages (vsize configuration, vsize first_page_num)
1441 Real page1_height = page_height (first_page_num, false);
1442 Real page2_height = page_height (first_page_num + 1, is_last ());
1443 bool ragged1 = ragged ();
1444 bool ragged2 = ragged () || (is_last () && ragged_last ());
1446 /* if there is a forced break, this reduces to 2 1-page problems */
1447 cache_line_details (configuration);
1448 for (vsize i = 0; i + 1 < cached_line_details_.size (); i++)
1449 if (cached_line_details_[i].page_permission_ == ly_symbol2scm ("force"))
1451 vector<Line_details> lines1 (cached_line_details_.begin (), cached_line_details_.begin () + i + 1);
1452 vector<Line_details> lines2 (cached_line_details_.begin () + i + 1, cached_line_details_.end ());
1453 Page_spacing_result p1 = space_systems_on_1_page (lines1, page1_height, ragged1);
1454 Page_spacing_result p2 = space_systems_on_1_page (lines2, page2_height, ragged2);
1456 p1.systems_per_page_.push_back (p2.systems_per_page_[0]);
1457 p1.force_.push_back (p2.force_[0]);
1458 p1.penalty_ += p2.penalty_ - cached_line_details_[i].turn_penalty_;
1459 p1.system_count_status_ |= p2.system_count_status_;
1460 return p1;
1463 vector<Real> page1_force;
1464 vector<Real> page2_force;
1466 // page1_penalty and page2_penalty store the penalties based
1467 // on min-systems-per-page and max-systems-per-page.
1468 vector<Real> page1_penalty;
1469 vector<Real> page2_penalty;
1471 // page1_status and page2_status keep track of whether the min-systems-per-page
1472 // and max-systems-per-page constraints are satisfied.
1473 vector<int> page1_status;
1474 vector<int> page2_status;
1476 Page_spacing page1 (page1_height, this);
1477 Page_spacing page2 (page2_height, this);
1478 int page1_line_count = 0;
1479 int page2_line_count = 0;
1481 page1_force.resize (cached_line_details_.size () - 1, infinity_f);
1482 page2_force.resize (cached_line_details_.size () - 1, infinity_f);
1483 page1_penalty.resize (cached_line_details_.size () - 1, infinity_f);
1484 page2_penalty.resize (cached_line_details_.size () - 1, infinity_f);
1485 page1_status.resize (cached_line_details_.size () - 1, 0);
1486 page2_status.resize (cached_line_details_.size () - 1, 0);
1488 /* find the page 1 and page 2 forces for each page-breaking position */
1489 for (vsize i = 0; i < page1_force.size (); i++)
1491 page1.append_system (cached_line_details_[i]);
1492 page2.prepend_system (cached_line_details_[cached_line_details_.size () - 1 - i]);
1493 page1_line_count += cached_line_details_[i].compressed_nontitle_lines_count_;
1494 page2_line_count += cached_line_details_[cached_line_details_.size () - 1 - i].compressed_nontitle_lines_count_;
1496 page1_force[i] = (ragged1 && page1.force_ < 0 && i > 0) ? infinity_f : page1.force_;
1497 page1_penalty[i] = line_count_penalty (page1_line_count);
1498 page1_status[i] = line_count_status (page1_line_count);
1500 if (ragged2)
1501 page2_force[page2_force.size () - 1 - i] =
1502 (page2.force_ < 0 && i + 1 < page1_force.size ()) ? infinity_f : 0;
1503 else
1504 page2_force[page2_force.size () - 1 - i] = page2.force_;
1505 page2_penalty[page2_penalty.size () - 1 - i] = line_count_penalty (page2_line_count);
1506 page2_status[page2_penalty.size () - 1 - i] = line_count_status (page2_line_count);
1509 /* find the position that minimises the sum of the page forces */
1510 vsize best_sys_count = 1;
1511 Real best_demerits = infinity_f;
1512 for (vsize i = 0; i < page1_force.size (); i++)
1514 Real f = page1_force[i] * page1_force[i] + page2_force[i] * page2_force[i];
1516 // NOTE: we treat max-systems-per-page and min-systems-per-page as soft
1517 // constraints. That is, we penalize harshly when they don't happen
1518 // but we don't completely reject.
1519 Real dem = f
1520 + page1_penalty[i] + page2_penalty[i]
1521 + cached_line_details_[i+1].page_penalty_
1522 + cached_line_details_.back ().page_penalty_ + cached_line_details_.back ().turn_penalty_;
1523 if (dem < best_demerits)
1525 best_demerits = dem;
1526 best_sys_count = i+1;
1530 Page_spacing_result ret;
1531 ret.systems_per_page_.push_back (best_sys_count);
1532 ret.systems_per_page_.push_back (cached_line_details_.size () - best_sys_count);
1533 ret.force_.push_back (page1_force[best_sys_count-1]);
1534 ret.force_.push_back (page2_force[best_sys_count-1]);
1535 ret.system_count_status_ = page1_status[best_sys_count-1] | page2_status[best_sys_count-1];
1536 ret.penalty_ = cached_line_details_[best_sys_count-1].page_penalty_
1537 + cached_line_details_.back ().page_penalty_
1538 + cached_line_details_.back ().turn_penalty_
1539 + page1_penalty[best_sys_count-1] + page2_penalty[best_sys_count-1];
1541 /* don't do finalize_spacing_result () because we are only an internal function */
1542 return ret;
1545 bool
1546 Page_breaking::all_lines_stretched (vsize configuration)
1548 cache_line_details (configuration);
1549 for (vsize i = 0; i < cached_line_details_.size (); i++)
1550 if (cached_line_details_[i].force_ < 0)
1551 return false;
1553 return true;
1556 Page_breaking::Line_division
1557 Page_breaking::current_configuration (vsize configuration_index) const
1559 return current_configurations_[configuration_index];
1562 bool
1563 Page_breaking::is_last () const
1565 return current_end_breakpoint_ == last_break_position ();
1568 bool
1569 Page_breaking::ends_score () const
1571 return breaks_[current_end_breakpoint_].score_ender_;
1574 vsize
1575 Page_breaking::last_break_position () const
1577 return breaks_.size () - 1;
1580 // This gives the minimum distance between the top of the
1581 // printable area (ie. the bottom of the top-margin) and
1582 // the extent box of the topmost system.
1583 Real
1584 Page_breaking::min_whitespace_at_top_of_page (Line_details const &line) const
1586 SCM first_system_spacing = book_->paper_->c_variable ("top-system-spacing");
1587 if (line.title_)
1588 first_system_spacing = book_->paper_->c_variable ("top-markup-spacing");
1590 Real min_distance = -infinity_f;
1591 Real padding = 0;
1593 Page_layout_problem::read_spacing_spec (first_system_spacing,
1594 &min_distance,
1595 ly_symbol2scm ("minimum-distance"));
1596 Page_layout_problem::read_spacing_spec (first_system_spacing,
1597 &padding,
1598 ly_symbol2scm ("padding"));
1600 // FIXME: take into account the height of the header
1601 Real translate = max (line.shape_.begin_[UP], line.shape_.rest_[UP]);
1602 return max (0.0, max (padding, min_distance - translate));
1605 Real
1606 Page_breaking::min_whitespace_at_bottom_of_page (Line_details const &line) const
1608 SCM last_system_spacing = book_->paper_->c_variable ("last-bottom-spacing");
1609 Real min_distance = -infinity_f;
1610 Real padding = 0;
1612 Page_layout_problem::read_spacing_spec (last_system_spacing,
1613 &min_distance,
1614 ly_symbol2scm ("minimum-distance"));
1615 Page_layout_problem::read_spacing_spec (last_system_spacing,
1616 &padding,
1617 ly_symbol2scm ("padding"));
1619 // FIXME: take into account the height of the footer
1620 Real translate = min (line.shape_.begin_[DOWN], line.shape_.rest_[DOWN]);
1621 return max (0.0, max (padding, min_distance + translate));
1625 Page_breaking::orphan_penalty () const
1627 return orphan_penalty_;