]> git.donarmstrong.com Git - lilypond.git/blob - lily/text-interface.cc
Update source file headers. Fixes using standard GNU package conventions.
[lilypond.git] / lily / text-interface.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1998--2009 Han-Wen Nienhuys <hanwen@xs4all.nl>
5   Jan Nieuwenhuizen <janneke@gnu.org>
6
7   LilyPond is free software: you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation, either version 3 of the License, or
10   (at your option) any later version.
11
12   LilyPond is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "text-interface.hh"
22
23 #include "config.hh"
24 #include "font-interface.hh"
25 #include "grob.hh"
26 #include "main.hh"
27 #include "misc.hh"
28 #include "modified-font-metric.hh"
29 #include "output-def.hh"
30 #include "pango-font.hh"
31 #include "warn.hh"
32
33 static void
34 replace_whitespace (string *str)
35 {
36   vsize i = 0;
37   vsize n = str->size ();
38
39   while (i < n)
40     {
41       char cur = (*str)[i];
42
43       // avoid the locale-dependent isspace
44       if (cur == '\n' || cur == '\t' || cur == '\v')
45         (*str)[i] = ' ';
46
47       vsize char_len = utf8_char_len (cur);
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                " @rextend{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