/*
This file is part of LilyPond, the GNU music typesetter.
- Copyright (C) 2006--2011 Joe Neeman <joeneeman@gmail.com>
+ Copyright (C) 2006--2014 Joe Neeman <joeneeman@gmail.com>
LilyPond is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
compressed.title_ = old.title_;
// adds footnotes of one line to the footnotes of another
- compressed.footnotes_.insert (compressed.footnotes_.begin (),
- old.footnotes_.begin (), old.footnotes_.end ());
+ compressed.footnote_heights_.insert (compressed.footnote_heights_.begin (),
+ old.footnote_heights_.begin (),
+ old.footnote_heights_.end ());
+ compressed.in_note_heights_.insert (compressed.in_note_heights_.begin (),
+ old.in_note_heights_.begin (),
+ old.in_note_heights_.end ());
ret.back () = compressed;
}
else
{
ret.push_back (orig[i]);
- ret.back ().force_ = 0;
}
}
return ret;
min_systems_per_page_ = max (0, robust_scm2int (pb->paper_->c_variable ("min-systems-per-page"), 0));
orphan_penalty_ = robust_scm2int (pb->paper_->c_variable ("orphan-penalty"), 100000);
- Stencil *footnote_separator = Page_layout_problem::get_footnote_separator_stencil (pb->paper_);
+ Stencil footnote_separator = Page_layout_problem::get_footnote_separator_stencil (pb->paper_);
- if (footnote_separator)
+ if (!footnote_separator.is_empty ())
{
- Interval separator_extent = footnote_separator->extent (Y_AXIS);
+ Interval separator_extent = footnote_separator.extent (Y_AXIS);
Real separator_span = separator_extent.length ();
footnote_separator_stencil_height_ = separator_span;
footnote_separator_stencil_height_ = 0.0;
footnote_padding_ = robust_scm2double (pb->paper_->c_variable ("footnote-padding"), 0.0);
+ in_note_padding_ = robust_scm2double (pb->paper_->c_variable ("in-note-padding"), 0.0);
footnote_footer_padding_ = robust_scm2double (pb->paper_->c_variable ("footnote-footer-padding"), 0.0);
- footnote_number_raise_ = (to_boolean (pb->paper_->c_variable ("footnote-auto-numbering"))
- ? robust_scm2double (pb->paper_->c_variable ("footnote-number-raise"), 0.0)
- : 0.0);
+ footnote_number_raise_ = robust_scm2double (pb->paper_->c_variable ("footnote-number-raise"), 0.0);
if (systems_per_page_ && (max_systems_per_page_ || min_systems_per_page_))
{
return footnote_separator_stencil_height_;
}
+Real
+Page_breaking::in_note_padding () const
+{
+ return in_note_padding_;
+}
+
Real
Page_breaking::footnote_padding () const
{
pb->unprotect ();
}
}
- return scm_append (scm_reverse (ret));
+ return scm_append (scm_reverse_x (ret, SCM_EOL));
}
SCM
// This means that we won't cache properly if page_num is negative or
// if calc_height returns a negative number. But that's likely to
// be rare, so it shouldn't affect performance.
- vector<Real>& cache = last ? last_page_height_cache_ : page_height_cache_;
+ vector<Real> &cache = last ? last_page_height_cache_ : page_height_cache_;
if (page_num >= 0 && (int) cache.size () > page_num && cache[page_num] >= 0)
return cache[page_num];
else
}
SCM
-Page_breaking::get_page_configuration (SCM systems, int page_num, int footnote_count, bool ragged, bool last)
+Page_breaking::get_page_configuration (SCM systems, int page_num, bool ragged, bool last)
{
SCM dummy_page = make_page (page_num, last);
- Page_layout_problem layout (book_, dummy_page, systems, footnote_count);
+ Page_layout_problem layout (book_, dummy_page, systems);
return scm_is_pair (systems) ? layout.solution (ragged) : SCM_EOL;
}
SCM
-Page_breaking::draw_page (SCM systems, SCM configuration, int page_num, int footnote_num, bool last)
+Page_breaking::draw_page (SCM systems, SCM configuration, int page_num, bool last)
{
// Create a stencil for each system.
SCM paper_systems = SCM_EOL;
- for (SCM s = scm_reverse (systems); scm_is_pair (s); s = scm_cdr (s))
+ for (SCM s = systems; scm_is_pair (s); s = scm_cdr (s))
{
SCM paper_system = scm_car (s);
- if (Grob *g = unsmob_grob (scm_car (s)))
+ if (Grob *g = Grob::unsmob (scm_car (s)))
{
System *sys = dynamic_cast<System *> (g);
paper_system = sys->get_paper_system ();
paper_systems = scm_cons (paper_system, paper_systems);
}
+ paper_systems = scm_reverse_x (paper_systems, SCM_EOL);
// Create the page and draw it.
SCM page = make_page (page_num, last);
- SCM page_module = scm_c_resolve_module ("scm page");
- SCM page_stencil = scm_c_module_lookup (page_module, "page-stencil");
- page_stencil = scm_variable_ref (page_stencil);
- Prob *p = unsmob_prob (page);
+ Prob *p = Prob::unsmob (page);
p->set_property ("lines", paper_systems);
p->set_property ("configuration", configuration);
- Stencil *foot = unsmob_stencil (p->get_property ("foot-stencil"));
-
- footnote_num = (to_boolean (book_->paper_->c_variable ("reset-footnotes-on-new-page"))
- ? 0
- : footnote_num);
+ Stencil *foot_p = Stencil::unsmob (p->get_property ("foot-stencil"));
+ Stencil foot = foot_p ? *foot_p : Stencil ();
- SCM footnotes = Page_layout_problem::get_footnotes_from_lines (systems,
- footnote_num,
- book_);
+ SCM footnotes = Page_layout_problem::get_footnotes_from_lines (systems);
- Page_layout_problem::add_footnotes_to_footer (footnotes, foot, book_);
+ foot = Page_layout_problem::add_footnotes_to_footer (footnotes, foot, book_);
- if (foot)
- p->set_property ("foot-stencil", foot->smobbed_copy ());
- scm_apply_1 (page_stencil, page, SCM_EOL);
+ p->set_property ("foot-stencil", foot.smobbed_copy ());
return page;
}
int first_page_number
= robust_scm2int (book_->paper_->c_variable ("first-page-number"), 1);
SCM ret = SCM_EOL;
+ bool reset_footnotes_on_new_page = to_boolean (book_->top_paper ()->c_variable ("reset-footnotes-on-new-page"));
SCM label_page_table = book_->top_paper ()->c_variable ("label-page-table");
if (label_page_table == SCM_UNDEFINED)
label_page_table = SCM_EOL;
- // Build a list of (systems . configuration) pairs. Note that we lay out
- // the staves and find the configurations before drawing anything. Some
+ // Build a list of (systems configuration . footnote-count) triples.
+ // Note that we lay out the staves and find the configurations,
+ // but we do not draw anything in this function. It is important
+ // that all staves are laid out vertically before any are drawn; some
// grobs (like tuplet brackets) look at their neighbours while drawing
- // themselves. If this happens before the neighbouring staves have
+ // themselves. If this happens before the neighbouring staves have
// been laid out, bad side-effects could happen (in particular,
// Align_interface::align_to_ideal_distances might be called).
SCM systems_configs_fncounts = SCM_EOL;
vsize footnote_count = 0;
+ Real last_page_force = 0;
for (vsize i = 0; i < lines_per_page.size (); i++)
{
SCM line_count = scm_from_int (lines_per_page[i]);
SCM lines = scm_list_head (systems, line_count);
int fn_lines = Page_layout_problem::get_footnote_count (lines);
- SCM config = get_page_configuration (lines, page_num, footnote_count, rag, bookpart_last_page);
+ Page_layout_problem::add_footnotes_to_lines (lines, reset_footnotes_on_new_page ? 0 : footnote_count, book_);
+
+ SCM config = SCM_EOL;
+ SCM dummy_page = make_page (page_num, bookpart_last_page);
+ Page_layout_problem layout (book_, dummy_page, lines);
+ if (!scm_is_pair (systems))
+ config = SCM_EOL;
+ else if (rag && !ragged ())
+ // If we're ragged-last but not ragged, make the last page
+ // have the same force as the previous page.
+ config = layout.fixed_force_solution (last_page_force);
+ else
+ config = layout.solution (rag);
- systems_configs_fncounts = scm_cons (scm_list_3 (lines, config, scm_from_int ((int)footnote_count)), systems_configs_fncounts);
+ if ((ragged () && layout.force () < 0.0)
+ || isinf (layout.force ()))
+ warning (_f ("page %d has been compressed", page_num));
+ else
+ last_page_force = layout.force ();
+
+ systems_configs_fncounts = scm_cons (scm_cons (lines, config), systems_configs_fncounts);
footnote_count += fn_lines;
systems = scm_list_tail (systems, line_count);
}
- // Now it's safe to make the pages.
+ // TODO: previously, the following loop caused the systems to be
+ // drawn. Now that we no longer draw anything in Page_breaking,
+ // it is safe to merge these two loops.
int page_num = first_page_number + lines_per_page.size () - 1;
for (SCM s = systems_configs_fncounts; scm_is_pair (s); s = scm_cdr (s))
{
SCM lines = scm_caar (s);
- SCM config = scm_cadar (s);
- int footnote_num = scm_to_int (scm_caddar (s));
+ SCM config = scm_cdar (s);
bool bookpart_last_page = (s == systems_configs_fncounts);
- SCM page = draw_page (lines, config, page_num, footnote_num, bookpart_last_page);
+ SCM page = draw_page (lines, config, page_num, bookpart_last_page);
/* collect labels */
SCM page_num_scm = scm_from_int (page_num);
for (SCM l = lines; scm_is_pair (l); l = scm_cdr (l))
{
SCM labels = SCM_EOL;
- if (Grob *line = unsmob_grob (scm_car (l)))
+ if (Grob *line = Grob::unsmob (scm_car (l)))
{
System *system = dynamic_cast<System *> (line);
labels = system->get_property ("labels");
}
- else if (Prob *prob = unsmob_prob (scm_car (l)))
+ else if (Prob *prob = Prob::unsmob (scm_car (l)))
labels = prob->get_property ("labels");
for (SCM lbls = labels; scm_is_pair (lbls); lbls = scm_cdr (lbls))
return ret;
}
-/* The page-turn-page-breaker needs to have a line-breaker between any two
- columns with non-NULL page-turn-permission.
-
- The optimal-breaker needs to have a line-breaker between any two columns
- with page-break-permission = 'force.
-
- By using a grob predicate, we can accommodate both of these uses.
-*/
void
Page_breaking::create_system_list ()
{
SCM specs = book_->get_system_specs ();
for (SCM s = specs; scm_is_pair (s); s = scm_cdr (s))
{
- if (Paper_score *ps = dynamic_cast<Paper_score *> (unsmob_music_output (scm_car (s))))
+ if (Paper_score *ps = dynamic_cast<Paper_score *> (Music_output::unsmob (scm_car (s))))
{
system_specs_.push_back (System_spec (ps));
}
else
{
- Prob *pb = unsmob_prob (scm_car (s));
+ Prob *pb = Prob::unsmob (scm_car (s));
assert (pb);
pb->protect ();
system_specs_.push_back (System_spec ());
}
+/* The page-turn-page-breaker needs to have a line-breaker between any two
+ columns with non-NULL page-turn-permission.
+
+ The optimal-breaker needs to have a line-breaker between any two columns
+ with page-break-permission = 'force.
+
+ By using a grob predicate, we can accommodate both of these uses.
+*/
void
Page_breaking::find_chunks_and_breaks (Break_predicate is_break, Prob_break_predicate prob_is_break)
{
cur_page_height -= min_whitespace_at_top_of_page (cached_line_details_[page_starter]);
cur_page_height -= min_whitespace_at_bottom_of_page (cached_line_details_.back ());
- Real cur_height = cur_rod_height + ((ragged_last () || ragged ()) ? cur_spring_height : 0);
if (!too_few_lines (line_count - cached_line_details_.back ().compressed_nontitle_lines_count_)
- && cur_height > cur_page_height
+ && cur_rod_height > cur_page_height
/* don't increase the page count if the last page had only one system */
&& cur_rod_height > cached_line_details_.back ().full_height ())
ret++;
SCM penalty_sym;
if (is_last ())
- penalty_sym = ly_symbol2scm ("blank-last-page-force");
+ penalty_sym = ly_symbol2scm ("blank-last-page-penalty");
else if (ends_score ())
- penalty_sym = ly_symbol2scm ("blank-after-score-page-force");
+ penalty_sym = ly_symbol2scm ("blank-after-score-page-penalty");
else
- penalty_sym = ly_symbol2scm ("blank-page-force");
+ penalty_sym = ly_symbol2scm ("blank-page-penalty");
Break_position const &pos = breaks_[current_end_breakpoint_];
if (Paper_score *ps = system_specs_[pos.system_spec_index_].pscore_)
line_penalty += uncompressed_line_details_[i].break_penalty_;
}
- for (vsize i = 0; i < res.force_.size (); i++)
+ for (vsize i = ragged () ? res.force_.size () - 1 : 0;
+ i < res.force_.size () - ragged_last ();
+ i++)
{
Real f = res.force_[i];
page1_penalty[i] = line_count_penalty (page1_line_count);
page1_status[i] = line_count_status (page1_line_count);
- if (ragged2)
+ if (ragged1)
page2_force[page2_force.size () - 1 - i]
= (page2.force_ < 0 && i + 1 < page1_force.size ()) ? infinity_f : 0;
+ else if (ragged2 && page2.force_ > 0)
+ page2_force[page2_force.size () - 1 - i] = 0.0;
else
page2_force[page2_force.size () - 1 - i] = page2.force_;
page2_penalty[page2_penalty.size () - 1 - i] = line_count_penalty (page2_line_count);