From c5650375b8ad18080474a1da9ba9a617d8075b21 Mon Sep 17 00:00:00 2001 From: Jason Crain Date: Fri, 15 Jan 2016 01:16:05 -0600 Subject: [PATCH] Fallback to looking up glyph by Unicode code point Sometimes glyphs don't display in documents because either font substitution picks a font without the required glyphs, or the PDF document uses different names from the font. Provide fontconfig the required characters so it can better choose a font. Fallback to looking up the glyph id from the Unicode code point if lookup by name or character code fails. Change buildFcPattern to make a copy of its argument instead of modifying in place. Bug #93299 --- poppler/CairoFontEngine.cc | 7 ++++ poppler/GfxFont.cc | 4 +++ poppler/GlobalParams.cc | 80 ++++++++++++++++++++++++++++++++++++++++------ splash/SplashFTFontFile.cc | 8 +++++ 4 files changed, 89 insertions(+), 10 deletions(-) diff --git a/poppler/CairoFontEngine.cc b/poppler/CairoFontEngine.cc index 1d611b5..012b6ea 100644 --- a/poppler/CairoFontEngine.cc +++ b/poppler/CairoFontEngine.cc @@ -471,6 +471,13 @@ CairoFreeTypeFont *CairoFreeTypeFont::create(GfxFont *gfxFont, XRef *xref, codeToGID[i] = FT_Get_Name_Index(face, (char*)name); } } + if (codeToGID[i] == 0) { + // lookup by name failed, try by Unicode + Unicode u = globalParams->mapNameToUnicodeAll(enc[i]); + if (u) { + codeToGID[i] = FT_Get_Char_Index(face, u); + } + } } } break; diff --git a/poppler/GfxFont.cc b/poppler/GfxFont.cc index 81f5903..bbb9fbc 100644 --- a/poppler/GfxFont.cc +++ b/poppler/GfxFont.cc @@ -1761,6 +1761,10 @@ int *Gfx8BitFont::getCodeToGIDMap(FoFiTrueType *ff) { if ((charName = enc[i])) { if ((code = globalParams->getMacRomanCharCode(charName))) { map[i] = ff->mapCodeToGID(cmap, code); + } else if (unicodeCmap >= 0 && + (code = globalParams->mapNameToUnicodeAll(charName))) { + // not in MacRoman encoding, try Unicode lookup + map[i] = ff->mapCodeToGID(unicodeCmap, code); } } else { map[i] = -1; diff --git a/poppler/GlobalParams.cc b/poppler/GlobalParams.cc index e543408..78bcc55 100644 --- a/poppler/GlobalParams.cc +++ b/poppler/GlobalParams.cc @@ -992,12 +992,14 @@ static FcPattern *buildFcPattern(GfxFont *font, GooString *base14Name) width = -1, spacing = -1; bool deleteFamily = false; + GooString *nameStr; char *family, *name, *modifiers; const char *start; FcPattern *p; // this is all heuristics will be overwritten if font had proper info - name = (base14Name == NULL) ? font->getName()->getCString() : base14Name->getCString(); + nameStr = (base14Name == NULL) ? font->getName() : base14Name; + name = copyString(nameStr->getCString()); modifiers = strchr (name, ','); if (modifiers == NULL) @@ -1097,6 +1099,7 @@ static FcPattern *buildFcPattern(GfxFont *font, GooString *base14Name) if (width != -1) FcPatternAddInteger(p, FC_WIDTH, width); if (spacing != -1) FcPatternAddInteger(p, FC_SPACING, spacing); + gfree(name); if (deleteFamily) delete[] family; return p; @@ -1159,11 +1162,75 @@ GooString *GlobalParams::findBase14FontFile(GooString *base14Name, GfxFont *font return findSystemFontFile(font, &type, &fontNum, NULL, base14Name); } +// Compare font names while skipping punctuation and spaces. Return true if +// names match. +bool fontNamesMatch(const char *s1, const char *s2) { + while (*s1 != '\0' && *s2 != '\0') { + while (isprint(*s1) && !isalpha(*s1)) + s1++; + while (isprint(*s2) && !isalpha(*s2)) + s2++; + if (*s1 != *s2) + return false; + s1++; s2++; + } + return true; +} + +FcFontSet *getFcFontSet(GfxFont *font, GooString *base14Name) { + FcResult res; + char *fontFamily; + bool skipCharSearch = font->isCIDFont() || + (base14Name && (base14Name->cmp("Symbol") == 0 || base14Name->cmp("ZapfDingbats") == 0)); + + // If a specific font was requested or a character set search would not be + // productive, search for a font based just on the name and attributes. + if (skipCharSearch || !base14Name) { + FcPattern *p = buildFcPattern(font, base14Name); + FcConfigSubstitute(NULL, p, FcMatchPattern); + FcDefaultSubstitute(p); + FcFontSet *set = FcFontSort(NULL, p, FcFalse, NULL, &res); + FcPatternDestroy(p); + + if (!set || set->nfont == 0 || skipCharSearch) + return set; + + res = FcPatternGetString(set->fonts[0], FC_FAMILY, 0, (FcChar8**)&fontFamily); + if (res == FcResultMatch && fontNamesMatch(font->getName()->getCString(), fontFamily)) + return set; // found specifically requested font + + FcFontSetDestroy(set); + } + + // No exact match found; include character set in search. + FcPattern *p = buildFcPattern(font, base14Name); + Gfx8BitFont *bFont = dynamic_cast(font); + FcCharSet *charSet = FcCharSetCreate(); + char **enc = bFont->getEncoding(); + + for (int i = 0; i < 256; ++i) { + if (enc[i]) { + Unicode u = globalParams->mapNameToUnicodeText(enc[i]); + // don't include characters in private use area + if (u < 0xE000 || u > 0xF8FF) { + FcCharSetAddChar(charSet, u); + } + } + } + + FcPatternAddCharSet(p, FC_CHARSET, charSet); + FcCharSetDestroy(charSet); + FcConfigSubstitute(NULL, p, FcMatchPattern); + FcDefaultSubstitute(p); + FcFontSet *set = FcFontSort(NULL, p, FcFalse, NULL, &res); + FcPatternDestroy(p); + return set; +} + GooString *GlobalParams::findSystemFontFile(GfxFont *font, SysFontType *type, int *fontNum, GooString *substituteFontName, GooString *base14Name) { SysFontInfo *fi = NULL; - FcPattern *p=0; GooString *path = NULL; GooString *fontName = font->getName(); GooString substituteName; @@ -1182,13 +1249,8 @@ GooString *GlobalParams::findSystemFontFile(GfxFont *font, FcFontSet *set; int i; FcLangSet *lb = NULL; - p = buildFcPattern(font, base14Name); - if (!p) - goto fin; - FcConfigSubstitute(NULL, p, FcMatchPattern); - FcDefaultSubstitute(p); - set = FcFontSort(NULL, p, FcFalse, NULL, &res); + set = getFcFontSet(font, base14Name); if (!set) goto fin; @@ -1315,8 +1377,6 @@ GooString *GlobalParams::findSystemFontFile(GfxFont *font, substituteFontName->Set(substituteName.getCString()); } fin: - if (p) - FcPatternDestroy(p); unlockGlobalParams; return path; } diff --git a/splash/SplashFTFontFile.cc b/splash/SplashFTFontFile.cc index f0dcf50..815796b 100644 --- a/splash/SplashFTFontFile.cc +++ b/splash/SplashFTFontFile.cc @@ -30,6 +30,7 @@ #include "goo/gmem.h" #include "goo/GooString.h" #include "poppler/GfxFont.h" +#include "poppler/GlobalParams.h" #include "SplashFTFontEngine.h" #include "SplashFTFont.h" #include "SplashFTFontFile.h" @@ -65,6 +66,13 @@ SplashFontFile *SplashFTFontFile::loadType1Font(SplashFTFontEngine *engineA, codeToGIDA[i] = FT_Get_Name_Index(faceA, (char *)name); } } + if (codeToGIDA[i] == 0) { + // lookup by name failed, try by Unicode + Unicode u = globalParams->mapNameToUnicodeAll(encA[i]); + if (u) { + codeToGIDA[i] = FT_Get_Char_Index(faceA, u); + } + } } } -- 2.7.0