X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fpage-breaking.cc;h=768cb79cc2150a88f81acdd04e7c09e719a9d64b;hb=47db9a3883d726ca53e2133a3b2298f78dd6a32e;hp=c46a04efa5c363b596da1fbf0ee83b91732cfa25;hpb=b38fd63a19190741c0c19faf6a904af82c3f434c;p=lilypond.git diff --git a/lily/page-breaking.cc b/lily/page-breaking.cc index c46a04efa5..768cb79cc2 100644 --- a/lily/page-breaking.cc +++ b/lily/page-breaking.cc @@ -1,7 +1,7 @@ /* This file is part of LilyPond, the GNU music typesetter. - Copyright (C) 2006--2011 Joe Neeman + Copyright (C) 2006--2015 Joe Neeman LilyPond is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -183,15 +183,18 @@ compress_lines (const vector &orig) 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; @@ -250,11 +253,11 @@ Page_breaking::Page_breaking (Paper_book *pb, Break_predicate is_break, Prob_bre 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; @@ -263,6 +266,7 @@ Page_breaking::Page_breaking (Paper_book *pb, Break_predicate is_break, Prob_bre 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_ = robust_scm2double (pb->paper_->c_variable ("footnote-number-raise"), 0.0); @@ -332,6 +336,12 @@ Page_breaking::footnote_separator_stencil_height () const return footnote_separator_stencil_height_; } +Real +Page_breaking::in_note_padding () const +{ + return in_note_padding_; +} + Real Page_breaking::footnote_padding () const { @@ -455,7 +465,7 @@ Page_breaking::systems () pb->unprotect (); } } - return scm_append (scm_reverse (ret)); + return scm_append (scm_reverse_x (ret, SCM_EOL)); } SCM @@ -493,7 +503,7 @@ Page_breaking::page_height (int page_num, bool last) const // 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& cache = last ? last_page_height_cache_ : page_height_cache_; + vector &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 @@ -529,22 +539,22 @@ Page_breaking::breakpoint_property (vsize breakpoint, char const *str) } 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 (g); paper_system = sys->get_paper_system (); @@ -552,32 +562,23 @@ Page_breaking::draw_page (SCM systems, SCM configuration, int page_num, int foot 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; } @@ -591,18 +592,22 @@ Page_breaking::make_pages (vector lines_per_page, SCM systems) 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++) { @@ -612,34 +617,53 @@ Page_breaking::make_pages (vector lines_per_page, SCM systems) 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 (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)) @@ -659,27 +683,19 @@ Page_breaking::make_pages (vector lines_per_page, SCM systems) 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 (unsmob_music_output (scm_car (s)))) + if (Paper_score *ps = dynamic_cast (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 (); @@ -690,6 +706,14 @@ Page_breaking::create_system_list () 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) { @@ -723,7 +747,7 @@ Page_breaking::find_chunks_and_breaks (Break_predicate is_break, Prob_break_pred vector line_breaker_columns; line_breaker_columns.push_back (0); - for (vsize j = 1; j < cols.size (); j++) + for (vsize j = 0; j < cols.size (); j++) { if (forced_line_break_cols.size ()) { @@ -1148,9 +1172,8 @@ Page_breaking::min_page_count (vsize configuration, vsize first_page_num) 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++; @@ -1203,11 +1226,11 @@ Page_breaking::blank_page_penalty () const 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_) @@ -1416,7 +1439,9 @@ Page_breaking::finalize_spacing_result (vsize configuration, Page_spacing_result 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 () - (is_last () && ragged_last ()); + i++) { Real f = res.force_[i]; @@ -1524,9 +1549,11 @@ Page_breaking::space_systems_on_2_pages (vsize configuration, vsize first_page_n 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);