3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Asger Alstrup
9 * Full author contact details are available in file CREDITS.
14 #include "FontLoader.h"
15 #include "qt_helpers.h"
20 #include "frontends/lyx_gui.h"
22 #include "support/convert.h"
23 #include "support/filetools.h"
24 #include "support/lstrings.h"
25 #include "support/systemcall.h"
27 #include <qfontinfo.h>
29 #include <boost/tuple/tuple.hpp>
37 using lyx::support::contains;
47 #include <ApplicationServices/ApplicationServices.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);
64 void FontLoader::initFontPath()
67 CFBundleRef myAppBundle = CFBundleGetMainBundle();
68 CFURLRef myAppResourcesURL, FontsURL;
71 CFStringRef filePath = CFStringCreateWithBytes(kCFAllocatorDefault,
72 (UInt8 *) "Fonts", strlen("Fonts"),
73 kCFStringEncodingISOLatin1, false);
75 myAppResourcesURL = CFBundleCopyResourcesDirectoryURL(myAppBundle);
76 FontsURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault,
77 myAppResourcesURL, filePath, true);
78 if (lyxerr.debugging(Debug::FONT)) {
80 if (CFURLGetFileSystemRepresentation(FontsURL, true, buf, 255))
81 lyxerr << "Adding Fonts directory: " << buf << endl;
83 CFURLGetFSRef (FontsURL, &fontDirRef);
84 OSStatus err = FSGetCatalogInfo (&fontDirRef, kFSCatInfoNone,
85 NULL, NULL, &fontDirSpec, NULL);
87 lyxerr << "FSGetCatalogInfo err = " << err << endl;
88 err = FMActivateFonts (&fontDirSpec, NULL, NULL,
89 kFMLocalActivationContext);
91 lyxerr << "FMActivateFonts err = " << err << endl;
95 // Windows only: Add BaKoMa TrueType font resources
96 string const fonts_dir = addPath(package().system_support(), "fonts");
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());
106 FontLoader::~FontLoader() {
108 // Windows only: Remove BaKoMa TrueType font resources
109 string const fonts_dir = addPath(package().system_support(), "fonts");
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());
122 LyXFont::FONT_FAMILY lyx_family;
127 symbol_font symbol_fonts[] = {
128 { LyXFont::SYMBOL_FAMILY,
130 "-*-symbol-*-*-*-*-*-*-*-*-*-*-adobe-fontspecific" },
132 { LyXFont::CMR_FAMILY,
134 "-*-cmr10-medium-*-*-*-*-*-*-*-*-*-*-*" },
136 { LyXFont::CMSY_FAMILY,
138 "-*-cmsy10-*-*-*-*-*-*-*-*-*-*-*-*" },
140 { LyXFont::CMM_FAMILY,
142 "-*-cmmi10-medium-*-*-*-*-*-*-*-*-*-*-*" },
144 { LyXFont::CMEX_FAMILY,
146 "-*-cmex10-*-*-*-*-*-*-*-*-*-*-*-*" },
148 { LyXFont::MSA_FAMILY,
150 "-*-msam10-*-*-*-*-*-*-*-*-*-*-*-*" },
152 { LyXFont::MSB_FAMILY,
154 "-*-msbm10-*-*-*-*-*-*-*-*-*-*-*-*" },
156 { LyXFont::EUFRAK_FAMILY,
158 "-*-eufm10-medium-*-*-*-*-*-*-*-*-*-*-*" },
160 { LyXFont::WASY_FAMILY,
162 "-*-wasy10-medium-*-*-*-*-*-*-*-*-*-*-*" }
165 size_t const nr_symbol_fonts = sizeof(symbol_fonts) / sizeof(symbol_font);
168 string getRawName(string const & family)
170 for (size_t i = 0; i < nr_symbol_fonts; ++i)
171 if (family == symbol_fonts[i].family)
172 return symbol_fonts[i].xlfd;
174 lyxerr[Debug::FONT] << "BUG: family not found !" << endl;
179 string const symbolFamily(LyXFont::FONT_FAMILY family)
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;
189 bool isSymbolFamily(LyXFont::FONT_FAMILY family)
191 return family >= LyXFont::SYMBOL_FAMILY &&
192 family <= LyXFont::WASY_FAMILY;
196 bool isChosenFont(QFont & font, string const & family)
198 lyxerr[Debug::FONT] << "raw: " << fromqstr(font.rawName()) << endl;
202 // Note Qt lies about family quite often
203 lyxerr[Debug::FONT] << "alleged fi family: "
204 << fromqstr(fi.family()) << endl;
206 // So we check rawName first
207 if (contains(fromqstr(font.rawName()), family)) {
208 lyxerr[Debug::FONT] << " got it ";
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) ";
225 pair<QFont, bool> const getSymbolFont(string const & family)
227 lyxerr[Debug::FONT] << "Looking for font family "
228 << family << " ... ";
229 string upper = family;
230 upper[0] = toupper(family[0]);
233 font.setFamily(toqstr(family));
235 if (isChosenFont(font, family)) {
236 lyxerr[Debug::FONT] << "normal!" << endl;
237 return make_pair<QFont, bool>(font, true);
240 font.setFamily(toqstr(upper));
242 if (isChosenFont(font, upper)) {
243 lyxerr[Debug::FONT] << "upper!" << endl;
244 return make_pair<QFont, bool>(font, true);
247 // A simple setFamily() fails on Qt 2
249 font.setRawName(toqstr(getRawName(family)));
251 if (isChosenFont(font, family)) {
252 lyxerr[Debug::FONT] << "raw version!" << endl;
253 return make_pair<QFont, bool>(font, true);
256 lyxerr[Debug::FONT] << " FAILED :-(" << endl;
257 return make_pair<QFont, bool>(font, false);
263 FontLoader::FontLoader()
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;
273 void FontLoader::update()
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;
285 /////////////////////////////////////////////////
288 QLFontInfo::QLFontInfo(LyXFont const & f)
292 string const pat = symbolFamily(f.family());
295 boost::tie(font, tmp) = getSymbolFont(pat);
297 switch (f.family()) {
298 case LyXFont::ROMAN_FAMILY:
299 font.setFamily(toqstr(makeFontName(lyxrc.roman_font_name,
300 lyxrc.roman_font_foundry)));
302 case LyXFont::SANS_FAMILY:
303 font.setFamily(toqstr(makeFontName(lyxrc.sans_font_name,
304 lyxrc.sans_font_foundry)));
306 case LyXFont::TYPEWRITER_FAMILY:
307 font.setFamily(toqstr(makeFontName(lyxrc.typewriter_font_name,
308 lyxrc.typewriter_font_foundry)));
315 font.setPointSizeFloat(convert<double>(lyxrc.font_sizes[f.size()])
316 * lyxrc.zoom / 100.0);
318 switch (f.series()) {
319 case LyXFont::MEDIUM_SERIES:
320 font.setWeight(QFont::Normal);
322 case LyXFont::BOLD_SERIES:
323 font.setWeight(QFont::Bold);
329 switch (f.realShape()) {
330 case LyXFont::ITALIC_SHAPE:
331 case LyXFont::SLANTED_SHAPE:
332 font.setItalic(true);
338 if (lyxerr.debugging(Debug::FONT)) {
339 lyxerr[Debug::FONT] << "Font '" << f.stateText(0)
340 << "' matched by\n" << (const char *) font.rawName() << endl;
343 lyxerr[Debug::FONT] << "The font has size: "
344 << font.pointSizeFloat() << endl;
346 // Is this an exact match?
347 if (font.exactMatch())
348 lyxerr[Debug::FONT] << "This font is an exact match" << endl;
350 lyxerr[Debug::FONT] << "This font is NOT an exact match"
353 lyxerr[Debug::FONT] << "XFLD: " << (const char *) font.rawName() << endl;
355 metrics = QFontMetrics(font);
359 int QLFontInfo::width(Uchar val)
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())
368 int const w = metrics.width(QChar(val));
372 return metrics.width(QChar(val));
377 bool FontLoader::available(LyXFont const & f)
379 if (!lyx_gui::use_gui)
382 static vector<int> cache_set(LyXFont::NUM_FAMILIES, false);
383 static vector<int> cache(LyXFont::NUM_FAMILIES, false);
385 LyXFont::FONT_FAMILY family = f.family();
386 if (cache_set[family])
387 return cache[family];
388 cache_set[family] = true;
390 string const pat = symbolFamily(family);
392 // We don't care about non-symbol fonts
395 pair<QFont, bool> tmp = getSymbolFont(pat);
399 cache[family] = true;