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