]> git.donarmstrong.com Git - lilypond.git/blob - lily/scaled-font-metric.cc
* lily/include/lily-guile.hh: is_x -> ly_c_X_p naming.
[lilypond.git] / lily / scaled-font-metric.cc
1 /*
2   scaled-font-metric.cc -- declare Modified_font_metric
3   
4   source file of the GNU LilyPond music typesetter
5   
6   (c) 1999--2004 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7   
8  */
9
10 #include <ctype.h>
11
12 #include "warn.hh"
13 #include "scaled-font-metric.hh"
14 #include "string.hh"
15 #include "stencil.hh"
16
17 Modified_font_metric::Modified_font_metric (String coding, Font_metric* m, Real magn)
18 {
19   coding_vector_ = SCM_EOL;
20   coding_mapping_ = SCM_EOL;
21   coding_table_ = SCM_EOL;
22   coding_description_ = SCM_EOL;
23   
24   coding_scheme_ = coding;
25   magnification_ = magn;
26   
27   SCM desc = m->description_;
28
29   Real total_mag = magn * ly_scm2double (ly_cdr (desc));
30   assert (total_mag);
31   
32   description_ = scm_cons (ly_car (desc), scm_make_real (total_mag));
33   orig_ = m;
34
35   if (coding_scheme_ != "TeX"
36       && coding_scheme_ != "ASCII"
37       && coding_scheme_ !=  orig_->coding_scheme ())
38     {
39       coding_vector_ = scm_call_1 (ly_scheme_function ("get-coding-vector"),
40                                    scm_makfrom0str (coding_scheme_.to_str0 ()));
41
42       if (!ly_c_vector_p (coding_vector_))
43         {
44           programming_error ("get-coding-vector  should return vector");
45           coding_vector_ = scm_c_make_vector (256, ly_symbol2scm (".notdef"));
46         }
47
48       
49       coding_table_ = scm_call_1 (ly_scheme_function ("get-coding-table"),
50                                   scm_makfrom0str (orig_->coding_scheme ().to_str0 ()));
51           
52       coding_mapping_  = scm_call_2 (ly_scheme_function ("make-encoding-mapping"),
53                                          coding_vector_,
54                                          coding_table_);
55
56       coding_description_= SCM_EOL;
57
58       coding_description_ = scm_acons (ly_symbol2scm ("input-name"),
59                                        scm_makfrom0str (coding_scheme_.to_str0 ()),
60                                        coding_description_);
61
62       coding_description_ = scm_acons (ly_symbol2scm ("input-vector"),
63                                        coding_vector_, coding_description_);
64       coding_description_ = scm_acons (ly_symbol2scm ("output-name"),
65                                        scm_makfrom0str (orig_->coding_scheme ().to_str0 ()),
66                                        coding_description_);
67       coding_description_ = scm_acons (ly_symbol2scm ("output-table"),
68                                        coding_table_,
69                                        coding_description_);
70       
71       coding_description_ = scm_acons (ly_symbol2scm ("char-mapping"),
72                                        coding_mapping_,
73                                        coding_description_);
74     } 
75 }
76
77
78
79 LY_DEFINE (ly_font_encoding_alist, "ly:font-encoding-alist",
80            1, 0, 0,
81            (SCM font),
82            "Given the Modified_font_metric @var{font}, return an "
83            "alist. Keys are input-name, input-vector, "
84            "output-name, output-table, mapping.")
85 {
86   Modified_font_metric *fm
87     = dynamic_cast<Modified_font_metric*> (unsmob_metrics (font));
88   
89   SCM_ASSERT_TYPE (fm, font, SCM_ARG1, __FUNCTION__, "Modified_font_metric");
90   return fm->coding_description_;
91 }
92
93 SCM
94 Modified_font_metric::make_scaled_font_metric (SCM coding, Font_metric *m, Real s)
95 {
96   /*
97     UGOHR.
98    */
99   if (ly_c_symbol_p (coding))
100     coding = scm_symbol_to_string (coding);
101   
102   String scheme = ly_scm2string (coding);
103   
104   Modified_font_metric *sfm = new Modified_font_metric (scheme, m, s);
105   
106   return sfm->self_scm ();
107 }
108
109 Real
110 Modified_font_metric::design_size () const
111 {
112   return orig_->design_size ();
113 }
114
115
116 Box 
117 Modified_font_metric::get_indexed_char (int i) const
118 {
119   Box b = orig_->get_indexed_char (i);
120   b.scale (magnification_);
121   return b;  
122 }
123
124 Box 
125 Modified_font_metric::get_ascii_char (int i) const
126 {
127   Box b = orig_->get_ascii_char (i);
128   b.scale (magnification_);
129   return b;  
130 }
131
132 int
133 Modified_font_metric::count () const
134 {
135   return orig_->count ();
136 }
137
138 Offset
139 Modified_font_metric::get_indexed_wxwy (int k) const
140 {
141   Offset o = orig_->get_indexed_wxwy (k);
142   return o * magnification_;
143 }
144
145 int
146 Modified_font_metric::name_to_index (String s) const
147 {
148   return orig_->name_to_index (s);
149 }
150
151 int
152 Modified_font_metric::index_to_ascii (int k) const
153 {
154   return orig_->index_to_ascii (k);
155 }
156
157 String
158 Modified_font_metric::coding_scheme () const
159 {
160   return coding_scheme_;
161 }
162
163 void
164 Modified_font_metric::derived_mark () const
165 {
166   scm_gc_mark (coding_vector_);
167   scm_gc_mark (coding_description_);
168   scm_gc_mark (coding_table_);
169   scm_gc_mark (coding_mapping_);
170 }
171
172 Box
173 Modified_font_metric::tex_kludge (String text) const
174 {
175   Interval ydims;
176   Real w=0.0;
177
178   /*
179     TODO: put this klutchness behind ly:option switch.
180   */  
181   for (int i = 0; i < text.length (); i++) 
182     {
183       switch (text[i]) 
184         {
185         case '\\':
186           // accent marks use width of base letter
187          if (i +1 < text.length ())
188            {
189              if (text[i+1]=='\'' || text[i+1]=='`' || text[i+1]=='"' ||
190                  text[i+1]=='^')
191                {
192                  i++;
193                  break;
194                }
195              // for string width \\ is a \ and \_ is a _.
196              if (text[i+1]=='\\' || text[i+1]=='_')        
197                {
198                  break;
199                }
200            }
201           
202           for (i++; (i < text.length ()) && !isspace (text[i]) 
203                  && text[i]!='{' && text[i]!='}'; i++)
204             ;
205           
206           // ugh.
207           i--; // Compensate for the increment in the outer loop!
208           break;
209         case '{':  // Skip '{' and '}'
210         case '}':
211           break;
212         
213         default: 
214           Box b = get_ascii_char ((unsigned char)text[i]);
215           
216           // Ugh, use the width of 'x' for unknown characters
217           if (b[X_AXIS].length () == 0) 
218             b = get_ascii_char ((unsigned char)'x');
219           
220           w += b[X_AXIS].length ();
221           ydims.unite (b[Y_AXIS]);
222           break;
223         }
224     }
225   
226   if (ydims.is_empty ())
227     ydims = Interval (0, 0);
228   
229   return Box (Interval (0, w), ydims);
230 }
231
232 Box
233 Modified_font_metric::text_dimension (String text) 
234 {
235   Box b; 
236   if (coding_scheme_ == "TeX")
237     {
238       b = tex_kludge (text);
239     }
240   else if (coding_scheme_ == "ASCII"
241            || coding_scheme_ ==  orig_->coding_scheme ())
242     {
243       Interval ydims;
244
245       Real w=0.0;
246
247       for (int i = 0; i < text.length (); i++) 
248         {
249           Box b = get_ascii_char ((unsigned char)text[i]);
250     
251           w += b[X_AXIS].length ();
252           ydims.unite (b[Y_AXIS]); 
253         }
254       if (ydims.is_empty ())
255         ydims = Interval (0, 0);
256
257       b = Box(Interval(0,w), ydims);
258     }
259   else
260     {
261       Interval ydims;
262       Real w = 0.0;
263
264       for (int i = 0; i < text.length (); i++) 
265         {
266           SCM sym = scm_vector_ref (coding_vector_,
267                                     SCM_MAKINUM((unsigned char) text[i]));
268
269           Box char_box;
270
271           if (!ly_c_symbol_p (sym))
272             continue;
273
274           char const * chars =  SCM_SYMBOL_CHARS(sym);
275           
276           int idx = orig_->name_to_index (chars);
277           if (idx >= 0)
278             {
279               char_box = orig_->get_indexed_char (idx);
280             }
281           
282           char_box.scale (magnification_);
283           if (!char_box[X_AXIS].is_empty ())
284             w += char_box[X_AXIS][RIGHT]; // length ?
285
286           ydims.unite (char_box[Y_AXIS]);
287         }
288
289       if (ydims.is_empty ())
290         ydims = Interval (0, 0);
291
292           
293       b = Box (Interval (0, w), ydims);
294     }
295   
296   return b;
297 }
298
299 Font_metric*
300 Modified_font_metric::original_font () const
301 {
302   return orig_;
303 }