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