X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fpaper-book.cc;h=08e378b41eb911542203fde1766fd970240f081f;hb=26cd516049c72cf63375979fd4a0fbe2f11a9395;hp=6bcbe0c40e74fd684fbacf159919f0f28ede56c8;hpb=a6e2861512e43ccd08f55ac276c0f2c7fb6f5dd2;p=lilypond.git diff --git a/lily/paper-book.cc b/lily/paper-book.cc index 6bcbe0c40e..08e378b41e 100644 --- a/lily/paper-book.cc +++ b/lily/paper-book.cc @@ -3,486 +3,359 @@ source file of the GNU LilyPond music typesetter - (c) 2004 Jan Nieuwenhuizen + (c) 2004--2005 Jan Nieuwenhuizen */ -#include -#include +#include "paper-book.hh" -#include "ly-module.hh" #include "main.hh" -#include "paper-book.hh" -#include "paper-def.hh" -#include "paper-outputter.hh" +#include "output-def.hh" #include "paper-score.hh" -#include "stencil.hh" +#include "paper-system.hh" +#include "text-interface.hh" +#include "warn.hh" -static Real const MIN_COVERAGE = 0.66; -static Real const MAX_CRAMP = 0.05; +#include "ly-smobs.icc" -static SCM -stencil2line (Stencil* stil) +Paper_book::Paper_book () { - static SCM z = ly_offset2scm (Offset (0, 0)); - Offset dim = Offset (stil->extent (X_AXIS).length (), - stil->extent (Y_AXIS).length ()); - return scm_cons (ly_offset2scm (dim), - scm_list_1 (scm_cons (z, stil->smobbed_copy ()))); + header_ = SCM_EOL; + header_0_ = SCM_EOL; + pages_ = SCM_BOOL_F; + scores_ = SCM_EOL; + performances_ = SCM_EOL; + systems_ = SCM_BOOL_F; + + paper_ = 0; + smobify_self (); } -static SCM -title2line (Stencil* stil) +Paper_book::~Paper_book () { - SCM s = stencil2line (stil); - /* whugh, add marker recognise titles. */ - return scm_cons (scm_cons (ly_symbol2scm ("title"), ly_car (s)), ly_cdr (s)); } -/* Simplistic page interface */ -class Page -{ -public: - Paper_def *paper_; - static int page_count_; - int number_; - int line_count_; - - Protected_scm lines_; - Protected_scm header_; - Protected_scm footer_; - Protected_scm copyright_; - Protected_scm tagline_; - - Stencil *get_header () { return unsmob_stencil (header_); } - Stencil *get_copyright () { return unsmob_stencil (copyright_); } - Stencil *get_tagline () { return unsmob_stencil (tagline_); } - Stencil *get_footer () { return unsmob_stencil (footer_); } - - /* actual height filled with text. */ - Real height_; - - // HMMM all this size stuff to paper/paper-outputter? - Real hsize_; - Real vsize_; - Real left_margin_; - Real top_margin_; - Real bottom_margin_; - Real foot_sep_; - Real head_sep_; - Real text_width_; - - /* available area for text. */ - Real text_height (); - - Page (Paper_def*, int); - void output (Paper_outputter*, bool); -}; - -int Page::page_count_ = 0; - -Page::Page (Paper_def *paper, int number) +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_ = paper; - number_ = number; - page_count_++; - - height_ = 0; - lines_ = SCM_EOL; - line_count_ = 0; - - hsize_ = paper->get_realvar (ly_symbol2scm ("hsize")); - vsize_ = paper->get_realvar (ly_symbol2scm ("vsize")); - top_margin_ = paper->get_realvar (ly_symbol2scm ("top-margin")); - bottom_margin_ = paper->get_realvar (ly_symbol2scm ("bottom-margin")); - head_sep_ = paper->get_realvar (ly_symbol2scm ("head-sep")); - foot_sep_ = paper->get_realvar (ly_symbol2scm ("foot-sep")); - text_width_ = paper->get_realvar (ly_symbol2scm ("linewidth")); - left_margin_ = (hsize_ - text_width_) / 2; - - copyright_ = SCM_EOL; - tagline_ = SCM_EOL; - - SCM make_header = scm_primitive_eval (ly_symbol2scm ("make-header")); - SCM make_footer = scm_primitive_eval (ly_symbol2scm ("make-footer")); - - header_ = scm_call_2 (make_header, paper_->smobbed_copy (), - scm_int2num (number_)); - // FIXME: why does this (generates Stencil) not trigger font load? - if (get_header ()) - get_header ()->align_to (Y_AXIS, UP); - - footer_ = scm_call_2 (make_footer, paper_->smobbed_copy (), - scm_int2num (number_)); - if (get_footer ()) - get_footer ()->align_to (Y_AXIS, UP); + Paper_book *b = (Paper_book *) SCM_CELL_WORD_1 (smob); + if (b->paper_) + scm_gc_mark (b->paper_->self_scm ()); + scm_gc_mark (b->header_); + scm_gc_mark (b->header_0_); + scm_gc_mark (b->pages_); + scm_gc_mark (b->performances_); + scm_gc_mark (b->scores_); + return b->systems_; } -void -Page::output (Paper_outputter *out, bool is_last) +int +Paper_book::print_smob (SCM smob, SCM port, scm_print_state*) { - progress_indication ("[" + to_string (number_)); - out->output_scheme (scm_list_1 (ly_symbol2scm ("start-page"))); - 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); - o[Y_AXIS] += head_sep_; - } - for (SCM s = lines_; gh_pair_p (s); s = ly_cdr (s)) - { - SCM line = ly_car (s); - SCM offset = ly_car (line); - if (ly_car (offset) == ly_symbol2scm ("title")) - line = scm_cons (ly_cdr (offset), ly_cdr (line)); - out->output_line (line, &o, - is_last && gh_pair_p (ly_cdr (s)) && !get_copyright () - && !get_tagline () && !get_footer ()); - if (gh_pair_p (ly_cdr (s)) && ly_car (offset) != ly_symbol2scm ("title")) - o[Y_AXIS] += vfill; - } + Paper_book *b = (Paper_book *) SCM_CELL_WORD_1 (smob); -#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 ()); - if (get_tagline ()) - out->output_line (stencil2line (get_tagline ()), &o, - is_last && !get_footer ()); - if (get_footer ()) - out->output_line (stencil2line (get_footer ()), &o, is_last); - out->output_scheme (scm_list_2 (ly_symbol2scm ("stop-page"), - gh_bool2scm (is_last && !get_footer ()))); - progress_indication ("]"); + scm_puts ("#<", port); + scm_puts (classname (b), port); + scm_puts (" ", port); + scm_puts (">", port); + return 1; } -Real -Page::text_height () +SCM +dump_fields () { - Real h = vsize_ - top_margin_ - bottom_margin_; - if (get_header ()) - h -= get_header ()->extent (Y_AXIS).length () + head_sep_; - if (get_copyright () || get_tagline () || get_footer ()) - h -= foot_sep_; - if (get_copyright ()) - h -= get_copyright ()->extent (Y_AXIS).length (); - if (get_tagline ()) - h -= get_tagline ()->extent (Y_AXIS).length (); - if (get_footer ()) - h -= get_footer ()->extent (Y_AXIS).length (); - return h; + SCM fields = SCM_EOL; + for (int i = dump_header_fieldnames_global.size (); i--;) + fields + = scm_cons (ly_symbol2scm (dump_header_fieldnames_global[i].to_str0 ()), + fields); + return fields; } -/****************************************************************/ +void +Paper_book::add_score (SCM s) +{ + scores_ = scm_cons (s, scores_); +} -/* Current global paper book. Gives default_rendering access from - input-file-results. */ -Paper_book *paper_book; -Paper_book::Paper_book () +void +Paper_book::add_performance (SCM s) { - smobify_self (); + performances_ = scm_cons (s, performances_); } -Paper_book::~Paper_book () + +void +Paper_book::output (SCM output_channel) { + if (scores_ == SCM_EOL) + return; + + /* Generate all stencils to trigger font loads. */ + pages (); + + SCM scopes = SCM_EOL; + if (ly_is_module (header_)) + scopes = scm_cons (header_, scopes); + + String mod_nm = "scm framework-" + output_backend_global; + + SCM mod = scm_c_resolve_module (mod_nm.to_str0 ()); + if (make_print) + { + SCM func = scm_c_module_lookup (mod, "output-framework"); + + func = scm_variable_ref (func); + scm_apply_0 (func, scm_list_n (output_channel, + self_scm (), + scopes, + dump_fields (), + SCM_UNDEFINED)); + } + + if (make_preview) + { + SCM func = scm_c_module_lookup (mod, "output-preview-framework"); + func = scm_variable_ref (func); + scm_apply_0 (func, scm_list_n (output_channel, + self_scm (), + scopes, + dump_fields (), + SCM_UNDEFINED)); + } } void -Paper_book::output (String outname) +Paper_book::classic_output (SCM output) { - if (!papers_.size ()) - return; - /* Generate all stencils to trigger font loads. */ - Link_array *pages = get_pages (); + systems (); + + SCM scopes = SCM_EOL; + if (ly_is_module (header_)) + scopes = scm_cons (header_, scopes); + + if (ly_is_module (header_0_)) + scopes = scm_cons (header_0_, scopes); - Paper_def *paper = papers_[0]; - Paper_outputter *out = paper->get_paper_outputter (outname); - out->output_header (paper, get_scopes (0), pages->size ()); + String format = output_backend_global; + String mod_nm = "scm framework-" + format; - int page_count = pages->size (); - for (int i = 0; i < page_count; i++) - (*pages)[i]->output (out, i + 1 == page_count); + SCM mod = scm_c_resolve_module (mod_nm.to_str0 ()); + SCM func = scm_c_module_lookup (mod, "output-classic-framework"); + + func = scm_variable_ref (func); + scm_apply_0 (func, scm_list_n (output, + self_scm (), + scopes, + dump_fields (), + SCM_UNDEFINED)); - out->output_scheme (scm_list_1 (ly_symbol2scm ("end-output"))); progress_indication ("\n"); } -SCM -Paper_book::get_scopes (int i) +/* TODO: resurrect more complex user-tweaks for titling? */ +Stencil +Paper_book::book_title () { + SCM title_func = paper_->lookup_variable (ly_symbol2scm ("book-title")); + Stencil title; + SCM scopes = SCM_EOL; - if (headers_[i]) - scopes = scm_cons (headers_[i], scopes); - if (global_headers_[i] && global_headers_[i] != headers_[i]) - scopes = scm_cons (global_headers_[i], scopes); - return scopes; + if (ly_is_module (header_)) + scopes = scm_cons (header_, scopes); + + SCM tit = SCM_EOL; + if (ly_is_procedure (title_func)) + tit = scm_call_2 (title_func, + paper_->self_scm (), + scopes); + + if (unsmob_stencil (tit)) + title = *unsmob_stencil (tit); + + if (!title.is_empty ()) + title.align_to (Y_AXIS, UP); + + return title; } -Stencil* -Paper_book::get_title (int i) +Stencil +Paper_book::score_title (SCM header) { - SCM user_title = scm_primitive_eval (ly_symbol2scm ("user-title")); - SCM book_title = scm_primitive_eval (ly_symbol2scm ("book-title")); - SCM score_title = scm_primitive_eval (ly_symbol2scm ("score-title")); - SCM field = (i == 0 ? ly_symbol2scm ("bookTitle") - : ly_symbol2scm ("scoreTitle")); - - Stencil *title = 0; - SCM scopes = get_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, - papers_[0]->self_scm (), - scm_variable_ref (s))); - else - title = unsmob_stencil (scm_call_2 (i == 0 ? book_title : score_title, - papers_[0]->self_scm (), - scopes)); - if (title) - title->align_to (Y_AXIS, UP); - + SCM title_func = paper_->lookup_variable (ly_symbol2scm ("score-title")); + + Stencil title; + + SCM scopes = SCM_EOL; + if (ly_is_module (header_)) + scopes = scm_cons (header_, scopes); + + if (ly_is_module (header)) + scopes = scm_cons (header, scopes); + + SCM tit = SCM_EOL; + if (ly_is_procedure (title_func)) + tit = scm_call_2 (title_func, + paper_->self_scm (), + scopes); + + if (unsmob_stencil (tit)) + title = *unsmob_stencil (tit); + + if (!title.is_empty ()) + title.align_to (Y_AXIS, UP); + return title; } -/* calculate book height, #lines, stencils. */ void -Paper_book::init () +set_system_penalty (Paper_system *ps, SCM header) { - int score_count = scores_.size (); - - /* Calculate the full book height. Hmm, can't we cache system - heights while making stencils? */ - height_ = 0; - for (int i = 0; i < score_count; i++) + if (ly_is_module (header)) { - Stencil *title = get_title (i); - if (title) - height_ += title->extent (Y_AXIS).length (); - - int line_count = SCM_VECTOR_LENGTH ((SCM) scores_[i]); - for (int j = 0; j < line_count; j++) + SCM force = ly_module_lookup (header, ly_symbol2scm ("breakbefore")); + if (SCM_VARIABLEP (force) + && scm_is_bool (SCM_VARIABLE_REF (force))) { - SCM line = scm_vector_ref ((SCM) scores_[i], scm_int2num (j)); - height_ += ly_scm2offset (ly_car (line))[Y_AXIS]; + ps->break_before_penalty_ = to_boolean (SCM_VARIABLE_REF (force)) + ? -10000 + : 10000; } } - - Paper_def *paper = papers_[0]; - SCM scopes = get_scopes (0); - - SCM make_tagline = scm_primitive_eval (ly_symbol2scm ("make-tagline")); - tagline_ = scm_call_2 (make_tagline, paper->smobbed_copy (), scopes); - Real tag_height = 0; - if (Stencil *s = unsmob_stencil (tagline_)) - tag_height = s->extent (Y_AXIS).length (); - height_ += tag_height; - - SCM make_copyright = scm_primitive_eval (ly_symbol2scm ("make-copyright")); - copyright_ = scm_call_2 (make_copyright, paper->smobbed_copy (), scopes); - Real copy_height = 0; - if (Stencil *s = unsmob_stencil (copyright_)) - copy_height = s->extent (Y_AXIS).length (); - 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 () +void +Paper_book::add_score_title (SCM header) { - init (); - Page::page_count_ = 0; - 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; - - 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) + Stencil title = score_title (header); + if (title.is_empty ()) + title = score_title (header_); + if (!title.is_empty ()) { - /* 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; - } + Paper_system *ps = new Paper_system (title, true); + systems_ = scm_cons (ps->self_scm (), systems_); + scm_gc_unprotect_object (ps->self_scm ()); + set_system_penalty (ps, header); } - - if (!pages) - /* Fudging failed; just fill pages. */ - pages = fill_pages (page, page_count, 0); - return pages; } -/* Simplistic page breaking: - add lines until HEIGHT > PAGE.TEXT_HEIGHT_ + FUDGE */ -Link_array* -Paper_book::fill_pages (Page *page, int page_count, Real fudge) +SCM +Paper_book::systems () { - 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++) + if (systems_ != SCM_BOOL_F) + return systems_; + + systems_ = SCM_EOL; + Stencil title = book_title (); + + if (!title.is_empty ()) { - Real h = 0; - Stencil *title = get_title (i); - if (title) - h = title->extent (Y_AXIS).length (); + Paper_system *ps = new Paper_system (title, true); + set_system_penalty (ps, header_); - int line_count = SCM_VECTOR_LENGTH ((SCM) scores_[i]); - for (int j = 0; j < line_count; j++) + systems_ = scm_cons (ps->self_scm (), systems_); + scm_gc_unprotect_object (ps->self_scm ()); + } + + SCM page_properties + = scm_call_1 (ly_lily_module_constant ("layout-extract-page-properties"), + paper_->self_scm ()); + + SCM header = SCM_EOL; + for (SCM s = scm_reverse (scores_); s != SCM_EOL; s = scm_cdr (s)) + { + if (ly_is_module (scm_car (s))) { - SCM line = scm_vector_ref ((SCM) scores_[i], scm_int2num (j)); - h += ly_scm2offset (ly_car (line))[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))))) + header = scm_car (s); + if (header_0_ == SCM_EOL) + header_0_ = header; + } + else if (Music_output *mop = unsmob_music_output (scm_car (s))) + + { + if (Paper_score *pscore = dynamic_cast (mop)) { - pages->push (page); - page = new Page (paper, ++page_number); - if (unsmob_stencil (tagline_) && page_number == page_count) - page->tagline_ = tagline_; - text_height = page->text_height (); + add_score_title (header); + + header = SCM_EOL; + + SCM system_list = scm_vector_to_list (pscore->get_paper_systems ()); + system_list = scm_reverse (system_list); + systems_ = scm_append (scm_list_2 (system_list, systems_)); } - 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; + else + { + /* + Ignore MIDI + */ + } + } + else if (scm_is_vector (scm_car (s))) + { + /* + UGH. code dup. + */ + add_score_title (header); + header = SCM_EOL; + + SCM system_list = scm_vector_to_list (scm_car (s)); + system_list = scm_reverse (system_list); + systems_ = scm_append (scm_list_2 (system_list, systems_)); } + else if (Text_interface::markup_p (scm_car (s))) + { + SCM t = Text_interface::interpret_markup (paper_->self_scm (), + page_properties, + scm_car (s)); + // FIXME: title=true? + Paper_system *ps = new Paper_system (*unsmob_stencil (t), true); + systems_ = scm_cons (ps->self_scm (), systems_); + scm_gc_unprotect_object (ps->self_scm ()); + // FIXME: figure out penalty. + //set_system_penalty (ps, scores_[i].header_); + } + else + assert (0); } - 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"); -} + systems_ = scm_reverse (systems_); + int i = 0; + Paper_system *last = 0; + for (SCM s = systems_; s != SCM_EOL; s = scm_cdr (s)) + { + Paper_system *ps = unsmob_paper_system (scm_car (s)); + ps->number_ = ++i; + + if (last + && last->is_title () + && !ps->break_before_penalty_) + ps->break_before_penalty_ = 10000; + last = ps; + } -#include "ly-smobs.icc" - -IMPLEMENT_DEFAULT_EQUAL_P (Paper_book); -IMPLEMENT_SMOBS (Paper_book) -IMPLEMENT_TYPE_P (Paper_book, "ly:paper-book?") + return systems_; +} SCM -Paper_book::mark_smob (SCM smob) +Paper_book::pages () { - 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]); - return SCM_EOL; + if (SCM_BOOL_F != pages_) + return pages_; + + pages_ = SCM_EOL; + SCM proc = paper_->c_variable ("page-breaking"); + pages_ = scm_apply_0 (proc, scm_list_2 (systems (), self_scm ())); + return pages_; } -int -Paper_book::print_smob (SCM smob, SCM port, scm_print_state*) +SCM +Paper_book::performances () const { - 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; + return scm_reverse (performances_); }