2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 2006--2010 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.
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
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).
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.
76 #include "page-breaking.hh"
78 #include "international.hh"
80 #include "output-def.hh"
81 #include "page-layout-problem.hh"
82 #include "page-spacing.hh"
83 #include "paper-book.hh"
84 #include "paper-score.hh"
85 #include "paper-system.hh"
89 /* for each forbidden page break, merge the systems around it into one
91 static vector<Line_details>
92 compress_lines (const vector<Line_details> &orig)
94 vector<Line_details> ret;
96 for (vsize i = 0; i < orig.size (); i++)
98 if (ret.size () && !scm_is_symbol (ret.back ().page_permission_))
100 Line_details const &old = ret.back ();
101 Line_details compressed = orig[i];
103 We must account for the padding between the lines that we are compressing.
104 The padding values come from "old," which is the upper system here. Note
105 the meaning of tight-spacing: if a system has tight-spacing, then the padding
106 _before_ it is ignored.
109 if (!orig[i].tight_spacing_)
110 padding = orig[i].title_ ? old.title_padding_ : old.padding_;
112 // FIXME: double check these. Doesn't foo.piggyback (bar) mean
113 // that foo goes on top?
114 // TODO: break out a Line_details::piggyback from here?
115 compressed.shape_ = old.shape_.piggyback (orig[i].shape_, padding);
116 compressed.refpoint_extent_[UP] = old.refpoint_extent_[UP];
117 compressed.refpoint_extent_[DOWN] += compressed.shape_.rest_[UP] - old.shape_.rest_[UP];
118 compressed.space_ += old.space_;
119 compressed.inverse_hooke_ += old.inverse_hooke_;
121 compressed.compressed_lines_count_ = old.compressed_lines_count_ + 1;
122 compressed.compressed_nontitle_lines_count_ =
123 old.compressed_nontitle_lines_count_ + (compressed.title_ ? 0 : 1);
125 // compressed.title_ is true if and only if the first of its
126 // compressed lines was a title.
127 compressed.title_ = old.title_;
128 ret.back () = compressed;
132 ret.push_back (orig[i]);
133 ret.back ().force_ = 0;
139 /* translate the number of systems-per-page into something meaningful for
140 the uncompressed lines.
143 uncompress_solution (vector<vsize> const &systems_per_page,
144 vector<Line_details> const &compressed)
149 for (vsize i = 0; i < systems_per_page.size (); i++)
151 int compressed_count = 0;
152 for (vsize j = start_sys; j < start_sys + systems_per_page[i]; j++)
153 compressed_count += compressed[j].compressed_lines_count_ - 1;
155 ret.push_back (systems_per_page[i] + compressed_count);
156 start_sys += systems_per_page[i];
161 /* for Page_breaking, the start index (when we are dealing with the stuff
162 between a pair of breakpoints) refers to the break_ index of the end of
163 the previous page. So the system index of the start of the current page
164 could either be the same as the end of the previous page or one more than
167 /* Turn a break index into the sys index that starts the next page */
169 Page_breaking::next_system (Break_position const &break_pos) const
171 vsize sys = break_pos.system_spec_index_;
173 if (sys == VPOS) /* beginning of the book */
175 if (system_specs_[sys].pscore_ && !break_pos.score_ender_)
176 return sys; /* the score overflows the previous page */
177 return sys + 1; /* this page starts with a new System_spec */
180 Page_breaking::Page_breaking (Paper_book *pb, Break_predicate is_break, Prob_break_predicate prob_break)
184 paper_height_ = robust_scm2double (pb->paper_->c_variable ("paper-height"), 1.0);
185 ragged_ = to_boolean (pb->paper_->c_variable ("ragged-bottom"));
186 ragged_last_ = to_boolean (pb->paper_->c_variable ("ragged-last-bottom"));
187 systems_per_page_ = max (0, robust_scm2int (pb->paper_->c_variable ("systems-per-page"), 0));
188 max_systems_per_page_ = max (0, robust_scm2int (pb->paper_->c_variable ("max-systems-per-page"), 0));
189 min_systems_per_page_ = max (0, robust_scm2int (pb->paper_->c_variable ("min-systems-per-page"), 0));
190 orphan_penalty_ = robust_scm2int (pb->paper_->c_variable ("orphan-penalty"), 100000);
192 if (systems_per_page_ && (max_systems_per_page_ || min_systems_per_page_))
194 warning (_f ("ignoring min-systems-per-page and max-systems-per-page because systems-per-page was set"));
195 min_systems_per_page_ = max_systems_per_page_ = 0;
197 if (max_systems_per_page_ && min_systems_per_page_ > max_systems_per_page_)
199 warning (_f ("min-systems-per-page is larger than max-systems-per-page, ignoring both values"));
200 min_systems_per_page_ = max_systems_per_page_ = 0;
203 create_system_list ();
204 find_chunks_and_breaks (is_break, prob_break);
207 Page_breaking::~Page_breaking ()
212 Page_breaking::ragged () const
218 Page_breaking::ragged_last () const
224 Page_breaking::systems_per_page () const
226 return systems_per_page_;
230 Page_breaking::max_systems_per_page () const
232 return max_systems_per_page_;
236 Page_breaking::min_systems_per_page () const
238 return min_systems_per_page_;
242 Page_breaking::system_count () const
244 return system_count_;
248 Page_breaking::too_many_lines (int line_count) const
250 return max_systems_per_page () > 0 && line_count > max_systems_per_page ();
254 Page_breaking::too_few_lines (int line_count) const
256 return line_count < min_systems_per_page ();
260 Page_breaking::line_count_penalty (int line_count) const
262 if (too_many_lines (line_count))
263 return (line_count - max_systems_per_page ()) * TERRIBLE_SPACING_PENALTY;
264 if (too_few_lines (line_count))
265 return (min_systems_per_page () - line_count) * TERRIBLE_SPACING_PENALTY;
271 Page_breaking::line_count_status (int line_count) const
273 if (too_many_lines (line_count))
274 return SYSTEM_COUNT_TOO_MANY;
275 if (too_few_lines (line_count))
276 return SYSTEM_COUNT_TOO_FEW;
278 return SYSTEM_COUNT_OK;
281 /* translate indices into breaks_ into start-end parameters for the line breaker */
283 Page_breaking::line_breaker_args (vsize sys,
284 Break_position const &start,
285 Break_position const &end,
286 vsize *line_breaker_start,
287 vsize *line_breaker_end)
289 assert (system_specs_[sys].pscore_);
290 assert (next_system (start) <= sys && sys <= end.system_spec_index_);
292 if (start.system_spec_index_ == sys)
293 *line_breaker_start = start.score_break_;
295 *line_breaker_start = 0;
297 if (end.system_spec_index_ == sys)
298 *line_breaker_end = end.score_break_;
300 *line_breaker_end = VPOS;
304 Page_breaking::break_into_pieces (vsize start_break, vsize end_break,
305 Line_division const &div)
307 vector<Break_position> chunks = chunk_list (start_break, end_break);
308 bool ignore_div = false;
309 if (chunks.size () != div.size () + 1)
311 programming_error ("did not find a valid page breaking configuration");
315 for (vsize i = 0; i + 1 < chunks.size (); i++)
317 vsize sys = next_system (chunks[i]);
318 if (system_specs_[sys].pscore_)
322 line_breaker_args (sys, chunks[i], chunks[i+1], &start, &end);
324 vector<Column_x_positions> pos = ignore_div
325 ? line_breaking_[sys].best_solution (start, end)
326 : line_breaking_[sys].solve (start, end, div[i]);
327 system_specs_[sys].pscore_->root_system ()->break_into_pieces (pos);
333 Page_breaking::systems ()
336 for (vsize sys = 0; sys < system_specs_.size (); sys++)
338 if (system_specs_[sys].pscore_)
340 system_specs_[sys].pscore_->root_system ()
341 ->do_break_substitution_and_fixup_refpoints ();
342 SCM lines = system_specs_[sys].pscore_->root_system ()
343 ->get_broken_system_grobs ();
344 ret = scm_cons (lines, ret);
346 else if (Prob *pb = system_specs_[sys].prob_)
348 ret = scm_cons (scm_list_1 (pb->self_scm ()), ret);
352 return scm_append (scm_reverse (ret));
356 Page_breaking::make_page (int page_num, bool last) const
358 bool last_part = ly_scm2bool (book_->paper_->c_variable ("is-last-bookpart"));
359 SCM mod = scm_c_resolve_module ("scm page");
360 SCM make_page_scm = scm_c_module_lookup (mod, "make-page");
362 make_page_scm = scm_variable_ref (make_page_scm);
364 return scm_apply_0 (make_page_scm,
365 scm_list_n (book_->self_scm (),
366 ly_symbol2scm ("page-number"), scm_from_int (page_num),
367 ly_symbol2scm ("is-last-bookpart"), scm_from_bool (last_part),
368 ly_symbol2scm ("is-bookpart-last-page"), scm_from_bool (last),
372 // Returns the total height of the paper, including margins and
373 // space for the header/footer. This is an upper bound on
374 // page_height, and it doesn't depend on the current page.
376 Page_breaking::paper_height () const
378 return paper_height_;
382 Page_breaking::page_height (int page_num, bool last) const
384 // The caches allow us to store the page heights for any
385 // non-negative page numbers. We use a negative value in the
386 // cache to signal that that position has not yet been initialized.
387 // This means that we won't cache properly if page_num is negative or
388 // if calc_height returns a negative number. But that's likely to
389 // be rare, so it shouldn't affect performance.
390 vector<Real>& cache = last ? last_page_height_cache_ : page_height_cache_;
391 if (page_num >= 0 && (int) cache.size () > page_num && cache[page_num] >= 0)
392 return cache[page_num];
395 SCM mod = scm_c_resolve_module ("scm page");
396 SCM page = make_page (page_num, last);
397 SCM calc_height = scm_c_module_lookup (mod, "calc-printable-height");
398 calc_height = scm_variable_ref (calc_height);
400 SCM height_scm = scm_apply_1 (calc_height, page, SCM_EOL);
401 Real height = scm_to_double (height_scm);
405 if ((int) cache.size () <= page_num)
406 cache.resize (page_num + 1, -1);
407 cache[page_num] = height;
414 Page_breaking::breakpoint_property (vsize breakpoint, char const *str)
416 Break_position const &pos = breaks_[breakpoint];
418 if (pos.system_spec_index_ == VPOS)
420 if (system_specs_[pos.system_spec_index_].pscore_)
421 return pos.col_->get_property (str);
422 return system_specs_[pos.system_spec_index_].prob_->get_property (str);
426 Page_breaking::get_page_configuration (SCM systems, int page_num, bool ragged, bool last)
428 SCM dummy_page = make_page (page_num, last);
429 Page_layout_problem layout (book_, dummy_page, systems);
430 return scm_is_pair (systems) ? layout.solution (ragged) : SCM_EOL;
434 Page_breaking::draw_page (SCM systems, SCM configuration, int page_num, bool last)
436 // Create a stencil for each system.
437 SCM paper_systems = SCM_EOL;
438 for (SCM s = scm_reverse (systems); scm_is_pair (s); s = scm_cdr (s))
440 SCM paper_system = scm_car (s);
441 if (Grob *g = unsmob_grob (scm_car (s)))
443 System *sys = dynamic_cast<System*> (g);
444 paper_system = sys->get_paper_system ();
447 paper_systems = scm_cons (paper_system, paper_systems);
450 // Create the page and draw it.
451 SCM page = make_page (page_num, last);
452 SCM page_module = scm_c_resolve_module ("scm page");
453 SCM page_stencil = scm_c_module_lookup (page_module, "page-stencil");
454 page_stencil = scm_variable_ref (page_stencil);
456 Prob *p = unsmob_prob (page);
457 p->set_property ("lines", paper_systems);
458 p->set_property ("configuration", configuration);
459 scm_apply_1 (page_stencil, page, SCM_EOL);
465 Page_breaking::make_pages (vector<vsize> lines_per_page, SCM systems)
467 if (scm_is_null (systems))
470 int first_page_number
471 = robust_scm2int (book_->paper_->c_variable ("first-page-number"), 1);
473 SCM label_page_table = book_->top_paper ()->c_variable ("label-page-table");
474 if (label_page_table == SCM_UNDEFINED)
475 label_page_table = SCM_EOL;
477 // Build a list of (systems . configuration) pairs. Note that we lay out
478 // the staves and find the configurations before drawing anything. Some
479 // grobs (like tuplet brackets) look at their neighbours while drawing
480 // themselves. If this happens before the neighbouring staves have
481 // been laid out, bad side-effects could happen (in particular,
482 // Align_interface::align_to_ideal_distances might be called).
483 SCM systems_and_configs = SCM_EOL;
485 for (vsize i = 0; i < lines_per_page.size (); i++)
487 int page_num = i + first_page_number;
488 bool bookpart_last_page = (i == lines_per_page.size () - 1);
489 bool rag = ragged () || (bookpart_last_page && ragged_last ());
490 SCM line_count = scm_from_int (lines_per_page[i]);
491 SCM lines = scm_list_head (systems, line_count);
492 SCM config = get_page_configuration (lines, page_num, rag, bookpart_last_page);
494 systems_and_configs = scm_cons (scm_cons (lines, config), systems_and_configs);
495 systems = scm_list_tail (systems, line_count);
498 // Now it's safe to make the pages.
499 int page_num = first_page_number + lines_per_page.size () - 1;
500 for (SCM s = systems_and_configs; scm_is_pair (s); s = scm_cdr (s))
502 SCM lines = scm_caar (s);
503 SCM config = scm_cdar (s);
504 bool bookpart_last_page = (s == systems_and_configs);
505 SCM page = draw_page (lines, config, page_num, bookpart_last_page);
508 SCM page_num_scm = scm_from_int (page_num);
509 for (SCM l = lines ; scm_is_pair (l) ; l = scm_cdr (l))
511 SCM labels = SCM_EOL;
512 if (Grob * line = unsmob_grob (scm_car (l)))
514 System *system = dynamic_cast<System*> (line);
515 labels = system->get_property ("labels");
517 else if (Prob *prob = unsmob_prob (scm_car (l)))
518 labels = prob->get_property ("labels");
520 for (SCM lbls = labels ; scm_is_pair (lbls) ; lbls = scm_cdr (lbls))
521 label_page_table = scm_cons (scm_cons (scm_car (lbls), page_num_scm),
525 ret = scm_cons (page, ret);
528 book_->top_paper ()->set_variable (ly_symbol2scm ("label-page-table"), label_page_table);
532 /* The page-turn-page-breaker needs to have a line-breaker between any two
533 columns with non-NULL page-turn-permission.
535 The optimal-breaker needs to have a line-breaker between any two columns
536 with page-break-permission = 'force.
538 By using a grob predicate, we can accommodate both of these uses.
541 Page_breaking::create_system_list ()
543 SCM specs = book_->get_system_specs ();
544 for (SCM s = specs; scm_is_pair (s); s = scm_cdr (s))
546 if (Paper_score *ps = dynamic_cast<Paper_score*> (unsmob_music_output (scm_car (s))))
548 system_specs_.push_back (System_spec (ps));
552 Prob *pb = unsmob_prob (scm_car (s));
556 system_specs_.push_back (System_spec (pb));
559 if (!system_specs_.size ())
560 system_specs_.push_back (System_spec ());
564 Page_breaking::find_chunks_and_breaks (Break_predicate is_break, Prob_break_predicate prob_is_break)
566 SCM force_sym = ly_symbol2scm ("force");
568 chunks_.push_back (Break_position ());
569 breaks_.push_back (Break_position ());
571 for (vsize i = 0; i < system_specs_.size (); i++)
573 if (system_specs_[i].pscore_)
575 vector<Grob*> cols = system_specs_[i].pscore_->root_system ()->used_columns ();
576 vector<Grob*> forced_line_break_cols;
578 SCM system_count = system_specs_[i].pscore_->layout ()->c_variable ("system-count");
579 if (scm_is_number (system_count))
581 // With system-count given, the line configuration for
582 // this score is fixed. We need to ensure that chunk
583 // boundaries only occur at line breaks.
584 Constrained_breaking breaking (system_specs_[i].pscore_);
585 vector<Line_details> details = breaking.line_details (0, VPOS, scm_to_int (system_count));
587 for (vsize j = 0; j < details.size (); j++)
588 forced_line_break_cols.push_back (details[j].last_column_);
591 int last_forced_line_break_idx = 0;
592 vsize forced_line_break_idx = 0;
593 vector<vsize> line_breaker_columns;
594 line_breaker_columns.push_back (0);
596 for (vsize j = 1; j < cols.size (); j++)
598 if (forced_line_break_cols.size ())
600 if (forced_line_break_idx >= forced_line_break_cols.size ()
601 || forced_line_break_cols[forced_line_break_idx] != cols[j])
604 forced_line_break_idx++;
607 bool last = (j == cols.size () - 1);
608 bool break_point = is_break && is_break (cols[j]);
609 bool chunk_end = cols[j]->get_property ("page-break-permission") == force_sym;
610 Break_position cur_pos = Break_position (i,
611 line_breaker_columns.size (),
615 // NOTE: even in the breaks_ list, forced_line_count_
616 // refers to the number of lines between a
617 // Break_position and the start of that /chunk/. This
618 // is needed for system_count_bounds to work correctly,
619 // since it mixes Break_positions from breaks_ and
621 if (scm_is_number (system_count))
622 cur_pos.forced_line_count_ = forced_line_break_idx - last_forced_line_break_idx;
624 if (break_point || (i == system_specs_.size () - 1 && last))
625 breaks_.push_back (cur_pos);
626 if (chunk_end || last)
628 chunks_.push_back (cur_pos);
629 last_forced_line_break_idx = forced_line_break_idx;
632 if ((break_point || chunk_end) && !last)
633 line_breaker_columns.push_back (j);
635 line_breaking_.push_back (Constrained_breaking (system_specs_[i].pscore_, line_breaker_columns));
637 else if (system_specs_[i].prob_)
639 bool break_point = prob_is_break && prob_is_break (system_specs_[i].prob_);
640 if (break_point || i == system_specs_.size () - 1)
641 breaks_.push_back (Break_position (i));
643 chunks_.push_back (Break_position (i));
645 /* FIXME: shouldn't we push a Null_breaker or similar dummy
647 line_breaking_.push_back (Constrained_breaking (NULL));
652 vector<Break_position>
653 Page_breaking::chunk_list (vsize start_index, vsize end_index)
655 Break_position start = breaks_[start_index];
656 Break_position end = breaks_[end_index];
659 for (; i < chunks_.size () && chunks_[i] <= start; i++)
662 vector<Break_position> ret;
663 ret.push_back (start);
664 for (; i < chunks_.size () && chunks_[i] < end; i++)
665 ret.push_back (chunks_[i]);
671 Page_breaking::min_system_count (vsize start, vsize end)
673 vector<Break_position> chunks = chunk_list (start, end);
674 Line_division div = system_count_bounds (chunks, true);
677 for (vsize i = 0; i < div.size (); i++)
683 Page_breaking::max_system_count (vsize start, vsize end)
685 vector<Break_position> chunks = chunk_list (start, end);
686 Line_division div = system_count_bounds (chunks, false);
689 for (vsize i = 0; i < div.size (); i++)
694 Page_breaking::Line_division
695 Page_breaking::system_count_bounds (vector<Break_position> const &chunks,
698 assert (chunks.size () >= 2);
701 ret.resize (chunks.size () - 1, 1);
703 for (vsize i = 0; i + 1 < chunks.size (); i++)
705 vsize sys = next_system (chunks[i]);
707 if (chunks[i+1].forced_line_count_)
708 ret[i] = chunks[i+1].forced_line_count_;
709 else if (system_specs_[sys].pscore_)
713 line_breaker_args (sys, chunks[i], chunks[i+1], &start, &end);
715 ? line_breaking_[sys].min_system_count (start, end)
716 : line_breaking_[sys].max_system_count (start, end);
724 Page_breaking::set_current_breakpoints (vsize start,
727 Line_division lower_bound,
728 Line_division upper_bound)
730 system_count_ = system_count;
731 current_chunks_ = chunk_list (start, end);
732 current_start_breakpoint_ = start;
733 current_end_breakpoint_ = end;
734 clear_line_details_cache ();
736 if (!lower_bound.size ())
737 lower_bound = system_count_bounds (current_chunks_, true);
738 if (!upper_bound.size ())
739 upper_bound = system_count_bounds (current_chunks_, false);
741 assert (lower_bound.size () == current_chunks_.size () - 1);
742 assert (upper_bound.size () == current_chunks_.size () - 1);
744 Line_division work_in_progress;
745 current_configurations_.clear ();
746 line_divisions_rec (system_count,
751 /* we only consider a constant number of configurations. Otherwise,
752 this becomes slow when there are many small scores. The constant
753 5 is somewhat arbitrary. */
754 if (current_configurations_.size () > 5)
756 vector<pair<Real,vsize> > dems_and_indices;
758 for (vsize i = 0; i < current_configurations_.size (); i++)
760 cache_line_details (i);
762 for (vsize j = 0; j < cached_line_details_.size (); j++)
763 dem += cached_line_details_[j].force_ * cached_line_details_[j].force_
764 + cached_line_details_[j].break_penalty_;
766 dems_and_indices.push_back (pair<Real,vsize> (dem, i));
768 vector_sort (dems_and_indices, less<pair<Real,vsize> > ());
770 vector<Line_division> best_5_configurations;
771 for (vsize i = 0; i < 5; i++)
772 best_5_configurations.push_back (current_configurations_[dems_and_indices[i].second]);
774 clear_line_details_cache ();
775 current_configurations_ = best_5_configurations;
780 Page_breaking::set_to_ideal_line_configuration (vsize start, vsize end)
782 current_chunks_ = chunk_list (start, end);
783 current_start_breakpoint_ = start;
784 current_end_breakpoint_ = end;
785 clear_line_details_cache ();
789 for (vsize i = 0; i+1 < current_chunks_.size (); i++)
791 vsize sys = next_system (current_chunks_[i]);
793 if (current_chunks_[i+1].forced_line_count_)
794 div.push_back (current_chunks_[i+1].forced_line_count_);
795 else if (system_specs_[sys].pscore_)
797 line_breaker_args (sys, current_chunks_[i], current_chunks_[i+1], &start, &end);
798 div.push_back (line_breaking_[sys].best_solution (start, end).size ());
803 system_count_ += div.back ();
805 current_configurations_.clear ();
806 current_configurations_.push_back (div);
810 Page_breaking::current_configuration_count () const
812 return current_configurations_.size ();
816 Page_breaking::cache_line_details (vsize configuration_index)
818 if (cached_configuration_index_ != configuration_index)
820 cached_configuration_index_ = configuration_index;
822 Line_division &div = current_configurations_[configuration_index];
823 uncompressed_line_details_.clear ();
824 for (vsize i = 0; i + 1 < current_chunks_.size (); i++)
826 vsize sys = next_system (current_chunks_[i]);
827 if (system_specs_[sys].pscore_)
831 line_breaker_args (sys, current_chunks_[i], current_chunks_[i+1], &start, &end);
833 vector<Line_details> details = line_breaking_[sys].line_details (start, end, div[i]);
834 uncompressed_line_details_.insert (uncompressed_line_details_.end (), details.begin (), details.end ());
838 assert (div[i] == 1);
839 uncompressed_line_details_.push_back (system_specs_[sys].prob_
840 ? Line_details (system_specs_[sys].prob_, book_->paper_)
844 cached_line_details_ = compress_lines (uncompressed_line_details_);
845 compute_line_heights ();
850 Page_breaking::clear_line_details_cache ()
852 cached_configuration_index_ = VPOS;
853 cached_line_details_.clear ();
854 uncompressed_line_details_.clear ();
858 Page_breaking::line_divisions_rec (vsize system_count,
859 Line_division const &min_sys,
860 Line_division const &max_sys,
861 Line_division *cur_division)
863 vsize my_index = cur_division->size ();
867 for (vsize i = my_index + 1; i < min_sys.size (); i++)
869 others_min += min_sys[i];
870 others_max += max_sys[i];
872 others_max = min (others_max, (int) system_count);
873 int real_min = max ((int) min_sys[my_index], (int) system_count - others_max);
874 int real_max = min ((int) max_sys[my_index], (int) system_count - others_min);
876 if (real_min > real_max || real_min <= 0)
878 /* this should never happen within a recursive call. If it happens
879 at all, it means that we were called with an unsolvable problem
880 and we should return an empty result */
881 assert (my_index == 0);
885 for (int i = real_min; i <= real_max; i++)
887 cur_division->push_back (i);
888 if (my_index == min_sys.size () - 1)
889 current_configurations_.push_back (*cur_division);
891 line_divisions_rec (system_count - i, min_sys, max_sys, cur_division);
892 cur_division->pop_back ();
897 Page_breaking::compute_line_heights ()
899 Real prev_hanging = 0;
900 Real prev_hanging_begin = 0;
901 Real prev_hanging_rest = 0;
903 // refpoint_hanging is the y coordinate of the origin of this system.
904 // It may not be the same as refpoint_extent[UP], which is the
905 // refpoint of the first spaceable staff in this system.
906 Real prev_refpoint_hanging = 0;
907 for (vsize i = 0; i < cached_line_details_.size (); i++)
909 Line_details& cur = cached_line_details_[i];
910 Line_shape shape = cur.shape_;
911 Real a = shape.begin_[UP];
912 Real b = shape.rest_[UP];
913 bool title = cur.title_;
914 Real refpoint_hanging = max (prev_hanging_begin + a, prev_hanging_rest + b);
919 Line_details const& prev = cached_line_details_[i-1];
920 if (!cur.tight_spacing_)
922 ? prev.title_padding_
924 Real min_dist = title
925 ? prev.title_min_distance_
926 : prev.min_distance_;
927 refpoint_hanging = max (refpoint_hanging + padding,
928 prev_refpoint_hanging - prev.refpoint_extent_[DOWN]
929 + cur.refpoint_extent_[UP] + min_dist);
932 Real hanging_begin = refpoint_hanging - shape.begin_[DOWN];
933 Real hanging_rest = refpoint_hanging - shape.rest_[DOWN];
934 Real hanging = max (hanging_begin, hanging_rest);
935 cur.tallness_ = hanging - prev_hanging;
936 prev_hanging = hanging;
937 prev_hanging_begin = hanging_begin;
938 prev_hanging_rest = hanging_rest;
939 prev_refpoint_hanging = refpoint_hanging;
944 Page_breaking::min_page_count (vsize configuration, vsize first_page_num)
947 vsize page_starter = 0;
948 Real cur_rod_height = 0;
949 Real cur_spring_height = 0;
950 Real cur_page_height = page_height (first_page_num, false);
953 cache_line_details (configuration);
955 if (cached_line_details_.size ())
956 cur_page_height -= min_whitespace_at_top_of_page (cached_line_details_[0]);
958 for (vsize i = 0; i < cached_line_details_.size (); i++)
961 if (cur_rod_height > 0)
962 ext_len = cached_line_details_[i].tallness_;
964 ext_len = cached_line_details_[i].full_height();
966 Real next_rod_height = cur_rod_height + ext_len;
967 Real next_spring_height = cur_spring_height + cached_line_details_[i].space_;
968 Real next_height = next_rod_height + (ragged () ? next_spring_height : 0)
969 + min_whitespace_at_bottom_of_page (cached_line_details_[i]);
970 int next_line_count = line_count + cached_line_details_[i].compressed_nontitle_lines_count_;
972 if ((!too_few_lines (line_count) && (next_height > cur_page_height && cur_rod_height > 0))
973 || too_many_lines (next_line_count)
975 && cached_line_details_[i-1].page_permission_ == ly_symbol2scm ("force")))
977 line_count = cached_line_details_[i].compressed_nontitle_lines_count_;
978 cur_rod_height = cached_line_details_[i].full_height();
979 cur_spring_height = cached_line_details_[i].space_;
982 cur_page_height = page_height (first_page_num + ret, false);
983 cur_page_height -= min_whitespace_at_top_of_page (cached_line_details_[i]);
989 cur_rod_height = next_rod_height;
990 cur_spring_height = next_spring_height;
991 line_count = next_line_count;
995 /* there are two potential problems with the last page (because we didn't know
996 it was the last page until after we managed to fit all the systems to it):
997 - we are ragged-last but the last page has a compressed spring
998 - the value returned by page_height (num, true) is smaller than the
999 value returned by page_height (num, false) and it causes the page not to
1002 In either case, we just need to add one more page. This is because the last
1003 line will always fit on the extra page and by adding one more page to the
1004 end, the previous page is no longer the last page, so our previous
1005 calculations that treated it as a non-last page were ok.
1010 cur_page_height = page_height (first_page_num + ret - 1, true);
1011 cur_page_height -= min_whitespace_at_top_of_page (cached_line_details_[page_starter]);
1012 cur_page_height -= min_whitespace_at_bottom_of_page (cached_line_details_.back ());
1014 Real cur_height = cur_rod_height + ((ragged_last () || ragged ()) ? cur_spring_height : 0);
1015 if (!too_few_lines (line_count - cached_line_details_.back ().compressed_nontitle_lines_count_)
1016 && cur_height > cur_page_height
1017 /* don't increase the page count if the last page had only one system */
1018 && cur_rod_height > cached_line_details_.back ().full_height ())
1020 assert (ret <= cached_line_details_.size ());
1026 // If systems_per_page_ is positive, we don't really try to space on N pages;
1027 // we just put the requested number of systems on each page and penalize
1028 // if the result doesn't have N pages.
1030 Page_breaking::space_systems_on_n_pages (vsize configuration, vsize n, vsize first_page_num)
1032 Page_spacing_result ret;
1034 if (systems_per_page_ > 0)
1036 Page_spacing_result ret = space_systems_with_fixed_number_per_page (configuration, first_page_num);
1037 ret.demerits_ += (ret.force_.size () == n) ? 0 : BAD_SPACING_PENALTY;
1041 cache_line_details (configuration);
1042 bool valid_n = (n >= min_page_count (configuration, first_page_num)
1043 && n <= cached_line_details_.size ());
1046 programming_error ("number of pages is out of bounds");
1048 if (n == 1 && valid_n)
1049 ret = space_systems_on_1_page (cached_line_details_,
1050 page_height (first_page_num, is_last ()),
1051 ragged () || (is_last () && ragged_last ()));
1052 else if (n == 2 && valid_n)
1053 ret = space_systems_on_2_pages (configuration, first_page_num);
1056 Page_spacer ps (cached_line_details_, first_page_num, this);
1060 return finalize_spacing_result (configuration, ret);
1064 Page_breaking::blank_page_penalty () const
1069 penalty_sym = ly_symbol2scm ("blank-last-page-force");
1070 else if (ends_score ())
1071 penalty_sym = ly_symbol2scm ("blank-after-score-page-force");
1073 penalty_sym = ly_symbol2scm ("blank-page-force");
1075 Break_position const &pos = breaks_[current_end_breakpoint_];
1076 if (Paper_score *ps = system_specs_[pos.system_spec_index_].pscore_)
1077 return robust_scm2double (ps->layout ()->lookup_variable (penalty_sym), 0.0);
1079 return robust_scm2double (book_->paper_->lookup_variable (penalty_sym), 0.0);
1082 // If systems_per_page_ is positive, we don't really try to space on N
1083 // or N+1 pages; see the comment to space_systems_on_n_pages.
1085 Page_breaking::space_systems_on_n_or_one_more_pages (vsize configuration, vsize n, vsize first_page_num,
1086 Real penalty_for_fewer_pages)
1088 Page_spacing_result n_res;
1089 Page_spacing_result m_res;
1091 if (systems_per_page_ > 0)
1093 Page_spacing_result ret = space_systems_with_fixed_number_per_page (configuration, first_page_num);
1094 ret.demerits_ += (ret.force_.size () == n || ret.force_.size () == (n-1)) ? 0 : BAD_SPACING_PENALTY;
1098 cache_line_details (configuration);
1099 vsize min_p_count = min_page_count (configuration, first_page_num);
1100 bool valid_n = n >= min_p_count || n <= cached_line_details_.size ();
1103 programming_error ("both page counts are out of bounds");
1105 if (n == 1 && valid_n)
1107 bool rag = ragged () || (is_last () && ragged_last ());
1108 Real height = page_height (first_page_num, is_last ());
1110 if (1 >= min_p_count)
1111 n_res = space_systems_on_1_page (cached_line_details_, height, rag);
1112 if (1 < cached_line_details_.size ())
1113 m_res = space_systems_on_2_pages (configuration, first_page_num);
1117 Page_spacer ps (cached_line_details_, first_page_num, this);
1119 if (n >= min_p_count || !valid_n)
1120 n_res = ps.solve (n);
1121 if (n < cached_line_details_.size () || !valid_n)
1122 m_res = ps.solve (n+1);
1125 m_res = finalize_spacing_result (configuration, m_res);
1126 n_res = finalize_spacing_result (configuration, n_res);
1128 Real page_spacing_weight = robust_scm2double (book_->paper_->c_variable ("page-spacing-weight"), 10);
1129 n_res.demerits_ += penalty_for_fewer_pages * page_spacing_weight;
1131 if (n_res.force_.size ())
1132 n_res.force_.back () += penalty_for_fewer_pages;
1134 return (m_res.demerits_ < n_res.demerits_) ? m_res : n_res;
1138 Page_breaking::space_systems_on_best_pages (vsize configuration, vsize first_page_num)
1140 if (systems_per_page_ > 0)
1141 return space_systems_with_fixed_number_per_page (configuration, first_page_num);
1143 cache_line_details (configuration);
1144 Page_spacer ps (cached_line_details_, first_page_num, this);
1146 return finalize_spacing_result (configuration, ps.solve ());
1150 Page_breaking::space_systems_with_fixed_number_per_page (vsize configuration,
1151 vsize first_page_num)
1153 Page_spacing_result res;
1154 Page_spacing space (page_height (first_page_num, false), this);
1157 vsize page_first_line = 0;
1159 cache_line_details (configuration);
1160 while (line < cached_line_details_.size ())
1164 space.resize (page_height (first_page_num + page, false));
1166 int system_count_on_this_page = 0;
1167 while (system_count_on_this_page < systems_per_page_
1168 && line < cached_line_details_.size ())
1170 Line_details const &cur_line = cached_line_details_[line];
1171 space.append_system (cur_line);
1172 system_count_on_this_page += cur_line.compressed_nontitle_lines_count_;
1175 if (cur_line.page_permission_ == ly_symbol2scm ("force"))
1179 res.systems_per_page_.push_back (line - page_first_line);
1181 res.force_.push_back (space.force_);
1182 res.penalty_ += cached_line_details_[line-1].page_penalty_;
1183 if (system_count_on_this_page != systems_per_page_)
1185 res.penalty_ += TERRIBLE_SPACING_PENALTY;
1186 res.system_count_status_ |= ((system_count_on_this_page < systems_per_page_))
1187 ? SYSTEM_COUNT_TOO_FEW : SYSTEM_COUNT_TOO_MANY;
1190 page_first_line = line;
1193 /* Recalculate forces for the last page because we know now that is
1194 really the last page. */
1195 space.resize (page_height (first_page_num + page, true));
1196 res.force_.back () = space.force_;
1197 return finalize_spacing_result (configuration, res);
1201 Page_breaking::pack_systems_on_least_pages (vsize configuration, vsize first_page_num)
1203 // TODO: add support for min/max-systems-per-page.
1204 Page_spacing_result res;
1206 vsize page_first_line = 0;
1207 Page_spacing space (page_height (first_page_num, false), this);
1209 cache_line_details (configuration);
1210 for (vsize line = 0; line < cached_line_details_.size (); line++)
1212 Real prev_force = space.force_;
1213 space.append_system (cached_line_details_[line]);
1214 if ((line > page_first_line)
1215 && (isinf (space.force_)
1217 && (cached_line_details_[line-1].page_permission_ == ly_symbol2scm ("force")))))
1219 res.systems_per_page_.push_back (line - page_first_line);
1220 res.force_.push_back (prev_force);
1221 res.penalty_ += cached_line_details_[line-1].page_penalty_;
1223 space.resize (page_height (first_page_num + page, false));
1225 space.append_system (cached_line_details_[line]);
1226 page_first_line = line;
1229 if (line == cached_line_details_.size () - 1)
1231 /* This is the last line */
1232 /* When the last page height was computed, we did not know yet that it
1233 * was the last one. If the systems put on it don't fit anymore, the last
1234 * system is moved to a new page */
1235 space.resize (page_height (first_page_num + page, true));
1236 if ((line > page_first_line) && (isinf (space.force_)))
1238 res.systems_per_page_.push_back (line - page_first_line);
1239 res.force_.push_back (prev_force);
1240 /* the last page containing the last line */
1241 space.resize (page_height (first_page_num + page + 1, true));
1243 space.append_system (cached_line_details_[line]);
1244 res.systems_per_page_.push_back (1);
1245 res.force_.push_back (space.force_);
1246 res.penalty_ += cached_line_details_[line-1].page_penalty_;
1247 res.penalty_ += cached_line_details_[line].page_penalty_;
1251 res.systems_per_page_.push_back (line + 1 - page_first_line);
1252 res.force_.push_back (space.force_);
1253 res.penalty_ += cached_line_details_[line].page_penalty_;
1257 return finalize_spacing_result (configuration, res);
1260 /* Calculate demerits and fix res.systems_per_page_ so that
1261 it refers to the original line numbers, not the ones given by compress_lines (). */
1263 Page_breaking::finalize_spacing_result (vsize configuration, Page_spacing_result res)
1265 if (res.force_.empty ())
1268 cache_line_details (configuration);
1269 res.systems_per_page_ = uncompress_solution (res.systems_per_page_, cached_line_details_);
1271 Real line_force = 0;
1272 Real line_penalty = 0;
1273 Real page_demerits = res.penalty_;
1274 Real page_weighting = robust_scm2double (book_->paper_->c_variable ("page-spacing-weight"), 10);
1276 for (vsize i = 0; i < uncompressed_line_details_.size (); i++)
1278 line_force += uncompressed_line_details_[i].force_ * uncompressed_line_details_[i].force_;
1279 line_penalty += uncompressed_line_details_[i].break_penalty_;
1282 for (vsize i = 0; i < res.force_.size (); i++)
1284 Real f = res.force_[i];
1286 page_demerits += min(f*f, BAD_SPACING_PENALTY);
1289 /* for a while we tried averaging page and line forces across pages instead
1290 of summing them, but it caused a problem: if there is a single page
1291 with a very bad page force (for example because of a forced page break),
1292 the page breaker will put in a _lot_ of pages so that the bad force
1293 becomes averaged out over many pages. */
1294 res.demerits_ = line_force + line_penalty + page_demerits * page_weighting;
1299 /* the cases for page_count = 1 or 2 can be done in O (n) time. Since they
1300 are by far the most common cases, we have special functions for them.
1302 space_systems_on_1_page has a different calling convention than most of the
1303 space_systems functions. This is because space_systems_on_1_page is (unlike
1304 the other space_systems functions) sometimes called on subsets of a full
1307 Page_breaking::space_systems_on_1_page (vector<Line_details> const &lines, Real page_height, bool ragged)
1309 Page_spacing space (page_height, this);
1310 Page_spacing_result ret;
1313 for (vsize i = 0; i < lines.size (); i++)
1315 space.append_system (lines[i]);
1316 line_count += lines[i].compressed_nontitle_lines_count_;
1319 ret.systems_per_page_.push_back (lines.size ());
1320 ret.force_.push_back (ragged ? min (space.force_, 0.0) : space.force_);
1321 ret.penalty_ = line_count_penalty (line_count) + lines.back ().page_penalty_ + lines.back ().turn_penalty_;
1322 ret.system_count_status_ |= line_count_status (line_count);
1324 /* don't do finalize_spacing_result () because we are only an internal function */
1329 Page_breaking::space_systems_on_2_pages (vsize configuration, vsize first_page_num)
1331 Real page1_height = page_height (first_page_num, false);
1332 Real page2_height = page_height (first_page_num + 1, is_last ());
1333 bool ragged1 = ragged ();
1334 bool ragged2 = ragged () || (is_last () && ragged_last ());
1336 /* if there is a forced break, this reduces to 2 1-page problems */
1337 cache_line_details (configuration);
1338 for (vsize i = 0; i + 1 < cached_line_details_.size (); i++)
1339 if (cached_line_details_[i].page_permission_ == ly_symbol2scm ("force"))
1341 vector<Line_details> lines1 (cached_line_details_.begin (), cached_line_details_.begin () + i + 1);
1342 vector<Line_details> lines2 (cached_line_details_.begin () + i + 1, cached_line_details_.end ());
1343 Page_spacing_result p1 = space_systems_on_1_page (lines1, page1_height, ragged1);
1344 Page_spacing_result p2 = space_systems_on_1_page (lines2, page2_height, ragged2);
1346 p1.systems_per_page_.push_back (p2.systems_per_page_[0]);
1347 p1.force_.push_back (p2.force_[0]);
1348 p1.penalty_ += p2.penalty_ - cached_line_details_[i].turn_penalty_;
1349 p1.system_count_status_ |= p2.system_count_status_;
1353 vector<Real> page1_force;
1354 vector<Real> page2_force;
1356 // page1_penalty and page2_penalty store the penalties based
1357 // on min-systems-per-page and max-systems-per-page.
1358 vector<Real> page1_penalty;
1359 vector<Real> page2_penalty;
1361 // page1_status and page2_status keep track of whether the min-systems-per-page
1362 // and max-systems-per-page constraints are satisfied.
1363 vector<int> page1_status;
1364 vector<int> page2_status;
1366 Page_spacing page1 (page1_height, this);
1367 Page_spacing page2 (page2_height, this);
1368 int page1_line_count = 0;
1369 int page2_line_count = 0;
1371 page1_force.resize (cached_line_details_.size () - 1, infinity_f);
1372 page2_force.resize (cached_line_details_.size () - 1, infinity_f);
1373 page1_penalty.resize (cached_line_details_.size () - 1, infinity_f);
1374 page2_penalty.resize (cached_line_details_.size () - 1, infinity_f);
1375 page1_status.resize (cached_line_details_.size () - 1, 0);
1376 page2_status.resize (cached_line_details_.size () - 1, 0);
1378 /* find the page 1 and page 2 forces for each page-breaking position */
1379 for (vsize i = 0; i < page1_force.size (); i++)
1381 page1.append_system (cached_line_details_[i]);
1382 page2.prepend_system (cached_line_details_[cached_line_details_.size () - 1 - i]);
1383 page1_line_count += cached_line_details_[i].compressed_nontitle_lines_count_;
1384 page2_line_count += cached_line_details_[cached_line_details_.size () - 1 - i].compressed_nontitle_lines_count_;
1386 page1_force[i] = (ragged1 && page1.force_ < 0 && i > 0) ? infinity_f : page1.force_;
1387 page1_penalty[i] = line_count_penalty (page1_line_count);
1388 page1_status[i] = line_count_status (page1_line_count);
1391 page2_force[page2_force.size () - 1 - i] =
1392 (page2.force_ < 0 && i + 1 < page1_force.size ()) ? infinity_f : 0;
1394 page2_force[page2_force.size () - 1 - i] = page2.force_;
1395 page2_penalty[page2_penalty.size () - 1 - i] = line_count_penalty (page2_line_count);
1396 page2_status[page2_penalty.size () - 1 - i] = line_count_status (page2_line_count);
1399 /* find the position that minimises the sum of the page forces */
1400 vsize best_sys_count = 1;
1401 Real best_demerits = infinity_f;
1402 for (vsize i = 0; i < page1_force.size (); i++)
1404 Real f = page1_force[i] * page1_force[i] + page2_force[i] * page2_force[i];
1406 // NOTE: we treat max-systems-per-page and min-systems-per-page as soft
1407 // constraints. That is, we penalize harshly when they don't happen
1408 // but we don't completely reject.
1410 + page1_penalty[i] + page2_penalty[i]
1411 + cached_line_details_[i+1].page_penalty_
1412 + cached_line_details_.back ().page_penalty_ + cached_line_details_.back ().turn_penalty_;
1413 if (dem < best_demerits)
1415 best_demerits = dem;
1416 best_sys_count = i+1;
1420 Page_spacing_result ret;
1421 ret.systems_per_page_.push_back (best_sys_count);
1422 ret.systems_per_page_.push_back (cached_line_details_.size () - best_sys_count);
1423 ret.force_.push_back (page1_force[best_sys_count-1]);
1424 ret.force_.push_back (page2_force[best_sys_count-1]);
1425 ret.system_count_status_ = page1_status[best_sys_count-1] | page2_status[best_sys_count-1];
1426 ret.penalty_ = cached_line_details_[best_sys_count-1].page_penalty_
1427 + cached_line_details_.back ().page_penalty_
1428 + cached_line_details_.back ().turn_penalty_
1429 + page1_penalty[best_sys_count-1] + page2_penalty[best_sys_count-1];
1431 /* don't do finalize_spacing_result () because we are only an internal function */
1436 Page_breaking::all_lines_stretched (vsize configuration)
1438 cache_line_details (configuration);
1439 for (vsize i = 0; i < cached_line_details_.size (); i++)
1440 if (cached_line_details_[i].force_ < 0)
1446 Page_breaking::Line_division
1447 Page_breaking::current_configuration (vsize configuration_index) const
1449 return current_configurations_[configuration_index];
1453 Page_breaking::is_last () const
1455 return current_end_breakpoint_ == last_break_position ();
1459 Page_breaking::ends_score () const
1461 return breaks_[current_end_breakpoint_].score_ender_;
1465 Page_breaking::last_break_position () const
1467 return breaks_.size () - 1;
1470 // This gives the minimum distance between the top of the
1471 // printable area (ie. the bottom of the top-margin) and
1472 // the extent box of the topmost system.
1474 Page_breaking::min_whitespace_at_top_of_page (Line_details const &line) const
1476 SCM first_system_spacing = book_->paper_->c_variable ("top-system-spacing");
1478 first_system_spacing = book_->paper_->c_variable ("top-markup-spacing");
1480 Real min_distance = -infinity_f;
1483 Page_layout_problem::read_spacing_spec (first_system_spacing,
1485 ly_symbol2scm ("minimum-distance"));
1486 Page_layout_problem::read_spacing_spec (first_system_spacing,
1488 ly_symbol2scm ("padding"));
1490 // FIXME: take into account the height of the header
1491 Real translate = max (line.shape_.begin_[UP], line.shape_.rest_[UP]);
1492 return max (0.0, max (padding, min_distance - translate));
1496 Page_breaking::min_whitespace_at_bottom_of_page (Line_details const &line) const
1498 SCM last_system_spacing = book_->paper_->c_variable ("last-bottom-spacing");
1499 Real min_distance = -infinity_f;
1502 Page_layout_problem::read_spacing_spec (last_system_spacing,
1504 ly_symbol2scm ("minimum-distance"));
1505 Page_layout_problem::read_spacing_spec (last_system_spacing,
1507 ly_symbol2scm ("padding"));
1509 // FIXME: take into account the height of the footer
1510 Real translate = min (line.shape_.begin_[DOWN], line.shape_.rest_[DOWN]);
1511 return max (0.0, max (padding, min_distance + translate));
1515 Page_breaking::orphan_penalty () const
1517 return orphan_penalty_;