Re: [DejaVu-fonts] [RFC] Fontconfig lang-specific font override

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

 



Le lundi 12 juin 2006 à 17:25 +0200, Ben Laenen a écrit :

...

> Okay, my personal views on this issue now:

...

> Behold the three features which would make the whole discussion about 
> the "omnibus font" completely unnecessary:
> 
> * BASE tables
> * locl feature
> * and most importantly: more control in the way the aliases are defined 
> in fonts.conf
> 
> (well, basically only number 3 would be sufficient to stop most people 
> discussing about it)

> * more control in fonts.conf aliases. What I mean with that: if you 
> define "Sans" for example, being able to have different lists for each 
> locale, and to cut out ranges which should not be used when the alias 
> is selected (when you have Arabic locale, you could have "dejavu" as 
> number 1 in the list and e.g. cut out the arabic block). Some work has 
> been done on this apparently, I don't know if everything is possible 
> now.

Well this is *exactly* what Jay's patch intends to do, and since he is
willing to massage it to get it included in fontconfig proper, we may
soon all forget about this particular problem.

It's past midnight here so I'll stop working on it, but if someone wants
to take the relay here is the current state of the patch (not building
here, but seems easy to fix)

As our exchange proved the choice of restrict for the tag may be
ambiguous (Jay meant it as restrict from, I understood it as restrict
to) so another verb may be better. I suggested Hide.

For those on the same timezone as me, good night

-- 
Nicolas Mailhot
diff -uNr fontconfig-2.3.95.orig/src/fccfg.c fontconfig-2.3.95/src/fccfg.c
--- fontconfig-2.3.95.orig/src/fccfg.c	2006-04-25 07:51:35.000000000 +0200
+++ fontconfig-2.3.95/src/fccfg.c	2006-06-12 23:31:37.000000000 +0200
@@ -117,6 +117,7 @@
 
     config->rescanTime = time(0);
     config->rescanInterval = 30;    
+    config->restrictFont = NULL;
     
     return config;
 
@@ -243,6 +244,7 @@
     for (set = FcSetSystem; set <= FcSetApplication; set++)
 	if (config->fonts[set])
 	    FcFontSetDestroy (config->fonts[set]);
+    FcRestrictDestroy (config->restrictFont);
 
     free (config);
     FcMemFree (FC_MEM_CONFIG, sizeof (FcConfig));
diff -uNr fontconfig-2.3.95.orig/src/fcint.h fontconfig-2.3.95/src/fcint.h
--- fontconfig-2.3.95.orig/src/fcint.h	2006-04-11 07:00:33.000000000 +0200
+++ fontconfig-2.3.95/src/fcint.h	2006-06-12 23:32:21.000000000 +0200
@@ -369,6 +369,19 @@
     FcChar32	*blanks;
 };
 
+typedef struct _FcFontLang {
+    FcChar8             *family;        /* Name of font family */
+    FcStrSet            *langs;         /* list of restricted languages */
+    struct _FcFontLang  *next;          /* Next font family */
+} FcFontLang;
+
+typedef struct _FcRestrict {
+    FcChar8             *alias;         /* Name of alias Sans/Serif */
+    FcFontLang          *family;        /* Restricted languages struct */
+    FcFontLang          *az[26];        /* Quick pointers */
+    struct _FcRestrict  *next;          /* Next alias */
+} FcRestrict;
+
 struct _FcConfig {
     /*
      * File names loaded from the configuration -- saved here as the
@@ -423,6 +436,14 @@
      */
     time_t	rescanTime;	    /* last time information was scanned */
     int		rescanInterval;	    /* interval between scans */
+    /*
+     * 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.
+     */
+    FcRestrict *restrictFont;
 };
  
 extern FcConfig	*_fcConfig;
@@ -747,6 +768,9 @@
 void
 FcEditDestroy (FcEdit *e);
 
+void
+FcRestrictDestroy ( FcRestrict *r );
+
 /* fcinit.c */
 
 void
@@ -797,6 +821,12 @@
 void *
 FcLangSetUnserialize (FcCache * metadata, void *block_ptr);
 
+FcBool
+FcLangSetRemove (FcLangSet *ls, const FcChar8 *lang);
+
+FcBool
+FcLangSetRemoveLangs (FcLangSet *ls, FcStrSet *langs);
+
 /* fclist.c */
 
 FcBool
