]> git.donarmstrong.com Git - lilypond.git/blob - lily/modified-font-metric.cc
*** empty log message ***
[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
11 #include <cctype>
12
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_scheme_function ("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_scheme_function ("get-coding-table"),
57                                   scm_makfrom0str (font_encoding.to_str0 ()));
58
59       coding_mapping_
60         = scm_call_2 (ly_scheme_function ("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 int
158 Modified_font_metric::index_to_ascii (int k) const
159 {
160   return orig_->index_to_ascii (k);
161 }
162
163 String
164 Modified_font_metric::coding_scheme () const
165 {
166   return input_encoding_;
167 }
168
169 void
170 Modified_font_metric::derived_mark () const
171 {
172   scm_gc_mark (coding_vector_);
173   scm_gc_mark (coding_description_);
174   scm_gc_mark (coding_table_);
175   scm_gc_mark (coding_mapping_);
176 }
177
178 /* TODO: put this klutchness behind ly:option switch.  */  
179 Box
180 Modified_font_metric::tex_kludge (String text) const
181 {
182   Interval ydims;
183   Real w = 0;
184   for (int i = 0; i < text.length (); i++) 
185     {
186       switch (text[i]) 
187         {
188         case '\\':
189           /* Accent marks use width of base letter */
190          if (i +1 < text.length ())
191            {
192              if (text[i+1]=='\'' || text[i+1]=='`' || text[i+1]=='"'
193                  || text[i+1]=='^')
194                {
195                  i++;
196                  break;
197                }
198              /* For string width \\ is a \ and \_ is a _. */
199              if (text[i+1]=='\\' || text[i+1]=='_')        
200                  break;
201            }
202           
203           for (i++; (i < text.length ()) && !isspace (text[i]) 
204                  && text[i]!='{' && text[i]!='}'; i++)
205             ;
206           
207           /* Compensate for the auto-increment in the outer loop. */
208           i--;
209           break;
210
211         case '{':  // Skip '{' and '}'
212         case '}':
213           break;
214         
215         default: 
216           Box b = get_ascii_char ((unsigned char)text[i]);
217           
218           /* Use the width of 'x' for unknown characters */
219           if (b[X_AXIS].length () == 0) 
220             b = get_ascii_char ((unsigned char)'x');
221           
222           w += b[X_AXIS].length ();
223           ydims.unite (b[Y_AXIS]);
224           break;
225         }
226     }
227   
228   if (ydims.is_empty ())
229     ydims = Interval (0, 0);
230   
231   return Box (Interval (0, w), ydims);
232 }
233
234 Box
235 Modified_font_metric::text_dimension (String text) 
236 {
237   Box b; 
238   if (input_encoding_ == "TeX")
239     b = tex_kludge (text);
240   else if (input_encoding_ == "ASCII"
241            || input_encoding_ == "" 
242            || input_encoding_ ==  orig_->coding_scheme ())
243     {
244       Interval ydims;
245
246       Real w = 0.0;
247
248       for (int i = 0; i < text.length (); i++) 
249         {
250           Box b = get_ascii_char ((unsigned char)text[i]);
251     
252           w += b[X_AXIS].length ();
253           ydims.unite (b[Y_AXIS]); 
254         }
255       if (ydims.is_empty ())
256         ydims = Interval (0, 0);
257
258       b = Box(Interval(0,w), ydims);
259     }
260   else
261     {
262       Interval ydims;
263       Real w = 0.0;
264
265       for (int i = 0; i < text.length (); i++) 
266         {
267           SCM sym = scm_vector_ref (coding_vector_,
268                                     scm_from_int((unsigned char) text[i]));
269
270           Box char_box;
271
272           if (!scm_is_symbol (sym))
273             continue;
274
275           char const *chars = scm_i_string_chars (scm_symbol_to_string (sym));
276           
277           int idx = orig_->name_to_index (chars);
278           if (idx >= 0)
279             char_box = orig_->get_indexed_char (idx);
280           
281           char_box.scale (magnification_);
282           if (!char_box[X_AXIS].is_empty ())
283             /* length ? */
284             w += char_box[X_AXIS][RIGHT];
285
286           ydims.unite (char_box[Y_AXIS]);
287         }
288
289       if (ydims.is_empty ())
290         ydims = Interval (0, 0);
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 }
303
304
305 LY_DEFINE (ly_font_encoding_alist, "ly:font-encoding-alist",
306            1, 0, 0,
307            (SCM font),
308            "Given the Modified_font_metric @var{font}, return an "
309            "alist.  Keys are input-name, input-vector, "
310            "output-name, output-table, mapping.")
311 {
312   Modified_font_metric *fm
313     = dynamic_cast<Modified_font_metric*> (unsmob_metrics (font));
314   
315   SCM_ASSERT_TYPE (fm, font, SCM_ARG1, __FUNCTION__, "Modified_font_metric");
316   return fm->coding_description_;
317 }
318
319 LY_DEFINE (ly_font_encoding, "ly:font-encoding",
320            1, 0, 0,
321            (SCM font),
322            "Return encoding of @var{font}.")
323 {
324   Modified_font_metric *fm
325     = dynamic_cast<Modified_font_metric*> (unsmob_metrics (font));
326   SCM_ASSERT_TYPE (fm, font, SCM_ARG1, __FUNCTION__, "Modified_font_metric");
327   return ly_symbol2scm (fm->original_font ()->coding_scheme ().to_str0 ());
328 }
329