diff options
Diffstat (limited to 'unix/tkUnixRFont.c')
-rw-r--r-- | unix/tkUnixRFont.c | 292 |
1 files changed, 257 insertions, 35 deletions
diff --git a/unix/tkUnixRFont.c b/unix/tkUnixRFont.c index 0a6be20..00b8095 100644 --- a/unix/tkUnixRFont.c +++ b/unix/tkUnixRFont.c @@ -8,7 +8,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkUnixRFont.c,v 1.26 2008/11/05 22:20:59 nijtmans Exp $ + * RCS: @(#) $Id: tkUnixRFont.c,v 1.27 2008/11/22 18:08:51 dkf Exp $ */ #include "tkUnixInt.h" @@ -18,8 +18,10 @@ typedef struct { XftFont *ftFont; + XftFont *ft0Font; FcPattern *source; FcCharSet *charset; + double angle; } UnixFtFace; typedef struct { @@ -62,13 +64,15 @@ TkpFontPkgInit( static XftFont * GetFont( UnixFtFont *fontPtr, - FcChar32 ucs4) + 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; } @@ -79,34 +83,52 @@ GetFont( } 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 ((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 = {c, -s, s, c}; + XftFont *ftFont; + 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: + * 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); + 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. + * 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; + 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 fontPtr->faces[i].ftFont; + return (angle==0.0? fontPtr->faces[i].ft0Font : fontPtr->faces[i].ftFont); } /* @@ -126,10 +148,10 @@ GetTkFontAttributes( int weight, slant, size, pxsize; double ptsize; - (void)XftPatternGetString(ftFont->pattern, XFT_FAMILY, 0, familyPtr); + (void) XftPatternGetString(ftFont->pattern, XFT_FAMILY, 0, familyPtr); if (XftPatternGetDouble(ftFont->pattern, XFT_SIZE, 0, &ptsize) == XftResultMatch) { - size = (int)ptsize; + size = (int) ptsize; } else if (XftPatternGetInteger(ftFont->pattern, XFT_PIXEL_SIZE, 0, &pxsize) == XftResultMatch) { size = -pxsize; @@ -165,7 +187,8 @@ GetTkFontAttributes( * Fill in TkFontMetrics from an XftFont. */ -static void GetTkFontMetrics( +static void +GetTkFontMetrics( XftFont *ftFont, TkFontMetrics *fmPtr) { @@ -222,7 +245,7 @@ InitFont( set = FcFontSort(0, pattern, FcTrue, NULL, &result); if (!set) { FcPatternDestroy(pattern); - ckfree((char *)fontPtr); + ckfree((char *) fontPtr); return NULL; } @@ -237,6 +260,7 @@ InitFont( for (i = 0; i < set->nfont; i++) { fontPtr->faces[i].ftFont = 0; + fontPtr->faces[i].ft0Font = 0; fontPtr->faces[i].source = set->fonts[i]; if (FcPatternGetCharSet(set->fonts[i], FC_CHARSET, 0, &charset) == FcResultMatch) { @@ -244,6 +268,7 @@ InitFont( } else { fontPtr->faces[i].charset = 0; } + fontPtr->faces[i].angle = 0.0; } fontPtr->display = Tk_Display(tkwin); @@ -258,7 +283,8 @@ InitFont( /* * Fill in platform-specific fields of TkFont. */ - ftFont = GetFont(fontPtr, 0); + + ftFont = GetFont(fontPtr, 0, 0.0); fontPtr->font.fid = XLoadFont(Tk_Display(tkwin), "fixed"); GetTkFontAttributes(ftFont, &fontPtr->font.fa); GetTkFontMetrics(ftFont, &fontPtr->font.fm); @@ -272,19 +298,22 @@ FinishedWithFont( { Display *display = fontPtr->display; int i; - Tk_ErrorHandler handler = Tk_CreateErrorHandler(display, -1, -1, -1, NULL, - (ClientData) NULL); + Tk_ErrorHandler handler = + Tk_CreateErrorHandler(display, -1, -1, -1, NULL, NULL); for (i = 0; i < fontPtr->nfaces; i++) { if (fontPtr->faces[i].ftFont) { XftFontClose(fontPtr->display, fontPtr->faces[i].ftFont); } + if (fontPtr->faces[i].ft0Font) { + XftFontClose(fontPtr->display, fontPtr->faces[i].ft0Font); + } if (fontPtr->faces[i].charset) { FcCharSetDestroy(fontPtr->faces[i].charset); } } if (fontPtr->faces) { - ckfree((char *)fontPtr->faces); + ckfree((char *) fontPtr->faces); } if (fontPtr->pattern) { FcPatternDestroy(fontPtr->pattern); @@ -432,14 +461,15 @@ TkpGetFontFamilies( resultPtr = Tcl_NewListObj(0, NULL); list = XftListFonts(Tk_Display(tkwin), Tk_ScreenNumber(tkwin), - (char*)0, /* pattern elements */ - XFT_FAMILY, (char*)0); /* fields */ + (char *) 0, /* pattern elements */ + XFT_FAMILY, (char*) 0); /* fields */ for (i = 0; i < list->nfont; i++) { char *family, **familyPtr = &family; + if (XftPatternGetString(list->fonts[i], XFT_FAMILY, 0, familyPtr) - == XftResultMatch) - { + == XftResultMatch) { Tcl_Obj *strPtr = Tcl_NewStringObj(family, -1); + Tcl_ListObjAppendElement(NULL, resultPtr, strPtr); } } @@ -517,7 +547,7 @@ TkpGetFontAttrsForChar( /* Structure describing the logical font */ FcChar32 ucs4 = (FcChar32) c; /* UCS-4 character to map */ - XftFont *ftFont = GetFont(fontPtr, ucs4); + XftFont *ftFont = GetFont(fontPtr, ucs4, 0.0); /* Actual font used to render the character */ GetTkFontAttributes(ftFont, faPtr); @@ -566,7 +596,7 @@ Tk_MeasureChars( Tcl_UniChar unichar; clen = Tcl_UtfToUniChar(source, &unichar); - c = (FcChar32)unichar; + c = (FcChar32) unichar; if (clen <= 0) { /* @@ -592,7 +622,7 @@ Tk_MeasureChars( #if DEBUG_FONTSEL string[len++] = (char) c; #endif /* DEBUG_FONTSEL */ - ftFont = GetFont(fontPtr, c); + ftFont = GetFont(fontPtr, c, 0.0); XftTextExtents32(fontPtr->display, ftFont, &c, 1, &extents); @@ -674,8 +704,8 @@ Tk_DrawChars( DefaultVisual(display, fontPtr->screen), DefaultColormap(display, fontPtr->screen)); } else { - Tk_ErrorHandler handler = Tk_CreateErrorHandler(display, -1, -1, -1, - NULL, (ClientData) NULL); + Tk_ErrorHandler handler = + Tk_CreateErrorHandler(display, -1, -1, -1, NULL, NULL); XftDrawChange(fontPtr->ftDraw, drawable); Tk_DeleteErrorHandler(handler); @@ -707,7 +737,7 @@ Tk_DrawChars( source += clen; numBytes -= clen; - ftFont = GetFont(fontPtr, c); + ftFont = GetFont(fontPtr, c, 0.0); if (ftFont) { specs[nspec].font = ftFont; specs[nspec].glyph = XftCharIndex(fontPtr->display, ftFont, c); @@ -729,3 +759,195 @@ Tk_DrawChars( XftDrawGlyphFontSpec(fontPtr->ftDraw, &fontPtr->color, specs, nspec); } } + +void +TkpDrawAngledChars( + Display *display, /* Display on which to draw. */ + Drawable drawable, /* Window or pixmap in which to draw. */ + GC gc, /* Graphics context for drawing characters. */ + Tk_Font tkfont, /* Font in which characters will be drawn; + * must be the same as font used in GC. */ + const char *source, /* UTF-8 string to be displayed. Need not be + * '\0' terminated. All Tk meta-characters + * (tabs, control characters, and newlines) + * should be stripped out of the string that + * is passed to this function. If they are not + * stripped out, they will be displayed as + * regular printing characters. */ + int numBytes, /* Number of bytes in string. */ + double x, double y, /* Coordinates at which to place origin of + * string when drawing. */ + double angle) /* What angle to put text at, in degrees. */ +{ + const int maxCoord = 0x7FFF;/* Xft coordinates are 16 bit values */ + const int minCoord = -1000; /* Should be good enough... */ + UnixFtFont *fontPtr = (UnixFtFont *) tkfont; + XGCValues values; + XColor xcolor; +#ifdef XFT_HAS_FIXED_ROTATED_PLACEMENT + int clen, nglyph; + FT_UInt glyphs[NUM_SPEC]; + XGlyphInfo metrics; + XftFont *currentFtFont; + int originX, originY; + + if (fontPtr->ftDraw == 0) { +#if DEBUG_FONTSEL + printf("Switch to drawable 0x%x\n", drawable); +#endif /* DEBUG_FONTSEL */ + fontPtr->ftDraw = XftDrawCreate(display, drawable, + DefaultVisual(display, fontPtr->screen), + DefaultColormap(display, fontPtr->screen)); + } else { + Tk_ErrorHandler handler = + Tk_CreateErrorHandler(display, -1, -1, -1, NULL, NULL); + + XftDrawChange(fontPtr->ftDraw, drawable); + Tk_DeleteErrorHandler(handler); + } + + XGetGCValues(display, gc, GCForeground, &values); + if (values.foreground != fontPtr->color.pixel) { + xcolor.pixel = values.foreground; + XQueryColor(display, DefaultColormap(display, fontPtr->screen), + &xcolor); + fontPtr->color.color.red = xcolor.red; + fontPtr->color.color.green = xcolor.green; + fontPtr->color.color.blue = xcolor.blue; + fontPtr->color.color.alpha = 0xffff; + fontPtr->color.pixel = values.foreground; + } + + nglyph = 0; + currentFtFont = NULL; + originX = originY = 0; /* lint */ + + while (numBytes > 0 && x <= maxCoord && x >= minCoord && y <= maxCoord + && y >= minCoord) { + XftFont *ftFont; + FcChar32 c; + + clen = FcUtf8ToUcs4((FcChar8 *) source, &c, numBytes); + if (clen <= 0) { + /* + * This should not happen, but it can. + */ + + return; + } + source += clen; + numBytes -= clen; + + ftFont = GetFont(fontPtr, c, angle); + if (!ftFont) { + continue; + } + + if (ftFont != currentFtFont || nglyph == NUM_SPEC) { + if (nglyph) { + /* + * We pass multiple glyphs at once to enable the code to + * perform better rendering of sub-pixel inter-glyph spacing. + * If only the current Xft implementation could make use of + * this information... but we'll be ready when it does! + */ + + XftDrawGlyphs(fontPtr->ftDraw, &fontPtr->color, currentFtFont, + originX, originY, glyphs, nglyph); + } + originX = (int) floor(x + 0.5); + originY = (int) floor(y + 0.5); + if (nglyph) { + XftGlyphExtents(fontPtr->display, currentFtFont, glyphs, + nglyph, &metrics); + nglyph = 0; + x += metrics.xOff; + y += metrics.yOff; + } + currentFtFont = ftFont; + } + glyphs[nglyph++] = XftCharIndex(fontPtr->display, ftFont, c); + } + if (nglyph) { + XftDrawGlyphs(fontPtr->ftDraw, &fontPtr->color, currentFtFont, + originX, originY, glyphs, nglyph); + } +#else /* !XFT_HAS_FIXED_ROTATED_PLACEMENT */ + int clen, nspec; + XftGlyphFontSpec specs[NUM_SPEC]; + XGlyphInfo metrics; + double sinA = sin(angle * PI/180.0), cosA = cos(angle * PI/180.0); + + if (fontPtr->ftDraw == 0) { +#if DEBUG_FONTSEL + printf("Switch to drawable 0x%x\n", drawable); +#endif /* DEBUG_FONTSEL */ + fontPtr->ftDraw = XftDrawCreate(display, drawable, + DefaultVisual(display, fontPtr->screen), + DefaultColormap(display, fontPtr->screen)); + } else { + Tk_ErrorHandler handler = + Tk_CreateErrorHandler(display, -1, -1, -1, NULL, NULL); + + XftDrawChange(fontPtr->ftDraw, drawable); + Tk_DeleteErrorHandler(handler); + } + XGetGCValues(display, gc, GCForeground, &values); + if (values.foreground != fontPtr->color.pixel) { + xcolor.pixel = values.foreground; + XQueryColor(display, DefaultColormap(display, fontPtr->screen), + &xcolor); + fontPtr->color.color.red = xcolor.red; + fontPtr->color.color.green = xcolor.green; + fontPtr->color.color.blue = xcolor.blue; + fontPtr->color.color.alpha = 0xffff; + fontPtr->color.pixel = values.foreground; + } + nspec = 0; + while (numBytes > 0 && x <= maxCoord && x >= minCoord + && y <= maxCoord && y >= minCoord) { + XftFont *ftFont, *ft0Font; + FcChar32 c; + + clen = FcUtf8ToUcs4((FcChar8 *) source, &c, numBytes); + if (clen <= 0) { + /* + * This should not happen, but it can. + */ + + return; + } + source += clen; + numBytes -= clen; + + ftFont = GetFont(fontPtr, c, angle); + ft0Font = GetFont(fontPtr, c, 0.0); + if (ftFont && ft0Font) { + specs[nspec].font = ftFont; + specs[nspec].glyph = XftCharIndex(fontPtr->display, ftFont, c); + specs[nspec].x = (int) floor(x + 0.5); + specs[nspec].y = (int) floor(y + 0.5); + XftGlyphExtents(fontPtr->display, ft0Font, &specs[nspec].glyph, 1, + &metrics); + x += metrics.xOff*cosA + metrics.yOff*sinA; + y += metrics.yOff*cosA - metrics.xOff*sinA; + nspec++; + if (nspec == NUM_SPEC) { + XftDrawGlyphFontSpec(fontPtr->ftDraw, &fontPtr->color, + specs, nspec); + nspec = 0; + } + } + } + if (nspec) { + XftDrawGlyphFontSpec(fontPtr->ftDraw, &fontPtr->color, specs, nspec); + } +#endif /* XFT_HAS_FIXED_ROTATED_PLACEMENT */ +} + +/* + * Local Variables: + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ |