X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;ds=sidebyside;f=lily%2Fstencil.cc;h=c684dcb31c7d7fc4feeb5cd12532f88592b290c3;hb=a33165e3b6af2d807d069e6eacd0e220ba2ef68a;hp=2b16efe8b66b1f6a7a54dadc6fdae313912e2add;hpb=9f3cd80128759b22321f41060eb5c53853ac0667;p=lilypond.git diff --git a/lily/stencil.cc b/lily/stencil.cc index 2b16efe8b6..c684dcb31c 100644 --- a/lily/stencil.cc +++ b/lily/stencil.cc @@ -6,49 +6,80 @@ (c) 1997--2004 Han-Wen Nienhuys */ +#include "stencil.hh" + #include + #include // isinf -#include "font-metric.hh" +#include "input-smob.hh" +#include "font-metric.hh" #include "dimensions.hh" -#include "interval.hh" -#include "string.hh" -#include "stencil.hh" +#include "string-convert.hh" #include "warn.hh" - #include "ly-smobs.icc" +Stencil::Stencil () +{ + expr_ = SCM_EOL; + set_empty (true); +} -SCM -Stencil::smobbed_copy () const +Stencil::Stencil (Box b, SCM func) { - Stencil *s = new Stencil (*this); - return s->smobbed_self (); + expr_ = func; + dim_ = b; } -Offset -Stencil::origin () const +int +Stencil::print_smob (SCM, SCM port, scm_print_state *) { - return origin_; + scm_puts ("#", port); + return 1; } +SCM +Stencil::mark_smob (SCM smob) +{ + Stencil *s = (Stencil*) SCM_CELL_WORD_1 (smob); + return s->expr_; +} + +IMPLEMENT_SIMPLE_SMOBS (Stencil); +IMPLEMENT_TYPE_P (Stencil, "ly:stencil?"); +IMPLEMENT_DEFAULT_EQUAL_P (Stencil); + Interval Stencil::extent (Axis a) const { return dim_[a]; } -Stencil::Stencil (Box b, SCM func) +/* Hmm... maybe this is not such a good idea ; stuff can be empty, + while expr_ == '() */ +bool +Stencil::is_empty () const { - expr_ = func; - dim_ = b; + return expr_ == SCM_EOL; } -Stencil::Stencil () +SCM +Stencil::expr () const { - expr_ = SCM_EOL; - set_empty (true); + return expr_; +} + +Box +Stencil::extent_box () const +{ + return dim_; +} +Offset +Stencil::origin () const +{ + return origin_; } void @@ -57,23 +88,24 @@ Stencil::translate (Offset o) Axis a = X_AXIS; while (a < NO_AXES) { - if (abs (o[a]) > 100 CM - || isinf (o[a]) || isnan (o[a])) + if (isinf (o[a]) || isnan (o[a])) { - programming_error ("Improbable offset for translation: setting to zero"); + programming_error (String_convert::form_string ("Improbable offset for stencil: %f staff space", o[a]) + + "\n" + + "Setting to zero."); o[a] = 0.0; } incr (a); } expr_ = scm_list_n (ly_symbol2scm ("translate-stencil"), - ly_offset2scm (o), - expr_, SCM_UNDEFINED); + ly_offset2scm (o), + expr_, SCM_UNDEFINED); if (!is_empty ()) dim_.translate (o); origin_ += o; } - + void Stencil::translate_axis (Real x, Axis a) { @@ -85,11 +117,12 @@ Stencil::translate_axis (Real x, Axis a) void Stencil::add_stencil (Stencil const &s) { - expr_ = scm_list_n (ly_symbol2scm ("combine-stencil"), - s.expr_, expr_, SCM_UNDEFINED); + expr_ = scm_list_3 (ly_symbol2scm ("combine-stencil"), s.expr_, expr_); dim_.unite (s.dim_); } + + void Stencil::set_empty (bool e) { @@ -109,87 +142,180 @@ void Stencil::align_to (Axis a, Real x) { if (is_empty ()) - return ; + return; Interval i (extent (a)); translate_axis (-i.linear_combination (x), a); } -/* - TODO: unintuitive naming, you would expect *this to be moved. Kept - API for compat with add_at_edge (). -*/ +/* FIXME: unintuitive naming, you would expect *this to be moved. + Kept (keeping?) API for compat with add_at_edge (). + + What is PADDING, what is MINIMUM, exactly? */ Stencil -Stencil::moved_to_edge (Axis a, Direction d, Stencil const &s, Real padding, - Real minimum) const +Stencil::moved_to_edge (Axis a, Direction d, Stencil const &s, + Real padding, Real minimum) const { - Real my_extent= is_empty () ? 0.0 : dim_[a][d]; + Interval my_extent = dim_[a]; Interval i (s.extent (a)); Real his_extent; if (i.is_empty ()) { - programming_error ("Stencil::move_to_edge: adding empty stencil."); + programming_error ("Stencil::moved_to_edge: adding empty stencil."); his_extent = 0.0; + SCM_ASSERT_TYPE(0, SCM_EOL, SCM_ARG1, __FUNCTION__, ""); } else his_extent = i[-d]; - Real offset = (my_extent - his_extent) + d * padding; + Real offset = (my_extent.is_empty () ? 0.0 : my_extent[d] - his_extent) + + d * padding; Stencil toadd (s); toadd.translate_axis (offset,a); - if (minimum > 0 - && d *(- origin ()[a] + toadd.origin ()[a]) < minimum) + if (minimum > 0 && d * (-origin ()[a] + toadd.origin ()[a]) < minimum) toadd.translate_axis ( -toadd.origin ()[a] - + origin ()[a] + d* minimum, a); - + + origin ()[a] + d * minimum, a); + return toadd; } /* See scheme Function. */ void Stencil::add_at_edge (Axis a, Direction d, Stencil const &s, Real padding, - Real minimum) + Real minimum) { - add_stencil (moved_to_edge (a,d,s,padding, minimum)); + add_stencil (moved_to_edge (a, d, s, padding, minimum)); } -/* Hmm... maybe this is not such a good idea ; stuff can be empty, - while expr_ == '() */ -bool -Stencil::is_empty () const + +/****************************************************************/ + + +void +interpret_stencil_expression (SCM expr, + void (*func) (void*, SCM), + void *func_arg, + Offset o) { - return expr_ == SCM_EOL; + while (1) + { + if (!scm_is_pair (expr)) + return; + + SCM head = scm_car (expr); + + if (head == ly_symbol2scm ("translate-stencil")) + { + o += ly_scm2offset (scm_cadr (expr)); + expr = scm_caddr (expr); + } + else if (head == ly_symbol2scm ("combine-stencil")) + { + for (SCM x = scm_cdr (expr); scm_is_pair (x); x = scm_cdr (x)) + interpret_stencil_expression (scm_car (x), func, func_arg, o); + return; + } + else if (head == ly_symbol2scm ("grob-cause")) + { + SCM grob = scm_cadr (expr); + + (*func) (func_arg, scm_list_2 (head, grob)); + interpret_stencil_expression (scm_caddr (expr), func, func_arg, o); + (*func) (func_arg, scm_list_1 (ly_symbol2scm ("no-origin"))); + return; + } + else + { + (*func) (func_arg, + scm_list_4 (ly_symbol2scm ("placebox"), + scm_make_real (o[X_AXIS]), + scm_make_real (o[Y_AXIS]), + expr)); + return; + } + } +} + + +struct Font_list +{ + SCM fonts_; +}; + +static void +find_font_function (void *fs, SCM x) +{ + Font_list *me = (Font_list*) fs; + + if (scm_car (x) == ly_symbol2scm ("placebox")) + { + SCM args = scm_cdr (x); + SCM what = scm_caddr (args); + + if (scm_is_pair (what)) + { + SCM head = scm_car (what); + if (ly_symbol2scm ("text") == head) + me->fonts_ = scm_cons (scm_cadr (what), me->fonts_); + else if (head == ly_symbol2scm ("char")) + me->fonts_ = scm_cons (scm_cadr (what), me->fonts_); + } + } } SCM -Stencil::get_expr () const +find_expression_fonts (SCM expr) { - return expr_; + Font_list fl; + + fl.fonts_ = SCM_EOL; + + interpret_stencil_expression (expr, &find_font_function, + (void*) &fl, Offset (0,0)); + + return fl.fonts_; } -Box -Stencil::extent_box () const + +LY_DEFINE (ly_stencil_fonts, "ly:stencil-fonts", + 1, 0, 0, (SCM s), + " Analyse @var{s}, and return a list of fonts used in @var{s}.") { - return dim_; + Stencil *stil = unsmob_stencil (s); + SCM_ASSERT_TYPE (stil, s, SCM_ARG1, __FUNCTION__, "Stencil"); + return find_expression_fonts (stil->expr ()); } -int -Stencil::print_smob (SCM , SCM port, scm_print_state *) +struct Stencil_interpret_arguments { - scm_puts ("#", port); - return 1; + SCM func; + SCM arg1; +}; + +void stencil_interpret_in_scm (void *p, SCM expr) +{ + Stencil_interpret_arguments *ap = (Stencil_interpret_arguments*) p; + scm_call_2 (ap->func, ap->arg1, expr); } -SCM -Stencil::mark_smob (SCM s) + + +LY_DEFINE (ly_interpret_stencil_expression, "ly:interpret-stencil-expression", + 4, 0, 0, (SCM expr, SCM func, SCM arg1, SCM offset), + "Parse EXPR, feed bits to FUNC with first arg ARG1") { - Stencil *r = (Stencil *) ly_cdr (s); - return r->expr_; + SCM_ASSERT_TYPE (ly_c_procedure_p(func), func, SCM_ARG1, __FUNCTION__, + "procedure"); + + Stencil_interpret_arguments a; + a.func = func; + a.arg1 = arg1; + Offset o = ly_scm2offset (offset); + + interpret_stencil_expression (expr, stencil_interpret_in_scm, (void*) &a, o); + + return SCM_UNSPECIFIED; } -IMPLEMENT_SIMPLE_SMOBS (Stencil); -IMPLEMENT_TYPE_P (Stencil, "ly:stencil?"); -IMPLEMENT_DEFAULT_EQUAL_P (Stencil);