diff -uNr fontconfig-2.3.95.orig/src/fclang.c fontconfig-2.3.95/src/fclang.c
--- fontconfig-2.3.95.orig/src/fclang.c	2006-04-13 06:22:25.000000000 +0200
+++ fontconfig-2.3.95/src/fclang.c	2006-06-12 23:32:48.000000000 +0200
@@ -43,6 +43,7 @@
 
 #define FcLangSetBitSet(ls, id)	((ls)->map[(id)>>5] |= ((FcChar32) 1 << ((id) & 0x1f)))
 #define FcLangSetBitGet(ls, id) (((ls)->map[(id)>>5] >> ((id) & 0x1f)) & 1)
+#define FcLangSetBitUnset(ls, id)       ((ls)->map[(id)>>5] &= ~((FcChar32) 1 << ((id) & 0x1f)))
 
 static FcBool langsets_populated = FcFalse;
 
@@ -355,6 +356,34 @@
     return FcStrSetAdd (ls->extra, lang);
 }
 
+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;
+}
+
 FcLangResult
 FcLangSetHasLang (const FcLangSet *ls, const FcChar8 *lang)
 {
diff -uNr fontconfig-2.3.95.orig/src/fcmatch.c fontconfig-2.3.95/src/fcmatch.c
--- fontconfig-2.3.95.orig/src/fcmatch.c	2006-04-25 07:51:35.000000000 +0200
+++ fontconfig-2.3.95/src/fcmatch.c	2006-06-12 23:54:34.000000000 +0200
@@ -502,6 +502,113 @@
     return new;
 }
 
+static FcRestrict *
+FcRestrictGetList (FcConfig *config, FcPattern *p)
+{
+    FcRestrict *r = NULL;
+
+    if ( config->restrictFont )
+    {
+        FcPatternElt *pe    = FcPatternFindElt (p, "family");
+
+        r = config->restrictFont;
+
+        /*
+         * Find the base family (alias) and see if it is in the
+         * restrict list
+         */
+        if ( pe )
+        {
+            FcValueList *vlist = pe->values;
+
+            while ( vlist->next )
+                vlist = vlist->next;
+
+            while ( r )
+            {
+                if ( !strcasecmp ( (char *)r->alias, (char *)vlist->value.u.s ))                    break;
+                else
+                    r = r->next;
+            }
+        }
+
+        /*
+         * At this point, we have the list of restricted fonts
+         * for the alias. We now need to check and see if the
+         * font we are comparing is on the restrict list.
+         */
+    }
+
+    return r;
+}
+
+static int
+FcRestrictFont (FcRestrict *r, FcPatternElt *pe, FcPattern *fnt, FcPatternElt **ppe, FcLangSet **pls)
+{
+    FcFontLang *fl;
+    int         ret = 0;
+
+    if ( r && pe )
+    {
+        FcLangSet  *ls;
+        int        pos = (int)(FcToLower(pe->values->value.u.s[0])) - 'a';
+
+        fl = r->az[pos];
+
+        while ( fl )
+        {
+            FcValueList *vlist = pe->values;
+            int          cmp   = strcasecmp ( (char *)fl->family,
+                                              (char *)vlist->value.u.s );
+
+            if ( !cmp )
+                break;
+            else if ( cmp > 0 )
+                fl = NULL;
+            else
+                fl = fl->next;
+        }
+
+        if ( fl )
+        {
+            *ppe = FcPatternFindElt (fnt, "lang");
+            if ( *ppe )
+            {
+                ret = 1;
+                if ( (*ppe)->values->value.type == FcTypeLangSet )
+                {
+                    ls = FcLangSetCopy ( (*ppe)->values->value.u.l );
+                    FcLangSetRemoveLangs ( ls, fl->langs );
+
+                    (*pls) = (FcLangSet *)(*ppe)->values->value.u.l;
+                    (*ppe)->values->value.u.l = ls;
+                }
+                else
+                {
+
+                }
+            }
+        }
+    }
+
+    return ret;
+}
+
+static void
+FcFontResetLangs (int          restrictFont, 
+		  FcPatternElt *pe2, 
+		  FcLangSet    *oldLangSet)
+{
+    if ( restrictFont )
+    {
+        if ( pe2->values->value.type == FcTypeLangSet )
+        {
+            FcLangSetDestroy ((FcLangSet *) pe2->values->value.u.l );
+            pe2->values->value.u.l = oldLangSet;
+        }
+    }
+}
+
 FcPattern *
 FcFontSetMatch (FcConfig    *config,
 		FcFontSet   **sets,
@@ -526,6 +633,7 @@
     int		    pat_elt;
     int		    *match_blocked;
     int		    block_start;
+    FcRestrict      *r = NULL;
 
     if (!nsets || !sets || !p)
     {
@@ -548,6 +656,8 @@
 	}
     }
 
