Return canonicalized paths from FcConfigRealFilename

FcConfigRealFilename() follows symlinks, but the link may be relative to the
directory containing the link.  For example, on my system, I have this file:

/etc/fonts/conf.d/99-language-selector-zh.conf ->
    ../conf.avail/99-language-selector-zh.conf

Since /etc/fonts/conf.d is probably not in PATH, open()ing the file would fail.
This change makes FcConfigRealFilename() return the canonicalized filename
instead.  So for the example above, it would return:

/etc/fonts/conf.avail/99-language-selector-zh.conf

This was causing bad font rendering in Chromium [1] after the regression I
introduced in 7ad010e80b.

[1] https://bugs.chromium.org/p/chromium/issues/detail?id=857511
This commit is contained in:
Tom Anderson 2018-07-11 15:50:26 -07:00 committed by Behdad Esfahbod
parent 48e9e5f4f0
commit d1f48f11d5
3 changed files with 49 additions and 30 deletions

View File

@ -2191,42 +2191,28 @@ FcConfigFilename (const FcChar8 *url)
}
file = 0;
#ifdef _WIN32
if (isalpha (*url) &&
url[1] == ':' &&
(url[2] == '/' || url[2] == '\\'))
goto absolute_path;
#endif
if (FcStrIsAbsoluteFilename(url))
return FcConfigFileExists (0, url);
switch (*url) {
case '~':
if (*url == '~')
{
dir = FcConfigHome ();
if (dir)
file = FcConfigFileExists (dir, url + 1);
else
file = 0;
break;
#ifdef _WIN32
case '\\':
absolute_path:
#endif
case '/':
file = FcConfigFileExists (0, url);
break;
default:
path = FcConfigGetPath ();
if (!path)
return NULL;
for (p = path; *p; p++)
{
file = FcConfigFileExists (*p, url);
if (file)
break;
}
FcConfigFreePath (path);
break;
}
path = FcConfigGetPath ();
if (!path)
return NULL;
for (p = path; *p; p++)
{
file = FcConfigFileExists (*p, url);
if (file)
break;
}
FcConfigFreePath (path);
return file;
}
@ -2252,8 +2238,27 @@ FcConfigRealFilename (FcConfig *config,
if ((len = FcReadLink (nn, buf, sizeof (buf) - 1)) != -1)
{
buf[len] = 0;
FcStrFree (nn);
nn = FcStrdup (buf);
if (!FcStrIsAbsoluteFilename (buf))
{
FcChar8 *dirname = FcStrDirname (nn);
FcStrFree (nn);
if (!dirname)
return NULL;
FcChar8 *path = FcStrBuildFilename (dirname, buf, NULL);
FcStrFree (dirname);
if (!path)
return NULL;
nn = FcStrCanonFilename (path);
FcStrFree (path);
}
else
{
FcStrFree (nn);
nn = FcStrdup (buf);
}
}
}

View File

@ -1279,6 +1279,9 @@ FcStrGlobMatch (const FcChar8 *glob,
FcPrivate FcBool
FcStrUsesHome (const FcChar8 *s);
FcPrivate FcBool
FcStrIsAbsoluteFilename (const FcChar8 *s);
FcPrivate FcChar8 *
FcStrBuildFilename (const FcChar8 *path,
...);

View File

@ -867,6 +867,17 @@ FcStrUsesHome (const FcChar8 *s)
return *s == '~';
}
FcBool
FcStrIsAbsoluteFilename (const FcChar8 *s)
{
#ifdef _WIN32
if (*s == '\\' ||
(isalpha (*s) && s[1] == ':' && (s[2] == '/' || s[2] == '\\'))
return FcTrue;
#endif
return *s == '/';
}
FcChar8 *
FcStrBuildFilename (const FcChar8 *path,
...)