GlobalParamsWin.cc 20.2 KB
Newer Older
1 2
/* Written by Krzysztof Kowalczyk (http://blog.kowalczyk.info)
   but mostly based on xpdf code.
3
   
4
   // Copyright (C) 2010, 2012 Hib Eris <hib@hiberis.nl>
Thomas Freitag's avatar
Thomas Freitag committed
5
   // Copyright (C) 2012, 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
suzuki toshiya's avatar
suzuki toshiya committed
6
   // Copyright (C) 2012 Suzuki Toshiya <mpsuzuki@hiroshima-u.ac.jp>
7
   // Copyright (C) 2012, 2017 Adrian Johnson <ajohnson@redneon.com>
Mark Brand's avatar
Mark Brand committed
8
   // Copyright (C) 2012 Mark Brand <mabrand@mabrand.nl>
9
   // Copyright (C) 2013, 2018 Adam Reichold <adamreichold@myopera.com>
Dmytro Morgun's avatar
Dmytro Morgun committed
10
   // Copyright (C) 2013 Dmytro Morgun <lztoad@gmail.com>
Albert Astals Cid's avatar
Albert Astals Cid committed
11
   // Copyright (C) 2017 Christoph Cullmann <cullmann@kde.org>
12
   // Copyright (C) 2017, 2018 Albert Astals Cid <aacid@kde.org>
Albert Astals Cid's avatar
Albert Astals Cid committed
13
   // Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, <info@kdab.com>. Work sponsored by the LiMux project of the city of Munich
14 15 16 17 18 19

TODO: instead of a fixed mapping defined in displayFontTab, it could
scan the whole fonts directory, parse TTF files and build font
description for all fonts available in Windows. That's how MuPDF works.
*/

20
#ifndef PACKAGE_NAME
21
#include <config.h>
22
#endif
23 24 25 26 27 28

#ifdef USE_GCC_PRAGMAS
#pragma implementation
#endif

#include <windows.h>
29 30 31
#if !(_WIN32_IE >= 0x0500)
#error "_WIN32_IE must be defined >= 0x0500 for SHGFP_TYPE_CURRENT from shlobj.h"
#endif
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
#include <shlobj.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <assert.h>

#include "goo/gmem.h"
#include "goo/GooString.h"
#include "goo/GooList.h"
#include "goo/gfile.h"
#include "Error.h"
#include "NameToCharCode.h"
#include "CharCodeToUnicode.h"
#include "UnicodeMap.h"
#include "CMap.h"
#include "BuiltinFontTables.h"
#include "FontEncodingTables.h"
#include "GlobalParams.h"
#include "GfxFont.h"
51 52 53 54 55
#include <sys/stat.h>
#include "Object.h"
#include "Stream.h"
#include "Lexer.h"
#include "Parser.h"
56

57
#ifdef MULTITHREADED
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
#  define lockGlobalParams            gLockMutex(&mutex)
#  define lockUnicodeMapCache         gLockMutex(&unicodeMapCacheMutex)
#  define lockCMapCache               gLockMutex(&cMapCacheMutex)
#  define unlockGlobalParams          gUnlockMutex(&mutex)
#  define unlockUnicodeMapCache       gUnlockMutex(&unicodeMapCacheMutex)
#  define unlockCMapCache             gUnlockMutex(&cMapCacheMutex)
#else
#  define lockGlobalParams
#  define lockUnicodeMapCache
#  define lockCMapCache
#  define unlockGlobalParams
#  define unlockUnicodeMapCache
#  define unlockCMapCache
#endif

#define DEFAULT_SUBSTITUTE_FONT "Helvetica"
74 75 76 77 78 79
#define DEFAULT_CID_FONT_AC1_MSWIN "MingLiU"   /* Adobe-CNS1 for Taiwan, HongKong */
#define DEFAULT_CID_FONT_AG1_MSWIN "SimSun"    /* Adobe-GB1 for PRC, Singapore */
#define DEFAULT_CID_FONT_AJ1_MSWIN "MS-Mincho" /* Adobe-Japan1 */
#define DEFAULT_CID_FONT_AJ2_MSWIN "MS-Mincho" /* Adobe-Japan2 (legacy) */
#define DEFAULT_CID_FONT_AK1_MSWIN "Batang"    /* Adobe-Korea1 */
#define DEFAULT_CID_FONT_MSWIN "ArialUnicode"  /* Unknown */
80

