]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/FontLoader.C
get rid of QT3_SUPPORT and some cleanup
[lyx.git] / src / frontends / qt4 / FontLoader.C
1 /**
2  * \file FontLoader.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 #include "FontLoader.h"
15 #include "qt_helpers.h"
16
17 #include "debug.h"
18 #include "lyxrc.h"
19
20 #include "frontends/lyx_gui.h"
21
22 #include "support/convert.h"
23 #include "support/filetools.h"
24 #include "support/lstrings.h"
25 #include "support/systemcall.h"
26
27 #include <qfontinfo.h>
28
29 #include <boost/tuple/tuple.hpp>
30
31 #ifdef Q_WS_X11
32 #include <qwidget.h>
33 #include <X11/Xlib.h>
34 #include <algorithm>
35 #endif
36
37 using lyx::support::contains;
38
39 using std::endl;
40 using std::make_pair;
41
42 using std::pair;
43 using std::vector;
44 using std::string;
45
46 #ifdef Q_WS_MACX
47 #include <ApplicationServices/ApplicationServices.h>
48 #endif
49
50 #ifdef Q_WS_WIN
51 #include "windows.h"
52 #include "support/os.h"
53 #include "support/package.h"
54 #include "support/path.h"
55 using lyx::support::addName;
56 using lyx::support::addPath;
57 using lyx::support::package;
58 namespace os = lyx::support::os;
59 string const win_fonts_truetype[] = {"cmex10", "cmmi10", "cmr10", "cmsy10",
60         "eufm10", "msam10", "msbm10", "wasy10"};
61 const int num_fonts_truetype = sizeof(win_fonts_truetype) / sizeof(*win_fonts_truetype);
62 #endif
63
64 void FontLoader::initFontPath()
65 {
66 #ifdef Q_WS_MACX
67         CFBundleRef  myAppBundle = CFBundleGetMainBundle();
68         CFURLRef  myAppResourcesURL, FontsURL;
69         FSRef  fontDirRef;
70         FSSpec  fontDirSpec;
71         CFStringRef  filePath = CFStringCreateWithBytes(kCFAllocatorDefault,
72                                         (UInt8 *) "Fonts", strlen("Fonts"),
73                                         kCFStringEncodingISOLatin1, false);
74
75         myAppResourcesURL = CFBundleCopyResourcesDirectoryURL(myAppBundle);
76         FontsURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault,
77                         myAppResourcesURL, filePath, true);
78         if (lyxerr.debugging(Debug::FONT)) {
79                 UInt8  buf[255];
80                 if (CFURLGetFileSystemRepresentation(FontsURL, true, buf, 255))
81                         lyxerr << "Adding Fonts directory: " << buf << endl;
82         }
83         CFURLGetFSRef (FontsURL, &fontDirRef);
84         OSStatus err = FSGetCatalogInfo (&fontDirRef, kFSCatInfoNone,
85                                          NULL, NULL, &fontDirSpec, NULL);
86         if (err)
87                 lyxerr << "FSGetCatalogInfo err = " << err << endl;
88         err = FMActivateFonts (&fontDirSpec, NULL, NULL,
89                                kFMLocalActivationContext);
90         if (err)
91                 lyxerr << "FMActivateFonts err = " << err << endl;
92 #endif
93
94 #ifdef Q_WS_WIN
95         // Windows only: Add BaKoMa TrueType font resources
96         string const fonts_dir = addPath(package().system_support(), "fonts");
97         
98         for (int i = 0 ; i < num_fonts_truetype ; ++i) {
99                 string const font_current = 
100                         addName(fonts_dir, win_fonts_truetype[i] + ".ttf");
101                 AddFontResource(os::external_path(font_current).c_str());
102         }
103 #endif
104 }
105
106 FontLoader::~FontLoader() {
107 #ifdef Q_WS_WIN
108         // Windows only: Remove BaKoMa TrueType font resources
109         string const fonts_dir = addPath(package().system_support(), "fonts");
110         
111         for(int i = 0 ; i < num_fonts_truetype ; ++i) {
112                 string const font_current = 
113                         addName(fonts_dir, win_fonts_truetype[i] + ".ttf");
114                 RemoveFontResource(os::external_path(font_current).c_str());
115         }
116 #endif
117 }
118
119 namespace {
120
121 struct symbol_font {
122         LyXFont::FONT_FAMILY lyx_family;
123         string family;
124         string xlfd;
125 };
126
127 symbol_font symbol_fonts[] = {
128         { LyXFont::SYMBOL_FAMILY,
129                 "symbol",
130                 "-*-symbol-*-*-*-*-*-*-*-*-*-*-adobe-fontspecific" },
131
132         { LyXFont::CMR_FAMILY,
133                 "cmr10",
134                 "-*-cmr10-medium-*-*-*-*-*-*-*-*-*-*-*" },
135
136         { LyXFont::CMSY_FAMILY,
137                 "cmsy10",
138                 "-*-cmsy10-*-*-*-*-*-*-*-*-*-*-*-*" },
139
140         { LyXFont::CMM_FAMILY,
141                 "cmmi10",
142                 "-*-cmmi10-medium-*-*-*-*-*-*-*-*-*-*-*" },
143
144         { LyXFont::CMEX_FAMILY,
145                 "cmex10",
146                 "-*-cmex10-*-*-*-*-*-*-*-*-*-*-*-*" },
147
148         { LyXFont::MSA_FAMILY,
149                 "msam10",
150                 "-*-msam10-*-*-*-*-*-*-*-*-*-*-*-*" },
151
152         { LyXFont::MSB_FAMILY,
153                 "msbm10",
154                 "-*-msbm10-*-*-*-*-*-*-*-*-*-*-*-*" },
155
156         { LyXFont::EUFRAK_FAMILY,
157                 "eufm10",
158                 "-*-eufm10-medium-*-*-*-*-*-*-*-*-*-*-*" },
159
160         { LyXFont::WASY_FAMILY,
161                 "wasy10",
162                 "-*-wasy10-medium-*-*-*-*-*-*-*-*-*-*-*" }
163 };
164
165 size_t const nr_symbol_fonts = sizeof(symbol_fonts) / sizeof(symbol_font);
166
167
168 string getRawName(string const & family)
169 {
170         for (size_t i = 0; i < nr_symbol_fonts; ++i)
171                 if (family == symbol_fonts[i].family)
172                         return symbol_fonts[i].xlfd;
173
174         lyxerr[Debug::FONT] << "BUG: family not found !" << endl;
175         return string();
176 }
177
178
179 string const symbolFamily(LyXFont::FONT_FAMILY family)
180 {
181         for (size_t i = 0; i < nr_symbol_fonts; ++i) {
182                 if (family == symbol_fonts[i].lyx_family)
183                         return symbol_fonts[i].family;
184         }
185         return string();
186 }
187
188
189 bool isSymbolFamily(LyXFont::FONT_FAMILY family)
190 {
191         return family >= LyXFont::SYMBOL_FAMILY &&
192                 family <= LyXFont::WASY_FAMILY;
193 }
194
195
196 bool isChosenFont(QFont & font, string const & family)
197 {
198         lyxerr[Debug::FONT] << "raw: " << fromqstr(font.rawName()) << endl;
199
200         QFontInfo fi(font);
201
202         // Note Qt lies about family quite often
203         lyxerr[Debug::FONT] << "alleged fi family: "
204                 << fromqstr(fi.family()) << endl;
205
206         // So we check rawName first
207         if (contains(fromqstr(font.rawName()), family)) {
208                 lyxerr[Debug::FONT] << " got it ";
209                 return true;
210         }
211
212         // Qt 3.2 beta1 returns "xft" for all xft fonts
213         // Qt 4.1 returns "Multi" for all ? xft fonts
214         if (font.rawName() == "xft" || font.rawName() == "Multi") {
215                 if (contains(fromqstr(fi.family()), family)) {
216                         lyxerr[Debug::FONT] << " got it (Xft) ";
217                         return true;
218                 }
219         }
220
221         return false;
222 }
223
224
225 pair<QFont, bool> const getSymbolFont(string const & family)
226 {
227         lyxerr[Debug::FONT] << "Looking for font family "
228                 << family << " ... ";
229         string upper = family;
230         upper[0] = toupper(family[0]);
231
232         QFont font;
233         font.setFamily(toqstr(family));
234
235         if (isChosenFont(font, family)) {
236                 lyxerr[Debug::FONT] << "normal!" << endl;
237                 return make_pair<QFont, bool>(font, true);
238         }
239
240         font.setFamily(toqstr(upper));
241
242         if (isChosenFont(font, upper)) {
243                 lyxerr[Debug::FONT] << "upper!" << endl;
244                 return make_pair<QFont, bool>(font, true);
245         }
246
247         // A simple setFamily() fails on Qt 2
248
249         font.setRawName(toqstr(getRawName(family)));
250
251         if (isChosenFont(font, family)) {
252                 lyxerr[Debug::FONT] << "raw version!" << endl;
253                 return make_pair<QFont, bool>(font, true);
254         }
255
256         lyxerr[Debug::FONT] << " FAILED :-(" << endl;
257         return make_pair<QFont, bool>(font, false);
258 }
259
260 } // namespace anon
261
262
263 FontLoader::FontLoader()
264 {
265         for (int i1 = 0; i1 < LyXFont::NUM_FAMILIES; ++i1)
266                 for (int i2 = 0; i2 < 2; ++i2)
267                         for (int i3 = 0; i3 < 4; ++i3)
268                                 for (int i4 = 0; i4 < 10; ++i4)
269                                         fontinfo_[i1][i2][i3][i4] = 0;
270 }
271
272
273 void FontLoader::update()
274 {
275         for (int i1 = 0; i1 < LyXFont::NUM_FAMILIES; ++i1)
276                 for (int i2 = 0; i2 < 2; ++i2)
277                         for (int i3 = 0; i3 < 4; ++i3)
278                                 for (int i4 = 0; i4 < 10; ++i4) {
279                                         delete fontinfo_[i1][i2][i3][i4];
280                                         fontinfo_[i1][i2][i3][i4] = 0;
281                                 }
282 }
283
284
285 /////////////////////////////////////////////////
286
287
288 QLFontInfo::QLFontInfo(LyXFont const & f)
289         : metrics(font)
290 {
291
292         string const pat = symbolFamily(f.family());
293         if (!pat.empty()) {
294                 bool tmp;
295                 boost::tie(font, tmp) = getSymbolFont(pat);
296         } else {
297                 switch (f.family()) {
298                 case LyXFont::ROMAN_FAMILY:
299                         font.setFamily(toqstr(makeFontName(lyxrc.roman_font_name,
300                                                     lyxrc.roman_font_foundry)));
301                         break;
302                 case LyXFont::SANS_FAMILY:
303                         font.setFamily(toqstr(makeFontName(lyxrc.sans_font_name,
304                                                     lyxrc.sans_font_foundry)));
305                         break;
306                 case LyXFont::TYPEWRITER_FAMILY:
307                         font.setFamily(toqstr(makeFontName(lyxrc.typewriter_font_name,
308                                                     lyxrc.typewriter_font_foundry)));
309                         break;
310                 default:
311                         break;
312                 }
313         }
314
315         font.setPointSizeF(convert<double>(lyxrc.font_sizes[f.size()])
316                                * lyxrc.zoom / 100.0);
317
318         switch (f.series()) {
319                 case LyXFont::MEDIUM_SERIES:
320                         font.setWeight(QFont::Normal);
321                         break;
322                 case LyXFont::BOLD_SERIES:
323                         font.setWeight(QFont::Bold);
324                         break;
325                 default:
326                         break;
327         }
328
329         switch (f.realShape()) {
330                 case LyXFont::ITALIC_SHAPE:
331                 case LyXFont::SLANTED_SHAPE:
332                         font.setItalic(true);
333                         break;
334                 default:
335                         break;
336         }
337
338         if (lyxerr.debugging(Debug::FONT)) {
339                 lyxerr[Debug::FONT] << "Font '" << f.stateText(0)
340                         << "' matched by\n" << fromqstr(font.rawName()) << endl;
341         }
342
343         lyxerr[Debug::FONT] << "The font has size: "
344                             << font.pointSizeF() << endl;
345
346         // Is this an exact match?
347         if (font.exactMatch())
348                 lyxerr[Debug::FONT] << "This font is an exact match" << endl;
349         else
350                 lyxerr[Debug::FONT] << "This font is NOT an exact match"
351                                     << endl;
352
353         lyxerr[Debug::FONT] << "XFLD: " << fromqstr(font.rawName()) << endl;
354
355         metrics = QFontMetrics(font);
356 }
357
358
359 int QLFontInfo::width(Uchar val)
360 {
361 // Starting with version 3.1.0, Qt/X11 does its own caching of
362 // character width, so it is not necessary to provide ours.
363 #if defined (USE_LYX_FONTCACHE)
364         QLFontInfo::WidthCache::const_iterator cit = widthcache.find(val);
365         if (cit != widthcache.end())
366                 return cit->second;
367
368         int const w = metrics.width(QChar(val));
369         widthcache[val] = w;
370         return w;
371 #else
372         return metrics.width(QChar(val));
373 #endif
374 }
375
376
377 bool FontLoader::available(LyXFont const & f)
378 {
379         if (!lyx_gui::use_gui)
380                 return false;
381
382         static vector<int> cache_set(LyXFont::NUM_FAMILIES, false);
383         static vector<int> cache(LyXFont::NUM_FAMILIES, false);
384
385         LyXFont::FONT_FAMILY family = f.family();
386         if (cache_set[family])
387                 return cache[family];
388         cache_set[family] = true;
389
390         string const pat = symbolFamily(family);
391         if (pat.empty())
392                 // We don't care about non-symbol fonts
393                 return false;
394
395         pair<QFont, bool> tmp = getSymbolFont(pat);
396         if (!tmp.second)
397                 return false;
398
399         cache[family] = true;
400         return true;
401 }