--- 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);