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