1 /* Written by Krzysztof Kowalczyk (http://blog.kowalczyk.info)
2 but mostly based on xpdf code.
3
4 // Copyright (C) 2010 Hib Eris <hib@hiberis.nl>
5
6 TODO: instead of a fixed mapping defined in displayFontTab, it could
7 scan the whole fonts directory, parse TTF files and build font
8 description for all fonts available in Windows. That's how MuPDF works.
9 */
10
11 #ifndef PACKAGE_NAME
12 #include <config.h>
13 #endif
14
15 #ifdef USE_GCC_PRAGMAS
16 #pragma implementation
17 #endif
18
19 #include <windows.h>
20 #if !(_WIN32_IE >= 0x0500)
21 #error "_WIN32_IE must be defined >= 0x0500 for SHGFP_TYPE_CURRENT from shlobj.h"
22 #endif
23 #include <shlobj.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include <ctype.h>
27 #include <assert.h>
28
29 #include "goo/gmem.h"
30 #include "goo/GooString.h"
31 #include "goo/GooList.h"
32 #include "goo/GooHash.h"
33 #include "goo/gfile.h"
34 #include "Error.h"
35 #include "NameToCharCode.h"
36 #include "CharCodeToUnicode.h"
37 #include "UnicodeMap.h"
38 #include "CMap.h"
39 #include "BuiltinFontTables.h"
40 #include "FontEncodingTables.h"
41 #include "GlobalParams.h"
42 #include "GfxFont.h"
43
44 #if MULTITHREADED
45 # define lockGlobalParams gLockMutex(&mutex)
46 # define lockUnicodeMapCache gLockMutex(&unicodeMapCacheMutex)
47 # define lockCMapCache gLockMutex(&cMapCacheMutex)
48 # define unlockGlobalParams gUnlockMutex(&mutex)
49 # define unlockUnicodeMapCache gUnlockMutex(&unicodeMapCacheMutex)
50 # define unlockCMapCache gUnlockMutex(&cMapCacheMutex)
51 #else
52 # define lockGlobalParams
53 # define lockUnicodeMapCache
54 # define lockCMapCache
55 # define unlockGlobalParams
56 # define unlockUnicodeMapCache
57 # define unlockCMapCache
58 #endif
59
60 #define DEFAULT_SUBSTITUTE_FONT "Helvetica"
61
62 static struct {
63 char *name;
64 char *t1FileName;
65 char *ttFileName;
66 } displayFontTab[] = {
67 {"Courier", "n022003l.pfb", "cour.ttf"},
68 {"Courier-Bold", "n022004l.pfb", "courbd.ttf"},
69 {"Courier-BoldOblique", "n022024l.pfb", "courbi.ttf"},
70 {"Courier-Oblique", "n022023l.pfb", "couri.ttf"},
71 {"Helvetica", "n019003l.pfb", "arial.ttf"},
72 {"Helvetica-Bold", "n019004l.pfb", "arialbd.ttf"},
73 {"Helvetica-BoldOblique", "n019024l.pfb", "arialbi.ttf"},
74 {"Helvetica-Oblique", "n019023l.pfb", "ariali.ttf"},
75 // TODO: not sure if "symbol.ttf" is right
76 {"Symbol", "s050000l.pfb", "symbol.ttf"},
77 {"Times-Bold", "n021004l.pfb", "timesbd.ttf"},
78 {"Times-BoldItalic", "n021024l.pfb", "timesbi.ttf"},
79 {"Times-Italic", "n021023l.pfb", "timesi.ttf"},
80 {"Times-Roman", "n021003l.pfb", "times.ttf"},
81 // TODO: not sure if "wingding.ttf" is right
82 {"ZapfDingbats", "d050000l.pfb", "wingding.ttf"},
83
84 // those seem to be frequently accessed by PDF files and I kind of guess
85 // which font file do the refer to
86 {"Palatino", NULL, "pala.ttf"},
87 {"Palatino-Roman", NULL, "pala.ttf"},
88 {"Palatino-Bold", NULL, "palab.ttf"},
89 {"Palatino-Italic", NULL, "palai.ttf"},
90 {"Palatino,Italic", NULL, "palai.ttf"},
91 {"Palatino-BoldItalic", NULL, "palabi.ttf"},
92
93 {"ArialBlack", NULL, "arialbd.ttf"},
94
95 {"ArialNarrow", NULL, "arialn.ttf"},
96 {"ArialNarrow,Bold", NULL, "arialnb.ttf"},
97 {"ArialNarrow,Italic", NULL, "arialni.ttf"},
98 {"ArialNarrow,BoldItalic", NULL, "arialnbi.ttf"},
99 {"ArialNarrow-Bold", NULL, "arialnb.ttf"},
100 {"ArialNarrow-Italic", NULL, "arialni.ttf"},
101 {"ArialNarrow-BoldItalic", NULL, "arialnbi.ttf"},
102
103 {"HelveticaNarrow", NULL, "arialn.ttf"},
104 {"HelveticaNarrow,Bold", NULL, "arialnb.ttf"},
105 {"HelveticaNarrow,Italic", NULL, "arialni.ttf"},
106 {"HelveticaNarrow,BoldItalic", NULL, "arialnbi.ttf"},
107 {"HelveticaNarrow-Bold", NULL, "arialnb.ttf"},
108 {"HelveticaNarrow-Italic", NULL, "arialni.ttf"},
109 {"HelveticaNarrow-BoldItalic", NULL, "arialnbi.ttf"},
110
111 {"BookAntiqua", NULL, "bkant.ttf"},
112 {"BookAntiqua,Bold", NULL, "bkant.ttf"},
113 {"BookAntiqua,Italic", NULL, "bkant.ttf"},
114 {"BookAntiqua,BoldItalic", NULL, "bkant.ttf"},
115 {"BookAntiqua-Bold", NULL, "bkant.ttf"},
116 {"BookAntiqua-Italic", NULL, "bkant.ttf"},
117 {"BookAntiqua-BoldItalic", NULL, "bkant.ttf"},
118
119 {"Verdana", NULL, "verdana.ttf"},
120 {"Verdana,Bold", NULL, "verdanab.ttf"},
121 {"Verdana,Italic", NULL, "verdanai.ttf"},
122 {"Verdana,BoldItalic", NULL, "verdanaz.ttf"},
123 {"Verdana-Bold", NULL, "verdanab.ttf"},
124 {"Verdana-Italic", NULL, "verdanai.ttf"},
125 {"Verdana-BoldItalic", NULL, "verdanaz.ttf"},
126
127 {"Tahoma", NULL, "tahoma.ttf"},
128 {"Tahoma,Bold", NULL, "tahomabd.ttf"},
129 {"Tahoma,Italic", NULL, "tahoma.ttf"},
130 {"Tahoma,BoldItalic", NULL, "tahomabd.ttf"},
131 {"Tahoma-Bold", NULL, "tahomabd.ttf"},
132 {"Tahoma-Italic", NULL, "tahoma.ttf"},
133 {"Tahoma-BoldItalic", NULL, "tahomabd.ttf"},
134
135 {"CCRIKH+Verdana", NULL, "verdana.ttf"},
136 {"CCRIKH+Verdana,Bold", NULL, "verdanab.ttf"},
137 {"CCRIKH+Verdana,Italic", NULL, "verdanai.ttf"},
138 {"CCRIKH+Verdana,BoldItalic", NULL, "verdanaz.ttf"},
139 {"CCRIKH+Verdana-Bold", NULL, "verdanab.ttf"},
140 {"CCRIKH+Verdana-Italic", NULL, "verdanai.ttf"},
141 {"CCRIKH+Verdana-BoldItalic", NULL, "verdanaz.ttf"},
142
143 {"Georgia", NULL, "georgia.ttf"},
144 {"Georgia,Bold", NULL, "georgiab.ttf"},
145 {"Georgia,Italic", NULL, "georgiai.ttf"},
146 {"Georgia,BoldItalic", NULL, "georgiaz.ttf"},
147 {"Georgia-Bold", NULL, "georgiab.ttf"},
148 {"Georgia-Italic", NULL, "georgiai.ttf"},
149 {"Georgia-BoldItalic", NULL, "georgiaz.ttf"},
150
151 {NULL}
152 };
153
154 #define FONTS_SUBDIR "\\fonts"
155
GetWindowsFontDir(char * winFontDir,int cbWinFontDirLen)156 static void GetWindowsFontDir(char *winFontDir, int cbWinFontDirLen)
157 {
158 BOOL (__stdcall *SHGetSpecialFolderPathFunc)(HWND hwndOwner,
159 LPTSTR lpszPath,
160 int nFolder,
161 BOOL fCreate);
162 HRESULT (__stdcall *SHGetFolderPathFunc)(HWND hwndOwner,
163 int nFolder,
164 HANDLE hToken,
165 DWORD dwFlags,
166 LPTSTR pszPath);
167
168 // SHGetSpecialFolderPath isn't available in older versions of shell32.dll (Win95 and
169 // WinNT4), so do a dynamic load of ANSI versions.
170 winFontDir[0] = '\0';
171
172 HMODULE hLib = LoadLibrary("shell32.dll");
173 if (hLib) {
174 SHGetFolderPathFunc = (HRESULT (__stdcall *)(HWND, int, HANDLE, DWORD, LPTSTR))
175 GetProcAddress(hLib, "SHGetFolderPathA");
176 if (SHGetFolderPathFunc)
177 (*SHGetFolderPathFunc)(NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT, winFontDir);
178
179 if (!winFontDir[0]) {
180 // Try an older function
181 SHGetSpecialFolderPathFunc = (BOOL (__stdcall *)(HWND, LPTSTR, int, BOOL))
182 GetProcAddress(hLib, "SHGetSpecialFolderPathA");
183 if (SHGetSpecialFolderPathFunc)
184 (*SHGetSpecialFolderPathFunc)(NULL, winFontDir, CSIDL_FONTS, FALSE);
185 }
186 FreeLibrary(hLib);
187 }
188 if (winFontDir[0])
189 return;
190
191 // Try older DLL
192 hLib = LoadLibrary("SHFolder.dll");
193 if (hLib) {
194 SHGetFolderPathFunc = (HRESULT (__stdcall *)(HWND, int, HANDLE, DWORD, LPTSTR))
195 GetProcAddress(hLib, "SHGetFolderPathA");
196 if (SHGetFolderPathFunc)
197 (*SHGetFolderPathFunc)(NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT, winFontDir);
198 FreeLibrary(hLib);
199 }
200 if (winFontDir[0])
201 return;
202
203 // Everything else failed so the standard fonts directory.
204 GetWindowsDirectory(winFontDir, cbWinFontDirLen);
205 if (winFontDir[0]) {
206 strncat(winFontDir, FONTS_SUBDIR, cbWinFontDirLen);
207 winFontDir[cbWinFontDirLen-1] = 0;
208 }
209 }
210
FileExists(const char * path)211 static bool FileExists(const char *path)
212 {
213 FILE * f = fopen(path, "rb");
214 if (f) {
215 fclose(f);
216 return true;
217 }
218 return false;
219 }
220
AddFont(GooHash * displayFonts,char * fontName,GooString * fontPath,DisplayFontParamKind kind)221 static void AddFont(GooHash *displayFonts, char *fontName, GooString *fontPath, DisplayFontParamKind kind)
222 {
223 DisplayFontParam *dfp = new DisplayFontParam(new GooString(fontName), kind);
224 dfp->setFileName(fontPath);
225 displayFonts->add(dfp->name, dfp);
226 }
227
setupBaseFonts(char * dir)228 void GlobalParams::setupBaseFonts(char * dir)
229 {
230 if (baseFontsInitialized)
231 return;
232 baseFontsInitialized = true;
233
234 char winFontDir[MAX_PATH];
235 GetWindowsFontDir(winFontDir, sizeof(winFontDir));
236
237 for (int i = 0; displayFontTab[i].name; ++i) {
238 char *fontName = displayFontTab[i].name;
239 if (displayFonts->lookup(fontName))
240 continue;
241
242 if (dir) {
243 GooString *fontPath = appendToPath(new GooString(dir), displayFontTab[i].t1FileName);
244 if (FileExists(fontPath->getCString())) {
245 AddFont(displayFonts, fontName, fontPath, displayFontT1);
246 continue;
247 }
248 delete fontPath;
249 }
250
251 if (winFontDir[0] && displayFontTab[i].ttFileName) {
252 GooString *fontPath = appendToPath(new GooString(winFontDir), displayFontTab[i].ttFileName);
253 if (FileExists(fontPath->getCString())) {
254 AddFont(displayFonts, fontName, fontPath, displayFontTT);
255 continue;
256 }
257 delete fontPath;
258 }
259
260 error(-1, "No display font for '%s'", fontName);
261 }
262 }
263
findSubstituteName(const char * origName)264 static char *findSubstituteName(const char *origName)
265 {
266 assert(origName);
267 if (!origName) return NULL;
268 /* TODO: try to at least guess bold/italic/bolditalic from the name */
269 return DEFAULT_SUBSTITUTE_FONT;
270 }
271
272 /* Windows implementation of external font matching code */
getDisplayFont(GfxFont * font)273 DisplayFontParam *GlobalParams::getDisplayFont(GfxFont *font) {
274 DisplayFontParam * dfp;
275 GooString * fontName = font->getName();
276 char * substFontName = NULL;
277
278 if (!fontName) return NULL;
279 lockGlobalParams;
280 setupBaseFonts(NULL);
281 dfp = (DisplayFontParam *)displayFonts->lookup(fontName);
282 if (!dfp) {
283 substFontName = findSubstituteName(fontName->getCString());
284 error(-1, "Couldn't find a font for '%s', subst is '%s'", fontName->getCString(), substFontName);
285 dfp = (DisplayFontParam *)displayFonts->lookup(substFontName);
286 assert(dfp);
287 }
288 unlockGlobalParams;
289 return dfp;
290 }
291
292