]> git.donarmstrong.com Git - lilypond.git/blob - lily/text-item.cc
release: 1.5.29
[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 #if 0
94   /*
95     Fixme; should be done differently, move to font-interface?
96
97     differently -- how/why?
98    */
99
100   SCM magnification = me->get_grob_property ("font-magnification");
101
102   Font_metric* metric = 0;
103   if (gh_number_p (magnification))
104     {
105
106       Real realmag = pow (1.2, gh_scm2int (magnification));
107       metric = all_fonts_global_p->find_scaled (ly_scm2string (font_name), realmag);
108
109       assert (false);
110     }
111 #else
112   SCM magnification = me->get_grob_property ("font-magnification");
113
114   if (gh_number_p (magnification) && gh_scm2double (magnification) > 1)
115     programming_error ("font-magnification disabled");
116 #endif
117   
118
119   SCM list = scm_list_n (ly_symbol2scm ("text"), text, SCM_UNDEFINED);
120   list = fontify_atom (fm, list);
121   
122   return Molecule (fm->text_dimension (ly_scm2string (text)), list);
123 }
124
125 /*
126   TODO:
127
128   DOCME.
129
130
131   MARKUP_TEXT must be compound (may not be simple string.)
132   
133  */
134 Molecule
135 Text_item::markup_text2molecule (Grob *me, SCM markup_text,
136                                  SCM alist_chain)
137 {
138   SCM sheet = me->paper_l ()->style_sheet_;
139   SCM f = ly_cdr (scm_assoc (ly_symbol2scm ("markup-to-properties"), sheet));
140   
141   SCM markup = ly_car (markup_text);
142   SCM text = ly_cdr (markup_text);
143
144   SCM p = gh_cons (gh_call2 (f, sheet, markup), alist_chain);
145
146   Real staff_space = Staff_symbol_referencer::staff_space (me);
147
148   /*
149     Line mode is default.
150    */
151   Axis axis = X_AXIS;
152
153   SCM a = ly_assoc_chain (ly_symbol2scm ("axis"), p);
154   if (gh_pair_p (a) && isaxis_b (ly_cdr (a)))
155     axis = (Axis)gh_scm2int (ly_cdr (a));
156
157   Real baseline_skip = 0;
158   SCM b = ly_assoc_chain (ly_symbol2scm ("baseline-skip"), p);
159   if (gh_pair_p (b) && gh_number_p (ly_cdr (b)))
160     baseline_skip = gh_scm2double (ly_cdr (b)) * staff_space;
161   
162   Real kern[2] = {0,0};
163
164   SCM k = ly_assoc_chain (ly_symbol2scm ("kern"), p);
165   if (gh_pair_p (k) && gh_number_p (ly_cdr (k)))
166     kern[axis] = gh_scm2double (ly_cdr (k)) * staff_space;
167                              
168   Real raise = 0;
169   SCM r = ly_assoc_chain (ly_symbol2scm ("raise"), p);
170   if (gh_pair_p (r) && gh_number_p (ly_cdr (r)))
171     raise = gh_scm2double (ly_cdr (r)) * staff_space;
172
173   Interval extent;
174   bool extent_b = false;
175   SCM e = ly_assoc_chain (ly_symbol2scm ("extent"), p);
176   if (gh_pair_p (e) && ly_number_pair_p (ly_cdr (e)))
177     {
178       extent = Interval (gh_scm2double (ly_cadr (e)) * staff_space,
179                        gh_scm2double (ly_cddr (e)) * staff_space);
180       extent_b = true;
181     }
182
183   Offset o (0, (axis == Y_AXIS ? - kern[axis] : 0));
184
185   Molecule mol;
186   while (gh_pair_p (text))
187     {
188    
189       Molecule m = text2molecule (me, ly_car (text), p);
190
191       /*
192         TODO: look at padding?
193         
194         Look ahead here for kern and raise.
195
196         (cols "foo" ((raise . 1) "bar"))
197         (cols "foo" ((bold (raise . 1)) "bar"))
198
199         When constructing the molecule for bar, all normal extra
200         properties found, such as bold, are used for the construction
201         of bar's molecule.  But for kern or raise, it seems that we're
202         too late then, translating bar's molecule has no effect (or
203         maybe the effect of translating gets nullified when bar's
204         molecule is `added_to_edge' of the molecule for foo?)
205
206         So, while constructing foo's molecule, we look ahead for the
207         raise of bar.  The HEAD of the description of bar may be a
208         single property, or a list, so we must check that too.
209       */
210         
211       SCM next_p = SCM_EOL;
212       if (gh_pair_p (ly_car (text)))
213         next_p = scm_list_n (gh_call2 (f, sheet, ly_caar (text)), SCM_UNDEFINED);
214       SCM next_k = ly_assoc_chain (ly_symbol2scm ("kern"), next_p);
215       Real next_kern = kern[axis];
216       if (gh_pair_p (next_k) && gh_number_p (ly_cdr (next_k)))
217         next_kern = gh_scm2double (ly_cdr (next_k)) * staff_space;
218
219       SCM next_r = ly_assoc_chain (ly_symbol2scm ("raise"), next_p);
220       Real next_raise = 0;
221       if (gh_pair_p (next_r) && gh_number_p (ly_cdr (next_r)))
222         next_raise = gh_scm2double (ly_cdr (next_r)) * staff_space;
223
224       o[Y_AXIS] = next_raise;
225
226       if (!m.empty_b ())
227         {
228           m.translate (o);
229           if (mol.empty_b ())
230             mol = m;
231           else
232             {
233               if (axis == Y_AXIS && baseline_skip)
234                 next_kern += baseline_skip - m.extent (Y_AXIS)[UP];
235               mol.add_at_edge (axis, axis == X_AXIS ? RIGHT : DOWN, m, next_kern);
236             }
237         }
238       text = ly_cdr (text);
239     }
240   
241   if (extent_b)
242     {
243 #if 0
244       /* Hmm, we're not allowed to change a Molecule's extent? */
245       mol.dim_[axis] = extent;
246       Molecule::ly_set_molecule_extent_x (mol.self_scm (), gh_int2scm (axis),
247                                           ly_cdr (e));
248 #else
249       // burp: unpredictable names, these...
250       Box b = mol.extent_box ();
251       SCM expr = mol.get_expr ();
252
253       b[axis] = extent;
254       mol = Molecule (b, expr);
255 #endif
256         }  
257   return mol;
258 }
259
260 MAKE_SCHEME_CALLBACK (Text_item, brew_molecule, 1);
261 SCM 
262 Text_item::brew_molecule (SCM smob)
263 {
264   Grob *me = unsmob_grob (smob);
265   
266   SCM text = me->get_grob_property ("text");
267
268   SCM properties = Font_interface::font_alist_chain (me);
269   Molecule mol = Text_item::text2molecule (me, text, properties);
270
271   SCM space = me->get_grob_property ("word-space");
272   if (gh_number_p (space))
273     {
274       Molecule m;
275       m.set_empty (false);
276       mol.add_at_edge (X_AXIS, RIGHT, m, gh_scm2double (space)
277                        * Staff_symbol_referencer::staff_space (me));
278     }
279   return mol.smobbed_copy (); 
280 }
281