81
static const struct {
82 83 84
    const char *name;
    const char *t1FileName;
    const char *ttFileName;
85
    GBool warnIfMissing;
86
} displayFontTab[] = {
87 88 89 90 91 92 93 94
    {"Courier",               "n022003l.pfb", "cour.ttf", gTrue},
    {"Courier-Bold",          "n022004l.pfb", "courbd.ttf", gTrue},
    {"Courier-BoldOblique",   "n022024l.pfb", "courbi.ttf", gTrue},
    {"Courier-Oblique",       "n022023l.pfb", "couri.ttf", gTrue},
    {"Helvetica",             "n019003l.pfb", "arial.ttf", gTrue},
    {"Helvetica-Bold",        "n019004l.pfb", "arialbd.ttf", gTrue},
    {"Helvetica-BoldOblique", "n019024l.pfb", "arialbi.ttf", gTrue},
    {"Helvetica-Oblique",     "n019023l.pfb", "ariali.ttf", gTrue},
95
    // TODO: not sure if "symbol.ttf" is right
96 97 98 99 100
    {"Symbol",                "s050000l.pfb", "symbol.ttf", gTrue},
    {"Times-Bold",            "n021004l.pfb", "timesbd.ttf", gTrue},
    {"Times-BoldItalic",      "n021024l.pfb", "timesbi.ttf", gTrue},
    {"Times-Italic",          "n021023l.pfb", "timesi.ttf", gTrue},
    {"Times-Roman",           "n021003l.pfb", "times.ttf", gTrue},
101
    // TODO: not sure if "wingding.ttf" is right
102
    {"ZapfDingbats",          "d050000l.pfb", "wingding.ttf", gTrue},
103 104 105

    // those seem to be frequently accessed by PDF files and I kind of guess
    // which font file do the refer to
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
    {"Palatino", nullptr, "pala.ttf", gTrue},
    {"Palatino-Roman", nullptr, "pala.ttf", gTrue},
    {"Palatino-Bold", nullptr, "palab.ttf", gTrue},
    {"Palatino-Italic", nullptr, "palai.ttf", gTrue},
    {"Palatino,Italic", nullptr, "palai.ttf", gTrue},
    {"Palatino-BoldItalic", nullptr, "palabi.ttf", gTrue},

    {"ArialBlack",        nullptr, "arialbd.ttf", gTrue},

    {"ArialNarrow", nullptr, "arialn.ttf", gTrue},
    {"ArialNarrow,Bold", nullptr, "arialnb.ttf", gTrue},
    {"ArialNarrow,Italic", nullptr, "arialni.ttf", gTrue},
    {"ArialNarrow,BoldItalic", nullptr, "arialnbi.ttf", gTrue},
    {"ArialNarrow-Bold", nullptr, "arialnb.ttf", gTrue},
    {"ArialNarrow-Italic", nullptr, "arialni.ttf", gTrue},
    {"ArialNarrow-BoldItalic", nullptr, "arialnbi.ttf", gTrue},

    {"HelveticaNarrow", nullptr, "arialn.ttf", gTrue},
    {"HelveticaNarrow,Bold", nullptr, "arialnb.ttf", gTrue},
    {"HelveticaNarrow,Italic", nullptr, "arialni.ttf", gTrue},
    {"HelveticaNarrow,BoldItalic", nullptr, "arialnbi.ttf", gTrue},
    {"HelveticaNarrow-Bold", nullptr, "arialnb.ttf", gTrue},
    {"HelveticaNarrow-Italic", nullptr, "arialni.ttf", gTrue},
    {"HelveticaNarrow-BoldItalic", nullptr, "arialnbi.ttf", gTrue},

    {"BookAntiqua", nullptr, "bkant.ttf", gTrue},
    {"BookAntiqua,Bold", nullptr, "bkant.ttf", gTrue},
    {"BookAntiqua,Italic", nullptr, "bkant.ttf", gTrue},
    {"BookAntiqua,BoldItalic", nullptr, "bkant.ttf", gTrue},
    {"BookAntiqua-Bold", nullptr, "bkant.ttf", gTrue},
    {"BookAntiqua-Italic", nullptr, "bkant.ttf", gTrue},
    {"BookAntiqua-BoldItalic", nullptr, "bkant.ttf", gTrue},

    {"Verdana", nullptr, "verdana.ttf", gTrue},
    {"Verdana,Bold", nullptr, "verdanab.ttf", gTrue},
    {"Verdana,Italic", nullptr, "verdanai.ttf", gTrue},
    {"Verdana,BoldItalic", nullptr, "verdanaz.ttf", gTrue},
    {"Verdana-Bold", nullptr, "verdanab.ttf", gTrue},
    {"Verdana-Italic", nullptr, "verdanai.ttf", gTrue},
    {"Verdana-BoldItalic", nullptr, "verdanaz.ttf", gTrue},

    {"Tahoma", nullptr, "tahoma.ttf", gTrue},
    {"Tahoma,Bold", nullptr, "tahomabd.ttf", gTrue},
    {"Tahoma,Italic", nullptr, "tahoma.ttf", gTrue},
    {"Tahoma,BoldItalic", nullptr, "tahomabd.ttf", gTrue},
    {"Tahoma-Bold", nullptr, "tahomabd.ttf", gTrue},
    {"Tahoma-Italic", nullptr, "tahoma.ttf", gTrue},
    {"Tahoma-BoldItalic", nullptr, "tahomabd.ttf", gTrue},

    {"CCRIKH+Verdana", nullptr, "verdana.ttf", gTrue},
    {"CCRIKH+Verdana,Bold", nullptr, "verdanab.ttf", gTrue},
    {"CCRIKH+Verdana,Italic", nullptr, "verdanai.ttf", gTrue},
    {"CCRIKH+Verdana,BoldItalic", nullptr, "verdanaz.ttf", gTrue},
    {"CCRIKH+Verdana-Bold", nullptr, "verdanab.ttf", gTrue},
    {"CCRIKH+Verdana-Italic", nullptr, "verdanai.ttf", gTrue},
    {"CCRIKH+Verdana-BoldItalic", nullptr, "verdanaz.ttf", gTrue},

    {"Georgia", nullptr, "georgia.ttf", gTrue},
    {"Georgia,Bold", nullptr, "georgiab.ttf", gTrue},
    {"Georgia,Italic", nullptr, "georgiai.ttf", gTrue},
    {"Georgia,BoldItalic", nullptr, "georgiaz.ttf", gTrue},
    {"Georgia-Bold", nullptr, "georgiab.ttf", gTrue},
    {"Georgia-Italic", nullptr, "georgiai.ttf", gTrue},
    {"Georgia-BoldItalic", nullptr, "georgiaz.ttf", gTrue},
170 171

    // fallback for Adobe CID fonts:
172 173 174 175 176
    {"MingLiU", nullptr, "mingliu.ttf", gFalse},
    {"SimSun", nullptr, "simsun.ttf", gFalse},
    {"MS-Mincho", nullptr, "msmincho.ttf", gFalse},
    {"Batang", nullptr, "batang.ttf", gFalse},
    {"ArialUnicode", nullptr, "arialuni.ttf", gTrue},
177
    { }
178 179 180 181 182 183 184
};

