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