]> git.donarmstrong.com Git - lilypond.git/blob - lily/modified-font-metric.cc
* scm/framework-texstr.scm (header): change extension to .textmetrics
[lilypond.git] / lily / modified-font-metric.cc
1 /*
2   modified-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 #include <cctype>
9
10 #include "modified-font-metric.hh"
11 #include "pango-font.hh"
12 #include "text-metrics.hh"
13 #include "warn.hh"
14 #include "stencil.hh"
15
16 Modified_font_metric::Modified_font_metric (Font_metric *fm,
17                                             Real magnification,
18                                             String font_encoding,
19                                             String input_encoding)
20 {
21   input_encoding_ = input_encoding;
22   coding_vector_ = SCM_EOL;
23   coding_mapping_ = SCM_EOL;
24   coding_table_ = SCM_EOL;
25   coding_description_ = SCM_EOL;
26   magnification_ = magnification;
27   
28   SCM desc = fm->description_;
29
30   Real total_mag = magnification * scm_to_double (scm_cdr (desc));
31   assert (total_mag);
32   
33   description_ = scm_cons (scm_car (desc), scm_make_real (total_mag));
34   orig_ = fm;
35
36   String metric_coding = orig_->coding_scheme ();
37   if (metric_coding != "FontSpecific"
38       && metric_coding != font_encoding)
39     warning (_f ("conflicting metric coding (%s) and font_encoding (%s)",
40                  metric_coding, font_encoding));
41
42   if (input_encoding_ != "" 
43       && input_encoding_ != "TeX"
44       && input_encoding_ != "ASCII"
45       && input_encoding_ !=  font_encoding)
46     {
47       coding_vector_ = scm_call_1 (ly_lily_module_constant ("get-coding-vector"),
48                                    scm_makfrom0str (font_encoding.to_str0 ()));
49
50       if (!ly_c_vector_p (coding_vector_))
51         {
52           programming_error ("get-coding-vector  should return vector");
53           coding_vector_ = scm_c_make_vector (256, ly_symbol2scm (".notdef"));
54         }
55
56       coding_table_ = scm_call_1 (ly_lily_module_constant ("get-coding-table"),
57                                   scm_makfrom0str (font_encoding.to_str0 ()));
58
59       coding_mapping_
60         = scm_call_2 (ly_lily_module_constant ("make-encoding-mapping"),
61                       coding_vector_,
62                       coding_table_);
63
64       coding_description_ = SCM_EOL;
65       coding_description_
66         = scm_acons (ly_symbol2scm ("input-name"),
67                      scm_makfrom0str (input_encoding_.to_str0 ()),
68                      coding_description_);
69       coding_description_
70         = scm_acons (ly_symbol2scm ("input-vector"),
71                      coding_vector_, coding_description_);
72       coding_description_
73         = scm_acons (ly_symbol2scm ("output-name"),
74                      scm_makfrom0str (orig_->coding_scheme ().to_str0 ()),
75                      coding_description_);
76       coding_description_
77         = scm_acons (ly_symbol2scm ("output-table"),
78                      coding_table_,
79                      coding_description_);
80       coding_description_
81         = scm_acons (ly_symbol2scm ("char-mapping"),
82                      coding_mapping_,
83                      coding_description_);
84     } 
85 }
86
87 SCM
88 Modified_font_metric::make_scaled_font_metric (Font_metric *fm, Real scaling,
89                                                SCM font_encoding,
90                                                SCM input_encoding)
91 {
92   /*
93     UGH.
94    */
95   if (scm_is_symbol (input_encoding))
96     input_encoding = scm_symbol_to_string (input_encoding);
97   
98   String font_encoding_str = ly_symbol2string (font_encoding);
99   String input_encoding_str
100     = scm_is_string (input_encoding) ? ly_scm2string (input_encoding) : ""; 
101   
102   Modified_font_metric *sfm = new Modified_font_metric (fm, scaling,
103                                                         font_encoding_str,
104                                                         input_encoding_str);
105   return sfm->self_scm ();
106 }
107
108 Real
109 Modified_font_metric::design_size () const
110 {
111   return orig_->design_size ();
112 }
113
114
115 Box 
116 Modified_font_metric::get_indexed_char (int i) const
117 {
118   Box b = orig_->get_indexed_char (i);
119   b.scale (magnification_);
120   return b;  
121 }
122
123 Box 
124 Modified_font_metric::get_ascii_char (int i) const
125 {
126   Box b = orig_->get_ascii_char (i);
127   b.scale (magnification_);
128   return b;  
129 }
130
131 int
132 Modified_font_metric::count () const
133 {
134   return orig_->count ();
135 }
136
137 Offset
138 Modified_font_metric::attachment_point (String s) const
139 {
140   Offset o = orig_->attachment_point (s);
141   return o * magnification_;
142 }
143
144 Offset
145 Modified_font_metric::get_indexed_wxwy (int k) const
146 {
147   Offset o = orig_->get_indexed_wxwy (k);
148   return o * magnification_;
149 }
150
151 int
152 Modified_font_metric::name_to_index (String s) const
153 {
154   return orig_->name_to_index (s);
155 }
156
157 unsigned
158 Modified_font_metric::index_to_charcode (int i) const
159 {
160   return orig_->index_to_charcode (i);
161 }
162
163 int
164 Modified_font_metric::index_to_ascii (int k) const
165 {
166   return orig_->index_to_ascii (k);
167 }
168
169 String
170 Modified_font_metric::coding_scheme () const
171 {
172   return input_encoding_;
173 }
174
175 void
176 Modified_font_metric::derived_mark () const
177 {
178   scm_gc_mark (coding_vector_);
179   scm_gc_mark (coding_description_);
180   scm_gc_mark (coding_table_);
181   scm_gc_mark (coding_mapping_);
182 }
183
184 /* TODO: put this klutchness behind ly:option switch.  */  
185 Box
186 Modified_font_metric::tex_kludge (String text) const
187 {
188   Interval ydims;
189   Real w = 0;
190   for (int i = 0; i < text.length (); i++) 
191     {
192       switch (text[i]) 
193         {
194         case '\\':
195           /* Accent marks use width of base letter */
196          if (i +1 < text.length ())
197            {
198              if (text[i+1]=='\'' || text[i+1]=='`' || text[i+1]=='"'
199                  || text[i+1]=='^')
200                {
201                  i++;
202                  break;
203                }
204              /* For string width \\ is a \ and \_ is a _. */
205              if (text[i+1]=='\\' || text[i+1]=='_')        
206                  break;
207            }
208           
209           for (i++; (i < text.length ()) && !isspace (text[i]) 
210                  && text[i]!='{' && text[i]!='}'; i++)
211             ;
212           
213           /* Compensate for the auto-increment in the outer loop. */
214           i--;
215           break;
216
217         case '{':  // Skip '{' and '}'
218         case '}':
219           break;
220         
221         default: 
222           Box b = get_ascii_char ((unsigned char)text[i]);
223           
224           /* Use the width of 'x' for unknown characters */
225           if (b[X_AXIS].length () == 0) 
226             b = get_ascii_char ((unsigned char)'x');
227           
228           w += b[X_AXIS].length ();
229           ydims.unite (b[Y_AXIS]);
230           break;
231         }
232     }
233   
234   if (ydims.is_empty ())
235     ydims = Interval (0, 0);
236   
237   return Box (Interval (0, w), ydims);
238 }
239
240 Stencil
241 Modified_font_metric::text_stencil (String text) const
242 {
243   Box b; 
244   if (Pango_font * pf = dynamic_cast<Pango_font*> (orig_))
245     {
246       Stencil stc = pf->text_stencil (text);
247
248       Box b = stc.extent_box ();
249
250       b.scale (magnification_);
251       return Stencil (b, stc.expr());
252     }
253
254   return Font_metric::text_stencil (text);
255 }
256
257 Box
258 Modified_font_metric::text_dimension (String text) const
259 {
260   SCM stext = scm_makfrom0str (text.to_str0 ());
261   Box b = lookup_tex_text_dimension (orig_, stext);
262   if (!b[Y_AXIS].is_empty ())
263     {
264       b.scale (magnification_); 
265       return b;
266     }
267   
268   if (input_encoding_ == "TeX")
269     b = tex_kludge (text);
270   else if (input_encoding_ == "ASCII"
271            || input_encoding_ == "" 
272            || input_encoding_ ==  orig_->coding_scheme ())
273     {
274       Interval ydims;
275
276       Real w = 0.0;
277
278       for (int i = 0; i < text.length (); i++) 
279         {
280           Box b = get_ascii_char ((unsigned char)text[i]);
281     
282           w += b[X_AXIS].length ();
283           ydims.unite (b[Y_AXIS]); 
284         }
285       if (ydims.is_empty ())
286         ydims = Interval (0, 0);
287
288       b = Box(Interval(0,w), ydims);
289     }
290   else
291     {
292       Interval ydims;
293       Real w = 0.0;
294
295       for (int i = 0; i < text.length (); i++) 
296         {
297           SCM sym = scm_vector_ref (coding_vector_,
298                                     scm_from_int((unsigned char) text[i]));
299
300           Box char_box;
301
302           if (!scm_is_symbol (sym))
303             continue;
304
305           char const *chars = scm_i_string_chars (scm_symbol_to_string (sym));
306           
307           int idx = orig_->name_to_index (chars);
308           if (idx >= 0)
309             char_box = orig_->get_indexed_char (idx);
310           
311           if (!char_box[X_AXIS].is_empty ())
312             /* length ? */
313             w += char_box[X_AXIS][RIGHT];
314
315           ydims.unite (char_box[Y_AXIS]);
316         }
317
318       if (ydims.is_empty ())
319         ydims = Interval (0, 0);
320
321       b = Box (Interval (0, w), ydims);
322       b.scale (magnification_);
323     }
324   
325   return b;
326 }
327
328 Font_metric*
329 Modified_font_metric::original_font () const
330 {
331   return orig_;
332 }
333
334
335 LY_DEFINE (ly_font_encoding_alist, "ly:font-encoding-alist",
336            1, 0, 0,
337            (SCM font),
338            "Given the Modified_font_metric @var{font}, return an "
339            "alist.  Keys are input-name, input-vector, "
340            "output-name, output-table, mapping.")
341 {
342   Modified_font_metric *fm
343     = dynamic_cast<Modified_font_metric*> (unsmob_metrics (font));
344   
345   SCM_ASSERT_TYPE (fm, font, SCM_ARG1, __FUNCTION__, "Modified_font_metric");
346   return fm->coding_description_;
347 }
348
349 LY_DEFINE (ly_font_encoding, "ly:font-encoding",
350            1, 0, 0,
351            (SCM font),
352            "Return encoding of @var{font}.")
353 {
354   Modified_font_metric *fm
355     = dynamic_cast<Modified_font_metric*> (unsmob_metrics (font));
356   SCM_ASSERT_TYPE (fm, font, SCM_ARG1, __FUNCTION__, "Modified_font_metric");
357   return ly_symbol2scm (fm->original_font ()->coding_scheme ().to_str0 ());
358 }
359
360 SCM
361 Modified_font_metric::sub_fonts () const
362 {
363   return orig_->sub_fonts();
364 }
365   
366 String
367 Modified_font_metric::font_name () const
368 {
369   return original_font ()->font_name();
370 }