#define FONTS_SUBDIR "\\fonts"

static void GetWindowsFontDir(char *winFontDir, int cbWinFontDirLen)
{
    BOOL (__stdcall *SHGetSpecialFolderPathFunc)(HWND  hwndOwner,
185
                                                  LPSTR lpszPath,
186 187 188 189 190 191
                                                  int    nFolder,
                                                  BOOL  fCreate);
    HRESULT (__stdcall *SHGetFolderPathFunc)(HWND  hwndOwner,
                                              int    nFolder,
                                              HANDLE hToken,
                                              DWORD  dwFlags,
192
                                              LPSTR pszPath);
193 194 195 196 197

    // SHGetSpecialFolderPath isn't available in older versions of shell32.dll (Win95 and
    // WinNT4), so do a dynamic load of ANSI versions.
    winFontDir[0] = '\0';

198
    HMODULE hLib = LoadLibraryA("shell32.dll");
199
    if (hLib) {
200
        SHGetFolderPathFunc = (HRESULT (__stdcall *)(HWND, int, HANDLE, DWORD, LPSTR))
201 202
                              GetProcAddress(hLib, "SHGetFolderPathA");
        if (SHGetFolderPathFunc)
203
            (*SHGetFolderPathFunc)(nullptr, CSIDL_FONTS, nullptr, SHGFP_TYPE_CURRENT, winFontDir);
204 205 206

        if (!winFontDir[0]) {
            // Try an older function
207
            SHGetSpecialFolderPathFunc = (BOOL (__stdcall *)(HWND, LPSTR, int, BOOL))
208 209
                                          GetProcAddress(hLib, "SHGetSpecialFolderPathA");
            if (SHGetSpecialFolderPathFunc)
210
                (*SHGetSpecialFolderPathFunc)(nullptr, winFontDir, CSIDL_FONTS, FALSE);
211 212 213 214 215 216 217
        }
        FreeLibrary(hLib);
    }
    if (winFontDir[0])
        return;

    // Try older DLL
218
    hLib = LoadLibraryA("SHFolder.dll");
219
    if (hLib) {
220
        SHGetFolderPathFunc = (HRESULT (__stdcall *)(HWND, int, HANDLE, DWORD, LPSTR))
221 222
                              GetProcAddress(hLib, "SHGetFolderPathA");
        if (SHGetFolderPathFunc)
223
            (*SHGetFolderPathFunc)(nullptr, CSIDL_FONTS, nullptr, SHGFP_TYPE_CURRENT, winFontDir);
224 225 226 227 228 229
        FreeLibrary(hLib);
    }
    if (winFontDir[0])
        return;

    // Everything else failed so the standard fonts directory.
230
    GetWindowsDirectoryA(winFontDir, cbWinFontDirLen);
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
    if (winFontDir[0]) {
        strncat(winFontDir, FONTS_SUBDIR, cbWinFontDirLen);
        winFontDir[cbWinFontDirLen-1] = 0;
    }
}

