]> git.lyx.org Git - lyx.git/blob - src/frontends/xforms/xfont_loader.C
Add missing headers. With thanks to Martin...
[lyx.git] / src / frontends / xforms / xfont_loader.C
1 /**
2  * \file xfont_loader.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Asger Alstrup
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "xfont_loader.h"
14 #include "FontInfo.h"
15
16 #include "debug.h"
17 #include "lyxrc.h"      // lyxrc.font_*
18
19 #include "frontends/lyx_gui.h"
20
21 #include "support/filetools.h"
22 #include "support/systemcall.h"
23
24 #include "lyx_forms.h"
25
26 #include <algorithm>
27
28 using namespace lyx::support;
29
30 using std::endl;
31
32
33 // The global fontloader
34 xfont_loader fontloader;
35
36
37 // Initialize font loader
38 xfont_loader::xfont_loader()
39 {
40         reset();
41 }
42
43
44 // Destroy font loader
45 xfont_loader::~xfont_loader()
46 {
47         unload();
48 }
49
50
51 // Update fonts after zoom, dpi, font names, or norm change
52 // For now, we just ditch all fonts we have. Later, we should
53 // reuse the ones that are already loaded.
54 void xfont_loader::update()
55 {
56         unload();
57 }
58
59
60 // Reset font loader
61 void xfont_loader::reset()
62 {
63         // Clear font infos, font structs and font metrics
64         for (int i1 = 0; i1 < LyXFont::NUM_FAMILIES; ++i1)
65                 for (int i2 = 0; i2 < 2; ++i2)
66                         for (int i3 = 0; i3 < 4; ++i3) {
67                                 fontinfo[i1][i2][i3] = 0;
68                                 for (int i4 = 0; i4<10; ++i4) {
69                                         fontstruct[i1][i2][i3][i4] = 0;
70                                 }
71                         }
72 }
73
74
75 // Unload all fonts
76 void xfont_loader::unload()
77 {
78         // Unload all fonts
79         for (int i1 = 0; i1 < LyXFont::NUM_FAMILIES; ++i1)
80                 for (int i2 = 0; i2 < 2; ++i2)
81                         for (int i3 = 0; i3 < 4; ++i3) {
82                                 if (fontinfo[i1][i2][i3]) {
83                                         delete fontinfo[i1][i2][i3];
84                                         fontinfo[i1][i2][i3] = 0;
85                                 }
86                                 for (int i4 = 0; i4 < 10; ++i4) {
87                                         if (fontstruct[i1][i2][i3][i4]) {
88                                                 XFreeFont(fl_get_display(), fontstruct[i1][i2][i3][i4]);
89                                                 fontstruct[i1][i2][i3][i4] = 0;
90                                         }
91                                 }
92                         }
93 }
94
95 namespace {
96
97 string const symbolPattern(LyXFont::FONT_FAMILY family)
98 {
99         switch (family) {
100         case LyXFont::SYMBOL_FAMILY:
101                 return "-*-symbol-*-*-*-*-*-*-*-*-*-*-adobe-fontspecific";
102
103         case LyXFont::CMR_FAMILY:
104                 return "-*-cmr10-medium-*-*-*-*-*-*-*-*-*-*-*";
105
106         case LyXFont::CMSY_FAMILY:
107                 return "-*-cmsy10-*-*-*-*-*-*-*-*-*-*-*-*";
108
109         case LyXFont::CMM_FAMILY:
110                 return "-*-cmmi10-medium-*-*-*-*-*-*-*-*-*-*-*";
111
112         case LyXFont::CMEX_FAMILY:
113                 return "-*-cmex10-*-*-*-*-*-*-*-*-*-*-*-*";
114
115         case LyXFont::MSA_FAMILY:
116                 return "-*-msam10-*-*-*-*-*-*-*-*-*-*-*-*";
117
118         case LyXFont::MSB_FAMILY:
119                 return "-*-msbm10-*-*-*-*-*-*-*-*-*-*-*-*";
120
121         case LyXFont::EUFRAK_FAMILY:
122                 return "-*-eufm10-medium-*-*-*-*-*-*-*-*-*-*-*";
123
124         case LyXFont::WASY_FAMILY:
125                 return "-*-wasy10-medium-*-*-*-*-*-*-*-*-*-*-*";
126
127         default:
128                 return string();
129         }
130 }
131
132 string const fontName(string const & family, string const & foundry)
133 {
134         if (foundry.empty() || foundry == "Xft")
135                 return "-*-"+family;
136         else
137                 return "-"+foundry+"-"+family;
138 }
139
140
141 bool addFontPath()
142 {
143         string const dir =  OnlyPath(LibFileSearch("xfonts", "fonts.dir"));
144         if (!dir.empty()) {
145                 int n;
146                 char ** p = XGetFontPath(fl_get_display(), &n);
147                 if (std::find(p, p + n, dir) != p + n)
148                         return false;
149                 lyxerr[Debug::FONT] << "Adding " << dir
150                                     << " to the font path." << endl;
151                 string const command = "xset fp+ " + dir;
152                 Systemcall s;
153                 if (!s.startscript(Systemcall::Wait, command))
154                         return true;
155                 lyxerr << "Unable to add " << dir << "to the font path."
156                        << endl;
157         }
158         return false;
159 }
160
161 } // namespace anon
162
163 // Get font info
164 /* Takes care of finding which font that can match the given request. Tries
165 different alternatives. */
166 void xfont_loader::getFontinfo(LyXFont::FONT_FAMILY family,
167                              LyXFont::FONT_SERIES series,
168                              LyXFont::FONT_SHAPE shape)
169 {
170         // Do we have the font info already?
171         if (fontinfo[family][series][shape] != 0)
172                 return;
173
174         // Special fonts
175         string pat = symbolPattern(family);
176         if (!pat.empty()) {
177                 static bool first_time = true;
178                 fontinfo[family][series][shape] = new FontInfo(pat);
179                 if (family != LyXFont::SYMBOL_FAMILY &&
180                     !fontinfo[family][series][shape]->exist() &&
181                     first_time) {
182                         first_time = false;
183                         if (addFontPath()) {
184                                 delete fontinfo[family][series][shape];
185                                 fontinfo[family][series][shape] = new FontInfo(pat);
186                         }
187                 }
188                 return;
189         }
190
191
192         // Normal font. Let's search for an existing name that matches.
193         string ffamily;
194         string fseries;
195         string fshape;
196         string norm = lyxrc.font_norm;
197         string fontname;
198
199         FontInfo * fi = new FontInfo;
200         fontinfo[family][series][shape] = fi;
201
202         for (int cfam = 0; cfam < 2; ++cfam) {
203                 // Determine family name
204                 switch (family) {
205                 case LyXFont::ROMAN_FAMILY:
206                         switch (cfam) {
207                         case 0: ffamily = fontName(lyxrc.roman_font_name,
208                                                    lyxrc.roman_font_foundry);
209                                 break;
210                         case 1: ffamily = "-*-times";
211                         default: cfam = 100;
212                         }
213                         break;
214                 case LyXFont::SANS_FAMILY:
215                         switch (cfam) {
216                         case 0: ffamily = fontName(lyxrc.sans_font_name,
217                                                    lyxrc.sans_font_foundry);
218                                 break;
219                         case 1: ffamily = "-*-helvetica";
220                         default: cfam = 100;
221                         }
222                         break;
223                 case LyXFont::TYPEWRITER_FAMILY:
224                         switch (cfam) {
225                         case 0: ffamily = fontName(lyxrc.typewriter_font_name,
226                                                    lyxrc.typewriter_font_foundry);
227                                 break;
228                         case 1: ffamily = "-*-courier";
229                         default: cfam = 100;
230                         }
231                         break;
232                 default: ;
233                 }
234
235                 for (int cser = 0; cser < 4; ++cser) {
236                         // Determine series name
237                         switch (series) {
238                         case LyXFont::MEDIUM_SERIES:
239                                 switch (cser) {
240                                 case 0: fseries = "-medium"; break;
241                                 case 1: fseries = "-book"; break;
242                                 case 2: fseries = "-light";
243                                 default: cser = 100;
244                                 }
245                                 break;
246                         case LyXFont::BOLD_SERIES:
247                                 switch (cser) {
248                                 case 0: fseries = "-bold"; break;
249                                 case 1: fseries = "-black"; break;
250                                 case 2: fseries = "-demi"; break;
251                                 case 3: fseries = "-demibold";
252                                 default: cser = 100;
253                                 }
254                                 break;
255                         default: ;
256                         }
257
258                         for (int csha = 0; csha < 2; ++csha) {
259                                 // Determine shape name
260                                 switch (shape) {
261                                 case LyXFont::UP_SHAPE:
262                                 case LyXFont::SMALLCAPS_SHAPE:
263                                         switch (csha) {
264                                         case 0: fshape = "-r";
265                                         default: csha = 100;
266                                         }
267                                         break;
268                                 case LyXFont::ITALIC_SHAPE:
269                                         switch (csha) {
270                                         case 0: fshape = "-i"; break;
271                                         case 1: fshape = "-o";
272                                         default: csha = 100;
273                                         }
274                                         break;
275                                 case LyXFont::SLANTED_SHAPE:
276                                         switch (csha) {
277                                         case 0: fshape = "-o"; break;
278                                         case 1: fshape = "-i";
279                                         default: csha = 100;
280                                         }
281                                         break;
282                                 default: ;
283                                 }
284                                 //
285                                 fontname = ffamily + fseries + fshape +
286                                            "-normal-*-*-*-*-*-*-*-" + norm;
287                                 fi->setPattern(fontname);
288                                 if (fi->exist()) {
289                                         return;
290                                 }
291                         }
292                 }
293         }
294 }
295
296
297 // A dummy fontstruct used when there is no gui.
298 namespace {
299
300 XFontStruct dummyXFontStruct;
301 bool dummyXFontStructisGood = false;
302
303 } // namespace anon
304
305 /// Do load font
306 XFontStruct * xfont_loader::doLoad(LyXFont::FONT_FAMILY family,
307                                 LyXFont::FONT_SERIES series,
308                                 LyXFont::FONT_SHAPE shape,
309                                 LyXFont::FONT_SIZE size)
310 {
311         if (!lyx_gui::use_gui) {
312                 if (!dummyXFontStructisGood) {
313                         // no character specific info
314                         dummyXFontStruct.per_char = 0;
315                         // unit ascent on character displays
316                         dummyXFontStruct.ascent = 1;
317                         // no descent on character displays
318                         dummyXFontStruct.descent = 0;
319                         dummyXFontStructisGood = true;
320                 }
321
322                 return &dummyXFontStruct;
323         }
324
325         getFontinfo(family, series, shape);
326         // FIXME! CHECK! Should we use 72.0 or 72.27? (Lgb)
327         int fsize = int((lyxrc.font_sizes[size] * lyxrc.dpi *
328                           (lyxrc.zoom/100.0)) / 72.27 + 0.5);
329
330         string font = fontinfo[family][series][shape]->getFontname(fsize);
331
332         if (font.empty()) {
333                 lyxerr << "No font matches request. Using 'fixed'." << endl;
334                 lyxerr << "Start LyX as 'lyx -dbg 515' to get more information." << endl;
335                 font = "fixed";
336         }
337
338         XFontStruct * fs = 0;
339
340         fs = XLoadQueryFont(fl_get_display(), font.c_str());
341
342         if (fs == 0) {
343                 if (font == "fixed") {
344                         lyxerr << "We're doomed. Can't get 'fixed' font." << endl;
345                 } else {
346                         lyxerr << "Could not get font '" << font
347                                 << "'. Using 'fixed'." << endl;
348                         fs = XLoadQueryFont(fl_get_display(), "fixed");
349                 }
350         } else if (lyxerr.debugging(Debug::FONT)) {
351                 // Tell user the font matching
352                 LyXFont f;
353                 f.setFamily(family);
354                 f.setSeries(series);
355                 f.setShape(shape);
356                 f.setSize(size);
357                 // The rest of the attributes are not interesting
358                 f.setEmph(LyXFont::INHERIT);
359                 f.setUnderbar(LyXFont::INHERIT);
360                 f.setNoun(LyXFont::INHERIT);
361                 f.setColor(LColor::inherit);
362                 lyxerr << "Font '" << f.stateText(0)
363                        << "' matched by\n" << font << endl;
364         }
365
366         fontstruct[family][series][shape][size] = fs;
367         return fs;
368 }
369
370
371 bool xfont_loader::available(LyXFont const & f)
372 {
373         if (!lyx_gui::use_gui)
374                 return false;
375
376         if (!fontinfo[f.family()][f.series()][f.realShape()])
377                 getFontinfo(f.family(), f.series(), f.realShape());
378         return fontinfo[f.family()][f.series()][f.realShape()]->exist();
379 }