+    r = FcRestrictGetList ( config, p );
+
     sets_offset = (int *)calloc(nsets, sizeof (int));
 
     nfonts = 0;
@@ -630,10 +740,15 @@
 		{
 		    int		    cand_elt;
 		    FcPatternElt    *cand_elts;
+            	    FcLangSet    *oldLangSet = NULL;
+            	    FcPatternElt *pe = FcPatternFindElt (s->fonts[f], "family"), *pe2;
+            	    int    restrictFont = 0;
+
 
 		    if (match_blocked[f + sets_offset[set]] == 1)
 			continue;
 
+		    restrictFont = FcRestrictFont ( r, pe, s->fonts[f], &pe2, &oldLangSet);
 		    score = 1e99;
 		    cand_elts = FcPatternEltU(s->fonts[f]->elts);
 
@@ -657,6 +772,7 @@
 				    *result = FcResultTypeMismatch;
 				    free (match_blocked);
 				    free (sets_offset);
+				    FcFontResetLangs (restrictFont, pe2, oldLangSet);
 				    return 0;
 				}
 
@@ -673,6 +789,8 @@
 			}
 		    }
 
+		    FcFontResetLangs (restrictFont, pe2, oldLangSet);
+
 		    /* We had no matching, just try the next one */
 		    if (score == 1e99)
 		    {
@@ -867,6 +985,7 @@
     int		    nPatternLang;
     FcBool    	    *patternLangSat;
     FcValue	    patternLang;
+    FcRestrict      *r = NULL;
 
     if (FcDebug () & FC_DBG_MATCH)
     {
@@ -900,6 +1019,9 @@
     
     new = nodes;
     nodep = nodeps;
+
+    r = FcRestrictGetList ( config, p );
+
     for (set = 0; set < nsets; set++)
     {
 	s = sets[set];
@@ -907,6 +1029,11 @@
 	    continue;
 	for (f = 0; f < s->nfont; f++)
 	{
+            FcLangSet    *oldLangSet = NULL;
+            FcPatternElt *pe = FcPatternFindElt (s->fonts[f], "family"), *pe2;
+            int    restrictFont = FcRestrictFont ( r, pe, s->fonts[f], &pe2, &oldLangSet);
+            int    res = 1;
+
 	    if (FcDebug () & FC_DBG_MATCHV)
 	    {
 		printf ("Font %d ", f);
@@ -914,6 +1041,11 @@
 	    }
 	    new->pattern = s->fonts[f];
 	    if (!FcCompare (p, new->pattern, new->score, result))
+                res = 0;
+
+	    FcFontResetLangs (restrictFont, pe2, oldLangSet);
+
+            if ( !res )
 		goto bail1;
 	    if (FcDebug () & FC_DBG_MATCHV)
 	    {
diff -uNr fontconfig-2.3.95.orig/src/fcxml.c fontconfig-2.3.95/src/fcxml.c
--- fontconfig-2.3.95.orig/src/fcxml.c	2006-04-25 07:51:35.000000000 +0200
+++ fontconfig-2.3.95/src/fcxml.c	2006-06-12 23:34:55.000000000 +0200
@@ -299,6 +299,9 @@
     FcElementDefault,
     FcElementFamily,
 
+    FcElementRestrict,
+    FcElementLang,
+
     FcElementSelectfont,
     FcElementAcceptfont,
     FcElementRejectfont,
@@ -359,6 +362,9 @@
     { "default",	FcElementDefault },
     { "family",		FcElementFamily },
 
+    { "restrict",	FcElementRestrict },
+    { "lang",       	FcElementLang },
+
     { "selectfont",	FcElementSelectfont },
     { "acceptfont",	FcElementAcceptfont },
     { "rejectfont",	FcElementRejectfont },
@@ -430,6 +436,9 @@
     FcVStackPrefer,
     FcVStackAccept,
     FcVStackDefault,
+
+    FcVStackRestrict,
+    FcVStackLang,
     
     FcVStackInteger,
     FcVStackDouble,
@@ -730,6 +739,7 @@
 	case FcVStackField:
 	case FcVStackConstant:
 	case FcVStackGlob:
+        case FcVStackLang:
 	    FcStrFree (vstack->u.string);
 	    break;
 	case FcVStackPattern:
@@ -737,6 +747,7 @@
 	    break;
 	case FcVStackInteger:
 	case FcVStackDouble:
+        case FcVStackRestrict:
 	    break;
 	case FcVStackMatrix:
 	    FcMatrixFree (vstack->u.matrix);
@@ -1346,12 +1357,200 @@
 }
 
 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
+FcParseRestrict (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 restrict");
+    }
+    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->langs       = lang;
+            fl->next        = NULL;
+        }
+    }
+    if ( fl )
+    {
+        expr = FcExprCreateInteger ((int)fl);
+        if (expr)
+            FcVStackPushExpr (parse, FcVStackRestrict, expr);
+    }
+}
+
+static void
+FcFontLangDestroy(FcFontLang *fl)
+{
+    FcFontLang *cur = fl;
+
+    while (fl)
+    {
+        cur = fl;
+        fl  = fl->next;
+
+        free (cur->family);
+        FcStrSetDestroy (cur->langs);
+        free (cur);
+    }
+}
+
+void
+FcRestrictDestroy ( FcRestrict *r )
+{
+    if ( r )
+    {
+        if ( r->alias )
+            free ( r->alias );
+        FcFontLangDestroy ( r->family );
+        FcRestrictDestroy ( r->next );
+        free ( r );
+    }
+}
+
+static void
+FcRestrictCreate(FcConfigParse *parse, FcFontLang *fl, FcExpr *family)
+{
+    FcRestrict *new = (FcRestrict *)malloc ( sizeof ( FcRestrict ));
+
+    if ( new )
+    {
+        int len = strlen ( (char *)family->u.sval );
+        int i;
+
+        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;
+        }
+        new->family = NULL;
+        new->next   = parse->config->restrictFont;
+        parse->config->restrictFont = new;
+
+        /*
+         * Add FontLang structure in alphabetical order based on family
+         * to the restrict list
+         */
+        while ( fl )
+        {
+            FcFontLang *next = fl->next;
+
+            fl->next = NULL;
+
+            if ( !new->family )
+                new->family = fl;
+            else
+            {
+                FcFontLang *ptr  = new->family;
+                FcFontLang *last = NULL;
+
+                while ( ptr )
+                {
+                    if ( strcasecmp ( (char *)fl->family, (char *)ptr->family) < 0)
+                    {
+                        fl->next = ptr;
+                        if ( !last )
+                            new->family = fl;
+                        else
+                            last->next = fl;
+                        break;
+                    }
+                    else
+                    {
+                        last = ptr;
+                        ptr = ptr->next;
+
+                        if ( !ptr )
+                            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;
+        }
+    }
+}
+
+static void
 FcParseAlias (FcConfigParse *parse)
 {
     FcExpr	*family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
     FcEdit	*edit = 0, *next;
     FcVStack	*vstack;
     FcTest	*test;
+    FcFontLang  *fl = NULL;
+    FcFontLang  *tmp;
 
     while ((vstack = FcVStackPop (parse))) 
     {
@@ -1373,6 +1572,13 @@
 		vstack->tag = FcVStackNone;
 	    }
 	    break;
+        case FcVStackRestrict:
+            tmp = (FcFontLang *)(vstack->u.expr->u.ival);
+            FcExprDestroy (vstack->u.expr);
+            tmp->next = fl;
+            fl = tmp;
+            vstack->tag = FcVStackNone;
+            break;
 	case FcVStackPrefer:
 	    if (prefer)
 		FcExprDestroy (prefer);
@@ -1446,6 +1652,11 @@
 	else
 	    FcExprDestroy (def);
     }
+    if (fl)
+    {
+        FcRestrictCreate(parse, fl, family);
+        FcExprDestroy (family);
+    }
     if (edit)
     {
 	test = FcTestCreate (parse, FcMatchPattern,
@@ -1473,6 +1684,7 @@
 	break;
     case FcVStackString:
     case FcVStackFamily:
+    case FcVStackLang:
 	expr = FcExprCreateString (vstack->u.string);
 	break;
     case FcVStackField:
@@ -2099,6 +2311,12 @@
     case FcElementFamily:
 	FcParseFamily (parse);
 	break;
+    case FcElementRestrict:
+        FcParseRestrict (parse, FcVStackLang);
+        break;
+    case FcElementLang:
+        FcParseLang (parse);
+        break;
 
     case FcElementTest:
 	FcParseTest (parse);

Attachment: signature.asc
Description: Ceci est une partie de message =?ISO-8859-1?Q?num=E9riquement?= =?ISO-8859-1?Q?_sign=E9e?=

_______________________________________________
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