static bool FileExists(const char *path)
{
    FILE * f = fopen(path, "rb");
    if (f) {
        fclose(f);
        return true;
    }
    return false;
}

247 248
void SysFontList::scanWindowsFonts(GooString *winFontDir) {
  OSVERSIONINFO version;
249
  const char *path;
250 251 252 253 254 255 256 257 258 259 260 261 262 263
  DWORD idx, valNameLen, dataLen, type;
  HKEY regKey;
  char valName[1024], data[1024];
  int n, fontNum;
  char *p0, *p1;
  GooString *fontPath;

  version.dwOSVersionInfoSize = sizeof(version);
  GetVersionEx(&version);
  if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) {
    path = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts\\";
  } else {
    path = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Fonts\\";
  }
264
  if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, path, 0,
265 266 267 268 269 270
		   KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS,
		   &regKey) == ERROR_SUCCESS) {
    idx = 0;
    while (1) {
      valNameLen = sizeof(valName) - 1;
      dataLen = sizeof(data) - 1;
271
      if (RegEnumValueA(regKey, idx, valName, &valNameLen, nullptr,
272 273 274 275 276 277 278 279 280 281
		       &type, (LPBYTE)data, &dataLen) != ERROR_SUCCESS) {
	break;
      }
      if (type == REG_SZ &&
	  valNameLen > 0 && valNameLen < sizeof(valName) &&
	  dataLen > 0 && dataLen < sizeof(data)) {
	valName[valNameLen] = '\0';
	data[dataLen] = '\0';
	n = strlen(data);
	if (!strcasecmp(data + n - 4, ".ttf") ||
282 283
	    !strcasecmp(data + n - 4, ".ttc") ||
	    !strcasecmp(data + n - 4, ".otf")) {
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
	  fontPath = new GooString(data);
	  if (!(dataLen >= 3 && data[1] == ':' && data[2] == '\\')) {
	    fontPath->insert(0, '\\');
	    fontPath->insert(0, winFontDir);
		fontPath->append('\0');
	  }
	  p0 = valName;
	  fontNum = 0;
	  while (*p0) {
	    p1 = strstr(p0, " & ");
	    if (p1) {
	      *p1 = '\0';
	      p1 = p1 + 3;
	    } else {
	      p1 = p0 + strlen(p0);
	    }
	    fonts->append(makeWindowsFont(p0, fontNum,
					  fontPath->getCString()));
	    p0 = p1;
	    ++fontNum;
	  }
	  delete fontPath;
	}
      }
      ++idx;
    }
    RegCloseKey(regKey);
  }
}

