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