X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fpage-breaking.cc;h=1ae769e82d641d79145e53491bd77795baf2d4a4;hb=60f1b9803323beff180758ebbe896d106c0aeb35;hp=1d96f7359fc45aca536405f115d4f469cc27349c;hpb=4c72b133f96204598051fea3d55c78329f368866;p=lilypond.git diff --git a/lily/page-breaking.cc b/lily/page-breaking.cc index 1d96f7359f..1ae769e82d 100644 --- a/lily/page-breaking.cc +++ b/lily/page-breaking.cc @@ -36,6 +36,7 @@ compress_lines (const vector &orig) compressed.extent_[UP] = old.extent_[UP] + orig[i].extent_.length () + old.padding_; compressed.space_ += old.space_; compressed.inverse_hooke_ += old.inverse_hooke_; + compressed.title_ = old.title_; /* we don't need the force_ field for the vertical spacing, so we use force_ = n to signal that the line was compressed, @@ -97,8 +98,10 @@ Page_breaking::next_system (Break_position const &break_pos) const Page_breaking::Page_breaking (Paper_book *pb, Break_predicate is_break) { book_ = pb; + system_count_ = 0; ragged_ = to_boolean (pb->paper_->c_variable ("ragged-bottom")); ragged_last_ = to_boolean (pb->paper_->c_variable ("ragged-last-bottom")); + page_top_space_ = robust_scm2double (pb->paper_->c_variable ("page-top-space"), 0); create_system_list (); find_chunks_and_breaks (is_break); } @@ -119,6 +122,18 @@ Page_breaking::ragged_last () const return ragged_last_; } +Real +Page_breaking::page_top_space () const +{ + return page_top_space_; +} + +vsize +Page_breaking::system_count () const +{ + return system_count_; +} + /* translate indices into breaks_ into start-end parameters for the line breaker */ void Page_breaking::line_breaker_args (vsize sys, @@ -210,7 +225,7 @@ Page_breaking::page_height (int page_num, bool last) const ly_symbol2scm ("is-last"), scm_from_bool (last), SCM_UNDEFINED)); SCM height = scm_apply_1 (calc_height, page, SCM_EOL); - return scm_to_double (height) - scm_to_double (book_->paper_->c_variable ("page-top-space")); + return scm_to_double (height) - page_top_space_; } SCM @@ -240,6 +255,7 @@ 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; + SCM label_page_table = SCM_EOL; for (vsize i = 0; i < lines_per_page.size (); i++) { @@ -253,10 +269,28 @@ Page_breaking::make_pages (vector lines_per_page, SCM systems) scm_list_n (book, lines, page_num, rag, last, SCM_UNDEFINED)); + /* collect labels */ + for (SCM l = lines ; scm_is_pair (l) ; l = scm_cdr (l)) + { + SCM labels = SCM_EOL; + if (Grob * line = unsmob_grob (scm_car (l))) + { + System *system = dynamic_cast (line); + labels = system->get_property ("labels"); + } + else if (Prob *prob = unsmob_prob (scm_car (l))) + labels = prob->get_property ("labels"); + + for (SCM lbls = labels ; scm_is_pair (lbls) ; lbls = scm_cdr (lbls)) + label_page_table = scm_cons (scm_cons (scm_car (lbls), page_num), + label_page_table); + } + scm_apply_1 (page_stencil, page, SCM_EOL); ret = scm_cons (page, ret); systems = scm_list_tail (systems, line_count); } + book_->paper_->set_variable (ly_symbol2scm ("label-page-table"), label_page_table); ret = scm_reverse (ret); return ret; } @@ -424,6 +458,7 @@ Page_breaking::set_current_breakpoints (vsize start, Line_division lower_bound, Line_division upper_bound) { + system_count_ = system_count; current_chunks_ = chunk_list (start, end); current_start_breakpoint_ = start; current_end_breakpoint_ = end; @@ -479,6 +514,7 @@ Page_breaking::set_to_ideal_line_configuration (vsize start, vsize end) current_start_breakpoint_ = start; current_end_breakpoint_ = end; clear_line_details_cache (); + system_count_ = 0; Line_division div; for (vsize i = 0; i+1 < current_chunks_.size (); i++) @@ -491,6 +527,8 @@ Page_breaking::set_to_ideal_line_configuration (vsize start, vsize end) } else div.push_back (1); + + system_count_ += div.back (); } current_configurations_.clear (); current_configurations_.push_back (div); @@ -507,6 +545,7 @@ Page_breaking::cache_line_details (vsize configuration_index) { if (cached_configuration_index_ != configuration_index) { + cached_configuration_index_ = configuration_index; SCM padding_scm = book_->paper_->c_variable ("page-breaking-between-system-padding"); if (!scm_is_number (padding_scm)) padding_scm = book_->paper_->c_variable ("between-system-padding"); @@ -530,7 +569,9 @@ Page_breaking::cache_line_details (vsize configuration_index) { assert (div[i] == 1); uncompressed_line_details_.push_back (Line_details (system_specs_[sys].prob_)); - uncompressed_line_details_.back ().padding_ = padding; + uncompressed_line_details_.back ().padding_ = + robust_scm2double (system_specs_[sys].prob_->get_property ("next-padding"), + padding); } } cached_line_details_ = compress_lines (uncompressed_line_details_); @@ -598,7 +639,7 @@ Page_breaking::min_page_count (vsize configuration, vsize first_page_num) Real ext_len = cached_line_details_[i].extent_.length (); Real next_rod_height = cur_rod_height + ext_len + ((cur_rod_height > 0) ? cached_line_details_[i].padding_: 0); - Real next_spring_height = cur_spring_height + line_space (cached_line_details_[i]); + Real next_spring_height = cur_spring_height + cached_line_details_[i].space_; Real next_height = next_rod_height + (ragged () ? next_spring_height : 0); @@ -607,7 +648,7 @@ Page_breaking::min_page_count (vsize configuration, vsize first_page_num) && cached_line_details_[i-1].page_permission_ == ly_symbol2scm ("force"))) { cur_rod_height = ext_len; - cur_spring_height = line_space (cached_line_details_[i]); + cur_spring_height = cached_line_details_[i].space_; cur_page_height = page_height (first_page_num + ret, false); ret++; } @@ -646,16 +687,19 @@ Page_spacing_result Page_breaking::space_systems_on_n_pages (vsize configuration, vsize n, vsize first_page_num) { Page_spacing_result ret; - assert (n >= min_page_count (configuration, first_page_num)); cache_line_details (configuration); - if (n > cached_line_details_.size ()) - return Page_spacing_result (); - if (n == 1) + bool valid_n = (n >= min_page_count (configuration, first_page_num) + && n <= cached_line_details_.size ()); + + if (!valid_n) + programming_error ("number of pages is out of bounds"); + + if (n == 1 && valid_n) ret = space_systems_on_1_page (cached_line_details_, page_height (first_page_num, is_last ()), ragged () || (is_last () && ragged_last ())); - else if (n == 2) + else if (n == 2 && valid_n) ret = space_systems_on_2_pages (configuration, first_page_num); else { @@ -669,7 +713,19 @@ Page_breaking::space_systems_on_n_pages (vsize configuration, vsize n, vsize fir Real Page_breaking::blank_page_penalty () const { - SCM penalty_sym = is_last () ? ly_symbol2scm ("blank-last-page-force") : ly_symbol2scm ("blank-page-force"); + SCM penalty_sym; + + if (is_last ()) + penalty_sym = ly_symbol2scm ("blank-last-page-force"); + else if (ends_score ()) + penalty_sym = ly_symbol2scm ("blank-after-score-page-force"); + else + penalty_sym = ly_symbol2scm ("blank-page-force"); + + Break_position const &pos = breaks_[current_end_breakpoint_]; + if (Paper_score *ps = system_specs_[pos.system_spec_index_].pscore_) + return robust_scm2double (ps->layout ()->lookup_variable (penalty_sym), 0.0); + return robust_scm2double (book_->paper_->lookup_variable (penalty_sym), 0.0); } @@ -679,30 +735,43 @@ Page_breaking::space_systems_on_n_or_one_more_pages (vsize configuration, vsize Page_spacing_result n_res; Page_spacing_result m_res; - if (n <= 2) + cache_line_details (configuration); + vsize min_p_count = min_page_count (configuration, first_page_num); + bool valid_n = n >= min_p_count || n <= cached_line_details_.size (); + + if (!valid_n) + programming_error ("both page counts are out of bounds"); + + if (n == 1 && valid_n) { - n_res = space_systems_on_n_pages (configuration, n, first_page_num); - m_res = space_systems_on_n_pages (configuration, n+1, first_page_num); + bool rag = ragged () || (is_last () && ragged_last ()); + Real height = page_height (first_page_num, is_last ()); + + if (1 >= min_p_count) + n_res = space_systems_on_1_page (cached_line_details_, height, rag); + if (1 < cached_line_details_.size ()) + m_res = space_systems_on_2_pages (configuration, first_page_num); } else { - cache_line_details (configuration); - - vsize min_p_count = min_page_count (configuration, first_page_num); Page_spacer ps (cached_line_details_, first_page_num, this); - if (n >= min_p_count) + + if (n >= min_p_count || !valid_n) n_res = ps.solve (n); - if (n < cached_line_details_.size ()) + if (n < cached_line_details_.size () || !valid_n) m_res = ps.solve (n+1); } + m_res = finalize_spacing_result (configuration, m_res); + n_res = finalize_spacing_result (configuration, n_res); + Real penalty = blank_page_penalty (); n_res.demerits_ += penalty; - n_res.force_.back () += penalty; - if (m_res.demerits_ < n_res.demerits_) - return m_res; - return n_res; + if (n_res.force_.size ()) + n_res.force_.back () += penalty; + + return (m_res.demerits_ < n_res.demerits_) ? m_res : n_res; } Page_spacing_result @@ -728,11 +797,73 @@ Page_breaking::space_systems_on_best_pages (vsize configuration, vsize first_pag return finalize_spacing_result (configuration, best); } +Page_spacing_result +Page_breaking::pack_systems_on_least_pages (vsize configuration, vsize first_page_num) +{ + Page_spacing_result res; + vsize page = 0; + vsize page_first_line = 0; + Page_spacing space (page_height (first_page_num, false), page_top_space_); + + cache_line_details (configuration); + for (vsize line = 0; line < cached_line_details_.size (); line++) + { + Real prev_force = space.force_; + space.append_system (cached_line_details_[line]); + if ((line > page_first_line) + && (isinf (space.force_) + || ((line > 0) + && (cached_line_details_[line-1].page_permission_ == ly_symbol2scm ("force"))))) + { + res.systems_per_page_.push_back (line - page_first_line); + res.force_.push_back (prev_force); + res.penalty_ += cached_line_details_[line-1].page_penalty_; + page++; + space.resize (page_height (first_page_num + page, false)); + space.clear (); + space.append_system (cached_line_details_[line]); + page_first_line = line; + } + + if (line == cached_line_details_.size () - 1) + { + /* This is the last line */ + /* When the last page height was computed, we did not know yet that it + * was the last one. If the systems put on it don't fit anymore, the last + * system is moved to a new page */ + space.resize (page_height (first_page_num + page, true)); + if ((line > page_first_line) && (isinf (space.force_))) + { + res.systems_per_page_.push_back (line - page_first_line); + res.force_.push_back (prev_force); + /* the last page containing the last line */ + space.resize (page_height (first_page_num + page + 1, true)); + space.clear (); + space.append_system (cached_line_details_[line]); + res.systems_per_page_.push_back (1); + res.force_.push_back (space.force_); + res.penalty_ += cached_line_details_[line-1].page_penalty_; + res.penalty_ += cached_line_details_[line].page_penalty_; + } + else + { + res.systems_per_page_.push_back (line + 1 - page_first_line); + res.force_.push_back (space.force_); + res.penalty_ += cached_line_details_[line].page_penalty_; + } + } + } + return finalize_spacing_result (configuration, res); +} + /* Calculate demerits and fix res.systems_per_page_ so that it refers to the original line numbers, not the ones given by compress_lines (). */ Page_spacing_result Page_breaking::finalize_spacing_result (vsize configuration, Page_spacing_result res) { + if (res.force_.empty ()) + return res; + cache_line_details (configuration); res.systems_per_page_ = uncompress_solution (res.systems_per_page_, cached_line_details_); @@ -776,7 +907,7 @@ Page_breaking::finalize_spacing_result (vsize configuration, Page_spacing_result Page_spacing_result Page_breaking::space_systems_on_1_page (vector const &lines, Real page_height, bool ragged) { - Page_spacing space (page_height); + Page_spacing space (page_height, page_top_space_); Page_spacing_result ret; for (vsize i = 0; i < lines.size (); i++) @@ -816,8 +947,8 @@ Page_breaking::space_systems_on_2_pages (vsize configuration, vsize first_page_n vector page1_force; vector page2_force; - Page_spacing page1 (page1_height); - Page_spacing page2 (page2_height); + Page_spacing page1 (page1_height, page_top_space_); + Page_spacing page2 (page2_height, page_top_space_); page1_force.resize (cached_line_details_.size () - 1, infinity_f); page2_force.resize (cached_line_details_.size () - 1, infinity_f); @@ -889,6 +1020,12 @@ Page_breaking::is_last () const return current_end_breakpoint_ == last_break_position (); } +bool +Page_breaking::ends_score () const +{ + return breaks_[current_end_breakpoint_].score_ender_; +} + vsize Page_breaking::last_break_position () const {