From b561ff2016ce84eef3c81f16dfb0481be6a13f9b Mon Sep 17 00:00:00 2001 From: Akira TAGOH Date: Fri, 18 Jan 2013 11:30:10 +0900 Subject: [PATCH] Bug 38737 - Wishlist: support FC_POSTSCRIPT_NAME Add the PostScript name into the cache and the matcher. Scoring the better font against the PostScript name by the forward-matching. --- fontconfig/fontconfig.h | 1 + src/fcfreetype.c | 49 +++++++++++++++++++++++- src/fcint.h | 6 +++ src/fcmatch.c | 21 ++++++++++ src/fcobjs.h | 1 + src/fcstr.c | 85 +++++++++++++++++++++++------------------ 6 files changed, 125 insertions(+), 38 deletions(-) diff --git a/fontconfig/fontconfig.h b/fontconfig/fontconfig.h index fc0ed1a..1949965 100644 --- a/fontconfig/fontconfig.h +++ b/fontconfig/fontconfig.h @@ -116,6 +116,7 @@ typedef int FcBool; #define FC_NAMELANG "namelang" /* String RFC 3866 langs */ #define FC_PRGNAME "prgname" /* String */ #define FC_HASH "hash" /* String */ +#define FC_POSTSCRIPT_NAME "postscriptname" /* String */ #define FC_CACHE_SUFFIX ".cache-" FC_CACHE_VERSION #define FC_DIR_CACHE_FILE "fonts.cache-" FC_CACHE_VERSION diff --git a/src/fcfreetype.c b/src/fcfreetype.c index 9bd789c..8a037c0 100644 --- a/src/fcfreetype.c +++ b/src/fcfreetype.c @@ -1101,6 +1101,8 @@ FcFreeTypeQueryFace (const FT_Face face, FcChar8 *style = 0; int st; + char psname[256]; + const char *tmp; FcChar8 *hashstr; @@ -1201,7 +1203,6 @@ FcFreeTypeQueryFace (const FT_Face face, case TT_NAME_ID_PREFERRED_FAMILY: case TT_NAME_ID_FONT_FAMILY: #if 0 - case TT_NAME_ID_PS_NAME: case TT_NAME_ID_UNIQUE_ID: #endif if (FcDebug () & FC_DBG_SCANV) @@ -1347,6 +1348,52 @@ FcFreeTypeQueryFace (const FT_Face face, ++nfamily; } + /* Add the PostScript name into the cache */ + tmp = FT_Get_Postscript_Name (face); + if (!tmp) + { + FcChar8 *family, *familylang = NULL; + size_t len; + int n = 0; + + /* Workaround when FT_Get_Postscript_Name didn't give any name. + * try to find out the English family name and convert. + */ + while (FcPatternObjectGetString (pat, FC_FAMILYLANG_OBJECT, n, &familylang) == FcResultMatch) + { + if (FcStrCmp (familylang, (const FcChar8 *)"en") == 0) + break; + n++; + familylang = NULL; + } + if (!familylang) + n = 0; + + if (FcPatternObjectGetString (pat, FC_FAMILY_OBJECT, n, &family) != FcResultMatch) + goto bail1; + len = strlen ((const char *)family); + /* the literal name in PostScript Language is limited to 127 characters though, + * It is the architectural limit. so assuming 255 characters may works enough. + */ + for (i = 0; i < len && i < 255; i++) + { + /* those characters are not allowed to be the literal name in PostScript */ + static const char exclusive_chars[] = "\x04()/<>[]{}\t\f\r\n "; + + if (strchr(exclusive_chars, family[i]) != NULL) + psname[i] = '-'; + else + psname[i] = family[i]; + } + psname[i] = 0; + } + else + { + strcpy (psname, tmp); + } + if (!FcPatternAddString (pat, FC_POSTSCRIPT_NAME, (const FcChar8 *)psname)) + goto bail1; + if (!FcPatternAddString (pat, FC_FILE, file)) goto bail1; diff --git a/src/fcint.h b/src/fcint.h index d5a7217..c45075e 100644 --- a/src/fcint.h +++ b/src/fcint.h @@ -1063,6 +1063,9 @@ FcStrBufData (FcStrBuf *buf, const FcChar8 *s, int len); FcPrivate int FcStrCmpIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2); +FcPrivate int +FcStrCmpIgnoreCaseAndDelims (const FcChar8 *s1, const FcChar8 *s2, const FcChar8 *delims); + FcPrivate FcBool FcStrRegexCmp (const FcChar8 *s, const FcChar8 *regex); @@ -1078,6 +1081,9 @@ FcStrContainsIgnoreCase (const FcChar8 *s1, const FcChar8 *s2); FcPrivate const FcChar8 * FcStrContainsWord (const FcChar8 *s1, const FcChar8 *s2); +FcPrivate int +FcStrMatchIgnoreCaseAndDelims (const FcChar8 *s1, const FcChar8 *s2, const FcChar8 *delims); + FcPrivate FcBool FcStrUsesHome (const FcChar8 *s); diff --git a/src/fcmatch.c b/src/fcmatch.c index 7993b81..68f39ae 100644 --- a/src/fcmatch.c +++ b/src/fcmatch.c @@ -76,6 +76,24 @@ FcCompareFamily (FcValue *v1, FcValue *v2) return (double) FcStrCmpIgnoreBlanksAndCase (v1_string, v2_string) != 0; } +static double +FcComparePostScript (FcValue *v1, FcValue *v2) +{ + const FcChar8 *v1_string = FcValueString (v1); + const FcChar8 *v2_string = FcValueString (v2); + int n; + size_t len; + + if (FcToLower (*v1_string) != FcToLower (*v2_string) && + *v1_string != ' ' && *v2_string != ' ') + return 1.0; + + n = FcStrMatchIgnoreCaseAndDelims (v1_string, v2_string, (const FcChar8 *)" -"); + len = strlen ((const char *)v1_string); + + return (double)(len - n) / (double)len; +} + static double FcCompareLang (FcValue *v1, FcValue *v2) { @@ -198,6 +216,7 @@ FcCompareFilename (FcValue *v1, FcValue *v2) #define PRI_FcCompareFilename(n) PRI1(n) #define PRI_FcCompareCharSet(n) PRI1(n) #define PRI_FcCompareLang(n) PRI1(n) +#define PRI_FcComparePostScript(n) PRI1(n) #define FC_OBJECT(NAME, Type, Cmp) PRI_##Cmp(NAME) @@ -219,8 +238,10 @@ typedef enum _FcMatcherPriority { PRI1(CHARSET), PRI_FAMILY_STRONG, PRI_LANG_STRONG, + PRI_POSTSCRIPT_NAME_STRONG, PRI_LANG_WEAK, PRI_FAMILY_WEAK, + PRI_POSTSCRIPT_NAME_WEAK, PRI1(SPACING), PRI1(PIXEL_SIZE), PRI1(STYLE), diff --git a/src/fcobjs.h b/src/fcobjs.h index 4c1138a..b735401 100644 --- a/src/fcobjs.h +++ b/src/fcobjs.h @@ -44,4 +44,5 @@ FC_OBJECT (NAMELANG, FcTypeString, NULL) FC_OBJECT (FONT_FEATURES, FcTypeString, NULL) FC_OBJECT (PRGNAME, FcTypeString, NULL) FC_OBJECT (HASH, FcTypeString, FcCompareString) +FC_OBJECT (POSTSCRIPT_NAME, FcTypeString, FcComparePostScript) /* ^-------------- Add new objects here. */ diff --git a/src/fcstr.c b/src/fcstr.c index 4d11a4c..339a346 100644 --- a/src/fcstr.c +++ b/src/fcstr.c @@ -137,27 +137,7 @@ FcStrCaseWalkerLong (FcCaseWalker *w, FcChar8 r) } static FcChar8 -FcStrCaseWalkerNext (FcCaseWalker *w) -{ - FcChar8 r; - - if (w->read) - { - if ((r = *w->read++)) - return r; - w->read = 0; - } - r = *w->src++; - - if ((r & 0xc0) == 0xc0) - return FcStrCaseWalkerLong (w, r); - if ('A' <= r && r <= 'Z') - r = r - 'A' + 'a'; - return r; -} - -static FcChar8 -FcStrCaseWalkerNextIgnoreBlanks (FcCaseWalker *w) +FcStrCaseWalkerNext (FcCaseWalker *w, const char *delims) { FcChar8 r; @@ -170,7 +150,7 @@ FcStrCaseWalkerNextIgnoreBlanks (FcCaseWalker *w) do { r = *w->src++; - } while (r == ' '); + } while (r != 0 && delims && strchr (delims, r)); if ((r & 0xc0) == 0xc0) return FcStrCaseWalkerLong (w, r); @@ -187,13 +167,13 @@ FcStrDowncase (const FcChar8 *s) FcChar8 *dst, *d; FcStrCaseWalkerInit (s, &w); - while (FcStrCaseWalkerNext (&w)) + while (FcStrCaseWalkerNext (&w, NULL)) len++; d = dst = malloc (len + 1); if (!d) return 0; FcStrCaseWalkerInit (s, &w); - while ((*d++ = FcStrCaseWalkerNext (&w))); + while ((*d++ = FcStrCaseWalkerNext (&w, NULL))); return dst; } @@ -210,8 +190,8 @@ FcStrCmpIgnoreCase (const FcChar8 *s1, const FcChar8 *s2) for (;;) { - c1 = FcStrCaseWalkerNext (&w1); - c2 = FcStrCaseWalkerNext (&w2); + c1 = FcStrCaseWalkerNext (&w1, NULL); + c2 = FcStrCaseWalkerNext (&w2, NULL); if (!c1 || (c1 != c2)) break; } @@ -220,6 +200,12 @@ FcStrCmpIgnoreCase (const FcChar8 *s1, const FcChar8 *s2) int FcStrCmpIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2) +{ + return FcStrCmpIgnoreCaseAndDelims (s1, s2, (const FcChar8 *)" "); +} + +int +FcStrCmpIgnoreCaseAndDelims (const FcChar8 *s1, const FcChar8 *s2, const FcChar8 *delims) { FcCaseWalker w1, w2; FcChar8 c1, c2; @@ -231,8 +217,8 @@ FcStrCmpIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2) for (;;) { - c1 = FcStrCaseWalkerNextIgnoreBlanks (&w1); - c2 = FcStrCaseWalkerNextIgnoreBlanks (&w2); + c1 = FcStrCaseWalkerNext (&w1, (const char *)delims); + c2 = FcStrCaseWalkerNext (&w2, (const char *)delims); if (!c1 || (c1 != c2)) break; } @@ -317,7 +303,7 @@ FcStrHashIgnoreCase (const FcChar8 *s) FcChar8 c; FcStrCaseWalkerInit (s, &w); - while ((c = FcStrCaseWalkerNext (&w))) + while ((c = FcStrCaseWalkerNext (&w, NULL))) h = ((h << 3) ^ (h >> 3)) ^ c; return h; } @@ -337,8 +323,8 @@ FcStrIsAtIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2) for (;;) { - c1 = FcStrCaseWalkerNextIgnoreBlanks (&w1); - c2 = FcStrCaseWalkerNextIgnoreBlanks (&w2); + c1 = FcStrCaseWalkerNext (&w1, " "); + c2 = FcStrCaseWalkerNext (&w2, " "); if (!c1 || (c1 != c2)) break; } @@ -396,8 +382,8 @@ FcStrIsAtIgnoreCase (const FcChar8 *s1, const FcChar8 *s2) for (;;) { - c1 = FcStrCaseWalkerNext (&w1); - c2 = FcStrCaseWalkerNext (&w2); + c1 = FcStrCaseWalkerNext (&w1, NULL); + c2 = FcStrCaseWalkerNext (&w2, NULL); if (!c1 || (c1 != c2)) break; } @@ -448,6 +434,31 @@ FcStrContainsWord (const FcChar8 *s1, const FcChar8 *s2) return 0; } +/* + * returns the number of strings (ignoring delimitors and case) being matched + */ + +int +FcStrMatchIgnoreCaseAndDelims (const FcChar8 *s1, const FcChar8 *s2, const FcChar8 *delims) +{ + FcCaseWalker w1, w2; + FcChar8 c1, c2; + + if (s1 == s2) return 0; + + FcStrCaseWalkerInit (s1, &w1); + FcStrCaseWalkerInit (s2, &w2); + + for (;;) + { + c1 = FcStrCaseWalkerNext (&w1, (const char *)delims); + c2 = FcStrCaseWalkerNext (&w2, (const char *)delims); + if (!c1 || (c1 != c2)) + break; + } + return w1.src - s1 - 1; +} + const FcChar8 * FcStrStrIgnoreCase (const FcChar8 *s1, const FcChar8 *s2) { @@ -464,12 +475,12 @@ FcStrStrIgnoreCase (const FcChar8 *s1, const FcChar8 *s2) FcStrCaseWalkerInit (s1, &w1); FcStrCaseWalkerInit (s2, &w2); - c2 = FcStrCaseWalkerNext (&w2); + c2 = FcStrCaseWalkerNext (&w2, NULL); for (;;) { cur = w1.src; - c1 = FcStrCaseWalkerNext (&w1); + c1 = FcStrCaseWalkerNext (&w1, NULL); if (!c1) break; if (c1 == c2) @@ -480,8 +491,8 @@ FcStrStrIgnoreCase (const FcChar8 *s1, const FcChar8 *s2) for (;;) { - c1t = FcStrCaseWalkerNext (&w1t); - c2t = FcStrCaseWalkerNext (&w2t); + c1t = FcStrCaseWalkerNext (&w1t, NULL); + c2t = FcStrCaseWalkerNext (&w2t, NULL); if (!c2t) return cur;