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