]> git.donarmstrong.com Git - lilypond.git/blob - lily/text-item.cc
release: 1.5.31
[lilypond.git] / lily / text-item.cc
1 /*   
2   text-item.cc -- implement Text_item
3
4   source file of the GNU LilyPond music typesetter
5   
6   (c) 1998--2002 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7   Jan Nieuwenhuizen <janneke@gnu.org>
8  */
9 #include <math.h>
10
11 #include "debug.hh"
12 #include "text-item.hh"
13 #include "paper-def.hh"
14 #include "font-interface.hh"
15 #include "staff-symbol-referencer.hh"
16 #include "staff-symbol-referencer.hh"
17 #include "main.hh"
18 #include "all-font-metrics.hh"
19 #include "afm.hh"
20
21
22 /*
23
24   TEXT: STRING
25         | (MARKUP? TEXT+)
26         ;
27
28   HEAD: MARKUP-ITEM | (MARKUP-ITEM+)
29
30   MARKUP-ITEM: PROPERTY | ABBREV | FONT-STYLE
31   PROPERTY: (key . value)
32   ABBREV: rows lines roman music bold italic named super sub text
33    
34 */
35
36 Molecule
37 Text_item::text2molecule (Grob *me, SCM text, SCM alist_chain) 
38 {
39   if (gh_string_p (text))
40     return string2molecule (me, text, alist_chain);
41   else if (gh_pair_p (text))
42     {
43       /* urg, why not just do  this in markup_text2molecule ? */
44       if (gh_string_p (ly_car (text)))
45         return markup_text2molecule (me,
46                                      gh_append2 (scm_list_n (SCM_EOL,
47                                                          SCM_UNDEFINED),
48                                                  text),
49                                      alist_chain);
50       /*
51         Allow (faulty) texts that are in an extra list:
52         #'(("foo"))
53        */
54       else if (scm_ilength (text) <= 1)
55         return text2molecule (me, ly_car (text), alist_chain);
56       else
57         return markup_text2molecule (me, text, alist_chain);
58     }
59   return Molecule ();
60 }
61              
62 Molecule
63 Text_item::string2molecule (Grob *me, SCM text, SCM alist_chain)
64 {
65   SCM style = ly_assoc_chain (ly_symbol2scm ("font-style"),
66                               alist_chain);
67   if (gh_pair_p (style) && gh_symbol_p (ly_cdr (style)))
68     alist_chain = Font_interface::add_style (me, ly_cdr (style), alist_chain);
69
70   Font_metric *fm = Font_interface::get_font (me, alist_chain);
71   
72   SCM lookup = ly_assoc_chain (ly_symbol2scm ("lookup"), alist_chain);
73     
74   Molecule mol;
75   if (gh_pair_p (lookup) && ly_cdr (lookup) ==ly_symbol2scm ("name"))
76     mol = lookup_character (me, fm, text);
77   else
78     mol = lookup_text (me, fm, text);
79   
80   return mol;
81 }
82
83 Molecule
84 Text_item::lookup_character (Grob *, Font_metric*fm, SCM char_name)
85 {
86   return fm->find_by_name (ly_scm2string (char_name));
87 }
88
89
90 Molecule
91 Text_item::lookup_text (Grob *me, Font_metric*fm, SCM text)
92 {
93   SCM list = scm_list_n (ly_symbol2scm ("text"), text, SCM_UNDEFINED);
94   list = fontify_atom (fm, list);
95   
96   return Molecule (fm->text_dimension (ly_scm2string (text)), list);
97 }
98
99 /*
100   TODO:
101
102   DOCME.
103
104
105   MARKUP_TEXT must be compound (may not be simple string.)
106   
107  */
108 Molecule
109 Text_item::markup_text2molecule (Grob *me, SCM markup_text,
110                                  SCM alist_chain)
111 {
112   SCM sheet = me->paper_l ()->style_sheet_;
113   SCM f = ly_cdr (scm_assoc (ly_symbol2scm ("markup-to-properties"), sheet));
114   
115   SCM markup = ly_car (markup_text);
116   SCM text = ly_cdr (markup_text);
117
118   SCM p = gh_cons (gh_call2 (f, sheet, markup), alist_chain);
119
120   Real staff_space = Staff_symbol_referencer::staff_space (me);
121
122   /*
123     Line mode is default.
124    */
125   Axis axis = X_AXIS;
126
127   SCM a = ly_assoc_chain (ly_symbol2scm ("axis"), p);
128   if (gh_pair_p (a) && isaxis_b (ly_cdr (a)))
129     axis = (Axis)gh_scm2int (ly_cdr (a));
130
131   Real baseline_skip = 0;
132   SCM b = ly_assoc_chain (ly_symbol2scm ("baseline-skip"), p);
133   if (gh_pair_p (b) && gh_number_p (ly_cdr (b)))
134     baseline_skip = gh_scm2double (ly_cdr (b)) * staff_space;
135   
136   Real kern[2] = {0,0};
137
138   SCM k = ly_assoc_chain (ly_symbol2scm ("kern"), p);
139   if (gh_pair_p (k) && gh_number_p (ly_cdr (k)))
140     kern[axis] = gh_scm2double (ly_cdr (k)) * staff_space;
141                              
142   Real raise = 0;
143   SCM r = ly_assoc_chain (ly_symbol2scm ("raise"), p);
144   if (gh_pair_p (r) && gh_number_p (ly_cdr (r)))
145     raise = gh_scm2double (ly_cdr (r)) * staff_space;
146
147   Interval extent;
148   bool extent_b = false;
149   SCM e = ly_assoc_chain (ly_symbol2scm ("extent"), p);
150   if (gh_pair_p (e) && ly_number_pair_p (ly_cdr (e)))
151     {
152       extent = Interval (gh_scm2double (ly_cadr (e)) * staff_space,
153                        gh_scm2double (ly_cddr (e)) * staff_space);
154       extent_b = true;
155     }
156
157   Offset o (0, (axis == Y_AXIS ? - kern[axis] : 0));
158
159   Molecule mol;
160   while (gh_pair_p (text))
161     {
162    
163       Molecule m = text2molecule (me, ly_car (text), p);
164
165       /*
166         TODO: look at padding?
167         
168         Look ahead here for kern and raise.
169
170         (cols "foo" ((raise . 1) "bar"))
171         (cols "foo" ((bold (raise . 1)) "bar"))
172
173         When constructing the molecule for bar, all normal extra
174         properties found, such as bold, are used for the construction
175         of bar's molecule.  But for kern or raise, it seems that we're
176         too late then, translating bar's molecule has no effect (or
177         maybe the effect of translating gets nullified when bar's
178         molecule is `added_to_edge' of the molecule for foo?)
179
180         So, while constructing foo's molecule, we look ahead for the
181         raise of bar.  The HEAD of the description of bar may be a
182         single property, or a list, so we must check that too.
183       */
184         
185       SCM next_p = SCM_EOL;
186       if (gh_pair_p (ly_car (text)))
187         next_p = scm_list_n (gh_call2 (f, sheet, ly_caar (text)), SCM_UNDEFINED);
188       SCM next_k = ly_assoc_chain (ly_symbol2scm ("kern"), next_p);
189       Real next_kern = kern[axis];
190       if (gh_pair_p (next_k) && gh_number_p (ly_cdr (next_k)))
191         next_kern = gh_scm2double (ly_cdr (next_k)) * staff_space;
192
193       SCM next_r = ly_assoc_chain (ly_symbol2scm ("raise"), next_p);
194       Real next_raise = 0;
195       if (gh_pair_p (next_r) && gh_number_p (ly_cdr (next_r)))
196         next_raise = gh_scm2double (ly_cdr (next_r)) * staff_space;
197
198       o[Y_AXIS] = next_raise;
199
200       if (!m.empty_b ())
201         {
202           m.translate (o);
203           if (mol.empty_b ())
204             mol = m;
205           else
206             {
207               if (axis == Y_AXIS && baseline_skip)
208                 next_kern += baseline_skip - m.extent (Y_AXIS)[UP];
209               mol.add_at_edge (axis, axis == X_AXIS ? RIGHT : DOWN, m, next_kern);
210             }
211         }
212       text = ly_cdr (text);
213     }
214   
215   if (extent_b)
216     {
217       /* we're not setting extents for unknown reasons. */
218       Box b = mol.extent_box ();
219       SCM expr = mol.get_expr ();
220
221       b[axis] = extent;
222       mol = Molecule (b, expr);
223     }  
224   return mol;
225 }
226
227 MAKE_SCHEME_CALLBACK (Text_item, brew_molecule, 1);
228 SCM 
229 Text_item::brew_molecule (SCM smob)
230 {
231   Grob *me = unsmob_grob (smob);
232   
233   SCM text = me->get_grob_property ("text");
234
235   SCM properties = Font_interface::font_alist_chain (me);
236   Molecule mol = Text_item::text2molecule (me, text, properties);
237
238   SCM space = me->get_grob_property ("word-space");
239   if (gh_number_p (space))
240     {
241       Molecule m;
242       m.set_empty (false);
243       mol.add_at_edge (X_AXIS, RIGHT, m, gh_scm2double (space)
244                        * Staff_symbol_referencer::staff_space (me));
245     }
246   return mol.smobbed_copy (); 
247 }
248