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