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);
348 Prob *pb = system_specs_[sys].prob_;
349 ret = scm_cons (scm_list_1 (pb->self_scm ()), ret);
353 return scm_append (scm_reverse (ret));
357 Page_breaking::make_page (int page_num, bool last) const
359 bool last_part = ly_scm2bool (book_->paper_->c_variable ("is-last-bookpart"));
360 SCM mod = scm_c_resolve_module ("scm page");
361 SCM make_page_scm = scm_c_module_lookup (mod, "make-page");
363 make_page_scm = scm_variable_ref (make_page_scm);
365 return scm_apply_0 (make_page_scm,
366 scm_list_n (book_->self_scm (),
367 ly_symbol2scm ("page-number"), scm_from_int (page_num),
368 ly_symbol2scm ("is-last-bookpart"), scm_from_bool (last_part),
369 ly_symbol2scm ("is-bookpart-last-page"), scm_from_bool (last),
373 // Returns the total height of the paper, including margins and
374 // space for the header/footer. This is an upper bound on
375 // page_height, and it doesn't depend on the current page.
377 Page_breaking::paper_height () const
379 return paper_height_;
383 Page_breaking::page_height (int page_num, bool last) const
385 // The caches allow us to store the page heights for any
386 // non-negative page numbers. We use a negative value in the
387 // cache to signal that that position has not yet been initialized.
388 // This means that we won't cache properly if page_num is negative or
389 // if calc_height returns a negative number. But that's likely to
390 // be rare, so it shouldn't affect performance.
391 vector<Real>& cache = last ? last_page_height_cache_ : page_height_cache_;
392 if (page_num >= 0 && (int) cache.size () > page_num && cache[page_num] >= 0)
393 return cache[page_num];
396 SCM mod = scm_c_resolve_module ("scm page");
397 SCM page = make_page (page_num, last);
398 SCM calc_height = scm_c_module_lookup (mod, "calc-printable-height");
399 calc_height = scm_variable_ref (calc_height);
401 SCM height_scm = scm_apply_1 (calc_height, page, SCM_EOL);
402 Real height = scm_to_double (height_scm);
406 if ((int) cache.size () <= page_num)
407 cache.resize (page_num + 1, -1);
408 cache[page_num] = height;
415 Page_breaking::breakpoint_property (vsize breakpoint, char const *str)
417 Break_position const &pos = breaks_[breakpoint];
419 if (pos.system_spec_index_ == VPOS)
421 if (system_specs_[pos.system_spec_index_].pscore_)
422 return pos.col_->get_property (str);
423 return system_specs_[pos.system_spec_index_].prob_->get_property (str);
427 Page_breaking::get_page_configuration (SCM systems, int page_num, bool ragged, bool last)
429 SCM dummy_page = make_page (page_num, last);
430 Page_layout_problem layout (book_, dummy_page, systems);
431 return scm_is_pair (systems) ? layout.solution (ragged) : SCM_EOL;
435 Page_breaking::draw_page (SCM systems, SCM configuration, int page_num, bool last)
437 // Create a stencil for each system.
438 SCM paper_systems = SCM_EOL;
439 for (SCM s = scm_reverse (systems); scm_is_pair (s); s = scm_cdr (s))
441 SCM paper_system = scm_car (s);
442 if (Grob *g = unsmob_grob (scm_car (s)))
444 System *sys = dynamic_cast<System*> (g);
445 paper_system = sys->get_paper_system ();
448 paper_systems = scm_cons (paper_system, paper_systems);
451 // Create the page and draw it.
452 SCM page = make_page (page_num, last);
453 SCM page_module = scm_c_resolve_module ("scm page");
454 SCM page_stencil = scm_c_module_lookup (page_module, "page-stencil");
455 page_stencil = scm_variable_ref (page_stencil);
457 Prob *p = unsmob_prob (page);
458 p->set_property ("lines", paper_systems);
459 p->set_property ("configuration", configuration);
460 scm_apply_1 (page_stencil, page, SCM_EOL);
466 Page_breaking::make_pages (vector<vsize> lines_per_page, SCM systems)
468 int first_page_number
469 = robust_scm2int (book_->paper_->c_variable ("first-page-number"), 1);
471 SCM label_page_table = book_->top_paper ()->c_variable ("label-page-table");
472 if (label_page_table == SCM_UNDEFINED)
473 label_page_table = SCM_EOL;
475 // Build a list of (systems . configuration) pairs. Note that we lay out
476 // the staves and find the configurations before drawing anything. Some
477 // grobs (like tuplet brackets) look at their neighbours while drawing
478 // themselves. If this happens before the neighbouring staves have
479 // been laid out, bad side-effects could happen (in particular,
480 // Align_interface::align_to_ideal_distances might be called).
481 SCM systems_and_configs = SCM_EOL;
483 for (vsize i = 0; i < lines_per_page.size (); i++)
485 int page_num = i + first_page_number;
486 bool bookpart_last_page = (i == lines_per_page.size () - 1);
487 bool rag = ragged () || (bookpart_last_page && ragged_last ());
488 SCM line_count = scm_from_int (lines_per_page[i]);
489 SCM lines = scm_list_head (systems, line_count);
490 SCM config = get_page_configuration (lines, page_num, rag, bookpart_last_page);
492 systems_and_configs = scm_cons (scm_cons (lines, config), systems_and_configs);
493 systems = scm_list_tail (systems, line_count);
496 // Now it's safe to make the pages.
497 int page_num = first_page_number + lines_per_page.size () - 1;
498 for (SCM s = systems_and_configs; scm_is_pair (s); s = scm_cdr (s))
500 SCM lines = scm_caar (s);
501 SCM config = scm_cdar (s);
502 bool bookpart_last_page = (s == systems_and_configs);
503 SCM page = draw_page (lines, config, page_num, bookpart_last_page);
506 SCM page_num_scm = scm_from_int (page_num);
507 for (SCM l = lines ; scm_is_pair (l) ; l = scm_cdr (l))
509 SCM labels = SCM_EOL;
510 if (Grob * line = unsmob_grob (scm_car (l)))
512 System *system = dynamic_cast<System*> (line);
513 labels = system->get_property ("labels");
515 else if (Prob *prob = unsmob_prob (scm_car (l)))
516 labels = prob->get_property ("labels");
518 for (SCM lbls = labels ; scm_is_pair (lbls) ; lbls = scm_cdr (lbls))
519 label_page_table = scm_cons (scm_cons (scm_car (lbls), page_num_scm),
523 ret = scm_cons (page, ret);
526 book_->top_paper ()->set_variable (ly_symbol2scm ("label-page-table"), label_page_table);
530 /* The page-turn-page-breaker needs to have a line-breaker between any two
531 columns with non-NULL page-turn-permission.
533 The optimal-breaker needs to have a line-breaker between any two columns
534 with page-break-permission = 'force.
536 By using a grob predicate, we can accommodate both of these uses.
539 Page_breaking::create_system_list ()
541 SCM specs = book_->get_system_specs ();
542 for (SCM s = specs; scm_is_pair (s); s = scm_cdr (s))
544 if (Paper_score *ps = dynamic_cast<Paper_score*> (unsmob_music_output (scm_car (s))))
546 system_specs_.push_back (System_spec (ps));
550 Prob *pb = unsmob_prob (scm_car (s));
554 system_specs_.push_back (System_spec (pb));
560 Page_breaking::find_chunks_and_breaks (Break_predicate is_break, Prob_break_predicate prob_is_break)
562 SCM force_sym = ly_symbol2scm ("force");
564 chunks_.push_back (Break_position ());
565 breaks_.push_back (Break_position ());
567 for (vsize i = 0; i < system_specs_.size (); i++)
569 if (system_specs_[i].pscore_)
571 vector<Grob*> cols = system_specs_[i].pscore_->root_system ()->used_columns ();
572 vector<Grob*> forced_line_break_cols;
574 SCM system_count = system_specs_[i].pscore_->layout ()->c_variable ("system-count");
575 if (scm_is_number (system_count))
577 // With system-count given, the line configuration for
578 // this score is fixed. We need to ensure that chunk
579 // boundaries only occur at line breaks.
580 Constrained_breaking breaking (system_specs_[i].pscore_);
581 vector<Line_details> details = breaking.line_details (0, VPOS, scm_to_int (system_count));
583 for (vsize j = 0; j < details.size (); j++)
584 forced_line_break_cols.push_back (details[j].last_column_);
587 int last_forced_line_break_idx = 0;
588 vsize forced_line_break_idx = 0;
589 vector<vsize> line_breaker_columns;
590 line_breaker_columns.push_back (0);
592 for (vsize j = 1; j < cols.size (); j++)
594 if (forced_line_break_cols.size ())
596 if (forced_line_break_idx >= forced_line_break_cols.size ()
597 || forced_line_break_cols[forced_line_break_idx] != cols[j])
600 forced_line_break_idx++;
603 bool last = (j == cols.size () - 1);
604 bool break_point = is_break && is_break (cols[j]);
605 bool chunk_end = cols[j]->get_property ("page-break-permission") == force_sym;
606 Break_position cur_pos = Break_position (i,
607 line_breaker_columns.size (),
611 // NOTE: even in the breaks_ list, forced_line_count_
612 // refers to the number of lines between a
613 // Break_position and the start of that /chunk/. This
614 // is needed for system_count_bounds to work correctly,
615 // since it mixes Break_positions from breaks_ and
617 if (scm_is_number (system_count))
618 cur_pos.forced_line_count_ = forced_line_break_idx - last_forced_line_break_idx;
620 if (break_point || (i == system_specs_.size () - 1 && last))
621 breaks_.push_back (cur_pos);
622 if (chunk_end || last)
624 chunks_.push_back (cur_pos);
625 last_forced_line_break_idx = forced_line_break_idx;
628 if ((break_point || chunk_end) && !last)
629 line_breaker_columns.push_back (j);
631 line_breaking_.push_back (Constrained_breaking (system_specs_[i].pscore_, line_breaker_columns));
635 bool break_point = prob_is_break && prob_is_break (system_specs_[i].prob_);
636 if (break_point || i == system_specs_.size () - 1)
637 breaks_.push_back (Break_position (i));
639 chunks_.push_back (Break_position (i));
641 /* FIXME: shouldn't we push a Null_breaker or similar dummy
643 line_breaking_.push_back (Constrained_breaking (NULL));
648 vector<Break_position>
649 Page_breaking::chunk_list (vsize start_index, vsize end_index)
651 Break_position start = breaks_[start_index];
652 Break_position end = breaks_[end_index];
655 for (; i < chunks_.size () && chunks_[i] <= start; i++)
658 vector<Break_position> ret;
659 ret.push_back (start);
660 for (; i < chunks_.size () && chunks_[i] < end; i++)
661 ret.push_back (chunks_[i]);
667 Page_breaking::min_system_count (vsize start, vsize end)
669 vector<Break_position> chunks = chunk_list (start, end);
670 Line_division div = system_count_bounds (chunks, true);
673 for (vsize i = 0; i < div.size (); i++)
679 Page_breaking::max_system_count (vsize start, vsize end)
681 vector<Break_position> chunks = chunk_list (start, end);
682 Line_division div = system_count_bounds (chunks, false);
685 for (vsize i = 0; i < div.size (); i++)
690 Page_breaking::Line_division
691 Page_breaking::system_count_bounds (vector<Break_position> const &chunks,
694 assert (chunks.size () >= 2);
697 ret.resize (chunks.size () - 1, 1);
699 for (vsize i = 0; i + 1 < chunks.size (); i++)
701 vsize sys = next_system (chunks[i]);
703 if (chunks[i+1].forced_line_count_)
704 ret[i] = chunks[i+1].forced_line_count_;
705 else if (system_specs_[sys].pscore_)
709 line_breaker_args (sys, chunks[i], chunks[i+1], &start, &end);
711 ? line_breaking_[sys].min_system_count (start, end)
712 : line_breaking_[sys].max_system_count (start, end);
720 Page_breaking::set_current_breakpoints (vsize start,
723 Line_division lower_bound,
724 Line_division upper_bound)
726 system_count_ = system_count;
727 current_chunks_ = chunk_list (start, end);
728 current_start_breakpoint_ = start;
729 current_end_breakpoint_ = end;
730 clear_line_details_cache ();
732 if (!lower_bound.size ())
733 lower_bound = system_count_bounds (current_chunks_, true);
734 if (!upper_bound.size ())
735 upper_bound = system_count_bounds (current_chunks_, false);
737 assert (lower_bound.size () == current_chunks_.size () - 1);
738 assert (upper_bound.size () == current_chunks_.size () - 1);
740 Line_division work_in_progress;
741 current_configurations_.clear ();
742 line_divisions_rec (system_count,
747 /* we only consider a constant number of configurations. Otherwise,
748 this becomes slow when there are many small scores. The constant
749 5 is somewhat arbitrary. */
750 if (current_configurations_.size () > 5)
752 vector<pair<Real,vsize> > dems_and_indices;
754 for (vsize i = 0; i < current_configurations_.size (); i++)
756 cache_line_details (i);
758 for (vsize j = 0; j < cached_line_details_.size (); j++)
759 dem += cached_line_details_[j].force_ * cached_line_details_[j].force_
760 + cached_line_details_[j].break_penalty_;
762 dems_and_indices.push_back (pair<Real,vsize> (dem, i));
764 vector_sort (dems_and_indices, less<pair<Real,vsize> > ());
766 vector<Line_division> best_5_configurations;
767 for (vsize i = 0; i < 5; i++)
768 best_5_configurations.push_back (current_configurations_[dems_and_indices[i].second]);
770 clear_line_details_cache ();
771 current_configurations_ = best_5_configurations;
776 Page_breaking::set_to_ideal_line_configuration (vsize start, vsize end)
778 current_chunks_ = chunk_list (start, end);
779 current_start_breakpoint_ = start;
780 current_end_breakpoint_ = end;
781 clear_line_details_cache ();
785 for (vsize i = 0; i+1 < current_chunks_.size (); i++)
787 vsize sys = next_system (current_chunks_[i]);
789 if (current_chunks_[i+1].forced_line_count_)
790 div.push_back (current_chunks_[i+1].forced_line_count_);
791 else if (system_specs_[sys].pscore_)
793 line_breaker_args (sys, current_chunks_[i], current_chunks_[i+1], &start, &end);
794 div.push_back (line_breaking_[sys].best_solution (start, end).size ());
799 system_count_ += div.back ();
801 current_configurations_.clear ();
802 current_configurations_.push_back (div);
806 Page_breaking::current_configuration_count () const
808 return current_configurations_.size ();
812 Page_breaking::cache_line_details (vsize configuration_index)
814 if (cached_configuration_index_ != configuration_index)
816 cached_configuration_index_ = configuration_index;
818 Line_division &div = current_configurations_[configuration_index];
819 uncompressed_line_details_.clear ();
820 for (vsize i = 0; i + 1 < current_chunks_.size (); i++)
822 vsize sys = next_system (current_chunks_[i]);
823 if (system_specs_[sys].pscore_)
827 line_breaker_args (sys, current_chunks_[i], current_chunks_[i+1], &start, &end);
829 vector<Line_details> details = line_breaking_[sys].line_details (start, end, div[i]);
830 uncompressed_line_details_.insert (uncompressed_line_details_.end (), details.begin (), details.end ());
834 assert (div[i] == 1);
835 uncompressed_line_details_.push_back (Line_details (system_specs_[sys].prob_, book_->paper_));
838 cached_line_details_ = compress_lines (uncompressed_line_details_);
839 compute_line_heights ();
844 Page_breaking::clear_line_details_cache ()
846 cached_configuration_index_ = VPOS;
847 cached_line_details_.clear ();
848 uncompressed_line_details_.clear ();
852 Page_breaking::line_divisions_rec (vsize system_count,
853 Line_division const &min_sys,
854 Line_division const &max_sys,
855 Line_division *cur_division)
857 vsize my_index = cur_division->size ();
861 for (vsize i = my_index + 1; i < min_sys.size (); i++)
863 others_min += min_sys[i];
864 others_max += max_sys[i];
866 others_max = min (others_max, (int) system_count);
867 int real_min = max ((int) min_sys[my_index], (int) system_count - others_max);
868 int real_max = min ((int) max_sys[my_index], (int) system_count - others_min);
870 if (real_min > real_max || real_min <= 0)
872 /* this should never happen within a recursive call. If it happens
873 at all, it means that we were called with an unsolvable problem
874 and we should return an empty result */
875 assert (my_index == 0);
879 for (int i = real_min; i <= real_max; i++)
881 cur_division->push_back (i);
882 if (my_index == min_sys.size () - 1)
883 current_configurations_.push_back (*cur_division);
885 line_divisions_rec (system_count - i, min_sys, max_sys, cur_division);
886 cur_division->pop_back ();
891 Page_breaking::compute_line_heights ()
893 Real prev_hanging = 0;
894 Real prev_hanging_begin = 0;
895 Real prev_hanging_rest = 0;
897 // refpoint_hanging is the y coordinate of the origin of this system.
898 // It may not be the same as refpoint_extent[UP], which is the
899 // refpoint of the first spaceable staff in this system.
900 Real prev_refpoint_hanging = 0;
901 for (vsize i = 0; i < cached_line_details_.size (); i++)
903 Line_details& cur = cached_line_details_[i];
904 Line_shape shape = cur.shape_;
905 Real a = shape.begin_[UP];
906 Real b = shape.rest_[UP];
907 bool title = cur.title_;
908 Real refpoint_hanging = max (prev_hanging_begin + a, prev_hanging_rest + b);
913 Line_details const& prev = cached_line_details_[i-1];
914 if (!cur.tight_spacing_)
916 ? prev.title_padding_
918 Real min_dist = title
919 ? prev.title_min_distance_
920 : prev.min_distance_;
921 refpoint_hanging = max (refpoint_hanging + padding,
922 prev_refpoint_hanging - prev.refpoint_extent_[DOWN]
923 + cur.refpoint_extent_[UP] + min_dist);
926 Real hanging_begin = refpoint_hanging - shape.begin_[DOWN];
927 Real hanging_rest = refpoint_hanging - shape.rest_[DOWN];
928 Real hanging = max (hanging_begin, hanging_rest);
929 cur.tallness_ = hanging - prev_hanging;
930 prev_hanging = hanging;
931 prev_hanging_begin = hanging_begin;
932 prev_hanging_rest = hanging_rest;
933 prev_refpoint_hanging = refpoint_hanging;
938 Page_breaking::min_page_count (vsize configuration, vsize first_page_num)
941 vsize page_starter = 0;
942 Real cur_rod_height = 0;
943 Real cur_spring_height = 0;
944 Real cur_page_height = page_height (first_page_num, false);
947 cache_line_details (configuration);
949 if (cached_line_details_.size ())
950 cur_page_height -= min_whitespace_at_top_of_page (cached_line_details_[0]);
952 for (vsize i = 0; i < cached_line_details_.size (); i++)
955 if (cur_rod_height > 0)
956 ext_len = cached_line_details_[i].tallness_;
958 ext_len = cached_line_details_[i].full_height();
960 Real next_rod_height = cur_rod_height + ext_len;
961 Real next_spring_height = cur_spring_height + cached_line_details_[i].space_;
962 Real next_height = next_rod_height + (ragged () ? next_spring_height : 0)
963 + min_whitespace_at_bottom_of_page (cached_line_details_[i]);
964 int next_line_count = line_count + cached_line_details_[i].compressed_nontitle_lines_count_;
966 if ((!too_few_lines (line_count) && (next_height > cur_page_height && cur_rod_height > 0))
967 || too_many_lines (next_line_count)
969 && cached_line_details_[i-1].page_permission_ == ly_symbol2scm ("force")))
971 line_count = cached_line_details_[i].compressed_nontitle_lines_count_;
972 cur_rod_height = cached_line_details_[i].full_height();
973 cur_spring_height = cached_line_details_[i].space_;
976 cur_page_height = page_height (first_page_num + ret, false);
977 cur_page_height -= min_whitespace_at_top_of_page (cached_line_details_[i]);
983 cur_rod_height = next_rod_height;
984 cur_spring_height = next_spring_height;
985 line_count = next_line_count;
989 /* there are two potential problems with the last page (because we didn't know
990 it was the last page until after we managed to fit all the systems to it):
991 - we are ragged-last but the last page has a compressed spring
992 - the value returned by page_height (num, true) is smaller than the
993 value returned by page_height (num, false) and it causes the page not to
996 In either case, we just need to add one more page. This is because the last
997 line will always fit on the extra page and by adding one more page to the
998 end, the previous page is no longer the last page, so our previous
999 calculations that treated it as a non-last page were ok.
1004 cur_page_height = page_height (first_page_num + ret - 1, true);
1005 cur_page_height -= min_whitespace_at_top_of_page (cached_line_details_[page_starter]);
1006 cur_page_height -= min_whitespace_at_bottom_of_page (cached_line_details_.back ());
1008 Real cur_height = cur_rod_height + ((ragged_last () || ragged ()) ? cur_spring_height : 0);
1009 if (!too_few_lines (line_count - cached_line_details_.back ().compressed_nontitle_lines_count_)
1010 && cur_height > cur_page_height
1011 /* don't increase the page count if the last page had only one system */
1012 && cur_rod_height > cached_line_details_.back ().full_height ())
1014 assert (ret <= cached_line_details_.size ());
1020 // If systems_per_page_ is positive, we don't really try to space on N pages;
1021 // we just put the requested number of systems on each page and penalize
1022 // if the result doesn't have N pages.
1024 Page_breaking::space_systems_on_n_pages (vsize configuration, vsize n, vsize first_page_num)
1026 Page_spacing_result ret;
1028 if (systems_per_page_ > 0)
1030 Page_spacing_result ret = space_systems_with_fixed_number_per_page (configuration, first_page_num);
1031 ret.demerits_ += (ret.force_.size () == n) ? 0 : BAD_SPACING_PENALTY;
1035 cache_line_details (configuration);
1036 bool valid_n = (n >= min_page_count (configuration, first_page_num)
1037 && n <= cached_line_details_.size ());
1040 programming_error ("number of pages is out of bounds");
1042 if (n == 1 && valid_n)
1043 ret = space_systems_on_1_page (cached_line_details_,
1044 page_height (first_page_num, is_last ()),
1045 ragged () || (is_last () && ragged_last ()));
1046 else if (n == 2 && valid_n)
1047 ret = space_systems_on_2_pages (configuration, first_page_num);
1050 Page_spacer ps (cached_line_details_, first_page_num, this);
1054 return finalize_spacing_result (configuration, ret);
1058 Page_breaking::blank_page_penalty () const
1063 penalty_sym = ly_symbol2scm ("blank-last-page-force");
1064 else if (ends_score ())
1065 penalty_sym = ly_symbol2scm ("blank-after-score-page-force");
1067 penalty_sym = ly_symbol2scm ("blank-page-force");
1069 Break_position const &pos = breaks_[current_end_breakpoint_];
1070 if (Paper_score *ps = system_specs_[pos.system_spec_index_].pscore_)
1071 return robust_scm2double (ps->layout ()->lookup_variable (penalty_sym), 0.0);
1073 return robust_scm2double (book_->paper_->lookup_variable (penalty_sym), 0.0);
1076 // If systems_per_page_ is positive, we don't really try to space on N
1077 // or N+1 pages; see the comment to space_systems_on_n_pages.
1079 Page_breaking::space_systems_on_n_or_one_more_pages (vsize configuration, vsize n, vsize first_page_num,
1080 Real penalty_for_fewer_pages)
1082 Page_spacing_result n_res;
1083 Page_spacing_result m_res;
1085 if (systems_per_page_ > 0)
1087 Page_spacing_result ret = space_systems_with_fixed_number_per_page (configuration, first_page_num);
1088 ret.demerits_ += (ret.force_.size () == n || ret.force_.size () == (n-1)) ? 0 : BAD_SPACING_PENALTY;
1092 cache_line_details (configuration);
1093 vsize min_p_count = min_page_count (configuration, first_page_num);
1094 bool valid_n = n >= min_p_count || n <= cached_line_details_.size ();
1097 programming_error ("both page counts are out of bounds");
1099 if (n == 1 && valid_n)
1101 bool rag = ragged () || (is_last () && ragged_last ());
1102 Real height = page_height (first_page_num, is_last ());
1104 if (1 >= min_p_count)
1105 n_res = space_systems_on_1_page (cached_line_details_, height, rag);
1106 if (1 < cached_line_details_.size ())
1107 m_res = space_systems_on_2_pages (configuration, first_page_num);
1111 Page_spacer ps (cached_line_details_, first_page_num, this);
1113 if (n >= min_p_count || !valid_n)
1114 n_res = ps.solve (n);
1115 if (n < cached_line_details_.size () || !valid_n)
1116 m_res = ps.solve (n+1);
1119 m_res = finalize_spacing_result (configuration, m_res);
1120 n_res = finalize_spacing_result (configuration, n_res);
1122 Real page_spacing_weight = robust_scm2double (book_->paper_->c_variable ("page-spacing-weight"), 10);
1123 n_res.demerits_ += penalty_for_fewer_pages * page_spacing_weight;
1125 if (n_res.force_.size ())
1126 n_res.force_.back () += penalty_for_fewer_pages;
1128 return (m_res.demerits_ < n_res.demerits_) ? m_res : n_res;
1132 Page_breaking::space_systems_on_best_pages (vsize configuration, vsize first_page_num)
1134 cache_line_details (configuration);
1135 Page_spacer ps (cached_line_details_, first_page_num, this);
1137 return finalize_spacing_result (configuration, ps.solve ());
1141 Page_breaking::space_systems_with_fixed_number_per_page (vsize configuration,
1142 vsize first_page_num)
1144 Page_spacing_result res;
1145 Page_spacing space (page_height (first_page_num, false), this);
1148 vsize page_first_line = 0;
1150 cache_line_details (configuration);
1151 while (line < cached_line_details_.size ())
1155 space.resize (page_height (first_page_num + page, false));
1157 int system_count_on_this_page = 0;
1158 while (system_count_on_this_page < systems_per_page_
1159 && line < cached_line_details_.size ())
1161 Line_details const &cur_line = cached_line_details_[line];
1162 space.append_system (cur_line);
1163 system_count_on_this_page += cur_line.compressed_nontitle_lines_count_;
1166 if (cur_line.page_permission_ == ly_symbol2scm ("force"))
1170 res.systems_per_page_.push_back (line - page_first_line);
1172 res.force_.push_back (space.force_);
1173 res.penalty_ += cached_line_details_[line-1].page_penalty_;
1174 if (system_count_on_this_page != systems_per_page_)
1176 res.penalty_ += TERRIBLE_SPACING_PENALTY;
1177 res.system_count_status_ |= ((system_count_on_this_page < systems_per_page_))
1178 ? SYSTEM_COUNT_TOO_FEW : SYSTEM_COUNT_TOO_MANY;
1181 page_first_line = line;
1184 /* Recalculate forces for the last page because we know now that is
1185 really the last page. */
1186 space.resize (page_height (first_page_num + page, true));
1187 res.force_.back () = space.force_;
1188 return finalize_spacing_result (configuration, res);
1192 Page_breaking::pack_systems_on_least_pages (vsize configuration, vsize first_page_num)
1194 // TODO: add support for min/max-systems-per-page.
1195 Page_spacing_result res;
1197 vsize page_first_line = 0;
1198 Page_spacing space (page_height (first_page_num, false), this);
1200 cache_line_details (configuration);
1201 for (vsize line = 0; line < cached_line_details_.size (); line++)
1203 Real prev_force = space.force_;
1204 space.append_system (cached_line_details_[line]);
1205 if ((line > page_first_line)
1206 && (isinf (space.force_)
1208 && (cached_line_details_[line-1].page_permission_ == ly_symbol2scm ("force")))))
1210 res.systems_per_page_.push_back (line - page_first_line);
1211 res.force_.push_back (prev_force);
1212 res.penalty_ += cached_line_details_[line-1].page_penalty_;
1214 space.resize (page_height (first_page_num + page, false));
1216 space.append_system (cached_line_details_[line]);
1217 page_first_line = line;
1220 if (line == cached_line_details_.size () - 1)
1222 /* This is the last line */
1223 /* When the last page height was computed, we did not know yet that it
1224 * was the last one. If the systems put on it don't fit anymore, the last
1225 * system is moved to a new page */
1226 space.resize (page_height (first_page_num + page, true));
1227 if ((line > page_first_line) && (isinf (space.force_)))
1229 res.systems_per_page_.push_back (line - page_first_line);
1230 res.force_.push_back (prev_force);
1231 /* the last page containing the last line */
1232 space.resize (page_height (first_page_num + page + 1, true));
1234 space.append_system (cached_line_details_[line]);
1235 res.systems_per_page_.push_back (1);
1236 res.force_.push_back (space.force_);
1237 res.penalty_ += cached_line_details_[line-1].page_penalty_;
1238 res.penalty_ += cached_line_details_[line].page_penalty_;
1242 res.systems_per_page_.push_back (line + 1 - page_first_line);
1243 res.force_.push_back (space.force_);
1244 res.penalty_ += cached_line_details_[line].page_penalty_;
1248 return finalize_spacing_result (configuration, res);
1251 /* Calculate demerits and fix res.systems_per_page_ so that
1252 it refers to the original line numbers, not the ones given by compress_lines (). */
1254 Page_breaking::finalize_spacing_result (vsize configuration, Page_spacing_result res)
1256 if (res.force_.empty ())
1259 cache_line_details (configuration);
1260 res.systems_per_page_ = uncompress_solution (res.systems_per_page_, cached_line_details_);
1262 Real line_force = 0;
1263 Real line_penalty = 0;
1264 Real page_demerits = res.penalty_;
1265 Real page_weighting = robust_scm2double (book_->paper_->c_variable ("page-spacing-weight"), 10);
1267 for (vsize i = 0; i < uncompressed_line_details_.size (); i++)
1269 line_force += uncompressed_line_details_[i].force_ * uncompressed_line_details_[i].force_;
1270 line_penalty += uncompressed_line_details_[i].break_penalty_;
1273 for (vsize i = 0; i < res.force_.size (); i++)
1275 Real f = res.force_[i];
1277 page_demerits += min(f*f, BAD_SPACING_PENALTY);
1280 /* for a while we tried averaging page and line forces across pages instead
1281 of summing them, but it caused a problem: if there is a single page
1282 with a very bad page force (for example because of a forced page break),
1283 the page breaker will put in a _lot_ of pages so that the bad force
1284 becomes averaged out over many pages. */
1285 res.demerits_ = line_force + line_penalty + page_demerits * page_weighting;
1290 /* the cases for page_count = 1 or 2 can be done in O (n) time. Since they
1291 are by far the most common cases, we have special functions for them.
1293 space_systems_on_1_page has a different calling convention than most of the
1294 space_systems functions. This is because space_systems_on_1_page is (unlike
1295 the other space_systems functions) sometimes called on subsets of a full
1298 Page_breaking::space_systems_on_1_page (vector<Line_details> const &lines, Real page_height, bool ragged)
1300 Page_spacing space (page_height, this);
1301 Page_spacing_result ret;
1304 for (vsize i = 0; i < lines.size (); i++)
1306 space.append_system (lines[i]);
1307 line_count += lines[i].compressed_nontitle_lines_count_;
1310 ret.systems_per_page_.push_back (lines.size ());
1311 ret.force_.push_back (ragged ? min (space.force_, 0.0) : space.force_);
1312 ret.penalty_ = line_count_penalty (line_count) + lines.back ().page_penalty_ + lines.back ().turn_penalty_;
1313 ret.system_count_status_ |= line_count_status (line_count);
1315 /* don't do finalize_spacing_result () because we are only an internal function */
1320 Page_breaking::space_systems_on_2_pages (vsize configuration, vsize first_page_num)
1322 Real page1_height = page_height (first_page_num, false);
1323 Real page2_height = page_height (first_page_num + 1, is_last ());
1324 bool ragged1 = ragged ();
1325 bool ragged2 = ragged () || (is_last () && ragged_last ());
1327 /* if there is a forced break, this reduces to 2 1-page problems */
1328 cache_line_details (configuration);
1329 for (vsize i = 0; i + 1 < cached_line_details_.size (); i++)
1330 if (cached_line_details_[i].page_permission_ == ly_symbol2scm ("force"))
1332 vector<Line_details> lines1 (cached_line_details_.begin (), cached_line_details_.begin () + i + 1);
1333 vector<Line_details> lines2 (cached_line_details_.begin () + i + 1, cached_line_details_.end ());
1334 Page_spacing_result p1 = space_systems_on_1_page (lines1, page1_height, ragged1);
1335 Page_spacing_result p2 = space_systems_on_1_page (lines2, page2_height, ragged2);
1337 p1.systems_per_page_.push_back (p2.systems_per_page_[0]);
1338 p1.force_.push_back (p2.force_[0]);
1339 p1.penalty_ += p2.penalty_ - cached_line_details_[i].turn_penalty_;
1340 p1.system_count_status_ |= p2.system_count_status_;
1344 vector<Real> page1_force;
1345 vector<Real> page2_force;
1347 // page1_penalty and page2_penalty store the penalties based
1348 // on min-systems-per-page and max-systems-per-page.
1349 vector<Real> page1_penalty;
1350 vector<Real> page2_penalty;
1352 // page1_status and page2_status keep track of whether the min-systems-per-page
1353 // and max-systems-per-page constraints are satisfied.
1354 vector<int> page1_status;
1355 vector<int> page2_status;
1357 Page_spacing page1 (page1_height, this);
1358 Page_spacing page2 (page2_height, this);
1359 int page1_line_count = 0;
1360 int page2_line_count = 0;
1362 page1_force.resize (cached_line_details_.size () - 1, infinity_f);
1363 page2_force.resize (cached_line_details_.size () - 1, infinity_f);
1364 page1_penalty.resize (cached_line_details_.size () - 1, infinity_f);
1365 page2_penalty.resize (cached_line_details_.size () - 1, infinity_f);
1366 page1_status.resize (cached_line_details_.size () - 1, 0);
1367 page2_status.resize (cached_line_details_.size () - 1, 0);
1369 /* find the page 1 and page 2 forces for each page-breaking position */
1370 for (vsize i = 0; i < page1_force.size (); i++)
1372 page1.append_system (cached_line_details_[i]);
1373 page2.prepend_system (cached_line_details_[cached_line_details_.size () - 1 - i]);
1374 page1_line_count += cached_line_details_[i].compressed_nontitle_lines_count_;
1375 page2_line_count += cached_line_details_[cached_line_details_.size () - 1 - i].compressed_nontitle_lines_count_;
1377 page1_force[i] = (ragged1 && page1.force_ < 0 && i > 0) ? infinity_f : page1.force_;
1378 page1_penalty[i] = line_count_penalty (page1_line_count);
1379 page1_status[i] = line_count_status (page1_line_count);
1382 page2_force[page2_force.size () - 1 - i] =
1383 (page2.force_ < 0 && i + 1 < page1_force.size ()) ? infinity_f : 0;
1385 page2_force[page2_force.size () - 1 - i] = page2.force_;
1386 page2_penalty[page2_penalty.size () - 1 - i] = line_count_penalty (page2_line_count);
1387 page2_status[page2_penalty.size () - 1 - i] = line_count_status (page2_line_count);
1390 /* find the position that minimises the sum of the page forces */
1391 vsize best_sys_count = 1;
1392 Real best_demerits = infinity_f;
1393 for (vsize i = 0; i < page1_force.size (); i++)
1395 Real f = page1_force[i] * page1_force[i] + page2_force[i] * page2_force[i];
1397 // NOTE: we treat max-systems-per-page and min-systems-per-page as soft
1398 // constraints. That is, we penalize harshly when they don't happen
1399 // but we don't completely reject.
1401 + page1_penalty[i] + page2_penalty[i]
1402 + cached_line_details_[i+1].page_penalty_
1403 + cached_line_details_.back ().page_penalty_ + cached_line_details_.back ().turn_penalty_;
1404 if (dem < best_demerits)
1406 best_demerits = dem;
1407 best_sys_count = i+1;
1411 Page_spacing_result ret;
1412 ret.systems_per_page_.push_back (best_sys_count);
1413 ret.systems_per_page_.push_back (cached_line_details_.size () - best_sys_count);
1414 ret.force_.push_back (page1_force[best_sys_count-1]);
1415 ret.force_.push_back (page2_force[best_sys_count-1]);
1416 ret.system_count_status_ = page1_status[best_sys_count-1] | page2_status[best_sys_count-1];
1417 ret.penalty_ = cached_line_details_[best_sys_count-1].page_penalty_
1418 + cached_line_details_.back ().page_penalty_
1419 + cached_line_details_.back ().turn_penalty_
1420 + page1_penalty[best_sys_count-1] + page2_penalty[best_sys_count-1];
1422 /* don't do finalize_spacing_result () because we are only an internal function */
1427 Page_breaking::all_lines_stretched (vsize configuration)
1429 cache_line_details (configuration);
1430 for (vsize i = 0; i < cached_line_details_.size (); i++)
1431 if (cached_line_details_[i].force_ < 0)
1437 Page_breaking::Line_division
1438 Page_breaking::current_configuration (vsize configuration_index) const
1440 return current_configurations_[configuration_index];
1444 Page_breaking::is_last () const
1446 return current_end_breakpoint_ == last_break_position ();
1450 Page_breaking::ends_score () const
1452 return breaks_[current_end_breakpoint_].score_ender_;
1456 Page_breaking::last_break_position () const
1458 return breaks_.size () - 1;
1461 // This gives the minimum distance between the top of the
1462 // printable area (ie. the bottom of the top-margin) and
1463 // the extent box of the topmost system.
1465 Page_breaking::min_whitespace_at_top_of_page (Line_details const &line) const
1467 SCM first_system_spacing = book_->paper_->c_variable ("top-system-spacing");
1469 first_system_spacing = book_->paper_->c_variable ("top-markup-spacing");
1471 Real min_distance = -infinity_f;
1474 Page_layout_problem::read_spacing_spec (first_system_spacing,
1476 ly_symbol2scm ("minimum-distance"));
1477 Page_layout_problem::read_spacing_spec (first_system_spacing,
1479 ly_symbol2scm ("padding"));
1481 // FIXME: take into account the height of the header
1482 Real translate = max (line.shape_.begin_[UP], line.shape_.rest_[UP]);
1483 return max (0.0, max (padding, min_distance - translate));
1487 Page_breaking::min_whitespace_at_bottom_of_page (Line_details const &line) const
1489 SCM last_system_spacing = book_->paper_->c_variable ("last-bottom-spacing");
1490 Real min_distance = -infinity_f;
1493 Page_layout_problem::read_spacing_spec (last_system_spacing,
1495 ly_symbol2scm ("minimum-distance"));
1496 Page_layout_problem::read_spacing_spec (last_system_spacing,
1498 ly_symbol2scm ("padding"));
1500 // FIXME: take into account the height of the footer
1501 Real translate = min (line.shape_.begin_[DOWN], line.shape_.rest_[DOWN]);
1502 return max (0.0, max (padding, min_distance + translate));
1506 Page_breaking::orphan_penalty () const
1508 return orphan_penalty_;