X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fpaper-book.cc;h=6c5c02dabb61fcd52fa9f6980b84c970d1f284b7;hb=a2e0081b9f6263a3ddb8e7bf898f6592dad5f89e;hp=6c1c21c75b8e6b704362044ecc3e973f48ef0ea1;hpb=58d70e865ebf68e038244fca99110bd2e2917912;p=lilypond.git diff --git a/lily/paper-book.cc b/lily/paper-book.cc index 6c1c21c75b..6c5c02dabb 100644 --- a/lily/paper-book.cc +++ b/lily/paper-book.cc @@ -6,200 +6,515 @@ (c) 2004 Jan Nieuwenhuizen */ -#include - +#include "ly-module.hh" #include "main.hh" +#include "page.hh" #include "paper-book.hh" +#include "output-def.hh" +#include "paper-outputter.hh" +#include "paper-line.hh" #include "paper-score.hh" -#include "paper-def.hh" #include "stencil.hh" -#include "paper-outputter.hh" - -// WIP -- simplistic page interface -// Do we need this at all? SCM, smob? -class Page -{ -public: - Paper_def *paper_; +#include "warn.hh" - SCM lines_; - Stencil *header_; - Stencil *footer_; - /* actual height filled with text. */ - Real height_; +/* + Ugh. the Function of the Paper_book class is unclear. Trim this + file. - //HMMM all this size stuff to paper/paper-outputter? - Real hsize_; - Real vsize_; - Real foot_sep_; - Real head_sep_; + */ - /* available area for text. */ - Real text_height (); +// JUNKME +SCM +stencil2line (Stencil stil, bool is_title = false) +{ + static SCM z; + if (!z) + 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), + -10001 * is_title, is_title); - Page (Paper_def*); - void output (Paper_outputter*, bool); -}; + return scm_gc_unprotect_object (pl->self_scm ()); +} -Page::Page (Paper_def *paper) + +Paper_book::Paper_book () { - paper_ = paper; - height_ = 0; - header_ = 0; - footer_ = 0; + pages_ = SCM_EOL; lines_ = SCM_EOL; + copyright_ = SCM_EOL; + tagline_ = SCM_EOL; + header_ = SCM_EOL; - hsize_ = paper->get_realvar (ly_symbol2scm ("hsize")); - vsize_ = paper->get_realvar (ly_symbol2scm ("vsize")); - head_sep_ = 0; //paper->get_realvar (ly_symbol2scm ("head-sep")); - foot_sep_ = 0; //paper->get_realvar (ly_symbol2scm ("foot-sep")); + bookpaper_ = 0; + smobify_self (); } -void -Page::output (Paper_outputter *out, bool is_last) +Paper_book::~Paper_book () { -#if ONE_SCORE_PER_PAGE - int line_count = SCM_VECTOR_LENGTH ((SCM) lines_); - for (int i = 0; i < line_count; i++) - out->output_line (scm_vector_ref (lines_, scm_int2num (i)), - is_last && i == line_count - 1); -#else - // TODO: header/footer etc - out->output_scheme (scm_list_1 (ly_symbol2scm ("start-page"))); - for (SCM s = lines_; gh_pair_p (s); s = ly_cdr (s)) - out->output_line (ly_car (s), is_last && gh_pair_p (ly_cdr (s))); - out->output_scheme (scm_list_2 (ly_symbol2scm ("stop-page"), - gh_bool2scm (is_last))); -#endif } -Real -Page::text_height () +#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) { - Real h = vsize_; - if (header_) - h -= header_->extent (Y_AXIS).length () + head_sep_; - if (footer_) - h -= footer_->extent (Y_AXIS).length () + foot_sep_; - return h; + Paper_book *b = (Paper_book*) SCM_CELL_WORD_1 (smob); + for (int i = 0; i < b->score_lines_.size (); i++) + b->score_lines_[i].gc_mark (); + + scm_gc_mark (b->copyright_); + if (b->bookpaper_) + scm_gc_mark (b->bookpaper_->self_scm ()); + scm_gc_mark (b->header_); + scm_gc_mark (b->pages_); + scm_gc_mark (b->lines_); + return b->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; +} + +Array +split_string (String s, char c) +{ + Array rv; + while (s.length ()) + { + int i = s.index (c); + + if (i == 0) + { + s = s.nomid_string (0, 1); + continue; + } + + if (i < 0) + i = s.length () ; + + rv.push (s.cut_string (0, i)); + s = s.nomid_string (0, i); + } -Paper_book *paper_book; + return rv; +} -Paper_book::Paper_book () +SCM +dump_fields () { + 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; } +/* + TODO: there is too much code dup, and the interface is not + clear. FIXME. + */ void -Paper_book::output () +Paper_book::output (String outname) { - Paper_outputter *out = paper_scores_[0]->outputter_; + if (!score_lines_.size ()) + return; + + /* Generate all stencils to trigger font loads. */ + pages (); + + Array output_formats = split_string (output_format_global, ','); + + for (int i = 0; i < output_formats.size (); i++) + { + String format = output_formats[i]; + Paper_outputter *out = get_paper_outputter (outname + "." + output_formats[i], format); + + + - Paper_def *paper = paper_scores_[0]->paper_; - out->output_header (paper); + SCM scopes = SCM_EOL; + if (ly_c_module_p (header_)) + scopes = scm_cons (header_, scopes); - if (paper_scores_[0]->book_title_) - out->output_expr (paper_scores_[0]->book_title_->get_expr (), - Offset (0, 0)); + String func_nm = format; + func_nm = "output-framework-" + func_nm; + + SCM func = ly_scheme_function (func_nm.to_str0 ()); + scm_apply_0 (func, scm_list_n (out->self_scm (), + self_scm (), + scopes, + dump_fields (), + scm_makfrom0str (outname.to_str0 ()), + SCM_UNDEFINED + )) ; - Link_array *pages = get_pages (); - int page_count = pages->size (); - for (int i = 0; i < page_count; i++) - (*pages)[i]->output (out, i + 1 == page_count); + scm_gc_unprotect_object (out->self_scm ()); + } +} + + +void +Paper_book::classic_output (String outname) +{ - out->output_scheme (scm_list_1 (ly_symbol2scm ("end-output"))); + /* Generate all stencils to trigger font loads. */ + lines (); + + + // ugh code dup + SCM scopes = SCM_EOL; + if (ly_c_module_p (header_)) + scopes = scm_cons (header_, scopes); + + if (ly_c_module_p (score_lines_[0].header_)) + scopes = scm_cons (score_lines_[0].header_, scopes); + //end ugh + + + Array output_formats = split_string (output_format_global, ','); + + for (int i = 0; i < output_formats.size (); i++) + { + String format = output_formats[i]; + String func_nm = format; + func_nm = "output-classic-framework-" + func_nm; + + SCM func = ly_scheme_function (func_nm.to_str0 ()); + + Paper_outputter *out = get_paper_outputter (outname + "." + format, format); + + scm_apply_0 (func, scm_list_n (out->self_scm (), + self_scm (), + scopes, + dump_fields (), + scm_makfrom0str (outname.to_str0 ()), + SCM_UNDEFINED + )) ; + + scm_gc_unprotect_object (out->self_scm ()); + } + progress_indication ("\n"); } + + + +LY_DEFINE(ly_paper_book_pages, "ly:paper-book-pages", + 1,0,0, + (SCM pb), + "Return pages in book PB.") +{ + return unsmob_paper_book(pb)->pages (); +} + + +LY_DEFINE(ly_paper_book_lines, "ly:paper-book-lines", + 1,0,0, + (SCM pb), + "Return lines in book PB.") +{ + return unsmob_paper_book (pb)->lines (); +} + + +LY_DEFINE(ly_paper_book_book_paper, "ly:paper-book-book-paper", + 1,0,0, + (SCM pb), + "Return pages in book PB.") +{ + return unsmob_paper_book(pb)->bookpaper_->self_scm (); +} + /* - WIP -- this simply adds one Page per \score - FIXME: titling is broken. - - TODO: - * ->SCM? - * decent page breaking algorithm - * header / footer (generate per Page, with page#) - * override: # pages, or pageBreakLines= #'(3 3 4), ? - * what about between-system-breaking, can we junk that? - +TODO: resurrect more complex user-tweaks for titling . + */ -Link_array* -Paper_book::get_pages () +Stencil +Paper_book::book_title () +{ + SCM title_func = bookpaper_->lookup_variable (ly_symbol2scm ("book-title")); + Stencil title; + + SCM scopes = SCM_EOL; + if (ly_c_module_p (header_)) + scopes = scm_cons (header_, scopes); + + + SCM tit = SCM_EOL; + if (ly_c_procedure_p (title_func)) + tit = scm_call_2 (title_func, + bookpaper_->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::score_title (int i) { - Link_array *pages = new Link_array; - Paper_def *paper = paper_scores_[0]->paper_; - int score_count = paper_scores_.size (); + SCM title_func = bookpaper_->lookup_variable (ly_symbol2scm ("score-title")); + + Stencil title; + + // ugh code dup + SCM scopes = SCM_EOL; + if (ly_c_module_p (header_)) + scopes = scm_cons (header_, scopes); + + if (ly_c_module_p (score_lines_[i].header_)) + scopes = scm_cons (score_lines_[i].header_, scopes); + //end ugh + + SCM tit = SCM_EOL; + if (ly_c_procedure_p (title_func)) + tit =scm_call_2 (title_func, + bookpaper_->self_scm (), + scopes); + + if (unsmob_stencil (tit)) + title = *unsmob_stencil (tit); + + + if (!title.is_empty ()) + title.align_to (Y_AXIS, UP); + + return title; +} - /* Calculate the full book height. Hmm, can't we cache system - heights while making stencils? */ - Real book_height = 0; + + +SCM +Paper_book::lines () +{ + if (ly_c_pair_p (lines_)) + return lines_; + + Stencil title = book_title (); + if (!title.is_empty ()) + lines_ = scm_cons (stencil2line (title, true), lines_); + + int score_count = score_lines_.size (); for (int i = 0; i < score_count; i++) { - Paper_score *pscore = paper_scores_[i]; - Stencil *title = (i == 0 ? pscore->book_title_ : pscore->score_title_); - if (title) - book_height += title->extent (Y_AXIS).length (); + Stencil title = score_title (i); + if (!title.is_empty ()) + lines_ = scm_cons (stencil2line (title, true), lines_); + + SCM line_list = scm_vector_to_list (score_lines_[i].lines_); // guh. + lines_ = scm_append (scm_list_2 (scm_reverse (line_list), lines_)); + } + + lines_ = scm_reverse (lines_); + + int i = 0; + for (SCM s = lines_; s != SCM_EOL; s = ly_cdr (s)) + unsmob_paper_line (ly_car (s))->number_ = ++i; + return lines_; +} + + +SCM +make_tagline (Output_def*paper, SCM scopes) +{ + SCM make_tagline = paper->c_variable ("make-tagline"); + SCM tagline = scm_call_2 (make_tagline, paper->self_scm (), scopes); + return tagline; +} + +SCM +make_copyright (Output_def *paper, SCM scopes) +{ + SCM make_copyright = paper->c_variable ("make-copyright"); + SCM copyright = scm_call_2 (make_copyright, paper->self_scm (), scopes); + return copyright; +} + +SCM +Paper_book::pages () +{ + if (ly_c_pair_p (pages_)) + return pages_; + + Output_def *paper = bookpaper_; + Page *page = new Page (paper, 1); + + Real text_height = page->text_height (); + + 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->c_variable ("page-breaking"); + SCM breaks = scm_apply_0 (proc, scm_list_n (all, + self_scm (), + scm_make_real (text_height), + scm_make_real (-copy_height), + scm_make_real (-tag_height), + SCM_UNDEFINED)); + + + /* + UGH - move this out of C++. + */ + SCM scopes = SCM_EOL; + if (ly_c_module_p (header_)) + scopes = scm_cons (header_, scopes); + + tagline_ = make_tagline (bookpaper_, scopes); + copyright_ = make_tagline (bookpaper_, scopes); + + int page_count = SCM_VECTOR_LENGTH ((SCM) breaks); + int line = 1; + + for (int i = 0; i < page_count; i++) + { + if (i) + page = new Page (paper, i + 1); - int line_count = SCM_VECTOR_LENGTH ((SCM) pscore->lines_); - for (int j = 0; j < line_count; j++) + int next = i + 1 < page_count + ? ly_scm2int (scm_vector_ref (breaks, scm_int2num (i))) : 0; + while ((!next && all != SCM_EOL) || line <= next) { - SCM line = scm_vector_ref (pscore->lines_, scm_int2num (j)); - book_height += ly_scm2offset (ly_car (line))[Y_AXIS]; + SCM s = ly_car (all); + page->lines_ = ly_snoc (s, page->lines_); + page->height_ += unsmob_paper_line (s)->dim ()[Y_AXIS]; + page->line_count_++; + all = ly_cdr (all); + line++; } + if (i == page_count-1) + page->is_last_ = true; + + pages_ = scm_cons (page->self_scm (), pages_); } - Page *page = new Page (paper); - fprintf (stderr, "book_height: %f\n", book_height); - fprintf (stderr, "vsize: %f\n", page->vsize_); + pages_ = scm_reverse (pages_); + return pages_; +} + -#if ONE_SCORE_PER_PAGE - for (int i = 0; i < score_count; i++) + +static SCM +c_ragged_page_breaks (SCM lines, + Paper_book *book, + Real text_height, + Real first, Real last) +{ + int page_number = 0; + + Real book_height =0.; + for (SCM s = lines ; ly_c_pair_p (s); s = ly_cdr (s)) { - page->lines_ = paper_scores_[i]->lines_; - pages->push (page); + book_height += unsmob_paper_line (ly_car (s))->dim ()[Y_AXIS]; } -#else - /* Simplistic page breaking. */ - Real text_height = page->text_height (); - for (int i = 0; i < score_count; i++) + + /* + UGH. following stuff should go out of C++. + */ + SCM scopes = SCM_EOL; + if (ly_c_module_p (book->header_)) + scopes = scm_cons (book->header_, scopes); + + + SCM tag = make_tagline (book->bookpaper_, scopes); + if (unsmob_stencil (tag)) + { + book_height += unsmob_stencil (tag)->extent (Y_AXIS).length (); + } + + SCM cr = make_copyright (book->bookpaper_, scopes); + if (unsmob_stencil (cr)) + { + book_height += unsmob_stencil (cr)->extent (Y_AXIS).length (); + } + + int page_count = int (book_height / text_height + 0.5); // ceil? + SCM breaks = SCM_EOL; + Real page_height = text_height + first; + Real h = 0; + int number = 0; + for (SCM s = lines; ly_c_pair_p (s); s = ly_cdr (s)) { - Paper_score *pscore = paper_scores_[i]; - Stencil *title = (i == 0 ? pscore->book_title_ : pscore->score_title_); - Real h = 0; - if (title) - h = title->extent (Y_AXIS).length (); - - int line_count = SCM_VECTOR_LENGTH ((SCM) pscore->lines_); - for (int j = 0; j < line_count; j++) + 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) { - SCM line = scm_vector_ref (pscore->lines_, scm_int2num (j)); - h += ly_scm2offset (ly_car (line))[Y_AXIS]; - if (page->height_ + h > text_height) - { - pages->push (page); - page = new Page (paper); - } - if (page->height_ + h <= text_height || page->height_ == 0) - { - if (j == 0 && title) - page->lines_ - = ly_snoc (scm_cons (ly_offset2scm (Offset (0, 0)), - scm_list_1 - (scm_cons - (ly_offset2scm (Offset (0, 0)), - title->smobbed_copy ()))), - page->lines_); - page->lines_ = ly_snoc (line, page->lines_); - page->height_ += h; - h = 0; - } + breaks = ly_snoc (scm_int2num (number), breaks); + page_number++; + page_height = text_height + (page_number == page_count) * last; + h = 0; } + if (ly_cdr (s) == SCM_EOL) + breaks = ly_snoc (scm_int2num (pl->number_), breaks); } -#endif - - pages->push (page); - 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.") +{ + Paper_book* b = unsmob_paper_book (book); + + SCM_ASSERT_TYPE (scm_pair_p (lines), lines, SCM_ARG1, __FUNCTION__, "list"); + SCM_ASSERT_TYPE (b, book, SCM_ARG2, __FUNCTION__, "Paper_book"); + SCM_ASSERT_TYPE (ly_c_number_p (text), text, SCM_ARG3, __FUNCTION__, "number"); + SCM_ASSERT_TYPE (ly_c_number_p (first), first, SCM_ARG4, __FUNCTION__, "number"); + SCM_ASSERT_TYPE (ly_c_number_p (last), last, SCM_ARG5, __FUNCTION__, "number"); + + return c_ragged_page_breaks (lines, b, + ly_scm2double (text), + ly_scm2double (first), ly_scm2double (last)); } + +/****************************************************************/ + +Score_lines::Score_lines () +{ + lines_ = SCM_EOL; + header_ = SCM_EOL; +} + +void +Score_lines::gc_mark () +{ + scm_gc_mark (lines_); + scm_gc_mark (header_); +} +