From fdf32024a6ab7ec992490ed567f9cd3edeff21ff Mon Sep 17 00:00:00 2001 From: Jan Nieuwenhuizen Date: Thu, 18 Mar 2004 10:11:55 +0000 Subject: [PATCH 1/1] * ly/declarations-init.ly (paper): Define page-breaking. * scm/page-layout.scm (optimal-page-breaking): New function. * lily/paper-book.cc (pages): Use it. * lily/include/paper-line.hh (class Paper_line): Full smob. --- ChangeLog | 14 ++ input/test/title-markup.ly | 4 + lily/include/paper-book.hh | 8 +- lily/include/paper-line.hh | 5 +- lily/lily-guile.cc | 2 +- lily/paper-book.cc | 349 ++++++++++++++++++++++--------------- lily/paper-line.cc | 62 +++++-- lily/paper-outputter.cc | 4 +- lily/parse-scm.cc | 11 +- lily/system.cc | 3 +- ly/declarations-init.ly | 2 + scm/documentation-lib.scm | 14 +- scm/lily.scm | 9 +- scm/music-functions.scm | 3 +- scm/page-layout.scm | 197 ++++++++++++++++++++- 15 files changed, 507 insertions(+), 180 deletions(-) diff --git a/ChangeLog b/ChangeLog index e44cc6877d..3b3207ecb7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2004-03-18 Jan Nieuwenhuizen + + * ly/declarations-init.ly (paper): Define page-breaking. + +2004-03-17 Jan Nieuwenhuizen + + * scm/page-layout.scm (optimal-page-breaking): New function. + + * lily/paper-book.cc (pages): Use it. + +2004-03-16 Jan Nieuwenhuizen + + * lily/include/paper-line.hh (class Paper_line): Full smob. + 2004-03-18 Han-Wen Nienhuys * lily/global-context.cc (run_iterator_on_me): fix grace note diff --git a/input/test/title-markup.ly b/input/test/title-markup.ly index 17ce4ee7e4..ea38f9e9b1 100644 --- a/input/test/title-markup.ly +++ b/input/test/title-markup.ly @@ -7,6 +7,10 @@ %} +\paper{ + #(define page-breaking ly:optimal-page-breaks) +} + latinTest = \markup { \latin-i "Hellö" } sizeTest = \markup { diff --git a/lily/include/paper-book.hh b/lily/include/paper-book.hh index 7496ed4646..24dab4e061 100644 --- a/lily/include/paper-book.hh +++ b/lily/include/paper-book.hh @@ -29,10 +29,10 @@ public: Paper_book (); void init (); - Link_array *get_pages (); - Link_array *fill_pages (Page*, int, Real); - SCM get_scopes (int); - Stencil* get_title (int); + Link_array *pages (); + SCM lines (); + SCM scopes (int); + Stencil* title (int); void output (String); void classic_output (String); DECLARE_SMOBS (Paper_book, ) diff --git a/lily/include/paper-line.hh b/lily/include/paper-line.hh index d0372d04fc..1d383a7627 100644 --- a/lily/include/paper-line.hh +++ b/lily/include/paper-line.hh @@ -14,14 +14,15 @@ class Paper_line { + DECLARE_SMOBS (Paper_line,) SCM stencils_; Offset dim_; bool is_title_; - DECLARE_SMOBS (Paper_line,); public: - Paper_line (Offset, SCM, bool = true); + Paper_line (Offset, SCM, bool = false); + int number_; Offset dim () const; SCM stencils () const; bool is_title () const; diff --git a/lily/lily-guile.cc b/lily/lily-guile.cc index ecde4495f2..4cb62c01ff 100644 --- a/lily/lily-guile.cc +++ b/lily/lily-guile.cc @@ -201,7 +201,7 @@ ly_init_ly_module (void *) } -SCM lily_module ; +SCM lily_module; void ly_init_guile () diff --git a/lily/paper-book.cc b/lily/paper-book.cc index edb4396d2d..5f8624f511 100644 --- a/lily/paper-book.cc +++ b/lily/paper-book.cc @@ -19,7 +19,6 @@ #include "stencil.hh" static Real const MIN_COVERAGE = 0.66; -static Real const MAX_CRAMP = 0.05; static SCM stencil2line (Stencil* stil, bool is_title = false) @@ -29,7 +28,8 @@ stencil2line (Stencil* stil, bool is_title = false) z = scm_permanent_object (ly_offset2scm (Offset (0, 0))); Offset dim = Offset (stil->extent (X_AXIS).length (), stil->extent (Y_AXIS).length ()); - Paper_line * pl = new Paper_line (dim, scm_cons (stil->smobbed_copy (), SCM_EOL), is_title); + Paper_line *pl = new Paper_line (dim, scm_cons (stil->smobbed_copy (), + SCM_EOL), is_title); return pl->self_scm (); } @@ -199,6 +199,43 @@ Paper_book::~Paper_book () { } +#include "ly-smobs.icc" + +IMPLEMENT_DEFAULT_EQUAL_P (Paper_book); +IMPLEMENT_SMOBS (Paper_book) +IMPLEMENT_TYPE_P (Paper_book, "ly:paper-book?") + +SCM +Paper_book::mark_smob (SCM smob) +{ + Paper_book *pb = (Paper_book*) SCM_CELL_WORD_1 (smob); + for (int i = 0; i < pb->headers_.size (); i++) + scm_gc_mark (pb->headers_[i]); + for (int i = 0; i < pb->global_headers_.size (); i++) + scm_gc_mark (pb->global_headers_[i]); + for (int i = 0; i < pb->papers_.size (); i++) + scm_gc_mark (pb->papers_[i]->self_scm ()); + for (int i = 0; i < pb->scores_.size (); i++) + scm_gc_mark (pb->scores_[i]); + + scm_gc_mark (pb->copyright_); + + return pb->tagline_; +} + +int +Paper_book::print_smob (SCM smob, SCM port, scm_print_state*) +{ + Paper_book *b = (Paper_book*) ly_cdr (smob); + + scm_puts ("#<", port); + scm_puts (classname (b), port); + scm_puts (" ", port); + //scm_puts (b->, port); + scm_puts (">", port); + return 1; +} + void Paper_book::output (String outname) { @@ -206,11 +243,11 @@ Paper_book::output (String outname) return; /* Generate all stencils to trigger font loads. */ - Link_array *pages = get_pages (); + Link_array *pages = this->pages (); Paper_def *paper = papers_[0]; Paper_outputter *out = paper->get_paper_outputter (outname); - out->output_header (paper, get_scopes (0), pages->size ()); + out->output_header (paper, scopes (0), pages->size ()); int page_count = pages->size (); for (int i = 0; i < page_count; i++) @@ -221,7 +258,7 @@ Paper_book::output (String outname) } SCM -Paper_book::get_scopes (int i) +Paper_book::scopes (int i) { SCM scopes = SCM_EOL; if (headers_[i]) @@ -232,7 +269,7 @@ Paper_book::get_scopes (int i) } Stencil* -Paper_book::get_title (int i) +Paper_book::title (int i) { SCM user_title = scm_primitive_eval (ly_symbol2scm ("user-title")); SCM book_title = scm_primitive_eval (ly_symbol2scm ("book-title")); @@ -241,7 +278,7 @@ Paper_book::get_title (int i) : ly_symbol2scm ("scoreTitle")); Stencil *title = 0; - SCM scopes = get_scopes (i); + SCM scopes = this->scopes (i); SCM s = ly_modules_lookup (scopes, field); if (s != SCM_UNDEFINED && scm_variable_bound_p (s) == SCM_BOOL_T) title = unsmob_stencil (scm_call_2 (user_title, @@ -257,6 +294,23 @@ Paper_book::get_title (int i) return title; } +void +Paper_book::classic_output (String outname) +{ + int count = scores_.size (); + Paper_outputter *out = papers_.top ()->get_paper_outputter (outname); + out->output_header (papers_.top (), scopes (count - 1), 0); + + int line_count = SCM_VECTOR_LENGTH ((SCM) scores_.top ()); + for (int i = 0; i < line_count; i++) + out->output_line (scm_vector_ref ((SCM) scores_.top (), scm_int2num (i)), + 0, i == line_count - 1); + + out->output_scheme (scm_list_1 (ly_symbol2scm ("end-output"))); + progress_indication ("\n"); +} + + /* calculate book height, #lines, stencils. */ void Paper_book::init () @@ -268,7 +322,7 @@ Paper_book::init () height_ = 0; for (int i = 0; i < score_count; i++) { - Stencil *title = get_title (i); + Stencil *title = this->title (i); if (title) height_ += title->extent (Y_AXIS).length (); @@ -281,7 +335,7 @@ Paper_book::init () } Paper_def *paper = papers_[0]; - SCM scopes = get_scopes (0); + SCM scopes = this->scopes (0); SCM make_tagline = scm_primitive_eval (ly_symbol2scm ("make-tagline")); tagline_ = scm_call_2 (make_tagline, paper->self_scm (), scopes); @@ -298,13 +352,26 @@ Paper_book::init () height_ += copy_height; } -/* Ideas: - - real page breaking algorithm (Gourlay?) - Hmmughr, Gourlay uses Grobs, columns etc -- looks like it needs serious - refactoring before it can be applied to Page breaking... - - override: # pages, or pageBreakLines= #'(3 3 4), ? */ +SCM +Paper_book::lines () +{ + int score_count = scores_.size (); + SCM lines = SCM_EOL; + for (int i = 0; i < score_count; i++) + { + if (Stencil *title = this->title (i)) + lines = ly_snoc (stencil2line (title, true), lines); + lines = scm_append (scm_list_2 (lines, scm_vector_to_list (scores_[i]))); + } + //debug helper; ughr + int i = 0; + for (SCM s = lines; s != SCM_EOL; s = ly_cdr (s)) + unsmob_paper_line (ly_car (s))->number_ = ++i; + return lines; +} + Link_array* -Paper_book::get_pages () +Paper_book::pages () { init (); Page::page_count_ = 0; @@ -312,81 +379,155 @@ Paper_book::get_pages () Page *page = new Page (paper, 1); Real text_height = page->text_height (); - Real page_frac = height_ / text_height; - int page_count = (int) ceil (page_frac); + + Real copy_height = 0; + if (Stencil *s = unsmob_stencil (copyright_)) + copy_height = s->extent (Y_AXIS).length (); + + Real tag_height = 0; + if (Stencil *s = unsmob_stencil (tagline_)) + tag_height = s->extent (Y_AXIS).length (); + + SCM all = lines (); + SCM proc = paper->get_scmvar ("page-breaking"); + // SCM proc = paper->scm_primitive_eval (ly_symbol2scm ("page-breaking")); + // SCM proc = scm_primitive_eval (ly_symbol2scm ("page-breaking")); + SCM breaks = scm_apply_0 (proc, scm_list_n (all, + gh_double2scm (height_), + gh_double2scm (text_height), + gh_double2scm (copy_height), + gh_double2scm (tag_height), + SCM_UNDEFINED)); + + /* Copyright on first page. */ if (unsmob_stencil (copyright_)) page->copyright_ = copyright_; - if (unsmob_stencil (tagline_) && page_count == 1) - page->tagline_ = tagline_; - /* Attempt to fill pages better using FUDGE kludge. */ - Real r = page_frac - (int) page_frac; - Real cramp_fudge = page_count > 1 ? (r / (page_count - 1)) * text_height : 0; - Real expand_fudge = - ((1 - r) / page_count) * text_height; - - Link_array* pages = 0; - if ((page_count > 1 && (r / (page_count - 1)) < MAX_CRAMP)) + Link_array *pages = new Link_array; + int page_count = SCM_VECTOR_LENGTH ((SCM) breaks); + int line = 1; + for (int i = 0; i < page_count; i++) { - /* Just a little more space (size () != page_count - 1) + if (i) + page = new Page (paper, i+1); + int next = i + 1 < page_count + ? gh_scm2int (scm_vector_ref (breaks, gh_int2scm (i))) : 0; + while ((!next && all != SCM_EOL) || line <= next) { - /* Cramping failed. */ - page = pages->get (0); - delete pages; - pages = 0; + page->lines_ = ly_snoc (ly_car (all), page->lines_); + all = ly_cdr (all); + line++; } - } - if (!pages && ((1 - r) / page_count) < 1 - MIN_COVERAGE) + pages->push (page); + } + + /* Tagline on last page. */ + if (unsmob_stencil (tagline_)) + page->tagline_ = tagline_; + return pages; +} + +static SCM +c_ragged_page_breaks (SCM lines, Real book_height, Real text_height, + Real first, Real last) +{ + int page_number = 0; + int page_count = int (book_height / text_height + 0.5); + SCM breaks = SCM_EOL; + Real page_height = text_height + first; + Real h = 0; + int number = 0; + for (SCM s = lines; s != SCM_EOL; s = ly_cdr (s)) { - /* There is space left, but not so much that paged would have too - little blackness (< MIN_COVERAGE), distribute evenly. */ - pages = fill_pages (page, page_count, expand_fudge); - bool badly_covered = false; - if (pages->size () == page_count) - for (int i = 0; i < page_count; i++) - { - Page *p = (*pages)[i]; - Real coverage = p ->height_ / p->text_height (); - if (coverage < MIN_COVERAGE) - { - badly_covered = true; - break; - } - } - if (pages->size () != page_count || badly_covered) + Paper_line *pl = unsmob_paper_line (ly_car (s)); + if (!pl->is_title () && h < page_height) + number++; + h += pl->dim ()[Y_AXIS]; + if (!pl->is_title () && h > page_height) { - /* expanding failed. */ - page = pages->get (0); - delete pages; - pages = 0; + breaks = ly_snoc (gh_int2scm (number), breaks); + page_number++; + page_height = text_height + (page_number == page_count) * last; + h = 0; } + if (ly_cdr (s) == SCM_EOL) + breaks = ly_snoc (gh_int2scm (pl->number_), breaks); } - - if (!pages) - /* Fudging failed; just fill pages. */ - pages = fill_pages (page, page_count, 0); - return pages; + + return scm_vector (breaks); +} + +LY_DEFINE (ly_ragged_page_breaks, "ly:ragged-page-breaks", + 5, 0, 0, (SCM lines, SCM book, SCM text, SCM first, SCM last), + "Return a vector with line numbers of page breaks.") +{ + SCM_ASSERT_TYPE (scm_pair_p (lines), lines, SCM_ARG1, __FUNCTION__, "list"); + SCM_ASSERT_TYPE (gh_number_p (book), book, SCM_ARG2, __FUNCTION__, "real"); + SCM_ASSERT_TYPE (gh_number_p (text), text, SCM_ARG2, __FUNCTION__, "real"); + SCM_ASSERT_TYPE (gh_number_p (first), first, SCM_ARG2, __FUNCTION__, "real"); + SCM_ASSERT_TYPE (gh_number_p (last), last, SCM_ARG2, __FUNCTION__, "real"); + + return c_ragged_page_breaks (lines, + gh_scm2double (book), gh_scm2double (text), + gh_scm2double (first), gh_scm2double (last)); } -/* Simplistic page breaking: - add lines until HEIGHT > PAGE.TEXT_HEIGHT_ + FUDGE */ +#if 0 Link_array* -Paper_book::fill_pages (Page *page, int page_count, Real fudge) +Paper_book::ragged_pages () { - int page_number = 1; + Link_array *pages = new Link_array; int score_count = scores_.size (); + + /* Calculate the full book height. Hmm, can't we cache system + heights while making stencils? */ + Real book_height = 0; + for (int i = 0; i < score_count; i++) + { + Stencil *title = this->title (i); + if (title) + book_height += title->extent (Y_AXIS).length (); + + int line_count = SCM_VECTOR_LENGTH ((SCM) scores_[i]); + for (int j = 0; j < line_count; j++) + { + SCM line = scm_vector_ref ((SCM) scores_[i], scm_int2num (j)); + book_height += ly_scm2offset (ly_car (line))[Y_AXIS]; + } + } + Paper_def *paper = papers_[0]; - Link_array *pages = new Link_array; - page->lines_ = SCM_EOL; - page->height_ = 0; - page->line_count_ = 0; + SCM scopes = this->scopes (0); + + SCM make_tagline = scm_primitive_eval (ly_symbol2scm ("make-tagline")); + SCM tagline = scm_call_2 (make_tagline, paper->self_scm (), scopes); + Real tag_height = 0; + if (Stencil *s = unsmob_stencil (tagline)) + tag_height = s->extent (Y_AXIS).length (); + book_height += tag_height; + + SCM make_copyright = scm_primitive_eval (ly_symbol2scm ("make-copyright")); + SCM copyright = scm_call_2 (make_copyright, paper->self_scm (), scopes); + Real copy_height = 0; + if (Stencil *s = unsmob_stencil (copyright)) + copy_height = s->extent (Y_AXIS).length (); + book_height += copy_height; + + Page::page_count_ = 0; + int page_number = 0; + Page *page = new Page (paper, ++page_number); + int page_count = int (book_height / page->text_height () + 0.5); + if (unsmob_stencil (copyright)) + page->copyright_ = copyright; + if (unsmob_stencil (tagline) && page_number == page_count) + page->tagline_ = tagline; + + /* Simplistic page breaking. */ Real text_height = page->text_height (); for (int i = 0; i < score_count; i++) { Real h = 0; - Stencil *title = get_title (i); + Stencil *title = this->title (i); if (title) h = title->extent (Y_AXIS).length (); @@ -395,17 +536,7 @@ Paper_book::fill_pages (Page *page, int page_count, Real fudge) { SCM line = scm_vector_ref ((SCM) scores_[i], scm_int2num (j)); h += unsmob_paper_line (line)->dim ()[Y_AXIS]; - Real fill = (page->height_ - text_height) / text_height; - // Real fill_h = (page->height_ + h - text_height) / text_height; - Real fudged_fill = (page->height_ - (text_height + fudge)) - / (text_height + fudge); - Real fudged_fill_h = ((page->height_ + h) - (text_height + fudge)) - / (text_height + fudge); - if (fill > -MAX_CRAMP - || (fudged_fill > -MAX_CRAMP - && (fudge < 0 - || !(fudged_fill_h > 0 - && abs (fudged_fill_h) < 4 * abs (fudged_fill))))) + if (page->height_ + h > text_height) { pages->push (page); page = new Page (paper, ++page_number); @@ -425,58 +556,4 @@ Paper_book::fill_pages (Page *page, int page_count, Real fudge) pages->push (page); return pages; } - -void -Paper_book::classic_output (String outname) -{ - int count = scores_.size (); - Paper_outputter *out = papers_.top ()->get_paper_outputter (outname); - out->output_header (papers_.top (), get_scopes (count - 1), 0); - - int line_count = SCM_VECTOR_LENGTH ((SCM) scores_.top ()); - for (int i = 0; i < line_count; i++) - out->output_line (scm_vector_ref ((SCM) scores_.top (), scm_int2num (i)), - 0, i == line_count - 1); - - out->output_scheme (scm_list_1 (ly_symbol2scm ("end-output"))); - progress_indication ("\n"); -} - - -#include "ly-smobs.icc" - -IMPLEMENT_DEFAULT_EQUAL_P (Paper_book); -IMPLEMENT_SMOBS (Paper_book) -IMPLEMENT_TYPE_P (Paper_book, "ly:paper-book?") - -SCM -Paper_book::mark_smob (SCM smob) -{ - Paper_book *pb = (Paper_book*) SCM_CELL_WORD_1 (smob); - for (int i = 0; i < pb->headers_.size (); i++) - scm_gc_mark (pb->headers_[i]); - for (int i = 0; i < pb->global_headers_.size (); i++) - scm_gc_mark (pb->global_headers_[i]); - for (int i = 0; i < pb->papers_.size (); i++) - scm_gc_mark (pb->papers_[i]->self_scm ()); - for (int i = 0; i < pb->scores_.size (); i++) - scm_gc_mark (pb->scores_[i]); - - scm_gc_mark (pb->copyright_); - - - return pb->tagline_; -} - -int -Paper_book::print_smob (SCM smob, SCM port, scm_print_state*) -{ - Paper_book *b = (Paper_book*) ly_cdr (smob); - - scm_puts ("#<", port); - scm_puts (classname (b), port); - scm_puts (" ", port); - //scm_puts (b->, port); - scm_puts (">", port); - return 1; -} +#endif diff --git a/lily/paper-line.cc b/lily/paper-line.cc index 38572f48b7..94a35cce26 100644 --- a/lily/paper-line.cc +++ b/lily/paper-line.cc @@ -8,6 +8,9 @@ #include "paper-line.hh" #include "ly-smobs.icc" +#include "string.hh" // to_string + +#define TITLE_PENALTY -1 Paper_line::Paper_line (Offset o, SCM stencils, bool is_title) { @@ -17,6 +20,33 @@ Paper_line::Paper_line (Offset o, SCM stencils, bool is_title) smobify_self (); } +Paper_line::~Paper_line () +{ +} + +IMPLEMENT_SMOBS (Paper_line); +IMPLEMENT_TYPE_P (Paper_line, "ly:paper-line?"); +IMPLEMENT_DEFAULT_EQUAL_P (Paper_line); + +SCM +Paper_line::mark_smob (SCM s) +{ + Paper_line *line = (Paper_line*) ly_cdr (s); + return line->stencils_; +} + +int +Paper_line::print_smob (SCM s, SCM port, scm_print_state*) +{ + scm_puts ("#number_).to_str0 (), port); + if (line->is_title ()) + scm_puts (" t", port); + scm_puts (" >", port); + return 1; +} + Offset Paper_line::dim () const { @@ -35,25 +65,29 @@ Paper_line::stencils () const return stencils_; } -SCM -Paper_line::mark_smob (SCM s) +LY_DEFINE (ly_paper_line_height, "ly:paper-line-height", + 1, 0, 0, (SCM line), + "Return the height of @var{line}.") { - Paper_line *line = (Paper_line*) ly_cdr (s); - return line->stencils_; + Paper_line *pl = unsmob_paper_line (line); + SCM_ASSERT_TYPE (pl, line, SCM_ARG1, __FUNCTION__, "paper-line"); + return gh_double2scm (pl->dim ()[Y_AXIS]); } -int -Paper_line::print_smob (SCM, SCM port, scm_print_state*) +LY_DEFINE (ly_paper_line_number, "ly:paper-line-number", + 1, 0, 0, (SCM line), + "Return the number of @var{line}.") { - scm_puts ("#", port); - return 1; + Paper_line *pl = unsmob_paper_line (line); + SCM_ASSERT_TYPE (pl, line, SCM_ARG1, __FUNCTION__, "paper-line"); + return gh_int2scm (pl->number_); } -Paper_line::~Paper_line () +LY_DEFINE (ly_paper_line_break_score, "ly:paper-line-break-score", + 1, 0, 0, (SCM line), + "Return the score for breaking after @var{line}.") { + Paper_line *pl = unsmob_paper_line (line); + SCM_ASSERT_TYPE (pl, line, SCM_ARG1, __FUNCTION__, "paper-line"); + return gh_int2scm (int (pl->is_title ()) * TITLE_PENALTY); } - -IMPLEMENT_SMOBS (Paper_line); -IMPLEMENT_TYPE_P (Paper_line, "ly:paper-line?"); -IMPLEMENT_DEFAULT_EQUAL_P (Paper_line); diff --git a/lily/paper-outputter.cc b/lily/paper-outputter.cc index 7e5fc947c9..5be3c89369 100644 --- a/lily/paper-outputter.cc +++ b/lily/paper-outputter.cc @@ -39,7 +39,7 @@ Paper_outputter::Paper_outputter (String name) if (output_format_global == PAGE_LAYOUT) { - output_func_ = SCM_UNDEFINED; + output_func_ = SCM_EOL; String name = "scm output-" + output_format_global; if (safe_global_b) { @@ -103,7 +103,7 @@ Paper_outputter::Paper_outputter (String name) output_func_ = scm_call_1 (find_dumper, scm_makfrom0str (output_format_global.to_str0 ())); - output_module_ = SCM_UNDEFINED; + output_module_ = SCM_EOL; } } diff --git a/lily/parse-scm.cc b/lily/parse-scm.cc index e9cc09ee8b..2523b33999 100644 --- a/lily/parse-scm.cc +++ b/lily/parse-scm.cc @@ -110,19 +110,16 @@ protected_ly_parse_scm (Parse_start *ps, bool safe) return scm_internal_catch (ly_symbol2scm (READ_ERROR), (safe ? &safe_catch_protected_parse_body : catch_protected_parse_body), - (void*)ps, - &parse_handler, (void*)ps); + (void*) ps, + &parse_handler, (void*) ps); } -bool parse_protect_global = true; +bool parse_protect_global = true; -/* - Try parsing. If failure, then return SCM_UNDEFINED. - */ +/* Try parsing. Upon failure return SCM_UNDEFINED. */ SCM ly_parse_scm (char const* s, int *n, Input i, bool safe) { - Parse_start ps ; ps.str = s; ps.start_location_ = i; diff --git a/lily/system.cc b/lily/system.cc index 42285df913..a03ed8cf9f 100644 --- a/lily/system.cc +++ b/lily/system.cc @@ -430,7 +430,8 @@ System::get_line () Interval x (extent (this, X_AXIS)); Interval y (extent (this, Y_AXIS)); - Paper_line *pl = new Paper_line (Offset (x.length (), y.length ()), stencils); + Paper_line *pl = new Paper_line (Offset (x.length (), y.length ()), + stencils); return pl->self_scm (); } diff --git a/ly/declarations-init.ly b/ly/declarations-init.ly index 6293006cac..428c78d248 100644 --- a/ly/declarations-init.ly +++ b/ly/declarations-init.ly @@ -61,6 +61,8 @@ melismaEnd = #(make-span-event 'ManualMelismaEvent STOP) (word-space . 0.6) )) + #(define page-breaking ly:ragged-page-breaks) + %#(define page-breaking ly:optimal-page-breaks) \include "engraver-init.ly" } diff --git a/scm/documentation-lib.scm b/scm/documentation-lib.scm index 14677006ce..943265e695 100644 --- a/scm/documentation-lib.scm +++ b/scm/documentation-lib.scm @@ -1,10 +1,10 @@ -;;; -;;; documentation-lib.scm -- Assorted Functions for generated documentation -;;; -;;; source file of the GNU LilyPond music typesetter -;;; -;;; (c) 2000--2004 Han-Wen Nienhuys -;;; Jan Nieuwenhuizen +;;;; +;;;; documentation-lib.scm -- Assorted Functions for generated documentation +;;;; +;;;; source file of the GNU LilyPond music typesetter +;;;; +;;;; (c) 2000--2004 Han-Wen Nienhuys +;;;; Jan Nieuwenhuizen (use-modules (oop goops) (srfi srfi-13) diff --git a/scm/lily.scm b/scm/lily.scm index 6cdc3656c8..08daa909f7 100644 --- a/scm/lily.scm +++ b/scm/lily.scm @@ -7,7 +7,8 @@ ;;; Library functions -(set-debug-cell-accesses! #t) +(if (defined? 'set-debug-cell-accesses!) + (set-debug-cell-accesses! #t)) (use-modules (ice-9 regex) (ice-9 safe) (oop goops) @@ -372,8 +373,8 @@ L1 is copied, L2 not. (scm output-pdftex)) -(define output-tex-module - (make-module 1021 (list (resolve-interface '(scm new-output-tex))))) +;;(define output-tex-module +;; (make-module 1021 (list (resolve-interface '(scm new-output-tex))))) (define (new-tex-output-expression expr port) (display (eval expr output-tex-module) port)) @@ -381,7 +382,7 @@ L1 is copied, L2 not. (define output-alist `( ("tex" . ("TeX output. The default output form." ,tex-output-expression)) - ("safetex" . ("TeX output. The default output form." ,new-tex-output-expression)) +;; ("safetex" . ("TeX output. The default output form." ,new-tex-output-expression)) ("scm" . ("Scheme dump: debug scheme stencil expressions" ,write)) ("sketch" . ("Bare bones Sketch output." ,sketch-output-expression)) ("sodipodi" . ("Bare bones Sodipodi output." ,sodipodi-output-expression)) diff --git a/scm/music-functions.scm b/scm/music-functions.scm index ba97c623d9..c366fbd5e3 100644 --- a/scm/music-functions.scm +++ b/scm/music-functions.scm @@ -547,7 +547,8 @@ without context specification. Called from parser." ;; automatic music transformations. (define (switch-on-debugging m) - (set-debug-cell-accesses! 15000) + (if (defined? 'set-debug-cell-accesses!) + (set-debug-cell-accesses! 15000)) m) (define-public toplevel-music-functions diff --git a/scm/page-layout.scm b/scm/page-layout.scm index 5d41927d0c..db4b4485ce 100644 --- a/scm/page-layout.scm +++ b/scm/page-layout.scm @@ -4,7 +4,6 @@ ;;;; ;;;; (c) 2004 Jan Nieuwenhuizen - (define (ly:modules-lookup modules sym) (let ((v (module-variable (car modules) sym))) (if (and v (variable-bound? v) (variable-ref v)) @@ -121,3 +120,199 @@ ((markup? copyright) (interpret-markup paper props copyright))))) +;;; optimal page breaking + +;;; This is not optimal page breaking, this is optimal distribution of +;;; lines over pages; line breaks are a given. + +;;; TODO: +;;; - user tweaking: +;;; + \pagebreak, \nopagebreak +;;; + #pages? +;;; - short circut SCORE=-1 (dismiss path) + + +(use-modules (oop goops describe)) + +(define-class () + (prev #:init-value '() #:accessor node-prev #:init-keyword #:prev) + (line #:init-value 'barf #:accessor node-line #:init-keyword #:line) + (page #:init-value 0 #:accessor node-page #:init-keyword #:page) + (score #:init-value 0 #:accessor node-score #:init-keyword #:score) + (height #:init-value 0 #:accessor node-height #:init-keyword #:score)) + +(define (node-line-number node) + (let ((line (node-line node))) + (if (null? line) 0 + (ly:paper-line-number line)))) + +(define (node-break-score node) + (let ((line (node-line node))) + (if (null? line) 0 + (ly:paper-line-break-score line)))) + +(define (make-node prev line page score) + (make #:prev prev #:line line #:page page #:score score)) + +;; print debuggging stuff +(define pld? #f) +(define MAX-CRAMP -5) + +(define-public (ly:optimal-page-breaks lines book-height text-height + first-diff last-diff) + + ;; FIXME: may need some tweaking: square, cubic + (define (height-score available used) + (let* ((empty (- available used)) + (norm-empty (* empty (/ 100 available)))) + (if (< norm-empty 0) + (if (< (/ empty available) MAX-CRAMP) + ;; cannot fill more than MAX-CRAMP + -1 + ;; overfull page is still worse by a power + (* -1 norm-empty norm-empty norm-empty)) + (* norm-empty norm-empty)))) + + (define (page-height page-number page-count) + (let ((h text-height)) + (if (= page-number 1) + (set! h (+ h first-diff))) + (if (= page-number page-count) + (set! h (+ h last-diff))) + h)) + + (define (cumulative-height lines) + (apply + (map ly:paper-line-height lines))) + + (define (get-path node) + (if (null? node) + '() + (cons node (get-path (node-prev node))))) + + (define (add-scores . lst) + (if (null? (filter (lambda (x) (> 0 x)) lst)) + (apply + lst) + -1)) + + (define (density-variance nodes) + (define (sqr x) (* x x)) + (define (density node) + (let ((p (page-height (node-page node) (node-page (car nodes)))) + (h (node-height node))) + (if (and p h) (* (- p h) (/ h 100)) 0))) + (let* ((densities (map density nodes)) + (mean (/ (apply + densities) (length densities))) + (diff (map (lambda (x) (- x mean)) densities)) + (var (map sqr diff))) + (if pld? + (begin + (format (current-error-port) "densities: ~S\n" densities) + (format (current-error-port) "mean: ~S\n" mean) + (format (current-error-port) "diff: ~S\n" diff) + (format (current-error-port) "density-var: ~S\n" var))) + (apply + var))) + + (define (walk-paths best node lines nodes paths) + (if pld? + (begin + (format (current-error-port) "node: ") + (describe node))) + (let* ((height (cumulative-height lines)) + (page (page-height (node-page node) (if (= (node-score node) 0) + (node-page node) 0)))) + (set! (node-height node) height) + + (let* ((break-score (node-break-score node)) + (density-score (if (null? paths) 0 + ;; FIXME: 5 may need some tweaking + (* 5 (density-variance + (cons node (get-path (car paths))))))) + (page-score (height-score page height)) + (this-score (add-scores page-score break-score density-score)) + (path-score (if (null? paths) 0 (node-score (car paths)))) + (score (add-scores path-score this-score)) + (nbpn (+ (if (null? paths) 0 (node-page (car paths))) 1))) + + (if pld? + (begin + (format (current-error-port) "lines: ~S\n" lines) + (format (current-error-port) "page-height: ~f\n" page) + (format (current-error-port) "height: ~f\n" height) + (format (current-error-port) "break-score: ~f\n" break-score) + (format (current-error-port) "density-score: ~f\n" density-score) + (format (current-error-port) "this-score: ~f\n" this-score) + (format (current-error-port) "path: ~f ~S\n" path-score + (if (null? paths) '() + (map node-line-number (get-path (car paths))))) + (format (current-error-port) "score: ~f\n" score) + (format (current-error-port) "best: ~f ~S\n" (node-score best) + (map node-line-number (get-path best))) + (format (current-error-port) "nbpn: ~f\n" nbpn) + (format (current-error-port) "breaking after: ~S scores: ~S\n" + (node-line-number node) + score))) + + (set! (node-score node) score) + (if (and (>= score 0) + (or (< score (node-score best)) + (= (node-score best) -1) + ;;ugh + (= (node-score best) 0))) + ;; FIXME: (set! best node) ? + (begin + (set! (node-score best) score) + (set! (node-page best) nbpn) + (set! (node-prev best) node) + (set! (node-height best) height) + + (if pld? + (format (current-error-port) "NEW BEST: ~f ~S\n" + (node-score best) + (map node-line-number (get-path best))) + (format (current-error-port) "breaking after: ~S scores: ~S\n" + (node-line-number node) + score))) + (if pld? + (format (current-error-port) "BEST still better\n"))) + (if (null? (cdr nodes)) + best + (walk-paths best (car paths) (cons (node-line node) lines) + (cdr nodes) (cdr paths)))))) + + (define (walk-lines lines nodes paths) + + (if (null? (cdr lines)) + paths + (let ((next (make-node (car nodes) (cadr lines) 0 0)) + (best (car nodes))) + + (if pld? + (begin + (format (current-error-port) "\n***********TOP*************") + (describe best)) + (newline (current-error-port))) + + (let ((break (walk-paths next best + (list (node-line best)) + (cons best nodes) + paths))) + + (if pld? + (format (current-error-port) "break: ~f ~S\n" + (node-score break) + (map node-line-number (get-path break)))) + (walk-lines (cdr lines) + (cons (make-node '() (cadr lines) 0 0) nodes) + (cons break paths)))))) + + (let* ((dummy (make-node '() '() 0 0)) + (result (walk-lines lines + (list (make-node dummy (car lines) 0 0)) + (list dummy))) + (path (get-path (car result))) + ;; CDR: junk dummy node + (breaks (cdr (reverse (map node-line-number path))))) + + (format (current-error-port) "breaks: ~S\n" breaks) + (force-output (current-error-port)) + (list->vector breaks))) -- 2.39.2