SysFontInfo *SysFontList::makeWindowsFont(char *name, int fontNum,
					  char *path) {
  int n;
Albert Astals Cid's avatar
Albert Astals Cid committed
317
  GBool bold, italic, oblique, fixedWidth;
318 319 320 321
  GooString *s;
  char c;
  int i;
  SysFontType type;
322
  GooString substituteName;
323 324

  n = strlen(name);
Albert Astals Cid's avatar
Albert Astals Cid committed
325
  bold = italic = oblique = fixedWidth = gFalse;
326 327 328 329 330 331

  // remove trailing ' (TrueType)'
  if (n > 11 && !strncmp(name + n - 11, " (TrueType)", 11)) {
    n -= 11;
  }

332 333 334 335 336
  // remove trailing ' (OpenType)'
  if (n > 11 && !strncmp(name + n - 11, " (OpenType)", 11)) {
    n -= 11;
  }

337 338 339 340 341 342
  // remove trailing ' Italic'
  if (n > 7 && !strncmp(name + n - 7, " Italic", 7)) {
    n -= 7;
    italic = gTrue;
  }

Albert Astals Cid's avatar
Albert Astals Cid committed
343 344 345 346 347 348
  // remove trailing ' Oblique'
  if (n > 7 && !strncmp(name + n - 8, " Oblique", 8)) {
    n -= 8;
    oblique = gTrue;
  }

349 350 351 352 353 354 355 356 357 358 359
  // remove trailing ' Bold'
  if (n > 5 && !strncmp(name + n - 5, " Bold", 5)) {
    n -= 5;
    bold = gTrue;
  }

  // remove trailing ' Regular'
  if (n > 5 && !strncmp(name + n - 8, " Regular", 8)) {
    n -= 8;
  }

Albert Astals Cid's avatar
Albert Astals Cid committed
360 361 362 363 364 365 366 367 368 369 370
  // the familyname cannot indicate whether a font is fixedWidth or not.
  // some well-known fixedWidth typeface family names or keyword are checked.
  if ( strstr(name, "Courier") ||
       strstr(name, "Fixed")   ||
      (strstr(name, "Mono") && !strstr(name, "Monotype")) ||
       strstr(name, "Typewriter") )
    fixedWidth = gTrue;
  else
    fixedWidth = gFalse;


371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
  //----- normalize the font name
  s = new GooString(name, n);
  i = 0;
  while (i < s->getLength()) {
    c = s->getChar(i);
    if (c == ' ' || c == ',' || c == '-') {
      s->del(i);
    } else {
      ++i;
    }
  }

  if (!strcasecmp(path + strlen(path) - 4, ".ttc")) {
    type = sysFontTTC;
  } else {
    type = sysFontTTF;
  }
Albert Astals Cid's avatar
Albert Astals Cid committed
388 389

  return new SysFontInfo(s, bold, italic, oblique, fixedWidth,
390
                         new GooString(path), type, fontNum, substituteName.copy());
391 392
}

393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410
static GooString* replaceSuffix(GooString *path,
                                const char* suffixA, const char* suffixB)
{
  int suffLenA = strlen(suffixA);
  int suffLenB = strlen(suffixB);
  int baseLenA = path->getLength() - suffLenA;
  int baseLenB = path->getLength() - suffLenB;

  if (!strcasecmp(path->getCString()+baseLenA, suffixA)) {
    path->del(baseLenA,suffLenA)->append(suffixB);
  } else if (!strcasecmp(path->getCString()+baseLenB, suffixB)) {
    path->del(baseLenB,suffLenB)->append(suffixA);
  }

  return path;
}


