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 if (systems_per_page_)
233 return systems_per_page_;
234 return max_systems_per_page_;
238 Page_breaking::min_systems_per_page () const
240 if (systems_per_page_)
241 return systems_per_page_;
242 return min_systems_per_page_;
246 Page_breaking::system_count () const
248 return system_count_;
252 Page_breaking::too_many_lines (int line_count) const
254 return max_systems_per_page () > 0 && line_count > max_systems_per_page ();
258 Page_breaking::too_few_lines (int line_count) const
260 return line_count < min_systems_per_page ();
264 Page_breaking::line_count_penalty (int line_count) const
266 if (too_many_lines (line_count))
267 return (line_count - max_systems_per_page ()) * TERRIBLE_SPACING_PENALTY;
268 if (too_few_lines (line_count))
269 return (min_systems_per_page () - line_count) * TERRIBLE_SPACING_PENALTY;
275 Page_breaking::line_count_status (int line_count) const
277 if (too_many_lines (line_count))
278 return SYSTEM_COUNT_TOO_MANY;
279 if (too_few_lines (line_count))
280 return SYSTEM_COUNT_TOO_FEW;
282 return SYSTEM_COUNT_OK;
285 /* translate indices into breaks_ into start-end parameters for the line breaker */
287 Page_breaking::line_breaker_args (vsize sys,
288 Break_position const &start,
289 Break_position const &end,
290 vsize *line_breaker_start,
291 vsize *line_breaker_end)
293 assert (system_specs_[sys].pscore_);
294 assert (next_system (start) <= sys && sys <= end.system_spec_index_);
296 if (start.system_spec_index_ == sys)
297 *line_breaker_start = start.score_break_;
299 *line_breaker_start = 0;
301 if (end.system_spec_index_ == sys)
302 *line_breaker_end = end.score_break_;
304 *line_breaker_end = VPOS;
308 Page_breaking::break_into_pieces (vsize start_break, vsize end_break,
309 Line_division const &div)
311 vector<Break_position> chunks = chunk_list (start_break, end_break);
312 bool ignore_div = false;
313 if (chunks.size () != div.size () + 1)
315 programming_error ("did not find a valid page breaking configuration");
319 for (vsize i = 0; i + 1 < chunks.size (); i++)
321 vsize sys = next_system (chunks[i]);
322 if (system_specs_[sys].pscore_)
326 line_breaker_args (sys, chunks[i], chunks[i+1], &start, &end);
328 vector<Column_x_positions> pos = ignore_div
329 ? line_breaking_[sys].best_solution (start, end)
330 : line_breaking_[sys].solve (start, end, div[i]);
331 system_specs_[sys].pscore_->root_system ()->break_into_pieces (pos);
337 Page_breaking::systems ()
340 for (vsize sys = 0; sys < system_specs_.size (); sys++)
342 if (system_specs_[sys].pscore_)
344 system_specs_[sys].pscore_->root_system ()
345 ->do_break_substitution_and_fixup_refpoints ();
346 SCM lines = system_specs_[sys].pscore_->root_system ()
347 ->get_broken_system_grobs ();
348 ret = scm_cons (lines, ret);
350 else if (Prob *pb = system_specs_[sys].prob_)
352 ret = scm_cons (scm_list_1 (pb->self_scm ()), ret);
356 return scm_append (scm_reverse (ret));
360 Page_breaking::make_page (int page_num, bool last) const
362 bool last_part = ly_scm2bool (book_->paper_->c_variable ("is-last-bookpart"));
363 SCM mod = scm_c_resolve_module ("scm page");
364 SCM make_page_scm = scm_c_module_lookup (mod, "make-page");
366 make_page_scm = scm_variable_ref (make_page_scm);
368 return scm_apply_0 (make_page_scm,
369 scm_list_n (book_->self_scm (),
370 ly_symbol2scm ("page-number"), scm_from_int (page_num),
371 ly_symbol2scm ("is-last-bookpart"), scm_from_bool (last_part),
372 ly_symbol2scm ("is-bookpart-last-page"), scm_from_bool (last),
376 // Returns the total height of the paper, including margins and
377 // space for the header/footer. This is an upper bound on
378 // page_height, and it doesn't depend on the current page.
380 Page_breaking::paper_height () const
382 return paper_height_;
386 Page_breaking::page_height (int page_num, bool last) const
388 // The caches allow us to store the page heights for any
389 // non-negative page numbers. We use a negative value in the
390 // cache to signal that that position has not yet been initialized.
391 // This means that we won't cache properly if page_num is negative or
392 // if calc_height returns a negative number. But that's likely to
393 // be rare, so it shouldn't affect performance.
394 vector<Real>& cache = last ? last_page_height_cache_ : page_height_cache_;
395 if (page_num >= 0 && (int) cache.size () > page_num && cache[page_num] >= 0)
396 return cache[page_num];
399 SCM mod = scm_c_resolve_module ("scm page");
400 SCM page = make_page (page_num, last);
401 SCM calc_height = scm_c_module_lookup (mod, "calc-printable-height");
402 calc_height = scm_variable_ref (calc_height);
404 SCM height_scm = scm_apply_1 (calc_height, page, SCM_EOL);
405 Real height = scm_to_double (height_scm);
409 if ((int) cache.size () <= page_num)
410 cache.resize (page_num + 1, -1);
411 cache[page_num] = height;
418 Page_breaking::breakpoint_property (vsize breakpoint, char const *str)
420 Break_position const &pos = breaks_[breakpoint];
422 if (pos.system_spec_index_ == VPOS)
424 if (system_specs_[pos.system_spec_index_].pscore_)
425 return pos.col_->get_property (str);
426 return system_specs_[pos.system_spec_index_].prob_->get_property (str);
430 Page_breaking::get_page_configuration (SCM systems, int page_num, bool ragged, bool last)
432 SCM dummy_page = make_page (page_num, last);
433 Page_layout_problem layout (book_, dummy_page, systems);
434 return scm_is_pair (systems) ? layout.solution (ragged) : SCM_EOL;
438 Page_breaking::draw_page (SCM systems, SCM configuration, int page_num, bool last)
440 // Create a stencil for each system.
441 SCM paper_systems = SCM_EOL;
442 for (SCM s = scm_reverse (systems); scm_is_pair (s); s = scm_cdr (s))
444 SCM paper_system = scm_car (s);
445 if (Grob *g = unsmob_grob (scm_car (s)))
447 System *sys = dynamic_cast<System*> (g);
448 paper_system = sys->get_paper_system ();
451 paper_systems = scm_cons (paper_system, paper_systems);
454 // Create the page and draw it.
455 SCM page = make_page (page_num, last);
456 SCM page_module = scm_c_resolve_module ("scm page");
457 SCM page_stencil = scm_c_module_lookup (page_module, "page-stencil");
458 page_stencil = scm_variable_ref (page_stencil);
460 Prob *p = unsmob_prob (page);
461 p->set_property ("lines", paper_systems);
462 p->set_property ("configuration", configuration);
463 scm_apply_1 (page_stencil, page, SCM_EOL);
469 Page_breaking::make_pages (vector<vsize> lines_per_page, SCM systems)
471 if (scm_is_null (systems))
474 int first_page_number
475 = robust_scm2int (book_->paper_->c_variable ("first-page-number"), 1);
477 SCM label_page_table = book_->top_paper ()->c_variable ("label-page-table");
478 if (label_page_table == SCM_UNDEFINED)
479 label_page_table = SCM_EOL;
481 // Build a list of (systems . configuration) pairs. Note that we lay out
482 // the staves and find the configurations before drawing anything. Some
483 // grobs (like tuplet brackets) look at their neighbours while drawing
484 // themselves. If this happens before the neighbouring staves have
485 // been laid out, bad side-effects could happen (in particular,
486 // Align_interface::align_to_ideal_distances might be called).
487 SCM systems_and_configs = SCM_EOL;
489 for (vsize i = 0; i < lines_per_page.size (); i++)
491 int page_num = i + first_page_number;
492 bool bookpart_last_page = (i == lines_per_page.size () - 1);
493 bool rag = ragged () || (bookpart_last_page && ragged_last ());
494 SCM line_count = scm_from_int (lines_per_page[i]);
495 SCM lines = scm_list_head (systems, line_count);
496 SCM config = get_page_configuration (lines, page_num, rag, bookpart_last_page);
498 systems_and_configs = scm_cons (scm_cons (lines, config), systems_and_configs);
499 systems = scm_list_tail (systems, line_count);
502 // Now it's safe to make the pages.
503 int page_num = first_page_number + lines_per_page.size () - 1;
504 for (SCM s = systems_and_configs; scm_is_pair (s); s = scm_cdr (s))
506 SCM lines = scm_caar (s);
507 SCM config = scm_cdar (s);
508 bool bookpart_last_page = (s == systems_and_configs);
509 SCM page = draw_page (lines, config, page_num, bookpart_last_page);
512 SCM page_num_scm = scm_from_int (page_num);
513 for (SCM l = lines ; scm_is_pair (l) ; l = scm_cdr (l))
515 SCM labels = SCM_EOL;
516 if (Grob * line = unsmob_grob (scm_car (l)))
518 System *system = dynamic_cast<System*> (line);
519 labels = system->get_property ("labels");
521 else if (Prob *prob = unsmob_prob (scm_car (l)))
522 labels = prob->get_property ("labels");
524 for (SCM lbls = labels ; scm_is_pair (lbls) ; lbls = scm_cdr (lbls))
525 label_page_table = scm_cons (scm_cons (scm_car (lbls), page_num_scm),
529 ret = scm_cons (page, ret);
532 book_->top_paper ()->set_variable (ly_symbol2scm ("label-page-table"), label_page_table);
536 /* The page-turn-page-breaker needs to have a line-breaker between any two
537 columns with non-NULL page-turn-permission.
539 The optimal-breaker needs to have a line-breaker between any two columns
540 with page-break-permission = 'force.
542 By using a grob predicate, we can accommodate both of these uses.
545 Page_breaking::create_system_list ()
547 SCM specs = book_->get_system_specs ();
548 for (SCM s = specs; scm_is_pair (s); s = scm_cdr (s))
550 if (Paper_score *ps = dynamic_cast<Paper_score*> (unsmob_music_output (scm_car (s))))
552 system_specs_.push_back (System_spec (ps));
556 Prob *pb = unsmob_prob (scm_car (s));
560 system_specs_.push_back (System_spec (pb));
563 if (!system_specs_.size ())
564 system_specs_.push_back (System_spec ());
568 Page_breaking::find_chunks_and_breaks (Break_predicate is_break, Prob_break_predicate prob_is_break)
570 SCM force_sym = ly_symbol2scm ("force");
572 chunks_.push_back (Break_position ());
573 breaks_.push_back (Break_position ());
575 for (vsize i = 0; i < system_specs_.size (); i++)
577 if (system_specs_[i].pscore_)
579 vector<Grob*> cols = system_specs_[i].pscore_->root_system ()->used_columns ();
580 vector<Grob*> forced_line_break_cols;
582 SCM system_count = system_specs_[i].pscore_->layout ()->c_variable ("system-count");
583 if (scm_is_number (system_count))
585 // With system-count given, the line configuration for
586 // this score is fixed. We need to ensure that chunk
587 // boundaries only occur at line breaks.
588 Constrained_breaking breaking (system_specs_[i].pscore_);
589 vector<Line_details> details = breaking.line_details (0, VPOS, scm_to_int (system_count));
591 for (vsize j = 0; j < details.size (); j++)
592 forced_line_break_cols.push_back (details[j].last_column_);
595 int last_forced_line_break_idx = 0;
596 vsize forced_line_break_idx = 0;
597 vector<vsize> line_breaker_columns;
598 line_breaker_columns.push_back (0);
600 for (vsize j = 1; j < cols.size (); j++)
602 if (forced_line_break_cols.size ())
604 if (forced_line_break_idx >= forced_line_break_cols.size ()
605 || forced_line_break_cols[forced_line_break_idx] != cols[j])
608 forced_line_break_idx++;
611 bool last = (j == cols.size () - 1);
612 bool break_point = is_break && is_break (cols[j]);
613 bool chunk_end = cols[j]->get_property ("page-break-permission") == force_sym;
614 Break_position cur_pos = Break_position (i,
615 line_breaker_columns.size (),
619 // NOTE: even in the breaks_ list, forced_line_count_
620 // refers to the number of lines between a
621 // Break_position and the start of that /chunk/. This
622 // is needed for system_count_bounds to work correctly,
623 // since it mixes Break_positions from breaks_ and
625 if (scm_is_number (system_count))
626 cur_pos.forced_line_count_ = forced_line_break_idx - last_forced_line_break_idx;
628 if (break_point || (i == system_specs_.size () - 1 && last))
629 breaks_.push_back (cur_pos);
630 if (chunk_end || last)
632 chunks_.push_back (cur_pos);
633 last_forced_line_break_idx = forced_line_break_idx;
636 if ((break_point || chunk_end) && !last)
637 line_breaker_columns.push_back (j);
639 line_breaking_.push_back (Constrained_breaking (system_specs_[i].pscore_, line_breaker_columns));
641 else if (system_specs_[i].prob_)
643 bool break_point = prob_is_break && prob_is_break (system_specs_[i].prob_);
644 if (break_point || i == system_specs_.size () - 1)
645 breaks_.push_back (Break_position (i));
647 chunks_.push_back (Break_position (i));
649 /* FIXME: shouldn't we push a Null_breaker or similar dummy
651 line_breaking_.push_back (Constrained_breaking (NULL));
656 vector<Break_position>
657 Page_breaking::chunk_list (vsize start_index, vsize end_index)
659 Break_position start = breaks_[start_index];
660 Break_position end = breaks_[end_index];
663 for (; i < chunks_.size () && chunks_[i] <= start; i++)
666 vector<Break_position> ret;
667 ret.push_back (start);
668 for (; i < chunks_.size () && chunks_[i] < end; i++)
669 ret.push_back (chunks_[i]);
674 // Returns the minimum number of _non-title_ lines.
676 Page_breaking::min_system_count (vsize start, vsize end)
678 vector<Break_position> chunks = chunk_list (start, end);
679 Line_division div = system_count_bounds (chunks, true);
682 for (vsize i = 0; i < div.size (); i++)
687 // Returns the maximum number of _non-title_ lines.
689 Page_breaking::max_system_count (vsize start, vsize end)
691 vector<Break_position> chunks = chunk_list (start, end);
692 Line_division div = system_count_bounds (chunks, false);
695 for (vsize i = 0; i < div.size (); i++)
700 // The numbers returned by this function represent either
701 // the maximum or minimum number of _non-title_ lines
703 Page_breaking::Line_division
704 Page_breaking::system_count_bounds (vector<Break_position> const &chunks,
707 assert (chunks.size () >= 2);
710 ret.resize (chunks.size () - 1, 0);
712 for (vsize i = 0; i + 1 < chunks.size (); i++)
714 vsize sys = next_system (chunks[i]);
716 if (chunks[i+1].forced_line_count_)
717 ret[i] = chunks[i+1].forced_line_count_;
718 else if (system_specs_[sys].pscore_)
722 line_breaker_args (sys, chunks[i], chunks[i+1], &start, &end);
724 ? line_breaking_[sys].min_system_count (start, end)
725 : line_breaking_[sys].max_system_count (start, end);
733 Page_breaking::set_current_breakpoints (vsize start,
736 Line_division lower_bound,
737 Line_division upper_bound)
739 system_count_ = system_count;
740 current_chunks_ = chunk_list (start, end);
741 current_start_breakpoint_ = start;
742 current_end_breakpoint_ = end;
743 clear_line_details_cache ();
745 if (!lower_bound.size ())
746 lower_bound = system_count_bounds (current_chunks_, true);
747 if (!upper_bound.size ())
748 upper_bound = system_count_bounds (current_chunks_, false);
750 assert (lower_bound.size () == current_chunks_.size () - 1);
751 assert (upper_bound.size () == current_chunks_.size () - 1);
753 Line_division work_in_progress;
754 current_configurations_.clear ();
755 line_divisions_rec (system_count,
760 /* we only consider a constant number of configurations. Otherwise,
761 this becomes slow when there are many small scores. The constant
762 5 is somewhat arbitrary. */
763 if (current_configurations_.size () > 5)
765 vector<pair<Real,vsize> > dems_and_indices;
767 for (vsize i = 0; i < current_configurations_.size (); i++)
769 cache_line_details (i);
771 for (vsize j = 0; j < cached_line_details_.size (); j++)
772 dem += cached_line_details_[j].force_ * cached_line_details_[j].force_
773 + cached_line_details_[j].break_penalty_;
775 dems_and_indices.push_back (pair<Real,vsize> (dem, i));
777 vector_sort (dems_and_indices, less<pair<Real,vsize> > ());
779 vector<Line_division> best_5_configurations;
780 for (vsize i = 0; i < 5; i++)
781 best_5_configurations.push_back (current_configurations_[dems_and_indices[i].second]);
783 clear_line_details_cache ();
784 current_configurations_ = best_5_configurations;
789 Page_breaking::set_to_ideal_line_configuration (vsize start, vsize end)
791 current_chunks_ = chunk_list (start, end);
792 current_start_breakpoint_ = start;
793 current_end_breakpoint_ = end;
794 clear_line_details_cache ();
798 for (vsize i = 0; i+1 < current_chunks_.size (); i++)
800 vsize sys = next_system (current_chunks_[i]);
802 if (current_chunks_[i+1].forced_line_count_)
803 div.push_back (current_chunks_[i+1].forced_line_count_);
804 else if (system_specs_[sys].pscore_)
806 line_breaker_args (sys, current_chunks_[i], current_chunks_[i+1], &start, &end);
807 div.push_back (line_breaking_[sys].best_solution (start, end).size ());
812 system_count_ += div.back ();
814 current_configurations_.clear ();
815 current_configurations_.push_back (div);
819 Page_breaking::current_configuration_count () const
821 return current_configurations_.size ();
825 Page_breaking::cache_line_details (vsize configuration_index)
827 if (cached_configuration_index_ != configuration_index)
829 cached_configuration_index_ = configuration_index;
831 Line_division &div = current_configurations_[configuration_index];
832 uncompressed_line_details_.clear ();
833 for (vsize i = 0; i + 1 < current_chunks_.size (); i++)
835 vsize sys = next_system (current_chunks_[i]);
836 if (system_specs_[sys].pscore_)
840 line_breaker_args (sys, current_chunks_[i], current_chunks_[i+1], &start, &end);
842 vector<Line_details> details = line_breaking_[sys].line_details (start, end, div[i]);
843 uncompressed_line_details_.insert (uncompressed_line_details_.end (), details.begin (), details.end ());
847 assert (div[i] == 0);
848 uncompressed_line_details_.push_back (system_specs_[sys].prob_
849 ? Line_details (system_specs_[sys].prob_, book_->paper_)
853 cached_line_details_ = compress_lines (uncompressed_line_details_);
854 compute_line_heights ();
859 Page_breaking::clear_line_details_cache ()
861 cached_configuration_index_ = VPOS;
862 cached_line_details_.clear ();
863 uncompressed_line_details_.clear ();
867 Page_breaking::line_divisions_rec (vsize system_count,
868 Line_division const &min_sys,
869 Line_division const &max_sys,
870 Line_division *cur_division)
872 vsize my_index = cur_division->size ();
876 for (vsize i = my_index + 1; i < min_sys.size (); i++)
878 others_min += min_sys[i];
879 others_max += max_sys[i];
881 others_max = min (others_max, (int) system_count);
882 int real_min = max ((int) min_sys[my_index], (int) system_count - others_max);
883 int real_max = min ((int) max_sys[my_index], (int) system_count - others_min);
885 if (real_min > real_max || real_min < 0)
887 /* this should never happen within a recursive call. If it happens
888 at all, it means that we were called with an unsolvable problem
889 and we should return an empty result */
890 assert (my_index == 0);
894 for (int i = real_min; i <= real_max; i++)
896 cur_division->push_back (i);
897 if (my_index == min_sys.size () - 1)
898 current_configurations_.push_back (*cur_division);
900 line_divisions_rec (system_count - i, min_sys, max_sys, cur_division);
901 cur_division->pop_back ();
906 Page_breaking::compute_line_heights ()
908 Real prev_hanging = 0;
909 Real prev_hanging_begin = 0;
910 Real prev_hanging_rest = 0;
912 // refpoint_hanging is the y coordinate of the origin of this system.
913 // It may not be the same as refpoint_extent[UP], which is the
914 // refpoint of the first spaceable staff in this system.
915 Real prev_refpoint_hanging = 0;
916 for (vsize i = 0; i < cached_line_details_.size (); i++)
918 Line_details& cur = cached_line_details_[i];
919 Line_shape shape = cur.shape_;
920 Real a = shape.begin_[UP];
921 Real b = shape.rest_[UP];
922 bool title = cur.title_;
923 Real refpoint_hanging = max (prev_hanging_begin + a, prev_hanging_rest + b);
928 Line_details const& prev = cached_line_details_[i-1];
929 if (!cur.tight_spacing_)
931 ? prev.title_padding_
933 Real min_dist = title
934 ? prev.title_min_distance_
935 : prev.min_distance_;
936 refpoint_hanging = max (refpoint_hanging + padding,
937 prev_refpoint_hanging - prev.refpoint_extent_[DOWN]
938 + cur.refpoint_extent_[UP] + min_dist);
941 Real hanging_begin = refpoint_hanging - shape.begin_[DOWN];
942 Real hanging_rest = refpoint_hanging - shape.rest_[DOWN];
943 Real hanging = max (hanging_begin, hanging_rest);
944 cur.tallness_ = hanging - prev_hanging;
945 prev_hanging = hanging;
946 prev_hanging_begin = hanging_begin;
947 prev_hanging_rest = hanging_rest;
948 prev_refpoint_hanging = refpoint_hanging;
953 Page_breaking::min_page_count (vsize configuration, vsize first_page_num)
956 vsize page_starter = 0;
957 Real cur_rod_height = 0;
958 Real cur_spring_height = 0;
959 Real cur_page_height = page_height (first_page_num, false);
962 cache_line_details (configuration);
964 if (cached_line_details_.size ())
965 cur_page_height -= min_whitespace_at_top_of_page (cached_line_details_[0]);
967 for (vsize i = 0; i < cached_line_details_.size (); i++)
969 Line_details const &cur = cached_line_details_[i];
970 Line_details const *const prev = (i > 0) ? &cached_line_details_[i-1] : 0;
972 if (cur_rod_height > 0)
973 ext_len = cur.tallness_;
975 ext_len = cur.full_height();
977 Real spring_len = (i > 0) ? prev->spring_length (cur) : 0;
978 Real next_rod_height = cur_rod_height + ext_len;
979 Real next_spring_height = cur_spring_height + spring_len;
980 Real next_height = next_rod_height + (ragged () ? next_spring_height : 0)
981 + min_whitespace_at_bottom_of_page (cur);
982 int next_line_count = line_count + cur.compressed_nontitle_lines_count_;
984 if ((!too_few_lines (line_count) && (next_height > cur_page_height && cur_rod_height > 0))
985 || too_many_lines (next_line_count)
986 || (prev && prev->page_permission_ == ly_symbol2scm ("force")))
988 line_count = cur.compressed_nontitle_lines_count_;
989 cur_rod_height = cur.full_height();
990 cur_spring_height = 0;
993 cur_page_height = page_height (first_page_num + ret, false);
994 cur_page_height -= min_whitespace_at_top_of_page (cur);
1000 cur_rod_height = next_rod_height;
1001 cur_spring_height = next_spring_height;
1002 line_count = next_line_count;
1006 /* there are two potential problems with the last page (because we didn't know
1007 it was the last page until after we managed to fit all the systems to it):
1008 - we are ragged-last but the last page has a compressed spring
1009 - the value returned by page_height (num, true) is smaller than the
1010 value returned by page_height (num, false) and it causes the page not to
1013 In either case, we just need to add one more page. This is because the last
1014 line will always fit on the extra page and by adding one more page to the
1015 end, the previous page is no longer the last page, so our previous
1016 calculations that treated it as a non-last page were ok.
1021 cur_page_height = page_height (first_page_num + ret - 1, true);
1022 cur_page_height -= min_whitespace_at_top_of_page (cached_line_details_[page_starter]);
1023 cur_page_height -= min_whitespace_at_bottom_of_page (cached_line_details_.back ());
1025 Real cur_height = cur_rod_height + ((ragged_last () || ragged ()) ? cur_spring_height : 0);
1026 if (!too_few_lines (line_count - cached_line_details_.back ().compressed_nontitle_lines_count_)
1027 && cur_height > cur_page_height
1028 /* don't increase the page count if the last page had only one system */
1029 && cur_rod_height > cached_line_details_.back ().full_height ())
1031 assert (ret <= cached_line_details_.size ());
1037 // If systems_per_page_ is positive, we don't really try to space on N pages;
1038 // we just put the requested number of systems on each page and penalize
1039 // if the result doesn't have N pages.
1041 Page_breaking::space_systems_on_n_pages (vsize configuration, vsize n, vsize first_page_num)
1043 Page_spacing_result ret;
1045 if (systems_per_page_ > 0)
1047 Page_spacing_result ret = space_systems_with_fixed_number_per_page (configuration, first_page_num);
1048 ret.demerits_ += (ret.force_.size () == n) ? 0 : BAD_SPACING_PENALTY;
1052 cache_line_details (configuration);
1053 bool valid_n = (n >= min_page_count (configuration, first_page_num)
1054 && n <= cached_line_details_.size ());
1057 programming_error ("number of pages is out of bounds");
1059 if (n == 1 && valid_n)
1060 ret = space_systems_on_1_page (cached_line_details_,
1061 page_height (first_page_num, is_last ()),
1062 ragged () || (is_last () && ragged_last ()));
1063 else if (n == 2 && valid_n)
1064 ret = space_systems_on_2_pages (configuration, first_page_num);
1067 Page_spacer ps (cached_line_details_, first_page_num, this);
1071 return finalize_spacing_result (configuration, ret);
1075 Page_breaking::blank_page_penalty () const
1080 penalty_sym = ly_symbol2scm ("blank-last-page-force");
1081 else if (ends_score ())
1082 penalty_sym = ly_symbol2scm ("blank-after-score-page-force");
1084 penalty_sym = ly_symbol2scm ("blank-page-force");
1086 Break_position const &pos = breaks_[current_end_breakpoint_];
1087 if (Paper_score *ps = system_specs_[pos.system_spec_index_].pscore_)
1088 return robust_scm2double (ps->layout ()->lookup_variable (penalty_sym), 0.0);
1090 return robust_scm2double (book_->paper_->lookup_variable (penalty_sym), 0.0);
1093 // If systems_per_page_ is positive, we don't really try to space on N
1094 // or N+1 pages; see the comment to space_systems_on_n_pages.
1096 Page_breaking::space_systems_on_n_or_one_more_pages (vsize configuration, vsize n, vsize first_page_num,
1097 Real penalty_for_fewer_pages)
1099 Page_spacing_result n_res;
1100 Page_spacing_result m_res;
1102 if (systems_per_page_ > 0)
1104 Page_spacing_result ret = space_systems_with_fixed_number_per_page (configuration, first_page_num);
1105 ret.demerits_ += (ret.force_.size () == n || ret.force_.size () == (n-1)) ? 0 : BAD_SPACING_PENALTY;
1109 cache_line_details (configuration);
1110 vsize min_p_count = min_page_count (configuration, first_page_num);
1111 bool valid_n = n >= min_p_count || n <= cached_line_details_.size ();
1114 programming_error ("both page counts are out of bounds");
1116 if (n == 1 && valid_n)
1118 bool rag = ragged () || (is_last () && ragged_last ());
1119 Real height = page_height (first_page_num, is_last ());
1121 if (1 >= min_p_count)
1122 n_res = space_systems_on_1_page (cached_line_details_, height, rag);
1123 if (1 < cached_line_details_.size ())
1124 m_res = space_systems_on_2_pages (configuration, first_page_num);
1128 Page_spacer ps (cached_line_details_, first_page_num, this);
1130 if (n >= min_p_count || !valid_n)
1131 n_res = ps.solve (n);
1132 if (n < cached_line_details_.size () || !valid_n)
1133 m_res = ps.solve (n+1);
1136 m_res = finalize_spacing_result (configuration, m_res);
1137 n_res = finalize_spacing_result (configuration, n_res);
1139 Real page_spacing_weight = robust_scm2double (book_->paper_->c_variable ("page-spacing-weight"), 10);
1140 n_res.demerits_ += penalty_for_fewer_pages * page_spacing_weight;
1142 if (n_res.force_.size ())
1143 n_res.force_.back () += penalty_for_fewer_pages;
1145 return (m_res.demerits_ < n_res.demerits_) ? m_res : n_res;
1149 Page_breaking::space_systems_on_best_pages (vsize configuration, vsize first_page_num)
1151 if (systems_per_page_ > 0)
1152 return space_systems_with_fixed_number_per_page (configuration, first_page_num);
1154 cache_line_details (configuration);
1155 Page_spacer ps (cached_line_details_, first_page_num, this);
1157 return finalize_spacing_result (configuration, ps.solve ());
1161 Page_breaking::space_systems_with_fixed_number_per_page (vsize configuration,
1162 vsize first_page_num)
1164 Page_spacing_result res;
1165 Page_spacing space (page_height (first_page_num, false), this);
1168 vsize page_first_line = 0;
1170 cache_line_details (configuration);
1171 while (line < cached_line_details_.size ())
1175 space.resize (page_height (first_page_num + page, false));
1177 int system_count_on_this_page = 0;
1178 while (system_count_on_this_page < systems_per_page_
1179 && line < cached_line_details_.size ())
1181 Line_details const &cur_line = cached_line_details_[line];
1182 space.append_system (cur_line);
1183 system_count_on_this_page += cur_line.compressed_nontitle_lines_count_;
1186 if (cur_line.page_permission_ == ly_symbol2scm ("force"))
1190 res.systems_per_page_.push_back (line - page_first_line);
1192 res.force_.push_back (space.force_);
1193 res.penalty_ += cached_line_details_[line-1].page_penalty_;
1194 if (system_count_on_this_page != systems_per_page_)
1196 res.penalty_ += abs (system_count_on_this_page - systems_per_page_) * TERRIBLE_SPACING_PENALTY;
1197 res.system_count_status_ |= ((system_count_on_this_page < systems_per_page_))
1198 ? SYSTEM_COUNT_TOO_FEW : SYSTEM_COUNT_TOO_MANY;
1201 page_first_line = line;
1204 /* Recalculate forces for the last page because we know now that is
1205 really the last page. */
1206 space.resize (page_height (first_page_num + page, true));
1207 res.force_.back () = space.force_;
1208 return finalize_spacing_result (configuration, res);
1212 Page_breaking::pack_systems_on_least_pages (vsize configuration, vsize first_page_num)
1214 // TODO: add support for min/max-systems-per-page.
1215 Page_spacing_result res;
1217 vsize page_first_line = 0;
1218 Page_spacing space (page_height (first_page_num, false), this);
1220 cache_line_details (configuration);
1221 for (vsize line = 0; line < cached_line_details_.size (); line++)
1223 Real prev_force = space.force_;
1224 space.append_system (cached_line_details_[line]);
1225 if ((line > page_first_line)
1226 && (isinf (space.force_)
1228 && (cached_line_details_[line-1].page_permission_ == ly_symbol2scm ("force")))))
1230 res.systems_per_page_.push_back (line - page_first_line);
1231 res.force_.push_back (prev_force);
1232 res.penalty_ += cached_line_details_[line-1].page_penalty_;
1234 space.resize (page_height (first_page_num + page, false));
1236 space.append_system (cached_line_details_[line]);
1237 page_first_line = line;
1240 if (line == cached_line_details_.size () - 1)
1242 /* This is the last line */
1243 /* When the last page height was computed, we did not know yet that it
1244 * was the last one. If the systems put on it don't fit anymore, the last
1245 * system is moved to a new page */
1246 space.resize (page_height (first_page_num + page, true));
1247 if ((line > page_first_line) && (isinf (space.force_)))
1249 res.systems_per_page_.push_back (line - page_first_line);
1250 res.force_.push_back (prev_force);
1251 /* the last page containing the last line */
1252 space.resize (page_height (first_page_num + page + 1, true));
1254 space.append_system (cached_line_details_[line]);
1255 res.systems_per_page_.push_back (1);
1256 res.force_.push_back (space.force_);
1257 res.penalty_ += cached_line_details_[line-1].page_penalty_;
1258 res.penalty_ += cached_line_details_[line].page_penalty_;
1262 res.systems_per_page_.push_back (line + 1 - page_first_line);
1263 res.force_.push_back (space.force_);
1264 res.penalty_ += cached_line_details_[line].page_penalty_;
1268 return finalize_spacing_result (configuration, res);
1271 /* Calculate demerits and fix res.systems_per_page_ so that
1272 it refers to the original line numbers, not the ones given by compress_lines (). */
1274 Page_breaking::finalize_spacing_result (vsize configuration, Page_spacing_result res)
1276 if (res.force_.empty ())
1279 cache_line_details (configuration);
1280 res.systems_per_page_ = uncompress_solution (res.systems_per_page_, cached_line_details_);
1282 Real line_force = 0;
1283 Real line_penalty = 0;
1284 Real page_demerits = res.penalty_;
1285 Real page_weighting = robust_scm2double (book_->paper_->c_variable ("page-spacing-weight"), 10);
1287 for (vsize i = 0; i < uncompressed_line_details_.size (); i++)
1289 line_force += uncompressed_line_details_[i].force_ * uncompressed_line_details_[i].force_;
1290 line_penalty += uncompressed_line_details_[i].break_penalty_;
1293 for (vsize i = 0; i < res.force_.size (); i++)
1295 Real f = res.force_[i];
1297 page_demerits += min(f*f, BAD_SPACING_PENALTY);
1300 /* for a while we tried averaging page and line forces across pages instead
1301 of summing them, but it caused a problem: if there is a single page
1302 with a very bad page force (for example because of a forced page break),
1303 the page breaker will put in a _lot_ of pages so that the bad force
1304 becomes averaged out over many pages. */
1305 res.demerits_ = line_force + line_penalty + page_demerits * page_weighting;
1310 /* the cases for page_count = 1 or 2 can be done in O (n) time. Since they
1311 are by far the most common cases, we have special functions for them.
1313 space_systems_on_1_page has a different calling convention than most of the
1314 space_systems functions. This is because space_systems_on_1_page is (unlike
1315 the other space_systems functions) sometimes called on subsets of a full
1318 Page_breaking::space_systems_on_1_page (vector<Line_details> const &lines, Real page_height, bool ragged)
1320 Page_spacing space (page_height, this);
1321 Page_spacing_result ret;
1324 for (vsize i = 0; i < lines.size (); i++)
1326 space.append_system (lines[i]);
1327 line_count += lines[i].compressed_nontitle_lines_count_;
1330 ret.systems_per_page_.push_back (lines.size ());
1331 ret.force_.push_back (ragged ? min (space.force_, 0.0) : space.force_);
1332 ret.penalty_ = line_count_penalty (line_count) + lines.back ().page_penalty_ + lines.back ().turn_penalty_;
1333 ret.system_count_status_ |= line_count_status (line_count);
1335 /* don't do finalize_spacing_result () because we are only an internal function */
1340 Page_breaking::space_systems_on_2_pages (vsize configuration, vsize first_page_num)
1342 Real page1_height = page_height (first_page_num, false);
1343 Real page2_height = page_height (first_page_num + 1, is_last ());
1344 bool ragged1 = ragged ();
1345 bool ragged2 = ragged () || (is_last () && ragged_last ());
1347 /* if there is a forced break, this reduces to 2 1-page problems */
1348 cache_line_details (configuration);
1349 for (vsize i = 0; i + 1 < cached_line_details_.size (); i++)
1350 if (cached_line_details_[i].page_permission_ == ly_symbol2scm ("force"))
1352 vector<Line_details> lines1 (cached_line_details_.begin (), cached_line_details_.begin () + i + 1);
1353 vector<Line_details> lines2 (cached_line_details_.begin () + i + 1, cached_line_details_.end ());
1354 Page_spacing_result p1 = space_systems_on_1_page (lines1, page1_height, ragged1);
1355 Page_spacing_result p2 = space_systems_on_1_page (lines2, page2_height, ragged2);
1357 p1.systems_per_page_.push_back (p2.systems_per_page_[0]);
1358 p1.force_.push_back (p2.force_[0]);
1359 p1.penalty_ += p2.penalty_ - cached_line_details_[i].turn_penalty_;
1360 p1.system_count_status_ |= p2.system_count_status_;
1364 vector<Real> page1_force;
1365 vector<Real> page2_force;
1367 // page1_penalty and page2_penalty store the penalties based
1368 // on min-systems-per-page and max-systems-per-page.
1369 vector<Real> page1_penalty;
1370 vector<Real> page2_penalty;
1372 // page1_status and page2_status keep track of whether the min-systems-per-page
1373 // and max-systems-per-page constraints are satisfied.
1374 vector<int> page1_status;
1375 vector<int> page2_status;
1377 Page_spacing page1 (page1_height, this);
1378 Page_spacing page2 (page2_height, this);
1379 int page1_line_count = 0;
1380 int page2_line_count = 0;
1382 page1_force.resize (cached_line_details_.size () - 1, infinity_f);
1383 page2_force.resize (cached_line_details_.size () - 1, infinity_f);
1384 page1_penalty.resize (cached_line_details_.size () - 1, infinity_f);
1385 page2_penalty.resize (cached_line_details_.size () - 1, infinity_f);
1386 page1_status.resize (cached_line_details_.size () - 1, 0);
1387 page2_status.resize (cached_line_details_.size () - 1, 0);
1389 /* find the page 1 and page 2 forces for each page-breaking position */
1390 for (vsize i = 0; i < page1_force.size (); i++)
1392 page1.append_system (cached_line_details_[i]);
1393 page2.prepend_system (cached_line_details_[cached_line_details_.size () - 1 - i]);
1394 page1_line_count += cached_line_details_[i].compressed_nontitle_lines_count_;
1395 page2_line_count += cached_line_details_[cached_line_details_.size () - 1 - i].compressed_nontitle_lines_count_;
1397 page1_force[i] = (ragged1 && page1.force_ < 0 && i > 0) ? infinity_f : page1.force_;
1398 page1_penalty[i] = line_count_penalty (page1_line_count);
1399 page1_status[i] = line_count_status (page1_line_count);
1402 page2_force[page2_force.size () - 1 - i] =
1403 (page2.force_ < 0 && i + 1 < page1_force.size ()) ? infinity_f : 0;
1405 page2_force[page2_force.size () - 1 - i] = page2.force_;
1406 page2_penalty[page2_penalty.size () - 1 - i] = line_count_penalty (page2_line_count);
1407 page2_status[page2_penalty.size () - 1 - i] = line_count_status (page2_line_count);
1410 /* find the position that minimises the sum of the page forces */
1411 vsize best_sys_count = 1;
1412 Real best_demerits = infinity_f;
1413 for (vsize i = 0; i < page1_force.size (); i++)
1415 Real f = page1_force[i] * page1_force[i] + page2_force[i] * page2_force[i];
1417 // NOTE: we treat max-systems-per-page and min-systems-per-page as soft
1418 // constraints. That is, we penalize harshly when they don't happen
1419 // but we don't completely reject.
1421 + page1_penalty[i] + page2_penalty[i]
1422 + cached_line_details_[i+1].page_penalty_
1423 + cached_line_details_.back ().page_penalty_ + cached_line_details_.back ().turn_penalty_;
1424 if (dem < best_demerits)
1426 best_demerits = dem;
1427 best_sys_count = i+1;
1431 Page_spacing_result ret;
1432 ret.systems_per_page_.push_back (best_sys_count);
1433 ret.systems_per_page_.push_back (cached_line_details_.size () - best_sys_count);
1434 ret.force_.push_back (page1_force[best_sys_count-1]);
1435 ret.force_.push_back (page2_force[best_sys_count-1]);
1436 ret.system_count_status_ = page1_status[best_sys_count-1] | page2_status[best_sys_count-1];
1437 ret.penalty_ = cached_line_details_[best_sys_count-1].page_penalty_
1438 + cached_line_details_.back ().page_penalty_
1439 + cached_line_details_.back ().turn_penalty_
1440 + page1_penalty[best_sys_count-1] + page2_penalty[best_sys_count-1];
1442 /* don't do finalize_spacing_result () because we are only an internal function */
1447 Page_breaking::all_lines_stretched (vsize configuration)
1449 cache_line_details (configuration);
1450 for (vsize i = 0; i < cached_line_details_.size (); i++)
1451 if (cached_line_details_[i].force_ < 0)
1457 Page_breaking::Line_division
1458 Page_breaking::current_configuration (vsize configuration_index) const
1460 return current_configurations_[configuration_index];
1464 Page_breaking::is_last () const
1466 return current_end_breakpoint_ == last_break_position ();
1470 Page_breaking::ends_score () const
1472 return breaks_[current_end_breakpoint_].score_ender_;
1476 Page_breaking::last_break_position () const
1478 return breaks_.size () - 1;
1481 // This gives the minimum distance between the top of the
1482 // printable area (ie. the bottom of the top-margin) and
1483 // the extent box of the topmost system.
1485 Page_breaking::min_whitespace_at_top_of_page (Line_details const &line) const
1487 SCM first_system_spacing = book_->paper_->c_variable ("top-system-spacing");
1489 first_system_spacing = book_->paper_->c_variable ("top-markup-spacing");
1491 Real min_distance = -infinity_f;
1494 Page_layout_problem::read_spacing_spec (first_system_spacing,
1496 ly_symbol2scm ("minimum-distance"));
1497 Page_layout_problem::read_spacing_spec (first_system_spacing,
1499 ly_symbol2scm ("padding"));
1501 // FIXME: take into account the height of the header
1502 Real translate = max (line.shape_.begin_[UP], line.shape_.rest_[UP]);
1503 return max (0.0, max (padding, min_distance - translate));
1507 Page_breaking::min_whitespace_at_bottom_of_page (Line_details const &line) const
1509 SCM last_system_spacing = book_->paper_->c_variable ("last-bottom-spacing");
1510 Real min_distance = -infinity_f;
1513 Page_layout_problem::read_spacing_spec (last_system_spacing,
1515 ly_symbol2scm ("minimum-distance"));
1516 Page_layout_problem::read_spacing_spec (last_system_spacing,
1518 ly_symbol2scm ("padding"));
1520 // FIXME: take into account the height of the footer
1521 Real translate = min (line.shape_.begin_[DOWN], line.shape_.rest_[DOWN]);
1522 return max (0.0, max (padding, min_distance + translate));
1526 Page_breaking::orphan_penalty () const
1528 return orphan_penalty_;