]> 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--2004 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 Pango_font *
63 All_font_metrics::find_pango_font (PangoFontDescription*description)
64 {
65   gchar *fn = pango_font_description_to_filename (description);
66   SCM key = ly_symbol2scm (fn);
67
68   SCM val;
69   if (!pango_dict_->try_retrieve (key, &val))
70     {
71       if (be_verbose_global)
72         progress_indication ("[" + String (fn));
73       Pango_font *pf = new Pango_font (pango_ft2_fontmap_,
74                                        RIGHT,
75                                        description);
76       val = pf->self_scm ();
77       pango_dict_->set (key, val);
78       scm_gc_unprotect_object (val);
79
80       if (be_verbose_global)
81         progress_indication ("]");
82
83       pf->description_ = scm_cons (SCM_BOOL_F,
84                                    scm_make_real (1.0));
85     }
86   g_free (fn); 
87   return dynamic_cast<Pango_font*> (unsmob_metrics (val));
88 }
89 #endif
90
91 /*
92   TODO: our AFM handling is broken: the units in an AFM file are
93   relative to the design size (1000 units = 1 designsize). Hence we
94   should include design size when generating an AFM metric.
95
96   ugr: copied from find_tfm.
97  */
98 Adobe_font_metric *
99 All_font_metrics::find_afm (String name)
100 {
101   SCM sname = ly_symbol2scm (name.to_str0 ());
102   SCM name_string = scm_makfrom0str (name.to_str0 ());
103   SCM val;
104   if (!afm_dict_->try_retrieve (sname, &val))
105     {
106       String file_name;
107
108       if (file_name.is_empty ())
109         file_name = search_path_.find (name  + ".afm");
110
111       if (file_name.is_empty ())
112         {
113           String p = kpathsea_find_afm (name.to_str0 ());
114           if (p.length ())
115             file_name = p;
116         }
117
118       if (file_name.is_empty ())
119         return 0;
120       
121       if (be_verbose_global)
122         progress_indication ("[" + file_name);
123       val = read_afm_file (file_name);
124       unsmob_metrics (val)->file_name_ = file_name;
125       
126       unsmob_metrics (val)->description_ = scm_cons (name_string, 
127                                                      scm_make_real (1.0));
128
129       if (be_verbose_global)
130         progress_indication ("]");
131
132       afm_dict_->set (sname, val);
133       scm_gc_unprotect_object (val);
134
135       Adobe_font_metric *afm
136         = dynamic_cast<Adobe_font_metric*> (unsmob_metrics (val));
137
138       /* Only check checksums if there is one.  We take the risk that
139          some file has valid checksum 0 */
140       if (afm->checksum_)
141         {
142           Tex_font_metric * tfm = find_tfm (name);
143           
144           /* FIXME: better warning message
145              (maybe check upon startup for feta16.afm, feta16.tfm?) */
146           if (tfm && tfm->info ().checksum != afm->checksum_)
147             {
148               // FIXME: broken sentence
149               String s = _f ("checksum mismatch for font file: `%s'",
150                              file_name.to_str0 ());
151               s += " " + _f ("does not match: `%s'",
152                              tfm->file_name_.to_str0 ());
153               s += "\n";
154               s += " TFM: " + to_string ((int) tfm->info ().checksum);
155               s += " AFM: " + to_string ((int) afm->checksum_);
156               s += "\n";
157               s += _ ("Rebuild all .afm files, and remove all .pk and .tfm files.");
158               s += "\n";
159               s += _ ("Rerun with -V to show font paths.");
160               s += "\n";
161               s += _("A script for removing font-files is delivered with the source-code:");
162               s += "\n";
163               s += "buildscripts/clean-fonts.sh";
164               error (s);
165             }
166         }
167     }
168   
169   return dynamic_cast<Adobe_font_metric*> (unsmob_metrics (val));
170 }
171
172 Open_type_font*
173 All_font_metrics::find_otf (String name)
174 {
175   SCM sname = ly_symbol2scm (name.to_str0 ());
176   SCM name_string = scm_makfrom0str (name.to_str0 ());
177   SCM val;
178   if (!otf_dict_->try_retrieve (sname, &val))
179     {
180       String file_name;
181       
182       if (file_name.is_empty ())
183         file_name = search_path_.find (name  + ".otf");
184       if (file_name.is_empty ())
185         return 0;
186
187       if (be_verbose_global)
188         progress_indication ("[" + file_name);
189       
190       val = Open_type_font::make_otf (file_name);
191
192       if (be_verbose_global)
193         progress_indication ("]");
194
195       unsmob_metrics (val)->file_name_ = file_name;
196       unsmob_metrics (val)->description_ = scm_cons (name_string,
197                                                      scm_make_real (1.0));
198       otf_dict_->set (sname, val);
199       scm_gc_unprotect_object (val);
200     }
201
202   return dynamic_cast<Open_type_font*> (unsmob_metrics (val));
203 }
204
205 Tex_font_metric*
206 All_font_metrics::find_tfm (String name)
207 {
208   SCM sname = ly_symbol2scm (name.to_str0 ());
209   SCM name_string = scm_makfrom0str (name.to_str0 ());
210   SCM val;
211   if (!tfm_dict_->try_retrieve (sname, &val))
212     {
213       String file_name;
214       
215       if (file_name.is_empty ())
216         {
217           /* FIXME: should add "cork-" prefix to lm* fonts.  How to do
218              that, cleanly?  */
219           String p = kpathsea_find_tfm (name.to_str0 ());
220           if (p.length ())
221             file_name = p;
222         }
223
224       if (file_name.is_empty ())
225         file_name = search_path_.find (name  + ".tfm");
226       if (file_name.is_empty ())
227         return 0;
228
229       if (be_verbose_global)
230         progress_indication ("[" + file_name);
231       
232       val = Tex_font_metric::make_tfm (file_name);
233
234       if (be_verbose_global)
235         progress_indication ("]");
236
237       unsmob_metrics (val)->file_name_ = file_name;
238       unsmob_metrics (val)->description_ = scm_cons (name_string,
239                                                      scm_make_real (1.0));
240       tfm_dict_->set (sname, val);
241       scm_gc_unprotect_object (val);
242     }
243
244   return dynamic_cast<Tex_font_metric*> (unsmob_metrics (val));
245 }
246
247 Font_metric*
248 All_font_metrics::find_font (String name)
249 {
250   Font_metric *f = find_otf (name);
251    
252   if (!f &&
253       (name.left_string (4) == "feta"
254        || name.left_string (8) == "parmesan"
255        || name.left_string (2) == "lm"))
256     {
257       f = find_afm (name);
258       if (!f)
259         f = find_tfm (name);
260     }
261   else if (!f)
262     {
263       f = find_tfm (name);
264       if (!f)
265         f = find_afm (name);
266     }
267
268   if (!f)
269     {
270       warning (_f ("can't find font: `%s'", name.to_str0 ()));
271       warning (_ ("Loading default font"));
272     }
273   
274   String def_name = default_font_str0_;
275
276   /* We're in emergency recovery mode here anyway, so don't try to do
277      anything smart that runs the risk of failing.  */
278   if (!f)
279     f = find_afm (def_name);
280
281   if (!f)
282     f = find_tfm (def_name);
283
284   if (!f)
285     {
286       error (_f ("can't find default font: `%s'", def_name.to_str0 ()));
287       error (_f ("(search path: `%s')", search_path_.to_string ()));
288       error (_ ("Giving up"));
289     }
290
291   return f;
292 }
293
294 All_font_metrics *all_fonts_global;
295
296
297 LY_DEFINE (ly_font_load, "ly:font-load", 1, 0, 0,
298            (SCM name),
299            "Load the font @var{name}. ")
300 {
301   SCM_ASSERT_TYPE (scm_is_string (name), name, SCM_ARG1, __FUNCTION__, "string");
302
303   Font_metric *fm = all_fonts_global->find_font (ly_scm2string (name));
304
305   return fm->self_scm ();
306 }
307