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