const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length)
{
#if defined(USE_FREETYPE)
    FcResult fresult;
    FontPlatformData* prim = const_cast<FontPlatformData*>(&font.primaryFont()->platformData());

    if (!prim->m_fallbacks)
        prim->m_fallbacks = FcFontSort(NULL, prim->m_pattern, FcTrue, NULL, &fresult);

    FcFontSet* fs = prim->m_fallbacks;

    for (int i = 0; i < fs->nfont; i++) {
        FcPattern* fin = FcFontRenderPrepare(NULL, prim->m_pattern, fs->fonts[i]);
        cairo_font_face_t* fontFace = cairo_ft_font_face_create_for_pattern(fin);
        FontPlatformData alternateFont(fontFace, font.fontDescription().computedPixelSize(), false, false);
        cairo_font_face_destroy(fontFace);
        alternateFont.m_pattern = fin;
        SimpleFontData* sfd = getCachedFontData(&alternateFont);
        if (sfd->containsCharacters(characters, length))
            return sfd;
    }
#endif

    return 0;
}
Beispiel #2
0
void
TkpGetSubFonts(
    Tcl_Interp *interp,
    Tk_Font tkfont)
{
    Tcl_Obj *objv[3], *listPtr, *resultPtr;
    UnixFtFont *fontPtr = (UnixFtFont *) tkfont;
    FcPattern *pattern;
    char *family = "Unknown", **familyPtr = &family;
    char *foundry = "Unknown", **foundryPtr = &foundry;
    char *encoding = "Unknown", **encodingPtr = &encoding;
    int i;

    resultPtr = Tcl_NewListObj(0, NULL);

    for (i = 0; i < fontPtr->nfaces ; ++i) {
 	pattern = FcFontRenderPrepare(0, fontPtr->pattern,
		fontPtr->faces[i].source);

	XftPatternGetString(pattern, XFT_FAMILY, 0, familyPtr);
	XftPatternGetString(pattern, XFT_FOUNDRY, 0, foundryPtr);
	XftPatternGetString(pattern, XFT_ENCODING, 0, encodingPtr);
	objv[0] = Tcl_NewStringObj(family, -1);
	objv[1] = Tcl_NewStringObj(foundry, -1);
	objv[2] = Tcl_NewStringObj(encoding, -1);
	listPtr = Tcl_NewListObj(3, objv);
	Tcl_ListObjAppendElement(NULL, resultPtr, listPtr);
    }
    Tcl_SetObjResult(interp, resultPtr);
}
Beispiel #3
0
static XftFont *
GetFont(
    UnixFtFont *fontPtr,
    FcChar32 ucs4)
{
    int i;

    if (ucs4) {
	for (i = 0; i < fontPtr->nfaces; i++) {
	    FcCharSet *charset = fontPtr->faces[i].charset;
	    if (charset && FcCharSetHasChar(charset, ucs4)) {
		break;
	    }
	}
	if (i == fontPtr->nfaces) {
	    i = 0;
	}
    } else {
	i = 0;
    }
    if (!fontPtr->faces[i].ftFont) {
	FcPattern *pat = FcFontRenderPrepare(0, fontPtr->pattern,
		fontPtr->faces[i].source);

	fontPtr->faces[i].ftFont = XftFontOpenPattern(fontPtr->display, pat);
    }
    return fontPtr->faces[i].ftFont;
}
// This method just need to bypass the cache as we could register our alternative font.
// This is a pity but is required to have asian fonts working.
PassRefPtr<SimpleFontData> FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length)
{
    // Avoid copying FontPlatformData.
    RefPtr<FontPlatformData> primaryFontPlatformData = font.primaryFont()->m_font;

    // Check if the cache was already filled.
    if (fallbacks.contains(&font)) {
        ASSERT(primaryFontPlatformData->m_fallbacks);
        FontFallbackCache::iterator it = fallbacks.find(&font);
        return it->second;
    }

    if (!primaryFontPlatformData->m_fallbacks) {
        FcResult fresult;
        primaryFontPlatformData->m_fallbacks = FcFontSort(NULL, primaryFontPlatformData->m_pattern, FcTrue, NULL, &fresult);
    }

    FcFontSet* fs = primaryFontPlatformData->m_fallbacks;
    
    for (int i = 0; i < fs->nfont; i++) {
        FcPattern* fin = FcFontRenderPrepare(0, primaryFontPlatformData->m_pattern, fs->fonts[i]);

        FcChar8* fc_filename;
        if (FcPatternGetString(fin, FC_FILE, 0, &fc_filename) != FcResultMatch)
            continue;

        char* filename = (char *) fc_filename; // Use C cast as FcChar is a fontconfig type.

        int id;
        if (FcPatternGetInteger(fin, FC_INDEX, 0, &id) != FcResultMatch)
            continue;

        FT_Face face;
        if (FT_Error error = FT_New_Face(FontPlatformData::m_library, filename, id, &face)) {
            printf("FT_New_Face failed for filename = %s with FT_Error = %d\n", filename, error);
            continue;
        }

        // FIXME: is it really necessary ?
        FT_Set_Pixel_Sizes(face, 0, static_cast<uint> (font.fontDescription().computedSize()));

        RefPtr<FontPlatformData> platformData = adoptRef(new FontPlatformData(face, font.fontDescription().computedPixelSize(), false, false));
        platformData->m_pattern = fin;

        if (platformData->containsCharacters(characters, length)) {
            RefPtr<SimpleFontData> fontData = adoptRef(new SimpleFontData(platformData.get()));
            fallbacks.add(&font, fontData);
            return fontData;
        }
    }
    // Fallback: use the font in the main cache.
    RefPtr<SimpleFontData> fontData = getCachedFontData(font.fontDescription(), font.family().family());
    return fontData;
}
Beispiel #5
0
static XftFont *
GetFont(
    UnixFtFont *fontPtr,
    FcChar32 ucs4)
{
    int i;

    if (ucs4) {
	for (i = 0; i < fontPtr->nfaces; i++) {
	    FcCharSet *charset = fontPtr->faces[i].charset;
	    if (charset && FcCharSetHasChar(charset, ucs4)) {
		break;
	    }
	}
	if (i == fontPtr->nfaces) {
	    i = 0;
	}
    } else {
	i = 0;
    }
    if (!fontPtr->faces[i].ftFont) {
	FcPattern *pat = FcFontRenderPrepare(0,
	    fontPtr->pattern, fontPtr->faces[i].source);
	XftFont *ftFont = XftFontOpenPattern(fontPtr->display, pat);

	if (!ftFont) {
	    /*
	     * The previous call to XftFontOpenPattern() should not fail,
	     * but sometimes does anyway.  Usual cause appears to be
	     * a misconfigured fontconfig installation; see [Bug 1090382].
	     * Try a fallback:
	     */
	    ftFont = XftFontOpen(fontPtr->display, fontPtr->screen,
			FC_FAMILY, FcTypeString, "sans",
			FC_SIZE, FcTypeDouble, 12.0,
			NULL);
	}
	if (!ftFont) {
	    /*
	     * The previous call should definitely not fail.
	     * Impossible to proceed at this point.
	     */
	    Tcl_Panic("Cannot find a usable font.");
	}

	fontPtr->faces[i].ftFont = ftFont;
    }
    return fontPtr->faces[i].ftFont;
}
const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length)
{
    FcResult fresult;
    // Avoid copying FontPlatformData.
    FontPlatformData* prim = const_cast<FontPlatformData*>(&font.primaryFont()->m_font);

    if (!prim->m_fallbacks)
        prim->m_fallbacks = FcFontSort(NULL, prim->m_pattern, FcTrue, NULL, &fresult);

    FcFontSet* fs = prim->m_fallbacks;
    
    FT_Library library = FontPlatformData::m_library;

    FcChar8* fc_filename;
    char* filename;
    int id;
    FT_Face face;
    for (int i = 0; i < fs->nfont; i++) {
        FcPattern* fin = FcFontRenderPrepare(0, prim->m_pattern, fs->fonts[i]);

        if (FcPatternGetString(fin, FC_FILE, 0, &fc_filename) != FcResultMatch)
            continue;

        filename = (char *) fc_filename; // Use C cast as FcChar is a fontconfig type.

        if (FcPatternGetInteger(fin, FC_INDEX, 0, &id) != FcResultMatch)
            continue;

        if (FT_Error error = FT_New_Face(library, filename, id, &face))
            continue;

        // FIXME: is it really necessary ?
        FT_Set_Pixel_Sizes(face, 0, static_cast<uint> (font.fontDescription().computedSize()));

        FontPlatformData alternateFont(face, font.fontDescription().computedPixelSize(), false, false);
        // FIXME: FT_Done_Face(face); we should clean the face correctly the FT_Face but we can't do that here...
        alternateFont.m_pattern = fin;
        SimpleFontData* sfd = getCachedFontData(&alternateFont);
        if (sfd->containsCharacters(characters, length))
            return sfd;
    }
    return 0;
}
Beispiel #7
0
/**
 * \brief Low-level font selection.
 * \param priv private data
 * \param family font family
 * \param treat_family_as_pattern treat family as fontconfig pattern
 * \param bold font weight value
 * \param italic font slant value
 * \param index out: font index inside a file
 * \param code: the character that should be present in the font, can be 0
 * \return font file path
*/
static char *select_font(ASS_Library *library, FCInstance *priv,
                          const char *family, int treat_family_as_pattern,
                          unsigned bold, unsigned italic, int *index,
                          uint32_t code)
{
    FcBool rc;
    FcResult result;
    FcPattern *pat = NULL, *rpat = NULL;
    int r_index, r_slant, r_weight;
    FcChar8 *r_family, *r_style, *r_file, *r_fullname;
    FcBool r_outline, r_embolden;
    FcCharSet *r_charset;
    FcFontSet *ffullname = NULL, *fsorted = NULL, *fset = NULL;
    int curf;
    char *retval = NULL;
    int family_cnt = 0;

    *index = 0;

    if (treat_family_as_pattern)
        pat = FcNameParse((const FcChar8 *) family);
    else
        pat = FcPatternCreate();

    if (!pat)
        goto error;

    if (!treat_family_as_pattern) {
        FcPatternAddString(pat, FC_FAMILY, (const FcChar8 *) family);

        // In SSA/ASS fonts are sometimes referenced by their "full name",
        // which is usually a concatenation of family name and font
        // style (ex. Ottawa Bold). Full name is available from
        // FontConfig pattern element FC_FULLNAME, but it is never
        // used for font matching.
        // Therefore, I'm removing words from the end of the name one
        // by one, and adding shortened names to the pattern. It seems
        // that the first value (full name in this case) has
        // precedence in matching.
        // An alternative approach could be to reimplement FcFontSort
        // using FC_FULLNAME instead of FC_FAMILY.
        family_cnt = 1;
        {
            char *s = strdup(family);
            char *p = s + strlen(s);
            while (--p > s)
                if (*p == ' ' || *p == '-') {
                    *p = '\0';
                    FcPatternAddString(pat, FC_FAMILY, (const FcChar8 *) s);
                    ++family_cnt;
                }
            free(s);
        }
    }
    FcPatternAddBool(pat, FC_OUTLINE, FcTrue);
    FcPatternAddInteger(pat, FC_SLANT, italic);
    FcPatternAddInteger(pat, FC_WEIGHT, bold);

    FcDefaultSubstitute(pat);

    rc = FcConfigSubstitute(priv->config, pat, FcMatchPattern);
    if (!rc)
        goto error;
    /* Fontconfig defaults include a language setting, which it sets based on
     * some environment variables or defaults to "en". Unset this as we don't
     * know the real language, and because some some attached fonts lack
     * non-ascii characters included in fontconfig's list of characters
     * required for English support and therefore don't match the lang=en
     * criterion.
     */
    FcPatternDel(pat, "lang");

    fsorted = FcFontSort(priv->config, pat, FcTrue, NULL, &result);
    ffullname = match_fullname(library, priv, family, bold, italic);
    if (!fsorted || !ffullname)
        goto error;

    fset = FcFontSetCreate();
    for (curf = 0; curf < ffullname->nfont; ++curf) {
        FcPattern *curp = ffullname->fonts[curf];
        FcPatternReference(curp);
        FcFontSetAdd(fset, curp);
    }
    for (curf = 0; curf < fsorted->nfont; ++curf) {
        FcPattern *curp = fsorted->fonts[curf];
        FcPatternReference(curp);
        FcFontSetAdd(fset, curp);
    }

    for (curf = 0; curf < fset->nfont; ++curf) {
        FcPattern *curp = fset->fonts[curf];

        result = FcPatternGetBool(curp, FC_OUTLINE, 0, &r_outline);
        if (result != FcResultMatch)
            continue;
        if (r_outline != FcTrue)
            continue;
        if (!code)
            break;
        result = FcPatternGetCharSet(curp, FC_CHARSET, 0, &r_charset);
        if (result != FcResultMatch)
            continue;
        if (FcCharSetHasChar(r_charset, code))
            break;
    }

    if (curf >= fset->nfont)
        goto error;

    if (!treat_family_as_pattern) {
        // Remove all extra family names from original pattern.
        // After this, FcFontRenderPrepare will select the most relevant family
        // name in case there are more than one of them.
        for (; family_cnt > 1; --family_cnt)
            FcPatternRemove(pat, FC_FAMILY, family_cnt - 1);
    }

    rpat = FcFontRenderPrepare(priv->config, pat, fset->fonts[curf]);
    if (!rpat)
        goto error;

    result = FcPatternGetInteger(rpat, FC_INDEX, 0, &r_index);
    if (result != FcResultMatch)
        goto error;
    *index = r_index;

    result = FcPatternGetString(rpat, FC_FILE, 0, &r_file);
    if (result != FcResultMatch)
        goto error;
    retval = strdup((const char *) r_file);

    result = FcPatternGetString(rpat, FC_FAMILY, 0, &r_family);
    if (result != FcResultMatch)
        r_family = NULL;

    result = FcPatternGetString(rpat, FC_FULLNAME, 0, &r_fullname);
    if (result != FcResultMatch)
        r_fullname = NULL;

    if (!treat_family_as_pattern &&
        !(r_family && strcasecmp((const char *) r_family, family) == 0) &&
        !(r_fullname && strcasecmp((const char *) r_fullname, family) == 0)) {
        char *fallback = (char *) (r_fullname ? r_fullname : r_family);
        if (code) {
            ass_msg(library, MSGL_WARN,
                    "fontconfig: cannot find glyph U+%04X in font '%s', falling back to '%s'",
                    (unsigned int)code, family, fallback);
        } else {
            ass_msg(library, MSGL_WARN,
                    "fontconfig: cannot find font '%s', falling back to '%s'",
                    family, fallback);
        }
    }

    result = FcPatternGetString(rpat, FC_STYLE, 0, &r_style);
    if (result != FcResultMatch)
        r_style = NULL;

    result = FcPatternGetInteger(rpat, FC_SLANT, 0, &r_slant);
    if (result != FcResultMatch)
        r_slant = 0;

    result = FcPatternGetInteger(rpat, FC_WEIGHT, 0, &r_weight);
    if (result != FcResultMatch)
        r_weight = 0;

    result = FcPatternGetBool(rpat, FC_EMBOLDEN, 0, &r_embolden);
    if (result != FcResultMatch)
        r_embolden = 0;

    ass_msg(library, MSGL_V,
           "Font info: family '%s', style '%s', fullname '%s',"
           " slant %d, weight %d%s", (const char *) r_family,
           (const char *) r_style, (const char *) r_fullname, r_slant,
           r_weight, r_embolden ? ", embolden" : "");

  error:
    if (pat)
        FcPatternDestroy(pat);
    if (rpat)
        FcPatternDestroy(rpat);
    if (fsorted)
        FcFontSetDestroy(fsorted);
    if (ffullname)
        FcFontSetDestroy(ffullname);
    if (fset)
        FcFontSetDestroy(fset);
    return retval;
}
Beispiel #8
0
/**
 * \brief Low-level font selection.
 * \param priv private data
 * \param family font family
 * \param bold font weight value
 * \param italic font slant value
 * \param index out: font index inside a file
 * \param code: the character that should be present in the font, can be 0
 * \return font file path
*/ 
static char* _select_font(fc_instance_t* priv, const char* family, unsigned bold, unsigned italic, int* index,
			  uint32_t code)
{
	FcBool rc;
	FcResult result;
	FcPattern *pat = NULL, *rpat = NULL;
	int r_index, r_slant, r_weight;
	FcChar8 *r_family, *r_style, *r_file, *r_fullname;
	FcBool r_outline, r_embolden;
	FcCharSet* r_charset;
	FcFontSet* fset = NULL;
	int curf;
	char* retval = NULL;
	int family_cnt;
	
	*index = 0;

	pat = FcPatternCreate();
	if (!pat)
		goto error;
	
	FcPatternAddString(pat, FC_FAMILY, (const FcChar8*)family);

	// In SSA/ASS fonts are sometimes referenced by their "full name",
	// which is usually a concatenation of family name and font
	// style (ex. Ottawa Bold). Full name is available from
	// FontConfig pattern element FC_FULLNAME, but it is never
	// used for font matching.
	// Therefore, I'm removing words from the end of the name one
	// by one, and adding shortened names to the pattern. It seems
	// that the first value (full name in this case) has
	// precedence in matching.
	// An alternative approach could be to reimplement FcFontSort
	// using FC_FULLNAME instead of FC_FAMILY.
	family_cnt = 1;
	{
		char* s = strdup(family);
		char* p = s + strlen(s);
		while (--p > s)
			if (*p == ' ' || *p == '-') {
				*p = '\0';
				FcPatternAddString(pat, FC_FAMILY, (const FcChar8*)s);
				++ family_cnt;
			}
		free(s);
	}
	FcPatternAddBool(pat, FC_OUTLINE, FcTrue);
	FcPatternAddInteger(pat, FC_SLANT, italic);
	FcPatternAddInteger(pat, FC_WEIGHT, bold);

	FcDefaultSubstitute(pat);
	
	rc = FcConfigSubstitute(priv->config, pat, FcMatchPattern);
	if (!rc)
		goto error;

	fset = FcFontSort(priv->config, pat, FcTrue, NULL, &result);
	if (!fset)
		goto error;

	for (curf = 0; curf < fset->nfont; ++curf) {
		FcPattern* curp = fset->fonts[curf];

		result = FcPatternGetBool(curp, FC_OUTLINE, 0, &r_outline);
		if (result != FcResultMatch)
			continue;
		if (r_outline != FcTrue)
			continue;
		if (!code)
			break;
		result = FcPatternGetCharSet(curp, FC_CHARSET, 0, &r_charset);
		if (result != FcResultMatch)
			continue;
		if (FcCharSetHasChar(r_charset, code))
			break;
	}

	if (curf >= fset->nfont)
		goto error;

#if (FC_VERSION >= 20297)
	// Remove all extra family names from original pattern.
	// After this, FcFontRenderPrepare will select the most relevant family
	// name in case there are more than one of them.
	for (; family_cnt > 1; --family_cnt)
		FcPatternRemove(pat, FC_FAMILY, family_cnt - 1);
#endif

	rpat = FcFontRenderPrepare(priv->config, pat, fset->fonts[curf]);
	if (!rpat)
		goto error;

	result = FcPatternGetInteger(rpat, FC_INDEX, 0, &r_index);
	if (result != FcResultMatch)
		goto error;
	*index = r_index;

	result = FcPatternGetString(rpat, FC_FILE, 0, &r_file);
	if (result != FcResultMatch)
		goto error;
	retval = strdup((const char*)r_file);

	result = FcPatternGetString(rpat, FC_FAMILY, 0, &r_family);
	if (result != FcResultMatch)
		r_family = NULL;

	result = FcPatternGetString(rpat, FC_FULLNAME, 0, &r_fullname);
	if (result != FcResultMatch)
		r_fullname = NULL;

	if (!(r_family && strcasecmp((const char*)r_family, family) == 0) &&
	    !(r_fullname && strcasecmp((const char*)r_fullname, family) == 0))
		mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_SelectedFontFamilyIsNotTheRequestedOne,
		       (const char*)(r_fullname ? r_fullname : r_family), family);

	result = FcPatternGetString(rpat, FC_STYLE, 0, &r_style);
	if (result != FcResultMatch)
		r_style = NULL;

	result = FcPatternGetInteger(rpat, FC_SLANT, 0, &r_slant);
	if (result != FcResultMatch)
		r_slant = 0;

	result = FcPatternGetInteger(rpat, FC_WEIGHT, 0, &r_weight);
	if (result != FcResultMatch)
		r_weight = 0;

	result = FcPatternGetBool(rpat, FC_EMBOLDEN, 0, &r_embolden);
	if (result != FcResultMatch)
		r_embolden = 0;

	mp_msg(MSGT_ASS, MSGL_V, "[ass] Font info: family '%s', style '%s', fullname '%s',"
	       " slant %d, weight %d%s\n",
	       (const char*)r_family, (const char*)r_style, (const char*)r_fullname,
	       r_slant, r_weight, r_embolden ? ", embolden" : "");

 error:
	if (pat) FcPatternDestroy(pat);
	if (rpat) FcPatternDestroy(rpat);
	if (fset) FcFontSetDestroy(fset);
	return retval;
}
int
main (int argc, char **argv)
{
    int			verbose = 0;
    int			sort = 0, all = 0;
    const FcChar8	*format = NULL;
    int			i;
    FcObjectSet		*os = 0;
    FcFontSet		*fs;
    FcPattern		*pat;
    FcResult		result;
#if HAVE_GETOPT_LONG || HAVE_GETOPT
    int			c;

#if HAVE_GETOPT_LONG
    while ((c = getopt_long (argc, argv, "asvf:Vh", longopts, NULL)) != -1)
#else
    while ((c = getopt (argc, argv, "asvf:Vh")) != -1)
#endif
    {
	switch (c) {
	case 'a':
	    all = 1;
	    break;
	case 's':
	    sort = 1;
	    break;
	case 'v':
	    verbose = 1;
	    break;
	case 'f':
	    format = (FcChar8 *) strdup (optarg);
	    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;
#endif

    if (!FcInit ())
    {
	fprintf (stderr, "Can't init font config library\n");
	return 1;
    }
    if (argv[i])
    {
	pat = FcNameParse ((FcChar8 *) argv[i]);
	while (argv[++i])
	{
	    if (!os)
		os = FcObjectSetCreate ();
	    FcObjectSetAdd (os, argv[i]);
	}
    }
    else
	pat = FcPatternCreate ();

    if (!pat)
	return 1;

    FcConfigSubstitute (0, pat, FcMatchPattern);
    FcDefaultSubstitute (pat);
    
    fs = FcFontSetCreate ();

    if (sort || all)
    {
	FcFontSet	*font_patterns;
	int	j;
	font_patterns = FcFontSort (0, pat, all ? FcFalse : FcTrue, 0, &result);

	if (!font_patterns || font_patterns->nfont == 0)
	{
	    fputs("No fonts installed on the system\n", stderr);
	    return 1;
	}
	for (j = 0; j < font_patterns->nfont; j++)
	{
	    FcPattern  *font_pattern;

	    font_pattern = FcFontRenderPrepare (NULL, pat, font_patterns->fonts[j]);
	    if (font_pattern)
		FcFontSetAdd (fs, font_pattern);
	}

	FcFontSetSortDestroy (font_patterns);
    }
    else
    {
	FcPattern   *match;
	match = FcFontMatch (0, pat, &result);
	if (match)
	    FcFontSetAdd (fs, match);
    }
    FcPatternDestroy (pat);

    if (!format)
    {
	if (os)
	    format = (const FcChar8 *) "%{=unparse}\n";
	else
	    format = (const FcChar8 *) "%{=fcmatch}\n";
    }

    if (fs)
    {
	int	j;

	for (j = 0; j < fs->nfont; j++)
	{
	    FcPattern *font;

	    font = FcPatternFilter (fs->fonts[j], os);

	    if (verbose)
	    {
		FcPatternPrint (font);
	    }
	    else
	    {
	        FcChar8 *s;

		s = FcPatternFormat (font, format);
		if (s)
		{
		    printf ("%s", s);
		    free (s);
		}
	    }

	    FcPatternDestroy (font);
	}
	FcFontSetDestroy (fs);
    }

    if (os)
	FcObjectSetDestroy (os);

    FcFini ();

    return 0;
}
Beispiel #10
0
static XftFont *
GetFont(
    UnixFtFont *fontPtr,
    FcChar32 ucs4,
    double angle)
{
    int i;

    if (ucs4) {
	for (i = 0; i < fontPtr->nfaces; i++) {
	    FcCharSet *charset = fontPtr->faces[i].charset;

	    if (charset && FcCharSetHasChar(charset, ucs4)) {
		break;
	    }
	}
	if (i == fontPtr->nfaces) {
	    i = 0;
	}
    } else {
	i = 0;
    }
    if ((angle == 0.0 && !fontPtr->faces[i].ft0Font) || (angle != 0.0 &&
	    (!fontPtr->faces[i].ftFont || fontPtr->faces[i].angle != angle))){
	FcPattern *pat = FcFontRenderPrepare(0, fontPtr->pattern,
		fontPtr->faces[i].source);
	double s = sin(angle*PI/180.0), c = cos(angle*PI/180.0);
	FcMatrix mat;
	XftFont *ftFont;

	/*
	 * Initialize the matrix manually so this can compile with HP-UX cc
	 * (which does not allow non-constant structure initializers). [Bug
	 * 2978410]
	 */

	mat.xx = mat.yy = c;
	mat.xy = -(mat.yx = s);

	if (angle != 0.0) {
	    FcPatternAddMatrix(pat, FC_MATRIX, &mat);
	}
	ftFont = XftFontOpenPattern(fontPtr->display, pat);
	if (!ftFont) {
	    /*
	     * The previous call to XftFontOpenPattern() should not fail, but
	     * sometimes does anyway. Usual cause appears to be a
	     * misconfigured fontconfig installation; see [Bug 1090382]. Try a
	     * fallback:
	     */

	    ftFont = XftFontOpen(fontPtr->display, fontPtr->screen,
		    FC_FAMILY, FcTypeString, "sans",
		    FC_SIZE, FcTypeDouble, 12.0,
		    FC_MATRIX, FcTypeMatrix, &mat,
		    NULL);
	}
	if (!ftFont) {
	    /*
	     * The previous call should definitely not fail. Impossible to
	     * proceed at this point.
	     */

	    Tcl_Panic("Cannot find a usable font");
	}

	if (angle == 0.0) {
	    fontPtr->faces[i].ft0Font = ftFont;
	} else {
	    if (fontPtr->faces[i].ftFont) {
		XftFontClose(fontPtr->display, fontPtr->faces[i].ftFont);
	    }
	    fontPtr->faces[i].ftFont = ftFont;
	    fontPtr->faces[i].angle = angle;
	}
    }
    return (angle==0.0? fontPtr->faces[i].ft0Font : fontPtr->faces[i].ftFont);
}