From d80a72a8d76c0813338b60ca23316bb9544dd82d Mon Sep 17 00:00:00 2001 From: Jan Nieuwenhuizen Date: Fri, 12 Mar 2004 21:30:39 +0000 Subject: [PATCH] (fill_pages): New method. Try to cramp or expand pages. --- ChangeLog | 5 + input/test/title-markup.ly | 2 +- lily/include/paper-book.hh | 5 + lily/paper-book.cc | 182 ++++++++++++++++++++++++++++--------- lily/parser.yy | 1 - lily/stencil-scheme.cc | 28 +++--- 6 files changed, 163 insertions(+), 60 deletions(-) diff --git a/ChangeLog b/ChangeLog index b3316b63de..cb511a7d60 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2004-03-12 Jan Nieuwenhuizen + + * lily/paper-book.cc (fill_pages): New method. Try to cramp or + expand pages. + 2004-03-12 Han-Wen Nienhuys * scm/part-combiner.scm (make-autochange-music): switch rests diff --git a/input/test/title-markup.ly b/input/test/title-markup.ly index 5b5311b403..a4ce65ff14 100644 --- a/input/test/title-markup.ly +++ b/input/test/title-markup.ly @@ -78,7 +78,7 @@ spaceTest = \markup { "two space chars" } \score { \context Staff \notes \relative c' { - \repeat unfold 30 { a b c d \break } + \repeat unfold 35 { a b c d \break } c1 } } diff --git a/lily/include/paper-book.hh b/lily/include/paper-book.hh index 2e58a51388..8a25040733 100644 --- a/lily/include/paper-book.hh +++ b/lily/include/paper-book.hh @@ -23,9 +23,14 @@ public: Array global_headers_; Link_array papers_; Array scores_; + Real height_; + Protected_scm copyright_; + Protected_scm tagline_; Paper_book (); + void init (); Link_array *get_pages (); + Link_array *fill_pages (Page*, int, Real); SCM get_scopes (int); Stencil* get_title (int); void output (String); diff --git a/lily/paper-book.cc b/lily/paper-book.cc index 0fed5b78fb..b89d0a86b6 100644 --- a/lily/paper-book.cc +++ b/lily/paper-book.cc @@ -7,6 +7,7 @@ */ #include +#include #include "ly-module.hh" #include "main.hh" @@ -16,6 +17,9 @@ #include "paper-score.hh" #include "stencil.hh" +static Real const MIN_COVERAGE = 0.66; +static Real const MAX_CRAMP = 0.05; + static SCM stencil2line (Stencil* stil) { @@ -121,6 +125,14 @@ Page::output (Paper_outputter *out, bool is_last) Offset o (left_margin_, top_margin_); Real vfill = line_count_ > 1 ? (text_height () - height_) / (line_count_ - 1) : 0; + + Real coverage = height_ / text_height (); + if (coverage < MIN_COVERAGE) + /* Do not space out a badly filled page. This is too simplistic + (ie broken), because this should not vary too much between + (subsequent?) pages in a book. */ + vfill = 0; + if (get_header ()) { out->output_line (stencil2line (get_header ()), &o, false); @@ -138,8 +150,20 @@ Page::output (Paper_outputter *out, bool is_last) if (gh_pair_p (ly_cdr (s)) && ly_car (offset) != ly_symbol2scm ("title")) o[Y_AXIS] += vfill; } + +#if 0 if (get_copyright () || get_tagline () || get_footer ()) o[Y_AXIS] += foot_sep_; +#else + o[Y_AXIS] = vsize_ - bottom_margin_; + if (get_copyright ()) + o[Y_AXIS] -= get_copyright ()->extent (Y_AXIS).length (); + if (get_tagline ()) + o[Y_AXIS] -= get_tagline ()->extent (Y_AXIS).length (); + if (get_footer ()) + o[Y_AXIS] -= get_footer ()->extent (Y_AXIS).length (); +#endif + if (get_copyright ()) out->output_line (stencil2line (get_copyright ()), &o, is_last && !get_tagline () && !get_footer ()); @@ -241,29 +265,26 @@ Paper_book::get_title (int i) return title; } -/* Ideas: - - real page breaking algorithm (Gourlay?) - - override: # pages, or pageBreakLines= #'(3 3 4), ? */ -Link_array* -Paper_book::get_pages () +/* calculate book height, #lines, stencils. */ +void +Paper_book::init () { - 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; + height_ = 0; for (int i = 0; i < score_count; i++) { Stencil *title = get_title (i); if (title) - book_height += title->extent (Y_AXIS).length (); + 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]; + height_ += ly_scm2offset (ly_car (line))[Y_AXIS]; } } @@ -271,35 +292,104 @@ Paper_book::get_pages () SCM scopes = get_scopes (0); SCM make_tagline = scm_primitive_eval (ly_symbol2scm ("make-tagline")); - SCM tagline = scm_call_2 (make_tagline, paper->smobbed_copy (), scopes); + tagline_ = scm_call_2 (make_tagline, paper->smobbed_copy (), scopes); Real tag_height = 0; - if (Stencil *s = unsmob_stencil (tagline)) + if (Stencil *s = unsmob_stencil (tagline_)) tag_height = s->extent (Y_AXIS).length (); - book_height += tag_height; + height_ += tag_height; SCM make_copyright = scm_primitive_eval (ly_symbol2scm ("make-copyright")); - SCM copyright = scm_call_2 (make_copyright, paper->smobbed_copy (), scopes); + copyright_ = scm_call_2 (make_copyright, paper->smobbed_copy (), scopes); Real copy_height = 0; - if (Stencil *s = unsmob_stencil (copyright)) + if (Stencil *s = unsmob_stencil (copyright_)) copy_height = s->extent (Y_AXIS).length (); - book_height += copy_height; - + 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), ? */ +Link_array* +Paper_book::get_pages () +{ + init (); 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; + Paper_def *paper = papers_[0]; + 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); + 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; -#if 0 - fprintf (stderr, "book_height: %f\n", book_height); - fprintf (stderr, "vsize: %f\n", page->vsize_); - fprintf (stderr, "pages: %d\n", page_count); -#endif + Link_array* pages = 0; + if ((page_count > 1 && (r / (page_count - 1)) < MAX_CRAMP)) + { + /* Just a little more space (size () != page_count - 1) + { + /* Cramping failed. */ + page = pages->get (0); + delete pages; + pages = 0; + } + } + if (!pages && ((1 - r) / page_count) < 1 - MIN_COVERAGE) + { + /* 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) + { + /* expanding failed. */ + page = pages->get (0); + delete pages; + pages = 0; + } + } + + if (!pages) + /* Fudging failed; just fill pages. */ + pages = fill_pages (page, page_count, 0); + return pages; +} - /* Simplistic page breaking. */ +/* Simplistic page breaking: + add lines until HEIGHT > PAGE.TEXT_HEIGHT_ + FUDGE */ +Link_array* +Paper_book::fill_pages (Page *page, int page_count, Real fudge) +{ + int page_number = 1; + int score_count = scores_.size (); + Paper_def *paper = papers_[0]; + Link_array *pages = new Link_array; + page->lines_ = SCM_EOL; + page->height_ = 0; + page->line_count_ = 0; Real text_height = page->text_height (); for (int i = 0; i < score_count; i++) { @@ -313,27 +403,33 @@ Paper_book::get_pages () { SCM line = scm_vector_ref ((SCM) scores_[i], scm_int2num (j)); h += ly_scm2offset (ly_car (line))[Y_AXIS]; - if (page->height_ + h > text_height) + 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))))) { pages->push (page); page = new Page (paper, ++page_number); - if (unsmob_stencil (tagline) && page_number == page_count) - page->tagline_ = tagline; + if (unsmob_stencil (tagline_) && page_number == page_count) + page->tagline_ = tagline_; text_height = page->text_height (); } - if (page->height_ + h <= text_height || page->height_ == 0) - { - if (j == 0 && title) - page->lines_ - = ly_snoc (title2line (title), page->lines_); - page->lines_ = ly_snoc (line, page->lines_); - page->line_count_++; - page->height_ += h; - h = 0; - } + if (j == 0 && title) + page->lines_ = ly_snoc (title2line (title), page->lines_); + page->lines_ = ly_snoc (line, page->lines_); + page->line_count_++; + page->height_ += h; + h = 0; } } - + pages->push (page); return pages; } diff --git a/lily/parser.yy b/lily/parser.yy index 17adedcc94..ef4ee30632 100644 --- a/lily/parser.yy +++ b/lily/parser.yy @@ -457,7 +457,6 @@ toplevel_expression: id = id ? id->clone () : new Paper_def; default_rendering (sc->music_, id->self_scm (), head, outname); - scm_gc_unprotect_object (id->self_scm ()); } scm_gc_unprotect_object (sc->self_scm ()); diff --git a/lily/stencil-scheme.cc b/lily/stencil-scheme.cc index 4e30e129ae..0f859d8227 100644 --- a/lily/stencil-scheme.cc +++ b/lily/stencil-scheme.cc @@ -16,7 +16,7 @@ UMGH. junkme! */ -LY_DEFINE (ly_stencil_set_extent_x,"ly:stencil-set-extent!", +LY_DEFINE (ly_stencil_set_extent_x, "ly:stencil-set-extent!", 3, 0, 0, (SCM stil, SCM axis, SCM np), "Set the extent of @var{stil} " "(@var{extent} must be a pair of numbers) " @@ -49,7 +49,7 @@ LY_DEFINE (ly_translate_stencil_axis, "ly:stencil-translate-axis", } -LY_DEFINE (ly_translate_stencil,"ly:stencil-translate", +LY_DEFINE (ly_translate_stencil, "ly:stencil-translate", 2, 0, 0, (SCM stil, SCM offset), "Return a @var{stil}, " "but translated by @var{offset} (a pair of numbers).") @@ -66,7 +66,7 @@ LY_DEFINE (ly_translate_stencil,"ly:stencil-translate", } LY_DEFINE (ly_stencil_get_expr, "ly:stencil-get-expr", - 1 , 0, 0, (SCM stil), + 1, 0, 0, (SCM stil), "Return the expression of @var{stil}.") { Stencil *s = unsmob_stencil (stil); @@ -74,8 +74,8 @@ LY_DEFINE (ly_stencil_get_expr, "ly:stencil-get-expr", return s->get_expr (); } -LY_DEFINE (ly_stencil_get_extent, - "ly:stencil-extent", 2 , 0, 0, (SCM stil, SCM axis), +LY_DEFINE (ly_stencil_get_extent, "ly:stencil-extent", + 2, 0, 0, (SCM stil, SCM axis), "Return a pair of numbers signifying the extent of @var{stil} in " "@var{axis} direction (0 or 1 for x and y axis respectively).") { @@ -87,10 +87,8 @@ LY_DEFINE (ly_stencil_get_extent, } LY_DEFINE (ly_stencil_moved_to_edge, "ly:stencil-moved-to-edge", - 4, 2, 0, (SCM first, SCM axis, SCM direction, - SCM second, - SCM padding, - SCM minimum), + 4, 2, 0, (SCM first, SCM axis, SCM direction, SCM second, + SCM padding, SCM minimum), "Similar to @code{ly:stencil-combine-edge}, but returns " "@var{second} positioned to be next to @var{first}. ") { @@ -171,8 +169,8 @@ LY_DEFINE (ly_stencil_combine_at_edge, "ly:stencil-combine-at-edge", return result.smobbed_copy (); } -LY_DEFINE (ly_stencil_add , - "ly:stencil-add", 0, 0, 1, (SCM args), +LY_DEFINE (ly_stencil_add , "ly:stencil-add", + 0, 0, 1, (SCM args), "Combine stencils. Takes any number of arguments.") { #define FUNC_NAME __FUNCTION__ @@ -193,8 +191,8 @@ LY_DEFINE (ly_stencil_add , return result.smobbed_copy (); } -LY_DEFINE (ly_make_stencil, - "ly:make-stencil", 3, 0, 0, (SCM expr, SCM xext, SCM yext), +LY_DEFINE (ly_make_stencil, "ly:make-stencil", + 3, 0, 0, (SCM expr, SCM xext, SCM yext), " \n" "Stencils are a device independent output expressions." "They carry two pieces of information: \n\n" @@ -221,8 +219,8 @@ fontify_atom (Font_metric const *met, SCM f) ly_quote_scm (met->description_), f, SCM_UNDEFINED); } -LY_DEFINE (ly_fontify_atom,"ly:fontify-atom", 2, 0, 0, - (SCM met, SCM f), +LY_DEFINE (ly_fontify_atom,"ly:fontify-atom", + 2, 0, 0, (SCM met, SCM f), "Add a font selection command for the font metric @var{met} " "to @var{f}.") { -- 2.39.2