Re: fontconfig support to exclude glyphs from fonts

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

[Index of Archives]     [Fedora Fonts]     [Fedora Users]     [Fedora Cloud]     [Kernel]     [Fedora Packaging]     [Fedora Desktop]     [PAM]     [Gimp Graphics Editor]     [Yosemite News]

  Powered by Linux