int main (int argc, char **argv) { int index_set = 0; int set_index = 0; FcChar8 *lang = NULL; const FcCharSet *fcs_lang = NULL; int err = 0; int i; FT_Library ftlib; FcBool verbose = FcFalse; #if HAVE_GETOPT_LONG || HAVE_GETOPT int c; setlocale (LC_ALL, ""); #if HAVE_GETOPT_LONG while ((c = getopt_long (argc, argv, "i:l:mVhv", longopts, NULL)) != -1) #else while ((c = getopt (argc, argv, "i:l:mVhv")) != -1) #endif { switch (c) { case 'i': index_set = 1; set_index = atoi (optarg); break; case 'l': lang = (FcChar8 *) FcLangNormalize ((const FcChar8 *) optarg); break; case 'v': verbose = FcTrue; break; case 'V': fprintf (stderr, "fontconfig version %d.%d.%d\n", FC_MAJOR, FC_MINOR, FC_REVISION); exit (0); case 'h': usage (argv[0], 0); default: usage (argv[0], 1); } } i = optind; #else i = 1; verbose = FcTrue; #endif if (i == argc) usage (argv[0], 1); if (!lang) lang = FcLangNormalize ((const FcChar8 *) setlocale (LC_CTYPE, NULL)); if (lang) fcs_lang = FcLangGetCharSet (lang); if (FT_Init_FreeType (&ftlib)) { fprintf (stderr, _("Can't initalize FreeType library\n")); return 1; } for (; i < argc; i++) { int index; index = set_index; do { FT_Face face; FcCharSet *fcs, *fcs_sub; if (FT_New_Face (ftlib, argv[i], index, &face)) { if (!index_set && index > 0) break; fprintf (stderr, _("Unable to open %s\n"), argv[i]); err = 1; } else { FcChar32 count; fcs = FcFreeTypeCharSet (face, NULL); fcs_sub = FcCharSetSubtract (fcs_lang, fcs); count = FcCharSetCount (fcs_sub); if (count > 0) { FcChar32 ucs4, pos, map[FC_CHARSET_MAP_SIZE]; printf (_("%s:%d Missing %d glyph(s) to satisfy the coverage for %s language\n"), argv[i], index, count, lang); if (verbose) { for (ucs4 = FcCharSetFirstPage (fcs_sub, map, &pos); ucs4 != FC_CHARSET_DONE; ucs4 = FcCharSetNextPage (fcs_sub, map, &pos)) { int j; for (j = 0; j < FC_CHARSET_MAP_SIZE; j++) { FcChar32 bits = map[j]; FcChar32 base = ucs4 + j * 32; int b = 0; while (bits) { if (bits & 1) printf (" 0x%04x\n", base + b); bits >>= 1; b++; } } } } } else { printf (_("%s:%d Satisfy the coverage for %s language\n"), argv[i], index, lang); } FcCharSetDestroy (fcs); FcCharSetDestroy (fcs_sub); FT_Done_Face (face); } index++; } while (index_set == 0);
FcLangSet * FcFreeTypeLangSet (const FcCharSet *charset, const FcChar8 *exclusiveLang) { int i, j; FcChar32 missing; const FcCharSet *exclusiveCharset = 0; FcLangSet *ls; if (exclusiveLang) exclusiveCharset = FcLangGetCharSet (exclusiveLang); ls = FcLangSetCreate (); if (!ls) return 0; if (FcDebug() & FC_DBG_LANGSET) { printf ("font charset\n"); FcCharSetPrint (charset); printf ("\n"); } for (i = 0; i < NUM_LANG_CHAR_SET; i++) { if (FcDebug() & FC_DBG_LANGSET) { printf ("%s charset\n", fcLangCharSets[i].lang); FcCharSetPrint (&fcLangCharSets[i].charset); printf ("\n"); } /* * Check for Han charsets to make fonts * which advertise support for a single language * not support other Han languages */ if (exclusiveCharset && FcFreeTypeIsExclusiveLang (fcLangCharSets[i].lang)) { if (fcLangCharSets[i].charset.num != exclusiveCharset->num) continue; for (j = 0; j < fcLangCharSets[i].charset.num; j++) if (FcCharSetLeaf(&fcLangCharSets[i].charset, j) != FcCharSetLeaf(exclusiveCharset, j)) continue; } missing = FcCharSetSubtractCount (&fcLangCharSets[i].charset, charset); if (FcDebug() & FC_DBG_SCANV) { if (missing && missing < 10) { FcCharSet *missed = FcCharSetSubtract (&fcLangCharSets[i].charset, charset); FcChar32 ucs4; FcChar32 map[FC_CHARSET_MAP_SIZE]; FcChar32 next; printf ("\n%s(%u) ", fcLangCharSets[i].lang, missing); printf ("{"); for (ucs4 = FcCharSetFirstPage (missed, map, &next); ucs4 != FC_CHARSET_DONE; ucs4 = FcCharSetNextPage (missed, map, &next)) { int i, j; for (i = 0; i < FC_CHARSET_MAP_SIZE; i++) if (map[i]) { for (j = 0; j < 32; j++) if (map[i] & (1 << j)) printf (" %04x", ucs4 + i * 32 + j); } } printf (" }\n\t"); FcCharSetDestroy (missed); } else printf ("%s(%u) ", fcLangCharSets[i].lang, missing); } if (!missing) FcLangSetBitSet (ls, i); } if (FcDebug() & FC_DBG_SCANV) printf ("\n"); return ls; }
static FcValue FcConfigEvaluate (FcPattern *p, FcExpr *e) { FcValue v, vl, vr; FcResult r; FcMatrix *m; FcChar8 *str; switch (e->op) { case FcOpInteger: v.type = FcTypeInteger; v.u.i = e->u.ival; break; case FcOpDouble: v.type = FcTypeDouble; v.u.d = e->u.dval; break; case FcOpString: v.type = FcTypeString; v.u.s = e->u.sval; v = FcValueSave (v); break; case FcOpMatrix: v.type = FcTypeMatrix; v.u.m = e->u.mval; v = FcValueSave (v); break; case FcOpCharSet: v.type = FcTypeCharSet; v.u.c = e->u.cval; v = FcValueSave (v); break; case FcOpLangSet: v.type = FcTypeLangSet; v.u.l = e->u.lval; v = FcValueSave (v); break; case FcOpBool: v.type = FcTypeBool; v.u.b = e->u.bval; break; case FcOpField: r = FcPatternObjectGet (p, e->u.object, 0, &v); if (r != FcResultMatch) v.type = FcTypeVoid; v = FcValueSave (v); break; case FcOpConst: if (FcNameConstant (e->u.constant, &v.u.i)) v.type = FcTypeInteger; else v.type = FcTypeVoid; break; case FcOpQuest: vl = FcConfigEvaluate (p, e->u.tree.left); if (vl.type == FcTypeBool) { if (vl.u.b) v = FcConfigEvaluate (p, e->u.tree.right->u.tree.left); else v = FcConfigEvaluate (p, e->u.tree.right->u.tree.right); } else v.type = FcTypeVoid; FcValueDestroy (vl); break; case FcOpEqual: case FcOpNotEqual: case FcOpLess: case FcOpLessEqual: case FcOpMore: case FcOpMoreEqual: case FcOpContains: case FcOpNotContains: case FcOpListing: vl = FcConfigEvaluate (p, e->u.tree.left); vr = FcConfigEvaluate (p, e->u.tree.right); v.type = FcTypeBool; v.u.b = FcConfigCompareValue (&vl, e->op, &vr); FcValueDestroy (vl); FcValueDestroy (vr); break; case FcOpOr: case FcOpAnd: case FcOpPlus: case FcOpMinus: case FcOpTimes: case FcOpDivide: vl = FcConfigEvaluate (p, e->u.tree.left); vr = FcConfigEvaluate (p, e->u.tree.right); vl = FcConfigPromote (vl, vr); vr = FcConfigPromote (vr, vl); if (vl.type == vr.type) { switch (vl.type) { case FcTypeDouble: switch (e->op) { case FcOpPlus: v.type = FcTypeDouble; v.u.d = vl.u.d + vr.u.d; break; case FcOpMinus: v.type = FcTypeDouble; v.u.d = vl.u.d - vr.u.d; break; case FcOpTimes: v.type = FcTypeDouble; v.u.d = vl.u.d * vr.u.d; break; case FcOpDivide: v.type = FcTypeDouble; v.u.d = vl.u.d / vr.u.d; break; default: v.type = FcTypeVoid; break; } if (v.type == FcTypeDouble && v.u.d == (double) (int) v.u.d) { v.type = FcTypeInteger; v.u.i = (int) v.u.d; } break; case FcTypeBool: switch (e->op) { case FcOpOr: v.type = FcTypeBool; v.u.b = vl.u.b || vr.u.b; break; case FcOpAnd: v.type = FcTypeBool; v.u.b = vl.u.b && vr.u.b; break; default: v.type = FcTypeVoid; break; } break; case FcTypeString: switch (e->op) { case FcOpPlus: v.type = FcTypeString; str = FcStrPlus (vl.u.s, vr.u.s); v.u.s = FcStrStaticName (str); FcStrFree (str); if (!v.u.s) v.type = FcTypeVoid; break; default: v.type = FcTypeVoid; break; } break; case FcTypeMatrix: switch (e->op) { case FcOpTimes: v.type = FcTypeMatrix; m = malloc (sizeof (FcMatrix)); if (m) { FcMemAlloc (FC_MEM_MATRIX, sizeof (FcMatrix)); FcMatrixMultiply (m, vl.u.m, vr.u.m); v.u.m = m; } else { v.type = FcTypeVoid; } break; default: v.type = FcTypeVoid; break; } break; case FcTypeCharSet: switch (e->op) { case FcOpPlus: v.type = FcTypeCharSet; v.u.c = FcCharSetUnion (vl.u.c, vr.u.c); if (!v.u.c) v.type = FcTypeVoid; break; case FcOpMinus: v.type = FcTypeCharSet; v.u.c = FcCharSetSubtract (vl.u.c, vr.u.c); if (!v.u.c) v.type = FcTypeVoid; break; default: v.type = FcTypeVoid; break; } break; case FcTypeLangSet: switch (e->op) { case FcOpPlus: v.type = FcTypeLangSet; v.u.l = FcLangSetUnion (vl.u.l, vr.u.l); if (!v.u.l) v.type = FcTypeVoid; break; case FcOpMinus: v.type = FcTypeLangSet; v.u.l = FcLangSetSubtract (vl.u.l, vr.u.l); if (!v.u.l) v.type = FcTypeVoid; break; default: v.type = FcTypeVoid; break; } break; default: v.type = FcTypeVoid; break; } } else v.type = FcTypeVoid; FcValueDestroy (vl); FcValueDestroy (vr); break; case FcOpNot: vl = FcConfigEvaluate (p, e->u.tree.left); switch (vl.type) { case FcTypeBool: v.type = FcTypeBool; v.u.b = !vl.u.b; break; default: v.type = FcTypeVoid; break; } FcValueDestroy (vl); break; case FcOpFloor: vl = FcConfigEvaluate (p, e->u.tree.left); switch (vl.type) { case FcTypeInteger: v = vl; break; case FcTypeDouble: v.type = FcTypeInteger; v.u.i = FcDoubleFloor (vl.u.d); break; default: v.type = FcTypeVoid; break; } FcValueDestroy (vl); break; case FcOpCeil: vl = FcConfigEvaluate (p, e->u.tree.left); switch (vl.type) { case FcTypeInteger: v = vl; break; case FcTypeDouble: v.type = FcTypeInteger; v.u.i = FcDoubleCeil (vl.u.d); break; default: v.type = FcTypeVoid; break; } FcValueDestroy (vl); break; case FcOpRound: vl = FcConfigEvaluate (p, e->u.tree.left); switch (vl.type) { case FcTypeInteger: v = vl; break; case FcTypeDouble: v.type = FcTypeInteger; v.u.i = FcDoubleRound (vl.u.d); break; default: v.type = FcTypeVoid; break; } FcValueDestroy (vl); break; case FcOpTrunc: vl = FcConfigEvaluate (p, e->u.tree.left); switch (vl.type) { case FcTypeInteger: v = vl; break; case FcTypeDouble: v.type = FcTypeInteger; v.u.i = FcDoubleTrunc (vl.u.d); break; default: v.type = FcTypeVoid; break; } FcValueDestroy (vl); break; default: v.type = FcTypeVoid; break; } return v; }