]> git.lyx.org Git - lyx.git/blob - src/frontends/qt2/qfont_loader.C
Strip trailing whitespace.
[lyx.git] / src / frontends / qt2 / qfont_loader.C
1 /**
2  * \file qfont_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  * \author John Levon
8  *
9  * Full author contact details are available in file CREDITS
10  */
11
12 #include <config.h>
13
14
15 #include "qfont_loader.h"
16 #include "qt_helpers.h"
17 #include "debug.h"
18 #include "lyxrc.h"
19 #include "BufferView.h"
20 #include "qt_helpers.h"
21
22 #include <qglobal.h>
23 #include <qfontmetrics.h>
24 #include <qfontdatabase.h>
25 #include <qstringlist.h>
26 #include "support/lstrings.h"
27
28 #ifdef Q_WS_X11
29 #include <qwidget.h>
30 #include <X11/Xlib.h>
31 #include "support/systemcall.h"
32 #include "support/filetools.h"
33 #endif
34
35 using std::endl;
36
37
38 namespace {
39
40 void addFontPath()
41 {
42 #ifdef Q_WS_X11
43         string const dir =  OnlyPath(LibFileSearch("xfonts", "fonts.dir"));
44         if (!dir.empty()) {
45                 QWidget w;
46                 int n;
47                 char ** p = XGetFontPath(w.x11Display(), &n);
48                 if (std::find(p, p + n, dir) != p + n)
49                         return;
50                 lyxerr[Debug::FONT] << "Adding " << dir
51                                     << " to the font path." << endl;
52                 string const command = "xset fp+ " + dir;
53                 Systemcall s;
54                 if (!s.startscript(Systemcall::Wait, command))
55                         return;
56                 lyxerr << "Unable to add " << dir << "to the font path."
57                        << endl;
58         }
59 #endif
60 }
61
62
63 struct symbol_font {
64         LyXFont::FONT_FAMILY lyx_family;
65         string family;
66         string xlfd;
67 };
68
69 symbol_font symbol_fonts[] = {
70         { LyXFont::SYMBOL_FAMILY,
71                 "symbol",
72                 "-*-symbol-*-*-*-*-*-*-*-*-*-*-adobe-fontspecific" },
73
74         { LyXFont::CMR_FAMILY,
75                 "cmr10",
76                 "-*-cmr10-medium-*-*-*-*-*-*-*-*-*-*-*" },
77
78         { LyXFont::CMSY_FAMILY,
79                 "cmsy10",
80                 "-*-cmsy10-*-*-*-*-*-*-*-*-*-*-*-*" },
81
82         { LyXFont::CMM_FAMILY,
83                 "cmmi10",
84                 "-*-cmmi10-medium-*-*-*-*-*-*-*-*-*-*-*" },
85
86         { LyXFont::CMEX_FAMILY,
87                 "cmex10",
88                 "-*-cmex10-*-*-*-*-*-*-*-*-*-*-*-*" },
89
90         { LyXFont::MSA_FAMILY,
91                 "msam10",
92                 "-*-msam10-*-*-*-*-*-*-*-*-*-*-*-*" },
93
94         { LyXFont::MSB_FAMILY,
95                 "msbm10",
96                 "-*-msbm10-*-*-*-*-*-*-*-*-*-*-*-*" },
97
98         { LyXFont::EUFRAK_FAMILY,
99                 "eufm10",
100                 "-*-eufm10-medium-*-*-*-*-*-*-*-*-*-*-*" },
101
102         { LyXFont::WASY_FAMILY,
103                 "wasy10",
104                 "-*-wasy10-medium-*-*-*-*-*-*-*-*-*-*-*" }
105 };
106
107 size_t const nr_symbol_fonts = sizeof(symbol_fonts) / sizeof(symbol_font);
108
109
110 string getRawName(string const & family)
111 {
112         for (size_t i = 0; i < nr_symbol_fonts; ++i) {
113                 if (family == symbol_fonts[i].family)
114                         return symbol_fonts[i].xlfd;
115         }
116         lyxerr[Debug::FONT] << "BUG: family not found !" << endl;
117         return string();
118 }
119
120
121 string const symbolFamily(LyXFont::FONT_FAMILY family)
122 {
123         for (size_t i = 0; i < nr_symbol_fonts; ++i) {
124                 if (family == symbol_fonts[i].lyx_family)
125                         return symbol_fonts[i].family;
126         }
127         return string();
128 }
129
130
131 bool isSymbolFamily(LyXFont::FONT_FAMILY family)
132 {
133         return family >= LyXFont::SYMBOL_FAMILY &&
134                 family <= LyXFont::WASY_FAMILY;
135 }
136
137
138 QFont const getSymbolFont(string const & family)
139 {
140         lyxerr[Debug::FONT] << "Looking for font family "
141                 << family << " ... ";
142         string upper = family;
143         upper[0] = toupper(family[0]);
144
145         QFont font;
146         font.setFamily(toqstr(family));
147
148         // Note Qt lies about family, so we use rawName.
149         if (contains(fromqstr(font.rawName()), family)) {
150                 lyxerr[Debug::FONT] << " got it !" << endl;
151                 return font;
152         }
153
154         font.setFamily(toqstr(upper));
155
156         if (contains(fromqstr(font.rawName()), upper)) {
157                 lyxerr[Debug::FONT] << " got it (uppercase version) !" << endl;
158                 return font;
159         }
160
161         // A simple setFamily() fails on Qt 2
162
163         font.setRawName(toqstr(getRawName(family)));
164
165         if (contains(fromqstr(font.rawName()), family)) {
166                 lyxerr[Debug::FONT] << " got it (raw version) !" << endl;
167                 return font;
168         }
169
170         lyxerr[Debug::FONT] << " FAILED :-(" << endl;
171         return font;
172 }
173
174
175 bool isAvailable(LyXFont const & f)
176 {
177         static std::vector<bool> cache(LyXFont::NUM_FAMILIES, false);
178         static std::vector<bool> cache_initialized(LyXFont::NUM_FAMILIES, false);
179         static bool first_call = true;
180
181         LyXFont::FONT_FAMILY lyxfamily = f.family();
182         if (cache_initialized[lyxfamily])
183                 return cache[lyxfamily];
184         cache_initialized[lyxfamily] = true;
185
186         if (first_call && isSymbolFamily(lyxfamily)) {
187                 first_call = false;
188                 addFontPath();
189         }
190
191         string const tmp = symbolFamily(lyxfamily);
192
193         if (tmp.empty())
194                 return false;
195
196         QString const family(toqstr(tmp));
197
198         lyxerr[Debug::FONT] << "Family " << tmp
199                << " isAvailable ?";
200
201         QFontDatabase db;
202         // pass false for match-locale: LaTeX fonts
203         // do not have non-matching locale according
204         // to Qt 2
205         QStringList sl(db.families(false));
206
207         for (QStringList::Iterator it = sl.begin(); it != sl.end(); ++it) {
208                 // Case-insensitive for Cmmi10 vs. cmmi10
209                 if ((*it).lower().startsWith(family.lower())) {
210                         lyxerr[Debug::FONT]
211                                 << "found family "
212                                 << fromqstr(*it) << endl;
213                         cache[lyxfamily] = true;
214                         return true;
215                 }
216         }
217         lyxerr[Debug::FONT] << " no." << endl;
218         return false;
219 }
220
221
222 } // namespace anon
223
224
225 qfont_loader::qfont_loader()
226 {
227         for (int i1 = 0; i1 < LyXFont::NUM_FAMILIES; ++i1) {
228                 for (int i2 = 0; i2 < 2; ++i2) {
229                         for (int i3 = 0; i3 < 4; ++i3) {
230                                 for (int i4 = 0; i4 < 10; ++i4) {
231                                         fontinfo_[i1][i2][i3][i4] = 0;
232                                 }
233                         }
234                 }
235         }
236 }
237
238
239 qfont_loader::~qfont_loader()
240 {
241 }
242
243
244 void qfont_loader::update()
245 {
246         for (int i1 = 0; i1 < LyXFont::NUM_FAMILIES; ++i1) {
247                 for (int i2 = 0; i2 < 2; ++i2) {
248                         for (int i3 = 0; i3 < 4; ++i3) {
249                                 for (int i4 = 0; i4 < 10; ++i4) {
250                                         delete fontinfo_[i1][i2][i3][i4];
251                                         fontinfo_[i1][i2][i3][i4] = 0;
252                                 }
253                         }
254                 }
255         }
256 }
257
258
259 QFont const & qfont_loader::get(LyXFont const & f)
260 {
261         static bool first_call = true;
262
263         if (first_call && isSymbolFamily(f.family())) {
264                 first_call = false;
265                 addFontPath();
266         }
267
268         QFont const & ret(getfontinfo(f)->font);
269
270         return ret;
271 }
272
273
274 qfont_loader::font_info::font_info(LyXFont const & f)
275         : metrics(font)
276 {
277
278         string const pat = symbolFamily(f.family());
279         if (!pat.empty()) {
280                 font = getSymbolFont(pat);
281         } else {
282                 switch (f.family()) {
283                 case LyXFont::ROMAN_FAMILY:
284                         font.setFamily(toqstr(makeFontName(lyxrc.roman_font_name,
285                                                     lyxrc.roman_font_foundry)));
286                         break;
287                 case LyXFont::SANS_FAMILY:
288                         font.setFamily(toqstr(makeFontName(lyxrc.sans_font_name,
289                                                     lyxrc.sans_font_foundry)));
290                         break;
291                 case LyXFont::TYPEWRITER_FAMILY:
292                         font.setFamily(toqstr(makeFontName(lyxrc.typewriter_font_name,
293                                                     lyxrc.typewriter_font_foundry)));
294                         break;
295                 default:
296                         break;
297                 }
298         }
299
300         font.setPointSizeFloat(lyxrc.font_sizes[f.size()]
301                                * lyxrc.zoom / 100.0);
302
303         switch (f.series()) {
304                 case LyXFont::MEDIUM_SERIES:
305                         font.setWeight(QFont::Normal);
306                         break;
307                 case LyXFont::BOLD_SERIES:
308                         font.setWeight(QFont::Bold);
309                         break;
310                 default:
311                         break;
312         }
313
314         switch (f.realShape()) {
315                 case LyXFont::ITALIC_SHAPE:
316                 case LyXFont::SLANTED_SHAPE:
317                         font.setItalic(true);
318                         break;
319                 default:
320                         break;
321         }
322
323         if (lyxerr.debugging(Debug::FONT)) {
324                 lyxerr[Debug::FONT] << "Font '" << f.stateText(0)
325                         << "' matched by\n" << font.rawName() << endl;
326         }
327
328         lyxerr[Debug::FONT] << "The font has size: "
329                             << font.pointSizeFloat() << endl;
330
331         // Is this an exact match?
332         if (font.exactMatch()) {
333                 lyxerr[Debug::FONT] << "This font is an exact match" << endl;
334         } else {
335                 lyxerr[Debug::FONT] << "This font is NOT an exact match"
336                                     << endl;
337         }
338
339         lyxerr[Debug::FONT] << "XFLD: " << font.rawName() << endl;
340
341         metrics = QFontMetrics(font);
342 }
343
344
345 qfont_loader::font_info * qfont_loader::getfontinfo(LyXFont const & f)
346 {
347         if (!lyxrc.use_gui) {
348                 // FIXME
349         }
350
351         font_info * fi = fontinfo_[f.family()][f.series()][f.realShape()][f.size()];
352         if (fi)
353                 return fi;
354
355         font_info * fi2 = new font_info(f);
356         fontinfo_[f.family()][f.series()][f.realShape()][f.size()] = fi2;
357         return fi2;
358 }
359
360
361 int qfont_loader::charwidth(LyXFont const & f, Uchar val)
362 {
363         font_info * fi = getfontinfo(f);
364
365         font_info::WidthCache::const_iterator cit = fi->widthcache.find(val);
366         if (cit != fi->widthcache.end())
367                 return cit->second;
368
369         int const w = fi->metrics.width(QChar(val));
370         fi->widthcache[val] = w;
371         return w;
372 }
373
374
375 bool qfont_loader::available(LyXFont const & f)
376 {
377         if (!lyxrc.use_gui)
378                 return false;
379
380         return isAvailable(f);
381 }