]> git.donarmstrong.com Git - lilypond.git/blob - lily/text-interface.cc
Merge branch 'lilypond/translation' of ssh://git.sv.gnu.org/srv/git/lilypond into...
[lilypond.git] / lily / text-interface.cc
1 /*
2   text-interface.cc -- implement Text_interface
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1998--2009 Han-Wen Nienhuys <hanwen@xs4all.nl>
7   Jan Nieuwenhuizen <janneke@gnu.org>
8 */
9
10 #include "text-interface.hh"
11
12
13 #include "main.hh"
14 #include "config.hh"
15 #include "pango-font.hh"
16 #include "warn.hh"
17 #include "grob.hh"
18 #include "font-interface.hh"
19 #include "output-def.hh"
20 #include "modified-font-metric.hh"
21
22 static void
23 replace_whitespace (string *str)
24 {
25   vsize i = 0;
26   vsize n = str->size ();
27
28   while (i < n)
29     {
30       vsize char_len = 1;
31       char cur = (*str)[i];
32       
33       // U+10000 - U+10FFFF
34       if ((cur & 0x11110000) == 0x11110000)
35         char_len = 4;
36       // U+0800 - U+FFFF
37       else if ((cur & 0x11100000) == 0x11100000)
38         char_len = 3;
39       // U+0080 - U+07FF
40       else if ((cur & 0x11000000) == 0x11000000)
41         char_len = 2;
42       else if (cur & 0x10000000)
43         programming_error ("invalid utf-8 string");
44       else
45         // avoid the locale-dependent isspace
46         if (cur == '\n' || cur == '\t' || cur == '\v')
47           (*str)[i] = ' ';
48
49       i += char_len;
50     }
51 }
52
53 MAKE_SCHEME_CALLBACK (Text_interface, interpret_string, 3);
54 SCM
55 Text_interface::interpret_string (SCM layout_smob,
56                                   SCM props,
57                                   SCM markup)
58 {
59   LY_ASSERT_SMOB (Output_def, layout_smob, 1);
60   LY_ASSERT_TYPE (scm_is_string, markup, 3);
61
62   string str = ly_scm2string (markup);
63   Output_def *layout = unsmob_output_def (layout_smob);
64   Font_metric *fm = select_encoded_font (layout, props);
65
66   replace_whitespace (&str);
67
68   /*
69     We want to use "glyph-string" in the SVG backend for all
70     music fonts (Emmentaler and Aybabtu) that pass through the
71     text interface.  Here the font encoding is checked to see if
72     it matches one of the music font encodings.  --pmccarty
73   */
74   SCM encoding = ly_chain_assoc_get (ly_symbol2scm ("font-encoding"),
75                                      props,
76                                      SCM_BOOL_F);
77   SCM music_encodings = ly_lily_module_constant ("all-music-font-encodings");
78
79   if (scm_memq (encoding, music_encodings) != SCM_BOOL_F)
80     return fm->word_stencil (str, true).smobbed_copy ();
81   else
82     return fm->word_stencil (str, false).smobbed_copy ();
83 }
84
85 MAKE_SCHEME_CALLBACK_WITH_OPTARGS (Text_interface, interpret_markup, 3, 0,
86                                    "Convert a text markup into a stencil."
87 "  Takes three arguments, @var{layout}, @var{props}, and @var{markup}.\n"
88 "\n"
89 "@var{layout} is a @code{\\layout} block; it may be obtained from a grob with"
90 " @code{ly:grob-layout}.  @var{props} is an alist chain, i.e. a list of"
91 "  alists.  This is typically obtained with"
92 " @code{(ly:grob-alist-chain grob (ly:output-def-lookup layout 'text-font-defaults))}."
93 "  @var{markup} is the markup text to be processed.");
94 SCM
95 Text_interface::interpret_markup (SCM layout_smob, SCM props, SCM markup)
96 {
97   if (scm_is_string (markup))
98     return interpret_string (layout_smob, props, markup);
99   else if (scm_is_pair (markup))
100     {
101       SCM func = scm_car (markup);
102       SCM args = scm_cdr (markup);
103       if (!is_markup (markup))
104         programming_error ("markup head has no markup signature");
105
106       return scm_apply_2 (func, layout_smob, props, args);
107     }
108   else
109     {
110       programming_error ("Object is not a markup. ");
111       scm_puts ("This object should be a markup: ", scm_current_error_port ());
112       scm_display (markup, scm_current_error_port ());
113       scm_puts ("\n", scm_current_error_port ());
114
115       Box b;
116       b[X_AXIS].set_empty ();
117       b[Y_AXIS].set_empty ();
118
119       Stencil s (b, SCM_EOL);
120       return s.smobbed_copy ();
121     }
122 }
123
124 MAKE_SCHEME_CALLBACK (Text_interface, print, 1);
125 SCM
126 Text_interface::print (SCM grob)
127 {
128   Grob *me = unsmob_grob (grob);
129
130   SCM t = me->get_property ("text");
131   SCM chain = Font_interface::text_font_alist_chain (me);
132   return interpret_markup (me->layout ()->self_scm (), chain, t);
133 }
134
135 /* Ugh. Duplicated from Scheme.  */
136 bool
137 Text_interface::is_markup (SCM x)
138 {
139   return (scm_is_string (x)
140           || (scm_is_pair (x)
141               && SCM_BOOL_F
142               != scm_object_property (scm_car (x),
143                                       ly_symbol2scm ("markup-signature"))));
144 }
145
146 bool
147 Text_interface::is_markup_list (SCM x)
148 {
149   SCM music_list_p = ly_lily_module_constant ("markup-list?");
150   return scm_is_true (scm_call_1 (music_list_p, x));
151 }
152
153
154 ADD_INTERFACE (Text_interface,
155                "A Scheme markup text, see @ruser{Formatting text} and"
156                " @ruser{New markup command definition}.\n"
157                "\n"
158                "There are two important commands:"
159                " @code{ly:text-interface::print}, which is a"
160                " grob callback, and"
161                " @code{ly:text-interface::interpret-markup}.",
162
163                /* properties */
164                "baseline-skip "
165                "text "
166                "word-space "
167                "text-direction "
168                );
169