411 412
void GlobalParams::setupBaseFonts(char * dir)
{
413
    const char *dataRoot = popplerDataDir ? popplerDataDir : POPPLER_DATADIR;
414
    GooString *fileName = nullptr;
415
    GooFile *file;
416

417 418 419 420 421 422 423 424
    if (baseFontsInitialized)
        return;
    baseFontsInitialized = true;

    char winFontDir[MAX_PATH];
    GetWindowsFontDir(winFontDir, sizeof(winFontDir));

    for (int i = 0; displayFontTab[i].name; ++i) {
Albert Astals Cid's avatar
Albert Astals Cid committed
425
        if (fontFiles.count(displayFontTab[i].name) > 0)
426 427
            continue;

Albert Astals Cid's avatar
Albert Astals Cid committed
428 429
        GooString  *fontName = new GooString(displayFontTab[i].name);

430 431
        if (dir) {
            GooString *fontPath = appendToPath(new GooString(dir), displayFontTab[i].t1FileName);
432 433
            if (FileExists(fontPath->getCString()) ||
                FileExists(replaceSuffix(fontPath, ".pfb", ".pfa")->getCString())) {
434
                addFontFile(fontName, fontPath);
435 436 437 438 439 440 441
                continue;
            }
            delete fontPath;
        }

        if (winFontDir[0] && displayFontTab[i].ttFileName) {
            GooString *fontPath = appendToPath(new GooString(winFontDir), displayFontTab[i].ttFileName);
442 443
            if (FileExists(fontPath->getCString()) ||
                FileExists(replaceSuffix(fontPath, ".ttc", ".ttf")->getCString())) {
444
                addFontFile(fontName, fontPath);
445 446 447 448 449
                continue;
            }
            delete fontPath;
        }

Dmytro Morgun's avatar
Dmytro Morgun committed
450 451 452 453
        if (displayFontTab[i].warnIfMissing) {
            error(errSyntaxError, -1, "No display font for '{0:s}'", displayFontTab[i].name);
            delete fontName;
        }
454
    }
455
    if (winFontDir[0]) {
Dmytro Morgun's avatar
Dmytro Morgun committed
456 457
        GooString gooWinFontsDir(winFontDir);
        sysFonts->scanWindowsFonts(&gooWinFontsDir);
458
    }
459 460 461

    fileName = new GooString(dataRoot);
    fileName->append("/cidfmap");
462

463
    // try to open file
464
    file = GooFile::open(fileName);
465

466
    if (file != nullptr) {
467
      Parser *parser;
468 469
      parser = new Parser(nullptr,
	      new Lexer(nullptr,
Albert Astals Cid's avatar
Albert Astals Cid committed
470
	      new FileStream(file, 0, gFalse, file->size(), Object(objNull))),
471
	      gTrue);
Albert Astals Cid's avatar
Albert Astals Cid committed
472
      Object obj1 = parser->getObj();
473
      while (!obj1.isEOF()) {
Albert Astals Cid's avatar
Albert Astals Cid committed
474
	    Object obj2 = parser->getObj();
Dmytro Morgun's avatar
Dmytro Morgun committed
475 476 477
	    if (obj1.isName()) {
	      // Substitutions
	      if (obj2.isDict()) {
Albert Astals Cid's avatar
Albert Astals Cid committed
478
	        Object obj3 = obj2.getDict()->lookup("Path");
Dmytro Morgun's avatar
Dmytro Morgun committed
479 480 481 482
	        if (obj3.isString())
	          addFontFile(new GooString(obj1.getName()), obj3.getString()->copy());
	      // Aliases
	      } else if (obj2.isName()) {
483
                substFiles.emplace(obj1.getName(), obj2.getName());
Dmytro Morgun's avatar
Dmytro Morgun committed
484 485
	      }
	    }
Albert Astals Cid's avatar
Albert Astals Cid committed
486
	    obj1 = parser->getObj();
Dmytro Morgun's avatar
Dmytro Morgun committed
487 488
	    // skip trailing ';'
	    while (obj1.isCmd(";")) {
Albert Astals Cid's avatar
Albert Astals Cid committed
489
	      obj1 = parser->getObj();
Dmytro Morgun's avatar
Dmytro Morgun committed
490
	    }
491
      }
492
      delete file;
493 494
      delete parser;
    }
Dmytro Morgun's avatar
Dmytro Morgun committed
495 496 497
    else {
        delete fileName;
    }
498 499
}

500 501
static const char *findSubstituteName(GfxFont *font, const std::unordered_map<std::string, std::string>& fontFiles,
                                      const std::unordered_map<std::string, std::string>& substFiles,
502
                                      const char *origName)
