X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Ftext-interface.cc;h=909ab9b099666203e133796e53c78e328fff40a7;hb=47db9a3883d726ca53e2133a3b2298f78dd6a32e;hp=53d5af4232165e94920b506d092c9fbe6f933375;hpb=28d8d9ac38857927790af5759c393adeff1ceb82;p=lilypond.git diff --git a/lily/text-interface.cc b/lily/text-interface.cc index 53d5af4232..909ab9b099 100644 --- a/lily/text-interface.cc +++ b/lily/text-interface.cc @@ -1,7 +1,7 @@ /* This file is part of LilyPond, the GNU music typesetter. - Copyright (C) 1998--2011 Han-Wen Nienhuys + Copyright (C) 1998--2015 Han-Wen Nienhuys Jan Nieuwenhuizen LilyPond is free software: you can redistribute it and/or modify @@ -19,7 +19,9 @@ */ #include "text-interface.hh" +#include "skyline-pair.hh" +#include "lookup.hh" #include "config.hh" #include "font-interface.hh" #include "grob.hh" @@ -28,39 +30,39 @@ #include "modified-font-metric.hh" #include "output-def.hh" #include "pango-font.hh" +#include "program-option.hh" +#include "international.hh" #include "warn.hh" static void -replace_special_characters (string *str, SCM props) +replace_special_characters (string &str, SCM props) { - vsize i = 0; SCM replacement_alist = ly_chain_assoc_get (ly_symbol2scm ("replacement-alist"), props, - SCM_BOOL_F); - - if (!to_boolean (scm_list_p (replacement_alist)) - || to_boolean (scm_null_p (replacement_alist))) - return; + SCM_EOL); int max_length = 0; for (SCM s = replacement_alist; scm_is_pair (s); s = scm_cdr (s)) { max_length = max (max_length, scm_to_int - (scm_string_length (scm_caar (s)))); + (scm_string_length (scm_caar (s)))); } - while (i <= str->size ()) + for (vsize i = 0; i < str.size (); i++) { - for (int j = max_length; j > 0; j--) + /* Don't match in mid-UTF-8 */ + if ((str[i] & 0xc0) == 0x80) + continue; + for (vsize j = max_length + 1; j--;) { - string dummy = str->substr (i, j); - string ligature = robust_scm2string - (ly_assoc_get (ly_string2scm (dummy), - replacement_alist, SCM_BOOL_F), ""); - if (ligature != "") - str->replace (i, j, ligature); + if (j > str.size () - i) + continue; + string dummy = str.substr (i, j); + SCM ligature = ly_assoc_get (ly_string2scm (dummy), + replacement_alist, SCM_BOOL_F); + if (scm_is_true (ligature)) + str.replace (i, j, robust_scm2string (ligature, "")); } - i += utf8_char_len ((*str)[i]); } } @@ -74,10 +76,10 @@ Text_interface::interpret_string (SCM layout_smob, LY_ASSERT_TYPE (scm_is_string, markup, 3); string str = ly_scm2string (markup); - Output_def *layout = unsmob_output_def (layout_smob); + Output_def *layout = Output_def::unsmob (layout_smob); Font_metric *fm = select_encoded_font (layout, props); - replace_special_characters (&str, props); + replace_special_characters (str, props); /* We want to filter strings with a music font that pass through @@ -93,6 +95,11 @@ Text_interface::interpret_string (SCM layout_smob, return fm->text_stencil (layout, str, is_music).smobbed_copy (); } +static size_t markup_depth = 0; + +void markup_up_depth (void *) { ++markup_depth; } +void markup_down_depth (void *) { --markup_depth; } + MAKE_SCHEME_CALLBACK_WITH_OPTARGS (Text_interface, interpret_markup, 3, 0, "Convert a text markup into a stencil." " Takes three arguments, @var{layout}, @var{props}, and @var{markup}.\n" @@ -107,28 +114,44 @@ Text_interface::interpret_markup (SCM layout_smob, SCM props, SCM markup) { if (scm_is_string (markup)) return interpret_string (layout_smob, props, markup); - else if (scm_is_pair (markup)) + else if (is_markup (markup)) { SCM func = scm_car (markup); SCM args = scm_cdr (markup); - if (!is_markup (markup)) - programming_error ("markup head has no markup signature"); - return scm_apply_2 (func, layout_smob, props, args); + /* Check for non-terminating markups, e.g. recursive calls with + * changing arguments */ + SCM opt_depth = ly_get_option (ly_symbol2scm ("max-markup-depth")); + size_t max_depth = robust_scm2int (opt_depth, 1024); + + // Don't use SCM_F_DYNWIND_REWINDABLE since it may be expensive + // without any obvious use for retaining continuations into + // markup expansion + scm_dynwind_begin ((scm_t_dynwind_flags)0); + // scm_dynwind_rewind_handler (markup_up_depth, 0, SCM_F_WIND_EXPLICITLY); + markup_up_depth (0); + scm_dynwind_unwind_handler (markup_down_depth, 0, SCM_F_WIND_EXPLICITLY); + if (markup_depth > max_depth) + { + string name = ly_symbol2string (scm_procedure_name (func)); + // TODO: Also print the arguments of the markup! + non_fatal_error (_f ("Markup depth exceeds maximal value of %d; " + "Markup: %s", max_depth, name.c_str ())); + return Stencil ().smobbed_copy (); + } + + SCM retval = scm_apply_2 (func, layout_smob, props, args); + scm_dynwind_end (); + return retval; } else { - programming_error ("Object is not a markup. "); + programming_error ("Object is not a markup."); scm_puts ("This object should be a markup: ", scm_current_error_port ()); scm_display (markup, scm_current_error_port ()); scm_puts ("\n", scm_current_error_port ()); - Box b; - b[X_AXIS].set_empty (); - b[Y_AXIS].set_empty (); - - Stencil s (b, SCM_EOL); - return s.smobbed_copy (); + return Stencil ().smobbed_copy (); } } @@ -136,7 +159,7 @@ MAKE_SCHEME_CALLBACK (Text_interface, print, 1); SCM Text_interface::print (SCM grob) { - Grob *me = unsmob_grob (grob); + Grob *me = Grob::unsmob (grob); SCM t = me->get_property ("text"); SCM chain = Font_interface::text_font_alist_chain (me); @@ -147,11 +170,14 @@ Text_interface::print (SCM grob) bool Text_interface::is_markup (SCM x) { - return (scm_is_string (x) - || (scm_is_pair (x) - && SCM_BOOL_F - != scm_object_property (scm_car (x), - ly_symbol2scm ("markup-signature")))); + return scm_is_string (x) + || (scm_is_pair (x) + && scm_is_true + (scm_object_property (scm_car (x), + ly_symbol2scm ("markup-signature"))) + && scm_is_false + (scm_object_property (scm_car (x), + ly_symbol2scm ("markup-list-command")))); } bool @@ -176,5 +202,6 @@ ADD_INTERFACE (Text_interface, "text " "word-space " "text-direction " + "flag-style " );