From cfb427f2b9e63128668d42b7905da26ab33414e7 Mon Sep 17 00:00:00 2001 From: Joe Neeman Date: Sun, 27 May 2012 17:17:00 -0700 Subject: [PATCH] Cleanups in one-line-page-breaking. Make sure that each page is wider than the widest system. --- input/regression/one-line-breaking.ly | 9 ++++ lily/one-line-page-breaking.cc | 69 ++++++++++++++++----------- lily/page-breaking-scheme.cc | 4 +- lily/page-breaking.cc | 31 ++++++------ lily/paper-book.cc | 9 ++++ 5 files changed, 76 insertions(+), 46 deletions(-) create mode 100644 input/regression/one-line-breaking.ly diff --git a/input/regression/one-line-breaking.ly b/input/regression/one-line-breaking.ly new file mode 100644 index 0000000000..9dbd804604 --- /dev/null +++ b/input/regression/one-line-breaking.ly @@ -0,0 +1,9 @@ +\version "2.15.40" + +\header { + texidoc = "The @var{ly:one-line-breaking} algorithm puts everything on one line." +} + +\paper { page-breaking = #ly:one-line-breaking } + +\include "typography-demo.ly" diff --git a/lily/one-line-page-breaking.cc b/lily/one-line-page-breaking.cc index 2175e1727a..018ef9cff3 100644 --- a/lily/one-line-page-breaking.cc +++ b/lily/one-line-page-breaking.cc @@ -40,42 +40,53 @@ One_line_page_breaking::~One_line_page_breaking () } /* - This is a somewhat unconventional page-breaking algorithm. Every + This is a somewhat unconventional page-breaking algorithm. Every score will be put on a single page, whose width is enough - to fit the entire score one one line. Line breaks and page breaks - are ignored, as are the page dimensions in the paper block. + to fit the entire score one one line. Line breaks and page breaks + are ignored, and the paper-width setting in the paper block + will be modified to fit the music. */ SCM One_line_page_breaking::solve () { SCM all_pages = SCM_EOL; + Real max_width = 0; for (vsize i = 0; i < system_specs_.size (); ++i) - if (Paper_score *ps = system_specs_[i].pscore_) - { - vector cols = ps->root_system ()->used_columns (); - - // No indent, "infinite" line width, ragged. - Column_x_positions pos = get_line_configuration (cols, numeric_limits::max (), 0, true); - vector positions; - positions.push_back (pos); - - ps->root_system ()->break_into_pieces (positions); - ps->root_system ()->do_break_substitution_and_fixup_refpoints (); - Grob *system = ps->root_system ()->broken_intos_[0]; - Real width = system->extent (system, X_AXIS).length (); - Real height = system->extent (system, Y_AXIS).length (); - - // HACK: probably shouldn't be modifying the paper_; better to modify the page - // afterwards. - book_->paper_->set_variable (ly_symbol2scm ("paper-width"), scm_from_double (width + 100)); - // TODO: figure out what the height should be. - //book_->paper_->set_variable (ly_symbol2scm ("paper-height"), scm_from_double (height)); - vector lines_per_page; - lines_per_page.push_back (1); - SCM systems = scm_list_1 (system->self_scm ()); - SCM pages = make_pages (lines_per_page, systems); - all_pages = scm_cons (scm_car (pages), all_pages); - } + { + if (Paper_score *ps = system_specs_[i].pscore_) + { + vector cols = ps->root_system ()->used_columns (); + + // No indent, "infinite" line width, ragged. + Column_x_positions pos = get_line_configuration (cols, numeric_limits::max (), 0, true); + vector positions; + positions.push_back (pos); + + ps->root_system ()->break_into_pieces (positions); + ps->root_system ()->do_break_substitution_and_fixup_refpoints (); + Grob *system = ps->root_system ()->broken_intos_[0]; + + vector lines_per_page; + lines_per_page.push_back (1); + SCM systems = scm_list_1 (system->self_scm ()); + SCM pages = make_pages (lines_per_page, systems); + + max_width = max (max_width, system->extent (system, X_AXIS).length ()); + all_pages = scm_cons (scm_car (pages), all_pages); + } + else if (Prob *pb = system_specs_[i].prob_) + // Because we don't call Page_breaking::systems in this algorithm, + // we need to manually unprotect the titles. + pb->unprotect (); + } + + // Alter paper-width so that it is large enough to fit every system. + // TODO: it might be nice to allow different pages to have different widths. + // This would need support in the backends (eg. framework-ps.scm). + Real right_margin = robust_scm2double (book_->paper_->c_variable ("right-margin"), 0.0); + Real left_margin = robust_scm2double (book_->paper_->c_variable ("left-margin"), 0.0); + Real width = max_width + right_margin + left_margin; + book_->paper_->set_variable (ly_symbol2scm ("paper-width"), scm_from_double (width)); return scm_reverse_x (all_pages, SCM_EOL); } diff --git a/lily/page-breaking-scheme.cc b/lily/page-breaking-scheme.cc index 796324cbc2..12929e510d 100644 --- a/lily/page-breaking-scheme.cc +++ b/lily/page-breaking-scheme.cc @@ -55,7 +55,9 @@ LY_DEFINE (ly_minimal_breaking, "ly:minimal-breaking", LY_DEFINE (ly_one_line_breaking, "ly:one-line-breaking", 1, 0, 0, (SCM pb), - "Put each score on a single line, and put each line on its own page.") + "Put each score on a single line, and put each line on its own" + " page. The paper-width setting will be modified so that" + " every page will be wider than the widest line.") { One_line_page_breaking b (unsmob_paper_book (pb)); return b.solve (); diff --git a/lily/page-breaking.cc b/lily/page-breaking.cc index 9956c9f978..692244b897 100644 --- a/lily/page-breaking.cc +++ b/lily/page-breaking.cc @@ -567,9 +567,6 @@ Page_breaking::draw_page (SCM systems, SCM configuration, int page_num, bool las // 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); p->set_property ("lines", paper_systems); @@ -583,7 +580,6 @@ Page_breaking::draw_page (SCM systems, SCM configuration, int page_num, bool las foot = Page_layout_problem::add_footnotes_to_footer (footnotes, foot, book_); p->set_property ("foot-stencil", foot.smobbed_copy ()); - scm_apply_1 (page_stencil, page, SCM_EOL); return page; } @@ -603,10 +599,11 @@ Page_breaking::make_pages (vector lines_per_page, SCM systems) label_page_table = SCM_EOL; // Build a list of (systems configuration . footnote-count) triples. - // Note that we lay out - // the staves and find the configurations before drawing anything. Some + // 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; @@ -642,7 +639,9 @@ Page_breaking::make_pages (vector lines_per_page, SCM systems) 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)) { @@ -681,14 +680,6 @@ 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 () { @@ -712,6 +703,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) { diff --git a/lily/paper-book.cc b/lily/paper-book.cc index f6d008f1db..aecafbe3a0 100644 --- a/lily/paper-book.cc +++ b/lily/paper-book.cc @@ -652,6 +652,15 @@ Paper_book::pages () { SCM page_breaking = paper_->c_variable ("page-breaking"); pages_ = scm_apply_0 (page_breaking, scm_list_1 (self_scm ())); + + // Create all the page stencils. + 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); + for (SCM pages = pages_; scm_is_pair (pages); pages = scm_cdr (pages)) + scm_apply_1 (page_stencil, scm_car (pages), SCM_EOL); + + // Perform any user-supplied post-processing. SCM post_process = paper_->c_variable ("page-post-process"); if (ly_is_procedure (post_process)) scm_apply_2 (post_process, paper_->self_scm (), pages_, SCM_EOL); -- 2.39.2