Keith,
I have been working with Nicolas Mailhot to provide a solution to
allow DejaVu to be added to fontconfig enabling support for some
languages while excluding support for others. I have attached a patch
which works with fontconfig-2.3.95.
The patch adds two new tags to supported XML tag list. The tags work
in conjuction with other tags already present in the library. The tags
require fonts.conf or its included counterparts to be amended, detailing
languages to restrict in specified families. The first added tag "hide"
documents which languages are restricted from use for the family. The
second tag "only" documents which languages the family is allowed to
support.
The patch works by copying the pattern out of the cache, then
modifying the local copy of the pattern to remove either a list of
languages to be hidden, or deleting the language set, creating a new one
and adding only the supported languages. This new pattern is then used
for comparison for a match, after which point it is deleted. This patch
only affects the comparison for families within an alias. If the user
requests a specific family by name, no modification of the language set
will occur. Additionally, as some families may be used in more than one
alias and need differing support for each, the alias name is required,
and modifications to the language set needs to be dynamic.
The key benefits for this patch are the ability to use fonts that
are works in progress, broken, or have poor quality glyphs for
particular languages. This patch can also be used to allow fonts to be
placed higher in the alias list with support for only targeted languages
without interfering with fonts intended for other language support.
Syntax for the new commands is shown in the following example:
<alias>
<family>Sans-serif</family>
<only>
<family>Arial</family>
<lang>en</lang>
<lang>de</lang>
</only>
<hide>
<family>DejaVuSans</family>
<lang>ar</lang>
</hide>
</alias>
<alias>
<family>Serif</family>
<hide>
<family>Times</family>
<lang>en</lang>
<lang>de</lang>
<lang>es</lang>
</hide>
</alias>
The above XML would only allow Arial to be used for English and
German, disallow DejaVu for Arabic, and disallow Times with English,
German and Spanish.
I am interested in your comments/questions and willing to work with
you to make this a part of the fontconfig library.
Thanks,
Jay
--- fcint.h.orig Tue Jun 13 10:29:50 2006
+++ fcint.h Tue Jun 27 13:06:31 2006
@@ -74,6 +74,9 @@
#define FC_DBG_SCANV 256
#define FC_DBG_MEMORY 512
#define FC_DBG_CONFIG 1024
+#ifdef HIDE
+#define FC_DBG_HIDDEN 2048
+#endif
#define FC_MEM_CHARSET 0
#define FC_MEM_CHARLEAF 1
@@ -369,6 +372,22 @@
FcChar32 *blanks;
};
+#ifdef HIDE
+typedef struct _FcFontLang {
+ FcChar8 *family; /* Name of font family */
+ FcStrSet *hides; /* list of hidden languages */
+ FcStrSet *only; /* list of only allowed languages */
+ struct _FcFontLang *next; /* Next font family */
+} FcFontLang;
+
+typedef struct _FcHide {
+ FcChar8 *alias; /* Name of alias Sans/Serif */
+ FcFontLang *family; /* Hidden languages struct */
+ FcFontLang *az[26]; /* Quick pointers */
+ struct _FcHide *next; /* Next alias */
+} FcHide;
+#endif
+
struct _FcConfig {
/*
* File names loaded from the configuration -- saved here as the
@@ -423,6 +442,16 @@
*/
time_t rescanTime; /* last time information was scanned */
int rescanInterval; /* interval between scans */
+#ifdef HIDE
+ /*
+ * Languages can be selectively turned off for some fonts to allow
+ * fonts to be used for specific languages only even if the font
+ * supports the language. This allows best fonts to be used per
+ * language where two fonts that both support the same language
+ * cannot be placed in the preference list appropriately.
+ */
+ FcHide *hideFont;
+#endif
};
extern FcConfig *_fcConfig;
@@ -747,6 +776,11 @@
void
FcEditDestroy (FcEdit *e);
+#ifdef HIDE
+void
+FcHideDestroy ( FcHide *r );
+#endif
+
/* fcinit.c */
void
@@ -778,6 +812,14 @@
FcBool
FcNameUnparseLangSet (FcStrBuf *buf, const FcLangSet *ls);
+#ifdef HIDE
+FcBool
+FcLangSetRemove (FcLangSet *ls, const FcChar8 *lang);
+
+FcBool
+FcLangSetRemoveLangs (FcLangSet *ls, FcStrSet *langs);
+#endif
+
void
FcLangSetNewBank (void);
--- fccfg.c.orig Tue Jun 13 10:28:46 2006
+++ fccfg.c Tue Jun 27 10:51:54 2006
@@ -117,6 +117,9 @@
config->rescanTime = time(0);
config->rescanInterval = 30;
+#ifdef HIDE
+ config->hideFont = NULL;
+#endif
return config;
@@ -243,6 +246,9 @@
for (set = FcSetSystem; set <= FcSetApplication; set++)
if (config->fonts[set])
FcFontSetDestroy (config->fonts[set]);
+#ifdef HIDE
+ FcHideDestroy (config->hideFont);
+#endif
free (config);
FcMemFree (FC_MEM_CONFIG, sizeof (FcConfig));
--- fclang.c.orig Tue Jun 13 10:28:40 2006
+++ fclang.c Tue Jun 27 10:55:02 2006
@@ -43,6 +43,9 @@
#define FcLangSetBitSet(ls, id) ((ls)->map[(id)>>5] |= ((FcChar32) 1 << ((id) & 0x1f)))
#define FcLangSetBitGet(ls, id) (((ls)->map[(id)>>5] >> ((id) & 0x1f)) & 1)
+#ifdef HIDE
+#define FcLangSetBitUnset(ls, id) ((ls)->map[(id)>>5] &= ~((FcChar32) 1 << ((id) & 0x1f)))
+#endif
static FcBool langsets_populated = FcFalse;
@@ -355,6 +358,36 @@
return FcStrSetAdd (ls->extra, lang);
}
+#ifdef HIDE
+FcBool
+FcLangSetRemove (FcLangSet *ls, const FcChar8 *lang)
+{
+ int id;
+
+ id = FcLangSetIndex (lang);
+ if (id >= 0)
+ {
+ FcLangSetBitUnset (ls, id);
+ return FcTrue;
+ }
+ if (ls->extra)
+ return FcStrSetDel (ls->extra, lang);
+ return FcFalse;
+}
+
+FcBool
+FcLangSetRemoveLangs (FcLangSet *ls, FcStrSet *langs)
+{
+ int i;
+
+ for ( i = 0; i < langs->num; i++ )
+ {
+ FcLangSetRemove ( ls, langs->strs[i] );
+ }
+ return FcTrue;
+}
+#endif
+
FcLangResult
FcLangSetHasLang (const FcLangSet *ls, const FcChar8 *lang)
{
--- fcmatch.c.orig Tue Jun 13 10:28:35 2006
+++ fcmatch.c Tue Jun 27 13:05:27 2006
@@ -465,7 +465,7 @@
FcPatternElt *fe, *pe;
FcValue v;
FcResult result;
-
+
new = FcPatternCreate ();
if (!new)
return 0;
@@ -502,6 +502,153 @@
return new;
}
+#ifdef HIDE
+static FcHide *
+FcHideGetList (FcConfig *config, FcPattern *p)
+{
+ FcHide *r = NULL;
+
+ if ( config->hideFont )
+ {
+ FcPatternElt *pe = FcPatternFindElt (p, "family");
+
+ r = config->hideFont;
+
+ /*
+ * Find the base family (alias) and see if it is in the
+ * hide list
+ */
+ if ( pe )
+ {
+ FcValueListPtr v1;
+ FcValueList *v1_ptrU;
+ int found = 0;
+
+ while ( r )
+ {
+ for ( v1 = pe->values, v1_ptrU = FcValueListPtrU(v1);
+ v1_ptrU;
+ v1 = v1_ptrU->next, v1_ptrU = FcValueListPtrU(v1))
+ {
+ const FcChar8* v1_string = fc_value_string ( &(v1_ptrU->value) );
+ if (FcDebug() & FC_DBG_HIDDEN)
+ {
+ printf ( "Compare family name: %s to Hide name: %s\n",
+ (char *)v1_string, (char *)r->alias );
+ }
+ if ( !strcasecmp ( (char *)r->alias, (char *)v1_string ))
+ found = 1;
+ }
+
+ if ( !found )
+ r = r->next;
+ else
+ break;
+ }
+ }
+
+ /*
+ * At this point, we have the list of hidden fonts
+ * for the alias. We now need to check and see if the
+ * font we are comparing is on the hide list.
+ */
+ }
+ if (FcDebug () & FC_DBG_HIDDEN)
+ {
+ if ( r )
+ printf ( "Hidden list for alias %s exists\n", r->alias );
+ else
+ printf ( "No hide list exists\n" );
+ }
+ return r;
+}
+
+static FcPattern *
+FcHideFont (FcHide *r, FcPatternElt *pe, FcPattern *fnt)
+{
+ FcPattern *new = NULL;
+ FcFontLang *fl;
+
+ if ( r && pe )
+ {
+ FcValueListPtr ev = pe->values;
+ FcValueList *ev_ptrU = FcValueListPtrU(ev);
+ const FcChar8 *ev_string = fc_value_string(& (ev_ptrU->value) );
+ int pos = (int)(FcToLower(*ev_string)) - (int)'a';
+
+ fl = r->az[pos];
+
+ /*
+ * Check to see if the family is in the hide list for this alias
+ */
+ while ( fl )
+ {
+ int cmp = strcasecmp ( (char *)fl->family, (char *)ev_string );
+
+ if ( !cmp )
+ break;
+ else if ( cmp > 0 )
+ fl = NULL;
+ else
+ fl = fl->next;
+ }
+
+ /*
+ * If the family is to be language restricted, then copy the pattern
+ * and modify the language support list
+ */
+ if ( fl )
+ {
+ FcPatternElt *ppe;
+
+ new = FcPatternDuplicate (fnt);
+ if ( new )
+ {
+ ppe = FcPatternFindElt (new, "lang");
+ if ( ppe )
+ {
+ FcValueList *fv_ptrU = FcValueListPtrU(ppe->values);
+ if ( fv_ptrU->value.type == FcTypeLangSet )
+ {
+ int i;
+ if (FcDebug () & FC_DBG_HIDDEN)
+ {
+ printf("Found family: %s ", (char *)fl->family);
+ FcHideShowLangs ( fl );
+ }
+ if ( fl->hides )
+ {
+ FcLangSetRemoveLangs ( (FcLangSet *)fv_ptrU->value.u.l, fl->hides );
+ }
+ if ( fl->only )
+ {
+ FcLangSetDestroy ( (FcLangSet *)fv_ptrU->value.u.l );
+ fv_ptrU->value.u.l = FcLangSetCreate ();
+ for ( i = 0; i < fl->only->num; i++ )
+ FcLangSetAdd ( (FcLangSet *)fv_ptrU->value.u.l,
+ fl->only->strs[i] );
+ }
+ }
+ else
+ {
+ /*
+ * Don't know what to do with this yet
+ */
+ }
+ }
+ else
+ {
+ FcPatternDestroy (new);
+ new = NULL;
+ }
+ }
+ }
+ }
+
+ return new;
+}
+#endif
+
FcPattern *
FcFontSetMatch (FcConfig *config,
FcFontSet **sets,
@@ -526,7 +673,11 @@
int pat_elt;
int *match_blocked;
int block_start;
+#ifdef HIDE
+ FcHide *r = NULL;
+#endif
+
if (!nsets || !sets || !p)
{
*result = FcResultNoMatch;
@@ -548,6 +699,10 @@
}
}
+#ifdef HIDE
+ r = FcHideGetList ( config, p );
+#endif
+
sets_offset = (int *)calloc(nsets, sizeof (int));
nfonts = 0;
@@ -630,11 +785,23 @@
{
int cand_elt;
FcPatternElt *cand_elts;
+#ifdef HIDE
+ FcPatternElt *pe = FcPatternFindElt (s->fonts[f], "family");
+ FcPattern *hideFont = NULL;
+#endif
+
if (match_blocked[f + sets_offset[set]] == 1)
continue;
score = 1e99;
+#ifdef HIDE
+ if ( scoring_index == MATCH_LANG_INDEX )
+ hideFont = FcHideFont ( r, pe, s->fonts[f]);
+ if ( hideFont )
+ cand_elts = FcPatternEltU (hideFont->elts );
+ else
+#endif
cand_elts = FcPatternEltU(s->fonts[f]->elts);
/* Look for the appropriate element in this candidate
@@ -657,6 +824,10 @@
*result = FcResultTypeMismatch;
free (match_blocked);
free (sets_offset);
+#ifdef HIDE
+ if ( hideFont )
+ FcPatternDestroy ( hideFont );
+#endif
return 0;
}
@@ -673,6 +844,11 @@
}
}
+#ifdef HIDE
+ if ( hideFont )
+ FcPatternDestroy ( hideFont );
+#endif
+
/* We had no matching, just try the next one */
if (score == 1e99)
{
@@ -867,6 +1043,9 @@
int nPatternLang;
FcBool *patternLangSat;
FcValue patternLang;
+#ifdef HIDE
+ FcHide *r = NULL;
+#endif
if (FcDebug () & FC_DBG_MATCH)
{
@@ -900,6 +1079,11 @@
new = nodes;
nodep = nodeps;
+
+#ifdef HIDE
+ r = FcHideGetList ( config, p );
+#endif
+
for (set = 0; set < nsets; set++)
{
s = sets[set];
@@ -907,14 +1091,33 @@
continue;
for (f = 0; f < s->nfont; f++)
{
+#ifdef HIDE
+ FcPatternElt *pe = FcPatternFindElt (s->fonts[f], "family");
+ FcPattern *hideFont = FcHideFont ( r, pe, s->fonts[f]);
+ int res = 1;
+#endif
if (FcDebug () & FC_DBG_MATCHV)
{
printf ("Font %d ", f);
FcPatternPrint (s->fonts[f]);
}
+#ifdef HIDE
+ if ( hideFont )
+ new->pattern = hideFont;
+ else
+#endif
new->pattern = s->fonts[f];
if (!FcCompare (p, new->pattern, new->score, result))
+#ifdef HIDE
+ res = 0;
+
+ if ( hideFont )
+ FcPatternDestroy ( hideFont );
+
+ if ( !res )
+#endif
goto bail1;
+
if (FcDebug () & FC_DBG_MATCHV)
{
printf ("Score");
--- fcxml.c.orig Tue Jun 13 10:28:29 2006
+++ fcxml.c Tue Jun 27 13:06:22 2006
@@ -299,6 +299,12 @@
FcElementDefault,
FcElementFamily,
+#ifdef HIDE
+ FcElementOnly,
+ FcElementHide,
+ FcElementLang,
+#endif
+
FcElementSelectfont,
FcElementAcceptfont,
FcElementRejectfont,
@@ -359,6 +365,12 @@
{ "default", FcElementDefault },
{ "family", FcElementFamily },
+#ifdef HIDE
+ { "only", FcElementOnly },
+ { "hide", FcElementHide },
+ { "lang", FcElementLang },
+#endif
+
{ "selectfont", FcElementSelectfont },
{ "acceptfont", FcElementAcceptfont },
{ "rejectfont", FcElementRejectfont },
@@ -430,6 +442,12 @@
FcVStackPrefer,
FcVStackAccept,
FcVStackDefault,
+
+#ifdef HIDE
+ FcVStackOnly,
+ FcVStackHide,
+ FcVStackLang,
+#endif
FcVStackInteger,
FcVStackDouble,
@@ -730,6 +748,9 @@
case FcVStackField:
case FcVStackConstant:
case FcVStackGlob:
+#ifdef HIDE
+ case FcVStackLang:
+#endif
FcStrFree (vstack->u.string);
break;
case FcVStackPattern:
@@ -737,6 +758,10 @@
break;
case FcVStackInteger:
case FcVStackDouble:
+#ifdef HIDE
+ case FcVStackOnly:
+ case FcVStackHide:
+#endif
break;
case FcVStackMatrix:
FcMatrixFree (vstack->u.matrix);
@@ -1345,7 +1370,370 @@
FcVStackPushExpr (parse, FcVStackFamily, expr);
}
+#ifdef HIDE
static void
+FcParseLang (FcConfigParse *parse)
+{
+ FcChar8 *s;
+ FcExpr *expr;
+
+ if (!parse->pstack)
+ return;
+ s = FcStrBufDone (&parse->pstack->str);
+ if (!s)
+ {
+ FcConfigMessage (parse, FcSevereError, "out of memory");
+ return;
+ }
+ expr = FcExprCreateString (s);
+ FcStrFree (s);
+ if (expr)
+ FcVStackPushExpr (parse, FcVStackLang, expr);
+}
+
+static void
+FcParseOnly (FcConfigParse *parse, FcVStackTag tag)
+{
+ FcExpr *family = 0;
+ FcStrSet *lang = 0;
+ FcVStack *vstack;
+ FcFontLang *fl = NULL;
+ FcExpr *expr;
+
+ while ((vstack = FcVStackPop (parse)))
+ {
+ switch (vstack->tag) {
+ case FcVStackFamily:
+ if (family)
+ FcExprDestroy (family);
+ family = vstack->u.expr;
+ vstack->tag = FcVStackNone;
+ break;
+ case FcVStackLang:
+ if (!lang)
+ lang = FcStrSetCreate ();
+ FcStrSetAdd (lang, vstack->u.expr->u.sval);
+ break;
+ default:
+ FcConfigMessage (parse, FcSevereWarning, "bad alias");
+ break;
+ }
+ FcVStackDestroy (vstack);
+ }
+ if (!family)
+ {
+ FcConfigMessage (parse, FcSevereError, "missing family in only");
+ }
+ if ( lang )
+ {
+ fl = (FcFontLang *)malloc (sizeof (FcFontLang));
+
+ if ( fl )
+ {
+ int len = strlen ( (char *)family->u.sval );
+ fl->family = (FcChar8 *)malloc ( sizeof ( char ) * ( len + 1 ));
+ strncpy ( (char *)fl->family, (char *)family->u.sval, len );
+ fl->family[len] = '\0';
+ fl->hides = NULL;
+ fl->only = lang;
+ fl->next = NULL;
+ }
+ }
+ if ( fl )
+ {
+ expr = FcExprCreateNil ();
+ if (expr)
+ {
+ expr->u.sval = (FcChar8 *)fl;
+ FcVStackPushExpr (parse, FcVStackOnly, expr);
+ }
+ }
+}
+
+static void
+FcParseHide (FcConfigParse *parse, FcVStackTag tag)
+{
+ FcExpr *family = 0;
+ FcStrSet *lang = 0;
+ FcVStack *vstack;
+ FcFontLang *fl = NULL;
+ FcExpr *expr;
+
+ while ((vstack = FcVStackPop (parse)))
+ {
+ switch (vstack->tag) {
+ case FcVStackFamily:
+ if (family)
+ FcExprDestroy (family);
+ family = vstack->u.expr;
+ vstack->tag = FcVStackNone;
+ break;
+ case FcVStackLang:
+ if (!lang)
+ lang = FcStrSetCreate ();
+ FcStrSetAdd (lang, vstack->u.expr->u.sval);
+ break;
+ default:
+ FcConfigMessage (parse, FcSevereWarning, "bad alias");
+ break;
+ }
+ FcVStackDestroy (vstack);
+ }
+ if (!family)
+ {
+ FcConfigMessage (parse, FcSevereError, "missing family in hide");
+ }
+ if ( lang )
+ {
+ fl = (FcFontLang *)malloc (sizeof (FcFontLang));
+
+ if ( fl )
+ {
+ int len = strlen ( (char *)family->u.sval );
+ fl->family = (FcChar8 *)malloc ( sizeof ( char ) * ( len + 1 ));
+ strncpy ( (char *)fl->family, (char *)family->u.sval, len );
+ fl->family[len] = '\0';
+ fl->hides = lang;
+ fl->only = NULL;
+ fl->next = NULL;
+ }
+ }
+ if ( fl )
+ {
+ expr = FcExprCreateNil ();
+ if (expr)
+ {
+ expr->u.sval = (FcChar8 *)fl;
+ FcVStackPushExpr (parse, FcVStackHide, expr);
+ }
+ }
+}
+
+static void
+FcFontLangDestroy(FcFontLang *fl)
+{
+ FcFontLang *cur = fl;
+
+ while (fl)
+ {
+ cur = fl;
+ fl = fl->next;
+ free (cur->family);
+ if ( cur->hides )
+ FcStrSetDestroy (cur->hides);
+ if ( cur->only )
+ FcStrSetDestroy (cur->only);
+ free (cur);
+ }
+}
+
+void
+FcHideDestroy ( FcHide *r )
+{
+ if ( r )
+ {
+ if ( r->alias )
+ free ( r->alias );
+ FcFontLangDestroy ( r->family );
+ FcHideDestroy ( r->next );
+ free ( r );
+ }
+}
+
+void
+FcHideShowLangs ( FcFontLang *fl )
+{
+ int i;
+
+ if ( fl->hides )
+ {
+ printf ( "hides: " );
+ for ( i = 0; i < fl->hides->num; i++ )
+ printf ( " %s,", fl->hides->strs[i]);
+ }
+ if ( fl->only )
+ {
+ printf ( "only allows: " );
+ for ( i = 0; i < fl->only->num; i++ )
+ printf ( " %s", fl->only->strs[i]);
+ }
+ printf("\n");
+}
+
+static int
+FcHideCreate(FcConfigParse *parse, FcFontLang *fl, FcExpr *family)
+{
+ FcHide *new = parse->config->hideFont;
+ int i;
+
+ /*
+ * Check to see if user has already hidden something in this alias
+ */
+ while ( new != NULL )
+ {
+ if ( !strcasecmp ( (char *)new->alias, (char *)family->u.sval ))
+ break;
+ else
+ new = new->next;
+ }
+
+ /*
+ * If no alias hides exist, then create an FcHide structure and
+ * fill in the base values.
+ */
+ if ( !new )
+ {
+ new = (FcHide *)malloc ( sizeof ( FcHide ));
+ if ( new )
+ {
+ int len = strlen ( (char *)family->u.sval );
+ new->alias = (FcChar8 *)malloc ( sizeof ( char ) * ( len + 1 ));
+ if ( new->alias )
+ {
+ strncpy ((char *)new->alias, (char *)family->u.sval, len);
+ new->alias[len] = '\0';
+ }
+ else
+ {
+ free (new);
+ return 0;
+ }
+ new->family = NULL;
+ new->next = parse->config->hideFont;
+ parse->config->hideFont = new;
+ if (FcDebug () & FC_DBG_HIDDEN)
+ {
+ printf("Add new hide for alias: %s\n", (char *)family->u.sval);
+ }
+ }
+ else
+ return 0;
+ }
+
+ /*
+ * Add FontLang structure in alphabetical order based on family
+ * to the hide list
+ */
+ while ( fl )
+ {
+ FcFontLang *next = fl->next;
+
+ fl->next = NULL;
+
+ /*
+ * If no hidden families exist, then just add this one
+ */
+ if ( !new->family )
+ {
+ new->family = fl;
+ if (FcDebug () & FC_DBG_HIDDEN)
+ {
+ printf("Family %s ", (char *)fl->family);
+ FcHideShowLangs(fl);
+ }
+ }
+ else
+ {
+ FcFontLang *ptr = new->family;
+ FcFontLang *last = NULL;
+
+ /*
+ * Check to see where to enter hidden family, or if it already
+ * exists
+ */
+ while ( ptr )
+ {
+ int cmp = strcasecmp ( (char *)fl->family, (char *)ptr->family);
+ /*
+ * Find out if new family is before current alphabetically
+ */
+ if ( cmp < 0 )
+ {
+ fl->next = ptr;
+ if ( !last )
+ new->family = fl;
+ else
+ last->next = fl;
+ if (FcDebug () & FC_DBG_HIDDEN)
+ {
+ printf("Family %s ", (char *)fl->family);
+ FcHideShowLangs(fl);
+ }
+ break;
+ }
+ /*
+ * If it already exists, then just add new lang(s)
+ */
+ else if ( cmp == 0 )
+ {
+ /*
+ * Check to see if we have a family with only langs and
+ * hidden langs. Return error. Otherwise, add langs to list
+ */
+ if (( fl->hides && ptr->only ) ||
+ ( fl->only && ptr->hides ))
+ return 1;
+ if ( fl->hides )
+ for ( i = 0; i < fl->hides->num; i++ )
+ {
+ if ( !FcStrSetMember ( ptr->hides, fl->hides->strs[i] ))
+ FcStrSetAdd ( ptr->hides, fl->hides->strs[i] );
+ }
+ if ( fl->only )
+ for ( i = 0; i < fl->only->num; i++ )
+ {
+ if ( !FcStrSetMember ( ptr->only, fl->only->strs[i] ))
+ FcStrSetAdd ( ptr->only, fl->only->strs[i] );
+ }
+ FcFontLangDestroy ( fl );
+if (FcDebug () & FC_DBG_HIDDEN)
+{
+ printf("Hide already exists for family %s\n", (char *)ptr->family);
+}
+ break;
+ }
+ /*
+ * If it is after, then continue moving down the list
+ */
+ else
+ {
+ last = ptr;
+ ptr = ptr->next;
+
+ if ( !ptr )
+ {
+ if (FcDebug () & FC_DBG_HIDDEN)
+ {
+ printf("Family %s ", (char *)fl->family);
+ FcHideShowLangs(fl);
+ }
+ last->next = fl;
+ }
+ }
+ }
+ }
+ fl = next;
+ }
+
+ for ( i = 0; i < 26; i++ )
+ new->az[i] = NULL;
+
+ fl = new->family;
+ while ( fl )
+ {
+ int pos = (int)(fl->family[0]) - (int)'A';
+ if ( !new->az[pos] )
+ {
+ new->az[pos] = fl;
+ }
+ fl = fl->next;
+ }
+
+ return 0;
+}
+#endif
+
+static void
FcParseAlias (FcConfigParse *parse)
{
FcExpr *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
@@ -1352,6 +1740,10 @@
FcEdit *edit = 0, *next;
FcVStack *vstack;
FcTest *test;
+#ifdef HIDE
+ FcFontLang *langs = NULL;
+ FcFontLang *tmp;
+#endif
while ((vstack = FcVStackPop (parse)))
{
@@ -1373,6 +1765,16 @@
vstack->tag = FcVStackNone;
}
break;
+#ifdef HIDE
+ case FcVStackOnly:
+ case FcVStackHide:
+ tmp = (FcFontLang *)(vstack->u.expr->u.sval);
+ FcExprDestroy (vstack->u.expr);
+ tmp->next = langs;
+ langs = tmp;
+ vstack->tag = FcVStackNone;
+ break;
+#endif
case FcVStackPrefer:
if (prefer)
FcExprDestroy (prefer);
@@ -1446,6 +1848,13 @@
else
FcExprDestroy (def);
}
+#ifdef HIDE
+ if (langs)
+ {
+ if ( FcHideCreate(parse, langs, family))
+ FcConfigMessage (parse, FcSevereError, "Cannot include hide and only for same family");
+ }
+#endif
if (edit)
{
test = FcTestCreate (parse, FcMatchPattern,
@@ -1473,6 +1882,9 @@
break;
case FcVStackString:
case FcVStackFamily:
+#ifdef HIDE
+ case FcVStackLang:
+#endif
expr = FcExprCreateString (vstack->u.string);
break;
case FcVStackField:
@@ -2099,6 +2511,17 @@
case FcElementFamily:
FcParseFamily (parse);
break;
+#ifdef HIDE
+ case FcElementOnly:
+ FcParseOnly (parse, FcVStackLang);
+ break;
+ case FcElementHide:
+ FcParseHide (parse, FcVStackLang);
+ break;
+ case FcElementLang:
+ FcParseLang (parse);
+ break;
+#endif
case FcElementTest:
FcParseTest (parse);
_______________________________________________
Fontconfig mailing list
Fontconfig@xxxxxxxxxxxxxxxxxxxxx
http://lists.freedesktop.org/mailman/listinfo/fontconfig