fontconfig/src/fcstr.c

1549 lines
27 KiB
C
Raw Normal View History

2002-02-15 00:34:13 +01:00
/*
2008-08-12 22:34:24 +02:00
* fontconfig/src/fcstr.c
2002-02-15 00:34:13 +01:00
*
2004-12-07 02:14:46 +01:00
* Copyright © 2000 Keith Packard
2002-02-15 00:34:13 +01:00
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of the author(s) not be used in
2002-02-15 00:34:13 +01:00
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. The authors make no
2002-02-15 00:34:13 +01:00
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
2002-02-15 00:34:13 +01:00
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
2002-02-15 00:34:13 +01:00
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "fcint.h"
2002-02-15 00:34:13 +01:00
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
/* Objects MT-safe for readonly access. */
FcChar8 *
FcStrCopy (const FcChar8 *s)
2002-02-15 00:34:13 +01:00
{
2013-01-02 09:06:15 +01:00
return FcStrdup (s);
2002-02-15 00:34:13 +01:00
}
Replace UUID file mechanism with per-directory 'map' attribute [v2] The UUID files would be placed in each font directory to provide the unique cache name, independent of path, for that directory. The UUID files are undesireable for a couple of reasons: 1) They must be placed in the font directories to be useful. This requires modifying the font directories themselves, introducing potential visible timestamp changes when running multiple applications, and makes the cache processing inconsistent between applications with permission to write to the font directories and applications without such permission. 2) The UUID contents were generated randomly, which makes the font cache not reproducible across multiple runs. One proposed fix for 2) is to make the UUID dependent on the font directory path, but once we do that, we can simply use the font directory path itself as the key as the original MD5-based font cache naming mechanism did. The goal of the UUID file mechanism was to fix startup time of flatpaks; as the font path names inside the flatpak did not match the font path names in the base system, the font cache would need to be reconstructed the first time the flatpak was launched. The new mechanism for doing this is to allow each '<dir>' element in the configuration include a 'map' attribute. When looking for a cache file for a particular directory, if the directory name starts with the contents of the <dir> element, that portion of the name will be replaced with the value of the 'map' attribute. Outside of the flatpak, nothing need change -- fontconfig will build cache files using real directory names. Inside the flatpak, the custom fonts.conf file will now include mappings such as this: <dir map="/usr/share/fonts">/run/host/fonts</dir> When scanning the directory /run/host/fonts/ttf, fontconfig will use the name /usr/share/fonts/ttf as the source for building the cache file name. The existing FC_FILE replacement code used for the UUID-based implementation continues to correctly adapt font path names seen by applications. v2: Leave FcDirCacheCreateUUID stub around to avoid removing public API function. Document 'map' attribute of <dir> element in fontconfig-user.sgml Suggested-by: Akira TAGOH <akira@tagoh.org> Signed-off-by: Keith Packard <keithp@keithp.com>
2018-10-30 00:39:05 +01:00
static FcChar8 *
FcStrMakeTriple (const FcChar8 *s1, const FcChar8 *s2, const FcChar8 *s3)
Replace UUID file mechanism with per-directory 'map' attribute [v2] The UUID files would be placed in each font directory to provide the unique cache name, independent of path, for that directory. The UUID files are undesireable for a couple of reasons: 1) They must be placed in the font directories to be useful. This requires modifying the font directories themselves, introducing potential visible timestamp changes when running multiple applications, and makes the cache processing inconsistent between applications with permission to write to the font directories and applications without such permission. 2) The UUID contents were generated randomly, which makes the font cache not reproducible across multiple runs. One proposed fix for 2) is to make the UUID dependent on the font directory path, but once we do that, we can simply use the font directory path itself as the key as the original MD5-based font cache naming mechanism did. The goal of the UUID file mechanism was to fix startup time of flatpaks; as the font path names inside the flatpak did not match the font path names in the base system, the font cache would need to be reconstructed the first time the flatpak was launched. The new mechanism for doing this is to allow each '<dir>' element in the configuration include a 'map' attribute. When looking for a cache file for a particular directory, if the directory name starts with the contents of the <dir> element, that portion of the name will be replaced with the value of the 'map' attribute. Outside of the flatpak, nothing need change -- fontconfig will build cache files using real directory names. Inside the flatpak, the custom fonts.conf file will now include mappings such as this: <dir map="/usr/share/fonts">/run/host/fonts</dir> When scanning the directory /run/host/fonts/ttf, fontconfig will use the name /usr/share/fonts/ttf as the source for building the cache file name. The existing FC_FILE replacement code used for the UUID-based implementation continues to correctly adapt font path names seen by applications. v2: Leave FcDirCacheCreateUUID stub around to avoid removing public API function. Document 'map' attribute of <dir> element in fontconfig-user.sgml Suggested-by: Akira TAGOH <akira@tagoh.org> Signed-off-by: Keith Packard <keithp@keithp.com>
2018-10-30 00:39:05 +01:00
{
int s1l = s1 ? strlen ((char *) s1) : 0;
int s2l = s2 ? strlen ((char *) s2) : 0;
int s3l = s3 ? strlen ((char *) s3) : 0;
int l = s1l + 1 + s2l + 1 + s3l + 1;
Replace UUID file mechanism with per-directory 'map' attribute [v2] The UUID files would be placed in each font directory to provide the unique cache name, independent of path, for that directory. The UUID files are undesireable for a couple of reasons: 1) They must be placed in the font directories to be useful. This requires modifying the font directories themselves, introducing potential visible timestamp changes when running multiple applications, and makes the cache processing inconsistent between applications with permission to write to the font directories and applications without such permission. 2) The UUID contents were generated randomly, which makes the font cache not reproducible across multiple runs. One proposed fix for 2) is to make the UUID dependent on the font directory path, but once we do that, we can simply use the font directory path itself as the key as the original MD5-based font cache naming mechanism did. The goal of the UUID file mechanism was to fix startup time of flatpaks; as the font path names inside the flatpak did not match the font path names in the base system, the font cache would need to be reconstructed the first time the flatpak was launched. The new mechanism for doing this is to allow each '<dir>' element in the configuration include a 'map' attribute. When looking for a cache file for a particular directory, if the directory name starts with the contents of the <dir> element, that portion of the name will be replaced with the value of the 'map' attribute. Outside of the flatpak, nothing need change -- fontconfig will build cache files using real directory names. Inside the flatpak, the custom fonts.conf file will now include mappings such as this: <dir map="/usr/share/fonts">/run/host/fonts</dir> When scanning the directory /run/host/fonts/ttf, fontconfig will use the name /usr/share/fonts/ttf as the source for building the cache file name. The existing FC_FILE replacement code used for the UUID-based implementation continues to correctly adapt font path names seen by applications. v2: Leave FcDirCacheCreateUUID stub around to avoid removing public API function. Document 'map' attribute of <dir> element in fontconfig-user.sgml Suggested-by: Akira TAGOH <akira@tagoh.org> Signed-off-by: Keith Packard <keithp@keithp.com>
2018-10-30 00:39:05 +01:00
FcChar8 *s = malloc (l);
if (!s)
return 0;
if (s1)
memcpy (s, s1, s1l + 1);
else
s[0] = '\0';
if (s2)
memcpy (s + s1l + 1, s2, s2l + 1);
else
s[s1l + 1] = '\0';
if (s3)
memcpy (s + s1l + 1 + s2l + 1, s3, s3l + 1);
else
s[s1l + 1 + s2l + 1] = '\0';
Replace UUID file mechanism with per-directory 'map' attribute [v2] The UUID files would be placed in each font directory to provide the unique cache name, independent of path, for that directory. The UUID files are undesireable for a couple of reasons: 1) They must be placed in the font directories to be useful. This requires modifying the font directories themselves, introducing potential visible timestamp changes when running multiple applications, and makes the cache processing inconsistent between applications with permission to write to the font directories and applications without such permission. 2) The UUID contents were generated randomly, which makes the font cache not reproducible across multiple runs. One proposed fix for 2) is to make the UUID dependent on the font directory path, but once we do that, we can simply use the font directory path itself as the key as the original MD5-based font cache naming mechanism did. The goal of the UUID file mechanism was to fix startup time of flatpaks; as the font path names inside the flatpak did not match the font path names in the base system, the font cache would need to be reconstructed the first time the flatpak was launched. The new mechanism for doing this is to allow each '<dir>' element in the configuration include a 'map' attribute. When looking for a cache file for a particular directory, if the directory name starts with the contents of the <dir> element, that portion of the name will be replaced with the value of the 'map' attribute. Outside of the flatpak, nothing need change -- fontconfig will build cache files using real directory names. Inside the flatpak, the custom fonts.conf file will now include mappings such as this: <dir map="/usr/share/fonts">/run/host/fonts</dir> When scanning the directory /run/host/fonts/ttf, fontconfig will use the name /usr/share/fonts/ttf as the source for building the cache file name. The existing FC_FILE replacement code used for the UUID-based implementation continues to correctly adapt font path names seen by applications. v2: Leave FcDirCacheCreateUUID stub around to avoid removing public API function. Document 'map' attribute of <dir> element in fontconfig-user.sgml Suggested-by: Akira TAGOH <akira@tagoh.org> Signed-off-by: Keith Packard <keithp@keithp.com>
2018-10-30 00:39:05 +01:00
return s;
}
FcChar8 *
FcStrPlus (const FcChar8 *s1, const FcChar8 *s2)
2002-02-15 00:34:13 +01:00
{
int s1l = strlen ((char *) s1);
int s2l = strlen ((char *) s2);
int l = s1l + s2l + 1;
FcChar8 *s = malloc (l);
2002-02-15 00:34:13 +01:00
if (!s)
return 0;
memcpy (s, s1, s1l);
memcpy (s + s1l, s2, s2l + 1);
2002-02-15 00:34:13 +01:00
return s;
}
void
FcStrFree (FcChar8 *s)
2002-02-15 00:34:13 +01:00
{
free (s);
}
#include "../fc-case/fccase.h"
#define FcCaseFoldUpperCount(cf) \
((cf)->method == FC_CASE_FOLD_FULL ? 1 : (cf)->count)
typedef struct _FcCaseWalker {
const FcChar8 *read;
const FcChar8 *src;
FcChar8 utf8[FC_MAX_CASE_FOLD_CHARS + 1];
} FcCaseWalker;
static void
FcStrCaseWalkerInit (const FcChar8 *src, FcCaseWalker *w)
{
w->src = src;
w->read = 0;
}
static FcChar8
FcStrCaseWalkerLong (FcCaseWalker *w, FcChar8 r)
{
FcChar32 ucs4;
int slen;
int len = strlen((char*)w->src);
slen = FcUtf8ToUcs4 (w->src - 1, &ucs4, len + 1);
if (slen <= 0)
return r;
if (FC_MIN_FOLD_CHAR <= ucs4 && ucs4 <= FC_MAX_FOLD_CHAR)
{
int min = 0;
int max = FC_NUM_CASE_FOLD;
while (min <= max)
{
int mid = (min + max) >> 1;
FcChar32 low = fcCaseFold[mid].upper;
FcChar32 high = low + FcCaseFoldUpperCount (&fcCaseFold[mid]);
2010-04-12 18:18:50 +02:00
if (high <= ucs4)
min = mid + 1;
else if (ucs4 < low)
max = mid - 1;
else
{
const FcCaseFold *fold = &fcCaseFold[mid];
int dlen;
switch (fold->method) {
case FC_CASE_FOLD_EVEN_ODD:
if ((ucs4 & 1) != (fold->upper & 1))
return r;
/* fall through ... */
default:
dlen = FcUcs4ToUtf8 (ucs4 + fold->offset, w->utf8);
break;
case FC_CASE_FOLD_FULL:
dlen = fold->count;
memcpy (w->utf8, fcCaseFoldChars + fold->offset, dlen);
break;
}
/* consume rest of src utf-8 bytes */
w->src += slen - 1;
/* read from temp buffer */
w->utf8[dlen] = '\0';
w->read = w->utf8;
return *w->read++;
}
}
}
return r;
}
static FcChar8
FcStrCaseWalkerNext (FcCaseWalker *w, const char *delims)
{
FcChar8 r;
if (w->read)
{
if ((r = *w->read++))
return r;
w->read = 0;
}
do
{
r = *w->src++;
} while (r != 0 && delims && strchr (delims, r));
2010-04-12 18:18:50 +02:00
if ((r & 0xc0) == 0xc0)
return FcStrCaseWalkerLong (w, r);
if ('A' <= r && r <= 'Z')
r = r - 'A' + 'a';
return r;
}
FcChar8 *
FcStrDowncase (const FcChar8 *s)
{
FcCaseWalker w;
int len = 0;
FcChar8 *dst, *d;
FcStrCaseWalkerInit (s, &w);
while (FcStrCaseWalkerNext (&w, NULL))
len++;
d = dst = malloc (len + 1);
if (!d)
return 0;
FcStrCaseWalkerInit (s, &w);
while ((*d++ = FcStrCaseWalkerNext (&w, NULL)));
return dst;
}
2002-02-15 00:34:13 +01:00
int
FcStrCmpIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
2002-02-15 00:34:13 +01:00
{
FcCaseWalker w1, w2;
FcChar8 c1, c2;
if (s1 == s2) return 0;
2010-04-12 18:18:50 +02:00
FcStrCaseWalkerInit (s1, &w1);
FcStrCaseWalkerInit (s2, &w2);
2010-04-12 18:18:50 +02:00
for (;;)
2002-02-15 00:34:13 +01:00
{
c1 = FcStrCaseWalkerNext (&w1, NULL);
c2 = FcStrCaseWalkerNext (&w2, NULL);
if (!c1 || (c1 != c2))
2002-02-15 00:34:13 +01:00
break;
2002-07-07 01:47:44 +02:00
}
return (int) c1 - (int) c2;
}
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)
2002-07-07 01:47:44 +02:00
{
FcCaseWalker w1, w2;
FcChar8 c1, c2;
if (s1 == s2) return 0;
2010-04-12 18:18:50 +02:00
FcStrCaseWalkerInit (s1, &w1);
FcStrCaseWalkerInit (s2, &w2);
2010-04-12 18:18:50 +02:00
for (;;)
2002-07-07 01:47:44 +02:00
{
c1 = FcStrCaseWalkerNext (&w1, (const char *)delims);
c2 = FcStrCaseWalkerNext (&w2, (const char *)delims);
if (!c1 || (c1 != c2))
2002-02-15 00:34:13 +01:00
break;
}
return (int) c1 - (int) c2;
2002-02-15 00:34:13 +01:00
}
int
FcStrCmp (const FcChar8 *s1, const FcChar8 *s2)
{
FcChar8 c1, c2;
2010-04-12 18:18:50 +02:00
if (s1 == s2)
return 0;
2010-04-12 18:18:50 +02:00
for (;;)
{
c1 = *s1++;
c2 = *s2++;
2003-03-05 07:09:36 +01:00
if (!c1 || c1 != c2)
break;
}
return (int) c1 - (int) c2;
}
/*
* Return a hash value for a string
*/
FcChar32
FcStrHashIgnoreCase (const FcChar8 *s)
{
FcChar32 h = 0;
FcCaseWalker w;
FcChar8 c;
FcStrCaseWalkerInit (s, &w);
while ((c = FcStrCaseWalkerNext (&w, NULL)))
h = ((h << 3) ^ (h >> 3)) ^ c;
return h;
}
/*
* Is the head of s1 equal to s2?
*/
static FcBool
FcStrIsAtIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2)
{
FcCaseWalker w1, w2;
FcChar8 c1, c2;
FcStrCaseWalkerInit (s1, &w1);
FcStrCaseWalkerInit (s2, &w2);
2010-04-12 18:18:50 +02:00
for (;;)
{
c1 = FcStrCaseWalkerNext (&w1, " ");
c2 = FcStrCaseWalkerNext (&w2, " ");
if (!c1 || (c1 != c2))
break;
}
return c1 == c2 || !c2;
}
/*
* Does s1 contain an instance of s2 (ignoring blanks and case)?
*/
const FcChar8 *
FcStrContainsIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2)
{
while (*s1)
{
if (FcStrIsAtIgnoreBlanksAndCase (s1, s2))
return s1;
s1++;
}
return 0;
}
static FcBool
FcCharIsPunct (const FcChar8 c)
{
if (c < '0')
return FcTrue;
if (c <= '9')
return FcFalse;
if (c < 'A')
return FcTrue;
if (c <= 'Z')
return FcFalse;
if (c < 'a')
return FcTrue;
if (c <= 'z')
return FcFalse;
if (c <= '~')
return FcTrue;
return FcFalse;
}
/*
* Is the head of s1 equal to s2?
*/
static FcBool
FcStrIsAtIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
{
FcCaseWalker w1, w2;
FcChar8 c1, c2;
FcStrCaseWalkerInit (s1, &w1);
FcStrCaseWalkerInit (s2, &w2);
2010-04-12 18:18:50 +02:00
for (;;)
{
c1 = FcStrCaseWalkerNext (&w1, NULL);
c2 = FcStrCaseWalkerNext (&w2, NULL);
if (!c1 || (c1 != c2))
break;
}
return c1 == c2 || !c2;
}
/*
* Does s1 contain an instance of s2 (ignoring blanks and case)?
*/
const FcChar8 *
FcStrContainsIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
{
while (*s1)
{
if (FcStrIsAtIgnoreCase (s1, s2))
return s1;
s1++;
}
return 0;
}
/*
* Does s1 contain an instance of s2 on a word boundary (ignoring case)?
*/
const FcChar8 *
FcStrContainsWord (const FcChar8 *s1, const FcChar8 *s2)
{
FcBool wordStart = FcTrue;
int s1len = strlen ((char *) s1);
int s2len = strlen ((char *) s2);
while (s1len >= s2len)
{
2010-04-12 18:18:50 +02:00
if (wordStart &&
FcStrIsAtIgnoreCase (s1, s2) &&
(s1len == s2len || FcCharIsPunct (s1[s2len])))
{
return s1;
}
wordStart = FcFalse;
if (FcCharIsPunct (*s1))
wordStart = FcTrue;
s1++;
s1len--;
}
return 0;
}
/*
* returns the number of strings (ignoring delimiters 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;
}
FcBool
FcStrGlobMatch (const FcChar8 *glob,
const FcChar8 *string)
{
FcChar8 c;
while ((c = *glob++))
{
switch (c) {
case '*':
/* short circuit common case */
if (!*glob)
return FcTrue;
/* short circuit another common case */
if (strchr ((char *) glob, '*') == 0)
{
size_t l1, l2;
l1 = strlen ((char *) string);
l2 = strlen ((char *) glob);
if (l1 < l2)
return FcFalse;
string += (l1 - l2);
}
while (*string)
{
if (FcStrGlobMatch (glob, string))
return FcTrue;
string++;
}
return FcFalse;
case '?':
if (*string++ == '\0')
return FcFalse;
break;
default:
if (*string++ != c)
return FcFalse;
break;
}
}
return *string == '\0';
}
const FcChar8 *
FcStrStrIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
{
FcCaseWalker w1, w2;
FcChar8 c1, c2;
const FcChar8 *cur;
if (!s1 || !s2)
return 0;
if (s1 == s2)
return s1;
2010-04-12 18:18:50 +02:00
FcStrCaseWalkerInit (s1, &w1);
FcStrCaseWalkerInit (s2, &w2);
2010-04-12 18:18:50 +02:00
c2 = FcStrCaseWalkerNext (&w2, NULL);
2010-04-12 18:18:50 +02:00
for (;;)
{
cur = w1.src;
c1 = FcStrCaseWalkerNext (&w1, NULL);
if (!c1)
break;
if (c1 == c2)
{
FcCaseWalker w1t = w1;
FcCaseWalker w2t = w2;
FcChar8 c1t, c2t;
for (;;)
{
c1t = FcStrCaseWalkerNext (&w1t, NULL);
c2t = FcStrCaseWalkerNext (&w2t, NULL);
if (!c2t)
return cur;
if (c2t != c1t)
break;
}
}
}
return 0;
}
const FcChar8 *
FcStrStr (const FcChar8 *s1, const FcChar8 *s2)
{
FcChar8 c1, c2;
const FcChar8 * p = s1;
const FcChar8 * b = s2;
if (!s1 || !s2)
return 0;
if (s1 == s2)
return s1;
again:
c2 = *s2++;
if (!c2)
return 0;
2010-04-12 18:18:50 +02:00
for (;;)
{
p = s1;
c1 = *s1++;
if (!c1 || c1 == c2)
break;
}
if (c1 != c2)
return 0;
for (;;)
{
c1 = *s1;
c2 = *s2;
if (c1 && c2 && c1 != c2)
{
s1 = p + 1;
s2 = b;
goto again;
}
if (!c2)
return p;
if (!c1)
return 0;
++ s1;
++ s2;
}
/* never reached. */
}
2002-02-15 00:34:13 +01:00
int
2002-08-24 22:08:53 +02:00
FcUtf8ToUcs4 (const FcChar8 *src_orig,
FcChar32 *dst,
int len)
2002-02-15 00:34:13 +01:00
{
2002-08-24 22:08:53 +02:00
const FcChar8 *src = src_orig;
FcChar8 s;
int extra;
FcChar32 result;
2002-02-15 00:34:13 +01:00
if (len == 0)
return 0;
2010-04-12 18:18:50 +02:00
2002-02-15 00:34:13 +01:00
s = *src++;
len--;
2010-04-12 18:18:50 +02:00
2002-02-15 00:34:13 +01:00
if (!(s & 0x80))
{
result = s;
extra = 0;
2010-04-12 18:18:50 +02:00
}
2002-02-15 00:34:13 +01:00
else if (!(s & 0x40))
{
return -1;
}
else if (!(s & 0x20))
{
result = s & 0x1f;
extra = 1;
}
else if (!(s & 0x10))
{
result = s & 0xf;
extra = 2;
}
else if (!(s & 0x08))
{
result = s & 0x07;
extra = 3;
}
else if (!(s & 0x04))
{
result = s & 0x03;
extra = 4;
}
else if ( ! (s & 0x02))
{
result = s & 0x01;
extra = 5;
}
else
{
return -1;
}
if (extra > len)
return -1;
2010-04-12 18:18:50 +02:00
2002-02-15 00:34:13 +01:00
while (extra--)
{
result <<= 6;
s = *src++;
if ((s & 0xc0) != 0x80)
return -1;
result |= s & 0x3f;
}
*dst = result;
return src - src_orig;
}
FcBool
2002-08-24 22:08:53 +02:00
FcUtf8Len (const FcChar8 *string,
int len,
int *nchar,
int *wchar)
2002-02-15 00:34:13 +01:00
{
int n;
int clen;
FcChar32 c;
FcChar32 max;
2010-04-12 18:18:50 +02:00
2002-02-15 00:34:13 +01:00
n = 0;
max = 0;
while (len)
{
clen = FcUtf8ToUcs4 (string, &c, len);
if (clen <= 0) /* malformed UTF8 string */
return FcFalse;
if (c > max)
max = c;
string += clen;
len -= clen;
n++;
}
*nchar = n;
if (max >= 0x10000)
*wchar = 4;
else if (max > 0x100)
*wchar = 2;
else
*wchar = 1;
return FcTrue;
}
int
FcUcs4ToUtf8 (FcChar32 ucs4,
FcChar8 dest[FC_UTF8_MAX_LEN])
{
int bits;
FcChar8 *d = dest;
2010-04-12 18:18:50 +02:00
if (ucs4 < 0x80) { *d++= ucs4; bits= -6; }
else if (ucs4 < 0x800) { *d++= ((ucs4 >> 6) & 0x1F) | 0xC0; bits= 0; }
else if (ucs4 < 0x10000) { *d++= ((ucs4 >> 12) & 0x0F) | 0xE0; bits= 6; }
else if (ucs4 < 0x200000) { *d++= ((ucs4 >> 18) & 0x07) | 0xF0; bits= 12; }
else if (ucs4 < 0x4000000) { *d++= ((ucs4 >> 24) & 0x03) | 0xF8; bits= 18; }
else if (ucs4 < 0x80000000) { *d++= ((ucs4 >> 30) & 0x01) | 0xFC; bits= 24; }
else return 0;
for ( ; bits >= 0; bits-= 6) {
*d++= ((ucs4 >> bits) & 0x3F) | 0x80;
}
return d - dest;
}
#define GetUtf16(src,endian) \
((FcChar16) ((src)[endian == FcEndianBig ? 0 : 1] << 8) | \
(FcChar16) ((src)[endian == FcEndianBig ? 1 : 0]))
int
2002-08-24 22:08:53 +02:00
FcUtf16ToUcs4 (const FcChar8 *src_orig,
FcEndian endian,
FcChar32 *dst,
int len) /* in bytes */
{
2002-08-24 22:08:53 +02:00
const FcChar8 *src = src_orig;
FcChar16 a, b;
FcChar32 result;
if (len < 2)
return 0;
2010-04-12 18:18:50 +02:00
a = GetUtf16 (src, endian); src += 2; len -= 2;
2010-04-12 18:18:50 +02:00
/*
* Check for surrogate
*/
if ((a & 0xfc00) == 0xd800)
{
if (len < 2)
return 0;
b = GetUtf16 (src, endian); src += 2; len -= 2;
/*
* Check for invalid surrogate sequence
*/
if ((b & 0xfc00) != 0xdc00)
return 0;
result = ((((FcChar32) a & 0x3ff) << 10) |
((FcChar32) b & 0x3ff)) + 0x10000;
}
else
result = a;
*dst = result;
return src - src_orig;
}
FcBool
2002-08-24 22:08:53 +02:00
FcUtf16Len (const FcChar8 *string,
FcEndian endian,
int len, /* in bytes */
int *nchar,
int *wchar)
{
int n;
int clen;
FcChar32 c;
FcChar32 max;
2010-04-12 18:18:50 +02:00
n = 0;
max = 0;
while (len)
{
clen = FcUtf16ToUcs4 (string, endian, &c, len);
if (clen <= 0) /* malformed UTF8 string */
return FcFalse;
if (c > max)
max = c;
string += clen;
len -= clen;
n++;
}
*nchar = n;
if (max >= 0x10000)
*wchar = 4;
else if (max > 0x100)
*wchar = 2;
else
*wchar = 1;
return FcTrue;
}
void
FcStrBufInit (FcStrBuf *buf, FcChar8 *init, int size)
{
if (init)
{
buf->buf = init;
buf->size = size;
} else
{
buf->buf = buf->buf_static;
buf->size = sizeof (buf->buf_static);
}
buf->allocated = FcFalse;
buf->failed = FcFalse;
buf->len = 0;
}
void
FcStrBufDestroy (FcStrBuf *buf)
{
if (buf->allocated)
{
free (buf->buf);
FcStrBufInit (buf, 0, 0);
}
}
FcChar8 *
FcStrBufDone (FcStrBuf *buf)
{
FcChar8 *ret;
if (buf->failed)
ret = NULL;
else
ret = malloc (buf->len + 1);
if (ret)
{
memcpy (ret, buf->buf, buf->len);
ret[buf->len] = '\0';
}
FcStrBufDestroy (buf);
return ret;
}
FcChar8 *
FcStrBufDoneStatic (FcStrBuf *buf)
{
FcStrBufChar (buf, '\0');
if (buf->failed)
return NULL;
return buf->buf;
}
FcBool
FcStrBufChar (FcStrBuf *buf, FcChar8 c)
{
if (buf->len == buf->size)
{
FcChar8 *new;
int size;
if (buf->failed)
return FcFalse;
if (buf->allocated)
{
size = buf->size * 2;
new = realloc (buf->buf, size);
}
else
{
size = buf->size + 64;
new = malloc (size);
if (new)
{
buf->allocated = FcTrue;
memcpy (new, buf->buf, buf->len);
}
}
if (!new)
{
buf->failed = FcTrue;
return FcFalse;
}
buf->size = size;
buf->buf = new;
}
buf->buf[buf->len++] = c;
return FcTrue;
}
FcBool
FcStrBufString (FcStrBuf *buf, const FcChar8 *s)
{
FcChar8 c;
while ((c = *s++))
if (!FcStrBufChar (buf, c))
return FcFalse;
return FcTrue;
}
FcBool
FcStrBufData (FcStrBuf *buf, const FcChar8 *s, int len)
{
while (len-- > 0)
if (!FcStrBufChar (buf, *s++))
return FcFalse;
return FcTrue;
}
FcBool
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,
...)
{
va_list ap;
FcStrSet *sset;
FcStrList *list;
FcChar8 *s, *ret = NULL, *p;
size_t len = 0;
if (!path)
return NULL;
sset = FcStrSetCreateEx (FCSS_ALLOW_DUPLICATES | FCSS_GROW_BY_64);
if (!sset)
return NULL;
if (!FcStrSetAdd (sset, path))
goto bail0;
va_start (ap, path);
while (1)
{
s = (FcChar8 *)va_arg (ap, FcChar8 *);
if (!s)
break;
if (!FcStrSetAdd (sset, s))
goto bail1;
}
list = FcStrListCreate (sset);
while ((s = FcStrListNext (list)))
{
len += strlen ((const char *)s) + 1;
}
list->n = 0;
ret = malloc (sizeof (FcChar8) * (len + 1));
if (!ret)
goto bail2;
p = ret;
while ((s = FcStrListNext (list)))
{
if (p != ret)
{
p[0] = FC_DIR_SEPARATOR;
p++;
}
len = strlen ((const char *)s);
memcpy (p, s, len);
p += len;
}
*p = 0;
bail2:
FcStrListDone (list);
bail1:
va_end (ap);
bail0:
FcStrSetDestroy (sset);
return ret;
}
FcChar8 *
FcStrCopyFilename (const FcChar8 *s)
{
FcChar8 *new;
2010-04-12 18:18:50 +02:00
if (*s == '~')
{
FcChar8 *home = FcConfigHome ();
FcChar8 *full;
2003-02-06 20:30:32 +01:00
int size;
if (!home)
return NULL;
2003-02-06 20:30:32 +01:00
size = strlen ((char *) home) + strlen ((char *) s);
full = (FcChar8 *) malloc (size + 1);
if (!full)
return NULL;
strcpy ((char *) full, (char *) home);
strcat ((char *) full, (char *) s + 1);
new = FcStrCanonFilename (full);
free (full);
}
else
new = FcStrCanonFilename (s);
return new;
}
FcChar8 *
FcStrLastSlash (const FcChar8 *path)
{
FcChar8 *slash;
slash = (FcChar8 *) strrchr ((const char *) path, '/');
#ifdef _WIN32
{
FcChar8 *backslash;
backslash = (FcChar8 *) strrchr ((const char *) path, '\\');
if (!slash || (backslash && backslash > slash))
slash = backslash;
}
#endif
return slash;
}
2010-04-12 18:18:50 +02:00
FcChar8 *
FcStrDirname (const FcChar8 *file)
{
FcChar8 *slash;
FcChar8 *dir;
slash = FcStrLastSlash (file);
if (!slash)
return FcStrCopy ((FcChar8 *) ".");
dir = malloc ((slash - file) + 1);
if (!dir)
return 0;
strncpy ((char *) dir, (const char *) file, slash - file);
dir[slash - file] = '\0';
return dir;
}
FcChar8 *
FcStrBasename (const FcChar8 *file)
{
FcChar8 *slash;
slash = FcStrLastSlash (file);
if (!slash)
return FcStrCopy (file);
return FcStrCopy (slash + 1);
}
static FcChar8 *
FcStrCanonAbsoluteFilename (const FcChar8 *s)
{
FcChar8 *file;
FcChar8 *f;
const FcChar8 *slash;
int size;
size = strlen ((char *) s) + 1;
file = malloc (size);
if (!file)
return NULL;
slash = NULL;
f = file;
#ifdef _WIN32
if (*s == '/' && *(s+1) == '/') /* Network path, do not squash // */
*f++ = *s++;
#endif
for (;;) {
if (*s == '/' || *s == '\0')
{
if (slash)
{
switch (s - slash) {
case 1:
f -= 1; /* squash // and trim final / from file */
break;
case 2:
if (!strncmp ((char *) slash, "/.", 2))
{
f -= 2; /* trim /. from file */
}
break;
case 3:
if (!strncmp ((char *) slash, "/..", 3))
{
f -= 3; /* trim /.. from file */
while (f > file) {
if (*--f == '/')
break;
}
}
break;
}
}
slash = s;
}
if (!(*f++ = *s++))
break;
}
return file;
}
2010-04-12 18:18:50 +02:00
#ifdef _WIN32
/*
2010-04-12 18:18:50 +02:00
* Convert '\\' to '/' , remove double '/'
*/
static void
FcConvertDosPath (char *str)
{
size_t len = strlen (str);
char *p = str;
char *dest = str;
char *end = str + len;
char last = 0;
if (*p == '\\')
{
*p = '/';
p++;
dest++;
}
while (p < end)
{
if (*p == '\\')
*p = '/';
if (*p != '/'
|| last != '/')
{
*dest++ = *p;
}
last = *p;
p++;
}
*dest = 0;
}
#endif
FcChar8 *
FcStrCanonFilename (const FcChar8 *s)
{
#ifdef _WIN32
FcChar8 full[FC_MAX_FILE_LEN + 2];
2012-06-13 13:01:30 +02:00
int size = GetFullPathName ((LPCSTR) s, sizeof (full) -1,
(LPSTR) full, NULL);
if (size == 0)
perror ("GetFullPathName");
2012-06-13 13:01:30 +02:00
FcConvertDosPath ((char *) full);
return FcStrCanonAbsoluteFilename (full);
#else
if (s[0] == '/')
return FcStrCanonAbsoluteFilename (s);
else
{
FcChar8 *full;
FcChar8 *file;
FcChar8 cwd[FC_MAX_FILE_LEN + 2];
if (getcwd ((char *) cwd, FC_MAX_FILE_LEN) == NULL)
return NULL;
full = FcStrBuildFilename (cwd, s, NULL);
file = FcStrCanonAbsoluteFilename (full);
FcStrFree (full);
return file;
}
#endif
}
FcStrSet *
FcStrSetCreate (void)
{
return FcStrSetCreateEx (FCSS_DEFAULT);
}
FcStrSet *
FcStrSetCreateEx (unsigned int control)
{
FcStrSet *set = malloc (sizeof (FcStrSet));
if (!set)
return 0;
FcRefInit (&set->ref, 1);
set->num = 0;
set->size = 0;
set->strs = 0;
set->control = control;
return set;
}
static FcBool
_FcStrSetGrow (FcStrSet *set, int growElements)
{
/* accommodate an additional NULL entry at the end of the array */
FcChar8 **strs = malloc ((set->size + growElements + 1) * sizeof (FcChar8 *));
if (!strs)
return FcFalse;
if (set->num)
memcpy (strs, set->strs, set->num * sizeof (FcChar8 *));
if (set->strs)
free (set->strs);
set->size = set->size + growElements;
set->strs = strs;
return FcTrue;
}
static FcBool
_FcStrSetAppend (FcStrSet *set, FcChar8 *s)
{
if (!FcStrSetHasControlBit (set, FCSS_ALLOW_DUPLICATES))
{
if (FcStrSetMember (set, s))
{
FcStrFree (s);
return FcTrue;
}
}
if (set->num == set->size)
{
int growElements = FcStrSetHasControlBit (set, FCSS_GROW_BY_64) ? 64 : 1;
if (!_FcStrSetGrow(set, growElements))
return FcFalse;
}
set->strs[set->num++] = s;
set->strs[set->num] = 0;
return FcTrue;
}
FcBool
FcStrSetMember (FcStrSet *set, const FcChar8 *s)
{
int i;
for (i = 0; i < set->num; i++)
if (!FcStrCmp (set->strs[i], s))
return FcTrue;
return FcFalse;
}
static int
fc_strcmp_r (const FcChar8 *s1, const FcChar8 *s2, const FcChar8 **ret)
{
FcChar8 c1, c2;
if (s1 == s2)
{
if (ret)
*ret = NULL;
return 0;
}
for (;;)
{
if (s1)
c1 = *s1++;
else
c1 = 0;
if (s2)
c2 = *s2++;
else
c2 = 0;
if (!c1 || c1 != c2)
break;
}
if (ret)
*ret = s1;
return (int) c1 - (int) c2;
}
FcBool
FcStrSetMemberAB (FcStrSet *set, const FcChar8 *a, FcChar8 *b, FcChar8 **ret)
{
int i;
const FcChar8 *s = NULL;
for (i = 0; i < set->num; i++)
{
if (!fc_strcmp_r (set->strs[i], a, &s) && s)
{
if (!fc_strcmp_r (s, b, NULL))
{
if (ret)
*ret = set->strs[i];
return FcTrue;
}
}
}
if (ret)
*ret = NULL;
return FcFalse;
}
FcBool
FcStrSetEqual (FcStrSet *sa, FcStrSet *sb)
{
int i;
if (sa->num != sb->num)
return FcFalse;
for (i = 0; i < sa->num; i++)
if (!FcStrSetMember (sb, sa->strs[i]))
return FcFalse;
return FcTrue;
}
FcBool
FcStrSetAdd (FcStrSet *set, const FcChar8 *s)
{
FcChar8 *new = FcStrCopy (s);
if (!new)
return FcFalse;
if (!_FcStrSetAppend (set, new))
{
FcStrFree (new);
return FcFalse;
}
return FcTrue;
}
Replace UUID file mechanism with per-directory 'map' attribute [v2] The UUID files would be placed in each font directory to provide the unique cache name, independent of path, for that directory. The UUID files are undesireable for a couple of reasons: 1) They must be placed in the font directories to be useful. This requires modifying the font directories themselves, introducing potential visible timestamp changes when running multiple applications, and makes the cache processing inconsistent between applications with permission to write to the font directories and applications without such permission. 2) The UUID contents were generated randomly, which makes the font cache not reproducible across multiple runs. One proposed fix for 2) is to make the UUID dependent on the font directory path, but once we do that, we can simply use the font directory path itself as the key as the original MD5-based font cache naming mechanism did. The goal of the UUID file mechanism was to fix startup time of flatpaks; as the font path names inside the flatpak did not match the font path names in the base system, the font cache would need to be reconstructed the first time the flatpak was launched. The new mechanism for doing this is to allow each '<dir>' element in the configuration include a 'map' attribute. When looking for a cache file for a particular directory, if the directory name starts with the contents of the <dir> element, that portion of the name will be replaced with the value of the 'map' attribute. Outside of the flatpak, nothing need change -- fontconfig will build cache files using real directory names. Inside the flatpak, the custom fonts.conf file will now include mappings such as this: <dir map="/usr/share/fonts">/run/host/fonts</dir> When scanning the directory /run/host/fonts/ttf, fontconfig will use the name /usr/share/fonts/ttf as the source for building the cache file name. The existing FC_FILE replacement code used for the UUID-based implementation continues to correctly adapt font path names seen by applications. v2: Leave FcDirCacheCreateUUID stub around to avoid removing public API function. Document 'map' attribute of <dir> element in fontconfig-user.sgml Suggested-by: Akira TAGOH <akira@tagoh.org> Signed-off-by: Keith Packard <keithp@keithp.com>
2018-10-30 00:39:05 +01:00
FcBool
FcStrSetAddTriple (FcStrSet *set, const FcChar8 *a, const FcChar8 *b, const FcChar8 *c)
Replace UUID file mechanism with per-directory 'map' attribute [v2] The UUID files would be placed in each font directory to provide the unique cache name, independent of path, for that directory. The UUID files are undesireable for a couple of reasons: 1) They must be placed in the font directories to be useful. This requires modifying the font directories themselves, introducing potential visible timestamp changes when running multiple applications, and makes the cache processing inconsistent between applications with permission to write to the font directories and applications without such permission. 2) The UUID contents were generated randomly, which makes the font cache not reproducible across multiple runs. One proposed fix for 2) is to make the UUID dependent on the font directory path, but once we do that, we can simply use the font directory path itself as the key as the original MD5-based font cache naming mechanism did. The goal of the UUID file mechanism was to fix startup time of flatpaks; as the font path names inside the flatpak did not match the font path names in the base system, the font cache would need to be reconstructed the first time the flatpak was launched. The new mechanism for doing this is to allow each '<dir>' element in the configuration include a 'map' attribute. When looking for a cache file for a particular directory, if the directory name starts with the contents of the <dir> element, that portion of the name will be replaced with the value of the 'map' attribute. Outside of the flatpak, nothing need change -- fontconfig will build cache files using real directory names. Inside the flatpak, the custom fonts.conf file will now include mappings such as this: <dir map="/usr/share/fonts">/run/host/fonts</dir> When scanning the directory /run/host/fonts/ttf, fontconfig will use the name /usr/share/fonts/ttf as the source for building the cache file name. The existing FC_FILE replacement code used for the UUID-based implementation continues to correctly adapt font path names seen by applications. v2: Leave FcDirCacheCreateUUID stub around to avoid removing public API function. Document 'map' attribute of <dir> element in fontconfig-user.sgml Suggested-by: Akira TAGOH <akira@tagoh.org> Signed-off-by: Keith Packard <keithp@keithp.com>
2018-10-30 00:39:05 +01:00
{
FcChar8 *new = FcStrMakeTriple (a, b, c);
Replace UUID file mechanism with per-directory 'map' attribute [v2] The UUID files would be placed in each font directory to provide the unique cache name, independent of path, for that directory. The UUID files are undesireable for a couple of reasons: 1) They must be placed in the font directories to be useful. This requires modifying the font directories themselves, introducing potential visible timestamp changes when running multiple applications, and makes the cache processing inconsistent between applications with permission to write to the font directories and applications without such permission. 2) The UUID contents were generated randomly, which makes the font cache not reproducible across multiple runs. One proposed fix for 2) is to make the UUID dependent on the font directory path, but once we do that, we can simply use the font directory path itself as the key as the original MD5-based font cache naming mechanism did. The goal of the UUID file mechanism was to fix startup time of flatpaks; as the font path names inside the flatpak did not match the font path names in the base system, the font cache would need to be reconstructed the first time the flatpak was launched. The new mechanism for doing this is to allow each '<dir>' element in the configuration include a 'map' attribute. When looking for a cache file for a particular directory, if the directory name starts with the contents of the <dir> element, that portion of the name will be replaced with the value of the 'map' attribute. Outside of the flatpak, nothing need change -- fontconfig will build cache files using real directory names. Inside the flatpak, the custom fonts.conf file will now include mappings such as this: <dir map="/usr/share/fonts">/run/host/fonts</dir> When scanning the directory /run/host/fonts/ttf, fontconfig will use the name /usr/share/fonts/ttf as the source for building the cache file name. The existing FC_FILE replacement code used for the UUID-based implementation continues to correctly adapt font path names seen by applications. v2: Leave FcDirCacheCreateUUID stub around to avoid removing public API function. Document 'map' attribute of <dir> element in fontconfig-user.sgml Suggested-by: Akira TAGOH <akira@tagoh.org> Signed-off-by: Keith Packard <keithp@keithp.com>
2018-10-30 00:39:05 +01:00
if (!new)
return FcFalse;
if (!_FcStrSetAppend (set, new))
{
FcStrFree (new);
return FcFalse;
}
return FcTrue;
}
const FcChar8 *
FcStrTripleSecond (FcChar8 *str)
Replace UUID file mechanism with per-directory 'map' attribute [v2] The UUID files would be placed in each font directory to provide the unique cache name, independent of path, for that directory. The UUID files are undesireable for a couple of reasons: 1) They must be placed in the font directories to be useful. This requires modifying the font directories themselves, introducing potential visible timestamp changes when running multiple applications, and makes the cache processing inconsistent between applications with permission to write to the font directories and applications without such permission. 2) The UUID contents were generated randomly, which makes the font cache not reproducible across multiple runs. One proposed fix for 2) is to make the UUID dependent on the font directory path, but once we do that, we can simply use the font directory path itself as the key as the original MD5-based font cache naming mechanism did. The goal of the UUID file mechanism was to fix startup time of flatpaks; as the font path names inside the flatpak did not match the font path names in the base system, the font cache would need to be reconstructed the first time the flatpak was launched. The new mechanism for doing this is to allow each '<dir>' element in the configuration include a 'map' attribute. When looking for a cache file for a particular directory, if the directory name starts with the contents of the <dir> element, that portion of the name will be replaced with the value of the 'map' attribute. Outside of the flatpak, nothing need change -- fontconfig will build cache files using real directory names. Inside the flatpak, the custom fonts.conf file will now include mappings such as this: <dir map="/usr/share/fonts">/run/host/fonts</dir> When scanning the directory /run/host/fonts/ttf, fontconfig will use the name /usr/share/fonts/ttf as the source for building the cache file name. The existing FC_FILE replacement code used for the UUID-based implementation continues to correctly adapt font path names seen by applications. v2: Leave FcDirCacheCreateUUID stub around to avoid removing public API function. Document 'map' attribute of <dir> element in fontconfig-user.sgml Suggested-by: Akira TAGOH <akira@tagoh.org> Signed-off-by: Keith Packard <keithp@keithp.com>
2018-10-30 00:39:05 +01:00
{
FcChar8 *second = str + strlen((char *) str) + 1;
if (*second == '\0')
return 0;
return second;
}
const FcChar8 *
FcStrTripleThird (FcChar8 *str)
{
FcChar8 *second = str + strlen ((char *) str) + 1;
FcChar8 *third = second + strlen ((char *) second) + 1;
if (*third == '\0')
return 0;
return third;
}
FcBool
FcStrSetAddFilename (FcStrSet *set, const FcChar8 *s)
{
FcChar8 *new = FcStrCopyFilename (s);
if (!new)
return FcFalse;
if (!_FcStrSetAppend (set, new))
{
FcStrFree (new);
return FcFalse;
}
return FcTrue;
}
Replace UUID file mechanism with per-directory 'map' attribute [v2] The UUID files would be placed in each font directory to provide the unique cache name, independent of path, for that directory. The UUID files are undesireable for a couple of reasons: 1) They must be placed in the font directories to be useful. This requires modifying the font directories themselves, introducing potential visible timestamp changes when running multiple applications, and makes the cache processing inconsistent between applications with permission to write to the font directories and applications without such permission. 2) The UUID contents were generated randomly, which makes the font cache not reproducible across multiple runs. One proposed fix for 2) is to make the UUID dependent on the font directory path, but once we do that, we can simply use the font directory path itself as the key as the original MD5-based font cache naming mechanism did. The goal of the UUID file mechanism was to fix startup time of flatpaks; as the font path names inside the flatpak did not match the font path names in the base system, the font cache would need to be reconstructed the first time the flatpak was launched. The new mechanism for doing this is to allow each '<dir>' element in the configuration include a 'map' attribute. When looking for a cache file for a particular directory, if the directory name starts with the contents of the <dir> element, that portion of the name will be replaced with the value of the 'map' attribute. Outside of the flatpak, nothing need change -- fontconfig will build cache files using real directory names. Inside the flatpak, the custom fonts.conf file will now include mappings such as this: <dir map="/usr/share/fonts">/run/host/fonts</dir> When scanning the directory /run/host/fonts/ttf, fontconfig will use the name /usr/share/fonts/ttf as the source for building the cache file name. The existing FC_FILE replacement code used for the UUID-based implementation continues to correctly adapt font path names seen by applications. v2: Leave FcDirCacheCreateUUID stub around to avoid removing public API function. Document 'map' attribute of <dir> element in fontconfig-user.sgml Suggested-by: Akira TAGOH <akira@tagoh.org> Signed-off-by: Keith Packard <keithp@keithp.com>
2018-10-30 00:39:05 +01:00
FcBool
FcStrSetAddFilenamePairWithSalt (FcStrSet *set, const FcChar8 *a, const FcChar8 *b, const FcChar8 *salt)
Replace UUID file mechanism with per-directory 'map' attribute [v2] The UUID files would be placed in each font directory to provide the unique cache name, independent of path, for that directory. The UUID files are undesireable for a couple of reasons: 1) They must be placed in the font directories to be useful. This requires modifying the font directories themselves, introducing potential visible timestamp changes when running multiple applications, and makes the cache processing inconsistent between applications with permission to write to the font directories and applications without such permission. 2) The UUID contents were generated randomly, which makes the font cache not reproducible across multiple runs. One proposed fix for 2) is to make the UUID dependent on the font directory path, but once we do that, we can simply use the font directory path itself as the key as the original MD5-based font cache naming mechanism did. The goal of the UUID file mechanism was to fix startup time of flatpaks; as the font path names inside the flatpak did not match the font path names in the base system, the font cache would need to be reconstructed the first time the flatpak was launched. The new mechanism for doing this is to allow each '<dir>' element in the configuration include a 'map' attribute. When looking for a cache file for a particular directory, if the directory name starts with the contents of the <dir> element, that portion of the name will be replaced with the value of the 'map' attribute. Outside of the flatpak, nothing need change -- fontconfig will build cache files using real directory names. Inside the flatpak, the custom fonts.conf file will now include mappings such as this: <dir map="/usr/share/fonts">/run/host/fonts</dir> When scanning the directory /run/host/fonts/ttf, fontconfig will use the name /usr/share/fonts/ttf as the source for building the cache file name. The existing FC_FILE replacement code used for the UUID-based implementation continues to correctly adapt font path names seen by applications. v2: Leave FcDirCacheCreateUUID stub around to avoid removing public API function. Document 'map' attribute of <dir> element in fontconfig-user.sgml Suggested-by: Akira TAGOH <akira@tagoh.org> Signed-off-by: Keith Packard <keithp@keithp.com>
2018-10-30 00:39:05 +01:00
{
FcChar8 *new_a = NULL;
FcChar8 *new_b = NULL;
FcChar8 *rs = NULL;
Replace UUID file mechanism with per-directory 'map' attribute [v2] The UUID files would be placed in each font directory to provide the unique cache name, independent of path, for that directory. The UUID files are undesireable for a couple of reasons: 1) They must be placed in the font directories to be useful. This requires modifying the font directories themselves, introducing potential visible timestamp changes when running multiple applications, and makes the cache processing inconsistent between applications with permission to write to the font directories and applications without such permission. 2) The UUID contents were generated randomly, which makes the font cache not reproducible across multiple runs. One proposed fix for 2) is to make the UUID dependent on the font directory path, but once we do that, we can simply use the font directory path itself as the key as the original MD5-based font cache naming mechanism did. The goal of the UUID file mechanism was to fix startup time of flatpaks; as the font path names inside the flatpak did not match the font path names in the base system, the font cache would need to be reconstructed the first time the flatpak was launched. The new mechanism for doing this is to allow each '<dir>' element in the configuration include a 'map' attribute. When looking for a cache file for a particular directory, if the directory name starts with the contents of the <dir> element, that portion of the name will be replaced with the value of the 'map' attribute. Outside of the flatpak, nothing need change -- fontconfig will build cache files using real directory names. Inside the flatpak, the custom fonts.conf file will now include mappings such as this: <dir map="/usr/share/fonts">/run/host/fonts</dir> When scanning the directory /run/host/fonts/ttf, fontconfig will use the name /usr/share/fonts/ttf as the source for building the cache file name. The existing FC_FILE replacement code used for the UUID-based implementation continues to correctly adapt font path names seen by applications. v2: Leave FcDirCacheCreateUUID stub around to avoid removing public API function. Document 'map' attribute of <dir> element in fontconfig-user.sgml Suggested-by: Akira TAGOH <akira@tagoh.org> Signed-off-by: Keith Packard <keithp@keithp.com>
2018-10-30 00:39:05 +01:00
FcBool ret;
if (a)
{
new_a = FcStrCopyFilename (a);
if (!new_a)
return FcFalse;
}
if (b)
{
new_b = FcStrCopyFilename(b);
if (!new_b)
{
if (new_a)
FcStrFree(new_a);
return FcFalse;
}
}
/* Override maps with new one if exists */
if (FcStrSetMemberAB (set, new_a, new_b, &rs))
{
FcStrSetDel (set, rs);
}
ret = FcStrSetAddTriple (set, new_a, new_b, salt);
Replace UUID file mechanism with per-directory 'map' attribute [v2] The UUID files would be placed in each font directory to provide the unique cache name, independent of path, for that directory. The UUID files are undesireable for a couple of reasons: 1) They must be placed in the font directories to be useful. This requires modifying the font directories themselves, introducing potential visible timestamp changes when running multiple applications, and makes the cache processing inconsistent between applications with permission to write to the font directories and applications without such permission. 2) The UUID contents were generated randomly, which makes the font cache not reproducible across multiple runs. One proposed fix for 2) is to make the UUID dependent on the font directory path, but once we do that, we can simply use the font directory path itself as the key as the original MD5-based font cache naming mechanism did. The goal of the UUID file mechanism was to fix startup time of flatpaks; as the font path names inside the flatpak did not match the font path names in the base system, the font cache would need to be reconstructed the first time the flatpak was launched. The new mechanism for doing this is to allow each '<dir>' element in the configuration include a 'map' attribute. When looking for a cache file for a particular directory, if the directory name starts with the contents of the <dir> element, that portion of the name will be replaced with the value of the 'map' attribute. Outside of the flatpak, nothing need change -- fontconfig will build cache files using real directory names. Inside the flatpak, the custom fonts.conf file will now include mappings such as this: <dir map="/usr/share/fonts">/run/host/fonts</dir> When scanning the directory /run/host/fonts/ttf, fontconfig will use the name /usr/share/fonts/ttf as the source for building the cache file name. The existing FC_FILE replacement code used for the UUID-based implementation continues to correctly adapt font path names seen by applications. v2: Leave FcDirCacheCreateUUID stub around to avoid removing public API function. Document 'map' attribute of <dir> element in fontconfig-user.sgml Suggested-by: Akira TAGOH <akira@tagoh.org> Signed-off-by: Keith Packard <keithp@keithp.com>
2018-10-30 00:39:05 +01:00
if (new_a)
FcStrFree (new_a);
if (new_b)
FcStrFree (new_b);
return ret;
}
FcBool
FcStrSetAddLangs (FcStrSet *strs, const char *languages)
{
const char *p = languages, *next;
FcChar8 lang[128] = {0}, *normalized_lang;
size_t len;
FcBool ret = FcFalse;
if (!languages)
return FcFalse;
while ((next = strchr (p, ':')))
{
len = next - p;
len = FC_MIN (len, 127);
strncpy ((char *) lang, p, len);
lang[len] = 0;
/* ignore an empty item */
if (*lang)
{
normalized_lang = FcLangNormalize ((const FcChar8 *) lang);
if (normalized_lang)
{
FcStrSetAdd (strs, normalized_lang);
FcStrFree (normalized_lang);
ret = FcTrue;
}
}
p = next + 1;
}
if (*p)
{
normalized_lang = FcLangNormalize ((const FcChar8 *) p);
if (normalized_lang)
{
FcStrSetAdd (strs, normalized_lang);
FcStrFree (normalized_lang);
ret = FcTrue;
}
}
return ret;
}
FcBool
FcStrSetDel (FcStrSet *set, const FcChar8 *s)
{
int i;
for (i = 0; i < set->num; i++)
if (!FcStrCmp (set->strs[i], s))
{
FcStrFree (set->strs[i]);
/*
* copy remaining string pointers and trailing
* NULL
*/
2010-04-12 18:18:50 +02:00
memmove (&set->strs[i], &set->strs[i+1],
(set->num - i) * sizeof (FcChar8 *));
set->num--;
return FcTrue;
}
return FcFalse;
}
FcBool
FcStrSetDeleteAll (FcStrSet *set)
{
int i;
if (FcRefIsConst (&set->ref))
return FcFalse;
for (i = set->num; i > 0; i--)
{
FcStrFree (set->strs[i - 1]);
set->num--;
}
return FcTrue;
}
/* TODO Make public */
static FcStrSet *
FcStrSetReference (FcStrSet *set)
{
if (FcRefIsConst (&set->ref))
return set;
FcRefInc (&set->ref);
return set;
}
void
FcStrSetDestroy (FcStrSet *set)
{
int i;
2010-04-12 18:18:50 +02:00
/* We rely on this in FcGetDefaultLangs for caching. */
if (FcRefIsConst (&set->ref))
return;
if (FcRefDec (&set->ref) != 1)
return;
for (i = 0; i < set->num; i++)
FcStrFree (set->strs[i]);
if (set->strs)
free (set->strs);
free (set);
}
FcStrList *
FcStrListCreate (FcStrSet *set)
{
FcStrList *list;
list = malloc (sizeof (FcStrList));
if (!list)
return 0;
list->set = set;
FcStrSetReference (set);
list->n = 0;
return list;
}
void
FcStrListFirst (FcStrList *list)
{
list->n = 0;
}
FcChar8 *
FcStrListNext (FcStrList *list)
{
if (list->n >= list->set->num)
return 0;
return list->set->strs[list->n++];
}
void
FcStrListDone (FcStrList *list)
{
FcStrSetDestroy (list->set);
free (list);
}
#define __fcstr__
#include "fcaliastail.h"
#undef __fcstr__