]> git.donarmstrong.com Git - lilypond.git/blob - lily/all-font-metrics.cc
*** empty log message ***
[lilypond.git] / lily / all-font-metrics.cc
1 /*
2   all-font-metrics.cc --  implement All_font_metrics
3   
4   source file of the GNU LilyPond music typesetter
5   
6   (c) 1999--2005 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
8
9 #include "all-font-metrics.hh"
10
11 #include "open-type-font.hh"
12 #include "main.hh"
13 #include "warn.hh"
14 #include "afm.hh"
15 #include "tfm.hh"
16 #include "scm-hash.hh"
17 #include "kpath.hh"
18 #include "pango-font.hh"
19
20 static char const *default_font_str0_ = "cmr10";
21
22 All_font_metrics::All_font_metrics (String path)
23 {
24   afm_dict_ = new Scheme_hash_table;
25   tfm_dict_ = new Scheme_hash_table;
26   otf_dict_ = new Scheme_hash_table;
27
28 #if HAVE_PANGO_FT2
29   PangoFontMap*pfm = pango_ft2_font_map_new ();
30
31   pango_ft2_fontmap_ =
32     G_TYPE_CHECK_INSTANCE_CAST(pfm,
33                                PANGO_TYPE_FT2_FONT_MAP,
34                                PangoFT2FontMap);
35   pango_dpi_ = 1200;
36   pango_ft2_font_map_set_resolution (pango_ft2_fontmap_,
37                                      pango_dpi_, pango_dpi_);
38
39   pango_dict_ = new Scheme_hash_table;
40 #endif
41   
42   search_path_.parse_path (path);
43 }
44
45 All_font_metrics::~All_font_metrics ()
46 {
47   scm_gc_unprotect_object (afm_dict_->self_scm ());
48   scm_gc_unprotect_object (tfm_dict_->self_scm ());
49   scm_gc_unprotect_object (otf_dict_->self_scm ());
50
51 #if HAVE_PANGO_FT2
52   scm_gc_unprotect_object (pango_dict_->self_scm ());
53   g_object_unref (pango_ft2_fontmap_);
54 #endif
55 }
56
57 All_font_metrics::All_font_metrics (All_font_metrics const&)
58 {
59 }
60
61 #if HAVE_PANGO_FT2
62
63 Pango_font *
64 All_font_metrics::find_pango_font (PangoFontDescription*description,
65                                    Real magnification,
66                                    Real output_scale)
67 {
68   pango_font_description_set_size (description,
69                                    gint (magnification *
70                                          pango_font_description_get_size (description)));
71   
72   gchar *fn = pango_font_description_to_filename (description);
73   SCM key = ly_symbol2scm (fn);
74
75   SCM val;
76   if (!pango_dict_->try_retrieve (key, &val))
77     {
78       if (be_verbose_global)
79         progress_indication ("[" + String (fn));
80       Pango_font *pf = new Pango_font (pango_ft2_fontmap_,
81                                        RIGHT,
82                                        description,
83                                        output_scale);
84       val = pf->self_scm ();
85       pango_dict_->set (key, val);
86       scm_gc_unprotect_object (val);
87
88       if (be_verbose_global)
89         progress_indication ("]");
90
91       pf->description_ = scm_cons (SCM_BOOL_F,
92                                    scm_make_real (1.0));
93     }
94   g_free (fn); 
95   return dynamic_cast<Pango_font*> (unsmob_metrics (val));
96 }
97
98 #endif
99
100 /*
101   TODO: our AFM handling is broken: the units in an AFM file are
102   relative to the design size (1000 units = 1 designsize). Hence we
103   should include design size when generating an AFM metric.
104
105   ugr: copied from find_tfm.
106  */
107 Adobe_font_metric *
108 All_font_metrics::find_afm (String name)
109 {
110   SCM sname = ly_symbol2scm (name.to_str0 ());
111   SCM name_string = scm_makfrom0str (name.to_str0 ());
112   SCM val;
113   if (!afm_dict_->try_retrieve (sname, &val))
114     {
115       String file_name;
116
117       if (file_name.is_empty ())
118         file_name = search_path_.find (name  + ".afm");
119
120       if (file_name.is_empty ())
121         {
122           String p = kpathsea_find_afm (name.to_str0 ());
123           if (p.length ())
124             file_name = p;
125         }
126
127       if (file_name.is_empty ())
128         return 0;
129       
130       if (be_verbose_global)
131         progress_indication ("[" + file_name);
132       val = read_afm_file (file_name);
133       unsmob_metrics (val)->file_name_ = file_name;
134       
135       unsmob_metrics (val)->description_ = scm_cons (name_string, 
136                                                      scm_make_real (1.0));
137
138       if (be_verbose_global)
139         progress_indication ("]");
140
141       afm_dict_->set (sname, val);
142       scm_gc_unprotect_object (val);
143
144       Adobe_font_metric *afm
145         = dynamic_cast<Adobe_font_metric*> (unsmob_metrics (val));
146
147       /* Only check checksums if there is one.  We take the risk that
148          some file has valid checksum 0 */
149       if (afm->checksum_)
150         {
151           Tex_font_metric * tfm = find_tfm (name);
152           
153           /* FIXME: better warning message
154              (maybe check upon startup for feta16.afm, feta16.tfm?) */
155           if (tfm && tfm->info ().checksum != afm->checksum_)
156             {
157               // FIXME: broken sentence
158               String s = _f ("checksum mismatch for font file: `%s'",
159                              file_name.to_str0 ());
160               s += " " + _f ("does not match: `%s'",
161                              tfm->file_name_.to_str0 ());
162               s += "\n";
163               s += " TFM: " + to_string ((int) tfm->info ().checksum);
164               s += " AFM: " + to_string ((int) afm->checksum_);
165               s += "\n";
166               s += _ ("Rebuild all .afm files, and remove all .pk and .tfm files.");
167               s += "\n";
168               s += _ ("Rerun with -V to show font paths.");
169               s += "\n";
170               s += _("A script for removing font-files is delivered with the source-code:");
171               s += "\n";
172               s += "buildscripts/clean-fonts.sh";
173               error (s);
174             }
175         }
176     }
177   
178   return dynamic_cast<Adobe_font_metric*> (unsmob_metrics (val));
179 }
180
181 Open_type_font*
182 All_font_metrics::find_otf (String name)
183 {
184   SCM sname = ly_symbol2scm (name.to_str0 ());
185   SCM name_string = scm_makfrom0str (name.to_str0 ());
186   SCM val;
187   if (!otf_dict_->try_retrieve (sname, &val))
188     {
189       String file_name;
190       
191       if (file_name.is_empty ())
192         file_name = search_path_.find (name  + ".otf");
193       if (file_name.is_empty ())
194         return 0;
195
196       if (be_verbose_global)
197         progress_indication ("[" + file_name);
198       
199       val = Open_type_font::make_otf (file_name);
200
201       if (be_verbose_global)
202         progress_indication ("]");
203
204       unsmob_metrics (val)->file_name_ = file_name;
205       unsmob_metrics (val)->description_ = scm_cons (name_string,
206                                                      scm_make_real (1.0));
207       otf_dict_->set (sname, val);
208       scm_gc_unprotect_object (val);
209     }
210
211   return dynamic_cast<Open_type_font*> (unsmob_metrics (val));
212 }
213
214 Tex_font_metric*
215 All_font_metrics::find_tfm (String name)
216 {
217   SCM sname = ly_symbol2scm (name.to_str0 ());
218   SCM name_string = scm_makfrom0str (name.to_str0 ());
219   SCM val;
220   if (!tfm_dict_->try_retrieve (sname, &val))
221     {
222       String file_name;
223       
224       if (file_name.is_empty ())
225         {
226           /* FIXME: should add "cork-" prefix to lm* fonts.  How to do
227              that, cleanly?  */
228           String p = kpathsea_find_tfm (name.to_str0 ());
229           if (p.length ())
230             file_name = p;
231         }
232
233       if (file_name.is_empty ())
234         file_name = search_path_.find (name  + ".tfm");
235       if (file_name.is_empty ())
236         return 0;
237
238       if (be_verbose_global)
239         progress_indication ("[" + file_name);
240       
241       val = Tex_font_metric::make_tfm (file_name);
242
243       if (be_verbose_global)
244         progress_indication ("]");
245
246       unsmob_metrics (val)->file_name_ = file_name;
247       unsmob_metrics (val)->description_ = scm_cons (name_string,
248                                                      scm_make_real (1.0));
249       tfm_dict_->set (sname, val);
250       scm_gc_unprotect_object (val);
251     }
252
253   return dynamic_cast<Tex_font_metric*> (unsmob_metrics (val));
254 }
255
256 Font_metric*
257 All_font_metrics::find_font (String name)
258 {
259   Font_metric *f = find_otf (name);
260    
261   if (!f &&
262       (name.left_string (4) == "feta"
263        || name.left_string (8) == "parmesan"
264        || name.left_string (2) == "lm"))
265     {
266       f = find_afm (name);
267       if (!f)
268         f = find_tfm (name);
269     }
270   else if (!f)
271     {
272       f = find_tfm (name);
273       if (!f)
274         f = find_afm (name);
275     }
276
277   if (!f)
278     {
279       warning (_f ("can't find font: `%s'", name.to_str0 ()));
280       warning (_ ("Loading default font"));
281     }
282   
283   String def_name = default_font_str0_;
284
285   /* We're in emergency recovery mode here anyway, so don't try to do
286      anything smart that runs the risk of failing.  */
287   if (!f)
288     f = find_afm (def_name);
289
290   if (!f)
291     f = find_tfm (def_name);
292
293   if (!f)
294     {
295       error (_f ("can't find default font: `%s'", def_name.to_str0 ()));
296       error (_f ("(search path: `%s')", search_path_.to_string ()));
297       error (_ ("Giving up"));
298     }
299
300   return f;
301 }
302
303 All_font_metrics *all_fonts_global;
304
305
306 LY_DEFINE (ly_font_load, "ly:font-load", 1, 0, 0,
307            (SCM name),
308            "Load the font @var{name}. ")
309 {
310   SCM_ASSERT_TYPE (scm_is_string (name), name, SCM_ARG1, __FUNCTION__, "string");
311
312   Font_metric *fm = all_fonts_global->find_font (ly_scm2string (name));
313
314   return fm->self_scm ();
315 }
316