503 504
{
    assert(origName);
505
    if (!origName) return nullptr;
506 507 508 509 510 511 512
    GooString *name2 = new GooString(origName);
    int n = strlen(origName);
    // remove trailing "-Identity-H"
    if (n > 11 && !strcmp(name2->getCString() + n - 11, "-Identity-H")) {
      name2->del(n - 11, 11);
      n -= 11;
    }
513 514 515 516 517
    // remove trailing "-Identity-V"
    if (n > 11 && !strcmp(name2->getCString() + n - 11, "-Identity-V")) {
      name2->del(n - 11, 11);
      n -= 11;
    }
518 519
    const auto substFile = substFiles.find(name2->getCString());
    if (substFile != substFiles.end()) {
520
      delete name2;
521
      return substFile->second.c_str();
522 523
    }

524
    /* TODO: try to at least guess bold/italic/bolditalic from the name */
525
    delete name2;
526 527
    if (font->isCIDFont()) {
      GooString *collection = ((GfxCIDFont *)font)->getCollection();
528

529
      const char* name3 = nullptr;
530
      if ( !collection->cmp("Adobe-CNS1") )
531
        name3 = DEFAULT_CID_FONT_AC1_MSWIN;
532
      else if ( !collection->cmp("Adobe-GB1") )
533
        name3 = DEFAULT_CID_FONT_AG1_MSWIN;
534
      else if ( !collection->cmp("Adobe-Japan1") )
535
        name3 = DEFAULT_CID_FONT_AJ1_MSWIN;
536
      else if ( !collection->cmp("Adobe-Japan2") )
537
        name3 = DEFAULT_CID_FONT_AJ2_MSWIN;
538
      else if ( !collection->cmp("Adobe-Korea1") )
539 540
        name3 = DEFAULT_CID_FONT_AK1_MSWIN;

541
      if (name3 && fontFiles.count(name3) != 0)
542 543
        return name3;

544
      if (fontFiles.count(DEFAULT_CID_FONT_MSWIN) != 0)
545
        return DEFAULT_CID_FONT_MSWIN;
546 547
    } 
    return DEFAULT_SUBSTITUTE_FONT;
548 549 550
}

/* Windows implementation of external font matching code */
551 552
GooString *GlobalParams::findSystemFontFile(GfxFont *font,
					  SysFontType *type,
Albert Astals Cid's avatar
Albert Astals Cid committed
553 554
					  int *fontNum, GooString *substituteFontName,
                                          GooString *base14Name) {
555
  SysFontInfo *fi;
556
  GooString *path = nullptr;
Albert Astals Cid's avatar
Albert Astals Cid committed
557
  const GooString *fontName = font->getName();
558
  if (!fontName) return nullptr;
559
  lockGlobalParams;
560
  setupBaseFonts(nullptr);
Albert Astals Cid's avatar
Albert Astals Cid committed
561 562 563 564 565 566

  // TODO: base14Name should be changed?
  // In the system using FontConfig, findSystemFontFile() uses
  // base14Name only for the creation of query pattern.

  if ((fi = sysFonts->find(fontName, gFalse, gFalse))) {
567 568 569
    path = fi->path->copy();
    *type = fi->type;
    *fontNum = fi->fontNum;
570
    if (substituteFontName)
Mark Brand's avatar
Mark Brand committed
571
      substituteFontName->Set(fi->substituteName->getCString());
572
  } else {
573 574 575
    GooString *substFontName = new GooString(findSubstituteName(font, fontFiles,
                                                                substFiles,
                                                                fontName->getCString()));
576
    error(errSyntaxError, -1, "Couldn't find a font for '{0:t}', subst is '{1:t}'", fontName, substFontName);
Albert Astals Cid's avatar
Albert Astals Cid committed
577
    const auto fontFile = fontFiles.find(substFontName->toStr());
578 579
    if (fontFile != fontFiles.end()) {
      path = new GooString(fontFile->second.c_str());
580 581 582 583 584 585 586 587
      if (substituteFontName)
	substituteFontName->Set(path->getCString());
      if (!strcasecmp(path->getCString() + path->getLength() - 4, ".ttc")) {
	*type = sysFontTTC;
      } else {
	*type = sysFontTTF;
      }
      *fontNum = 0;
588
    }
589
  }
590 591
  unlockGlobalParams;
  return path;
592
}