summaryrefslogtreecommitdiffstats
path: root/unix/tkUnixRFont.c
diff options
context:
space:
mode:
Diffstat (limited to 'unix/tkUnixRFont.c')
-rw-r--r--unix/tkUnixRFont.c819
1 files changed, 819 insertions, 0 deletions
diff --git a/unix/tkUnixRFont.c b/unix/tkUnixRFont.c
new file mode 100644
index 0000000..fd0b556
--- /dev/null
+++ b/unix/tkUnixRFont.c
@@ -0,0 +1,819 @@
+/*
+ * tkUnixRFont.c --
+ *
+ * Alternate implementation of tkUnixFont.c using Xft.
+ *
+ * Copyright (c) 2002-2003 Keith Packard
+ *
+ * See the file "license.terms" for information on usage and redistribution of
+ * this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ */
+
+#include "tkUnixInt.h"
+#include "tkFont.h"
+#include <X11/Xft/Xft.h>
+#include <ctype.h>
+
+typedef struct {
+ XftFont *ftFont;
+ FcPattern *source;
+ FcCharSet *charset;
+} UnixFtFace;
+
+typedef struct {
+ TkFont font; /* Stuff used by generic font package. Must be
+ * first in structure. */
+ UnixFtFace *faces;
+ int nfaces;
+ FcFontSet *fontset;
+ FcPattern *pattern;
+
+ Display *display;
+ int screen;
+ XftDraw *ftDraw;
+ XftColor color;
+} UnixFtFont;
+
+/*
+ * Used to describe the current clipping box. Can't be passed normally because
+ * the information isn't retrievable from the GC.
+ */
+
+typedef struct ThreadSpecificData {
+ Region clipRegion; /* The clipping region, or None. */
+} ThreadSpecificData;
+static Tcl_ThreadDataKey dataKey;
+
+/*
+ * Package initialization:
+ * Nothing to do here except register the fact that we're using Xft in
+ * the TIP 59 configuration database.
+ */
+
+#ifndef TCL_CFGVAL_ENCODING
+#define TCL_CFGVAL_ENCODING "ascii"
+#endif
+
+void
+TkpFontPkgInit(
+ TkMainInfo *mainPtr) /* The application being created. */
+{
+ static Tcl_Config cfg[] = {
+ { "fontsystem", "xft" },
+ { 0,0 }
+ };
+
+ Tcl_RegisterConfig(mainPtr->interp, "tk", cfg, TCL_CFGVAL_ENCODING);
+}
+
+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;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * GetTkFontAttributes --
+ * Fill in TkFontAttributes from an XftFont.
+ */
+
+static void
+GetTkFontAttributes(
+ XftFont *ftFont,
+ TkFontAttributes *faPtr)
+{
+ char *family = "Unknown", **familyPtr = &family;
+ int weight, slant, size, pxsize;
+ double ptsize;
+
+ (void)XftPatternGetString(ftFont->pattern, XFT_FAMILY, 0, familyPtr);
+ if (XftPatternGetDouble(ftFont->pattern, XFT_SIZE, 0,
+ &ptsize) == XftResultMatch) {
+ size = (int)ptsize;
+ } else if (XftPatternGetInteger(ftFont->pattern, XFT_PIXEL_SIZE, 0,
+ &pxsize) == XftResultMatch) {
+ size = -pxsize;
+ } else {
+ size = 12;
+ }
+ if (XftPatternGetInteger(ftFont->pattern, XFT_WEIGHT, 0,
+ &weight) != XftResultMatch) {
+ weight = XFT_WEIGHT_MEDIUM;
+ }
+ if (XftPatternGetInteger(ftFont->pattern, XFT_SLANT, 0,
+ &slant) != XftResultMatch) {
+ slant = XFT_SLANT_ROMAN;
+ }
+
+#if DEBUG_FONTSEL
+ printf("family %s size %d weight %d slant %d\n",
+ family, size, weight, slant);
+#endif /* DEBUG_FONTSEL */
+
+ faPtr->family = Tk_GetUid(family);
+ faPtr->size = size;
+ faPtr->weight = (weight > XFT_WEIGHT_MEDIUM) ? TK_FW_BOLD : TK_FW_NORMAL;
+ faPtr->slant = (slant > XFT_SLANT_ROMAN) ? TK_FS_ITALIC : TK_FS_ROMAN;
+ faPtr->underline = 0;
+ faPtr->overstrike = 0;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * GetTkFontMetrics --
+ * Fill in TkFontMetrics from an XftFont.
+ */
+
+static void GetTkFontMetrics(
+ XftFont *ftFont,
+ TkFontMetrics *fmPtr)
+{
+ int spacing;
+
+ if (XftPatternGetInteger(ftFont->pattern, XFT_SPACING, 0,
+ &spacing) != XftResultMatch) {
+ spacing = XFT_PROPORTIONAL;
+ }
+
+ fmPtr->ascent = ftFont->ascent;
+ fmPtr->descent = ftFont->descent;
+ fmPtr->maxWidth = ftFont->max_advance_width;
+ fmPtr->fixed = spacing != XFT_PROPORTIONAL;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * InitFont --
+ *
+ * Initializes the fields of a UnixFtFont structure. If fontPtr is NULL,
+ * also allocates a new UnixFtFont.
+ *
+ * Results:
+ * On error, frees fontPtr and returns NULL, otherwise returns fontPtr.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+static UnixFtFont *
+InitFont(
+ Tk_Window tkwin,
+ FcPattern *pattern,
+ UnixFtFont *fontPtr)
+{
+ FcFontSet *set;
+ FcCharSet *charset;
+ FcResult result;
+ XftFont *ftFont;
+ int i;
+
+ if (!fontPtr) {
+ fontPtr = (UnixFtFont *) ckalloc(sizeof(UnixFtFont));
+ }
+
+ FcConfigSubstitute(0, pattern, FcMatchPattern);
+ XftDefaultSubstitute(Tk_Display(tkwin), Tk_ScreenNumber(tkwin), pattern);
+
+ /*
+ * Generate the list of fonts
+ */
+
+ set = FcFontSort(0, pattern, FcTrue, NULL, &result);
+ if (!set) {
+ ckfree((char *)fontPtr);
+ return NULL;
+ }
+
+ fontPtr->fontset = set;
+ fontPtr->pattern = pattern;
+ fontPtr->faces = (UnixFtFace *) ckalloc(set->nfont * sizeof(UnixFtFace));
+ fontPtr->nfaces = set->nfont;
+
+ /*
+ * Fill in information about each returned font
+ */
+
+ for (i = 0; i < set->nfont; i++) {
+ fontPtr->faces[i].ftFont = 0;
+ fontPtr->faces[i].source = set->fonts[i];
+ if (FcPatternGetCharSet(set->fonts[i], FC_CHARSET, 0,
+ &charset) == FcResultMatch) {
+ fontPtr->faces[i].charset = FcCharSetCopy(charset);
+ } else {
+ fontPtr->faces[i].charset = 0;
+ }
+ }
+
+ fontPtr->display = Tk_Display(tkwin);
+ fontPtr->screen = Tk_ScreenNumber(tkwin);
+ fontPtr->ftDraw = 0;
+ fontPtr->color.color.red = 0;
+ fontPtr->color.color.green = 0;
+ fontPtr->color.color.blue = 0;
+ fontPtr->color.color.alpha = 0xffff;
+ fontPtr->color.pixel = 0xffffffff;
+
+ /*
+ * Fill in platform-specific fields of TkFont.
+ */
+ ftFont = GetFont(fontPtr, 0);
+ fontPtr->font.fid = XLoadFont(Tk_Display(tkwin), "fixed");
+ GetTkFontAttributes(ftFont, &fontPtr->font.fa);
+ GetTkFontMetrics(ftFont, &fontPtr->font.fm);
+
+ /*
+ * Fontconfig can't report any information about the position or thickness
+ * of underlines or overstrikes. Thus, we use some defaults that are
+ * hacked around from backup defaults in tkUnixFont.c, which are in turn
+ * based on recommendations in the X manual. The comments from that file
+ * leading to these computations were:
+ *
+ * If the XA_UNDERLINE_POSITION property does not exist, the X manual
+ * recommends using half the descent.
+ *
+ * If the XA_UNDERLINE_THICKNESS property does not exist, the X
+ * manual recommends using the width of the stem on a capital letter.
+ * I don't know of a way to get the stem width of a letter, so guess
+ * and use 1/3 the width of a capital I.
+ *
+ * Note that nothing corresponding to *either* property is reported by
+ * Fontconfig at all. [Bug 1961455]
+ */
+
+ {
+ TkFont *fPtr = &fontPtr->font;
+ int iWidth;
+
+ fPtr->underlinePos = fPtr->fm.descent / 2;
+ Tk_MeasureChars((Tk_Font) fPtr, "I", 1, -1, 0, &iWidth);
+ fPtr->underlineHeight = iWidth / 3;
+ if (fPtr->underlineHeight == 0) {
+ fPtr->underlineHeight = 1;
+ }
+ if (fPtr->underlineHeight + fPtr->underlinePos > fPtr->fm.descent) {
+ fPtr->underlineHeight = fPtr->fm.descent - fPtr->underlinePos;
+ if (fPtr->underlineHeight == 0) {
+ fPtr->underlinePos--;
+ fPtr->underlineHeight = 1;
+ }
+ }
+ }
+
+ return fontPtr;
+}
+
+static void
+FinishedWithFont(
+ UnixFtFont *fontPtr)
+{
+ Display *display = fontPtr->display;
+ int i;
+ Tk_ErrorHandler handler = Tk_CreateErrorHandler(display, -1, -1, -1, NULL,
+ (ClientData) NULL);
+
+ for (i = 0; i < fontPtr->nfaces; i++) {
+ if (fontPtr->faces[i].ftFont) {
+ XftFontClose(fontPtr->display, fontPtr->faces[i].ftFont);
+ }
+ if (fontPtr->faces[i].charset) {
+ FcCharSetDestroy(fontPtr->faces[i].charset);
+ }
+ }
+ if (fontPtr->faces) {
+ ckfree((char *)fontPtr->faces);
+ }
+ if (fontPtr->pattern) {
+ FcPatternDestroy(fontPtr->pattern);
+ }
+ if (fontPtr->ftDraw) {
+ XftDrawDestroy(fontPtr->ftDraw);
+ }
+ if (fontPtr->font.fid) {
+ XUnloadFont(fontPtr->display, fontPtr->font.fid);
+ }
+ if (fontPtr->fontset) {
+ FcFontSetDestroy(fontPtr->fontset);
+ }
+ Tk_DeleteErrorHandler(handler);
+}
+
+TkFont *
+TkpGetNativeFont(
+ Tk_Window tkwin, /* For display where font will be used. */
+ CONST char *name) /* Platform-specific font name. */
+{
+ UnixFtFont *fontPtr;
+ FcPattern *pattern;
+#if DEBUG_FONTSEL
+ printf("TkpGetNativeFont %s\n", name);
+#endif /* DEBUG_FONTSEL */
+
+ pattern = XftXlfdParse(name, FcFalse, FcFalse);
+ if (!pattern) {
+ return NULL;
+ }
+
+ /*
+ * Should also try: pattern = FcNameParse(name); but generic/tkFont.c
+ * expects TkpGetNativeFont() to only work on XLFD names under Unix.
+ */
+
+ fontPtr = InitFont(tkwin, pattern, NULL);
+ if (!fontPtr) {
+ FcPatternDestroy(pattern);
+ return NULL;
+ }
+ return &fontPtr->font;
+}
+
+TkFont *
+TkpGetFontFromAttributes(
+ TkFont *tkFontPtr, /* If non-NULL, store the information in this
+ * existing TkFont structure, rather than
+ * allocating a new structure to hold the
+ * font; the existing contents of the font
+ * will be released. If NULL, a new TkFont
+ * structure is allocated. */
+ Tk_Window tkwin, /* For display where font will be used. */
+ CONST TkFontAttributes *faPtr)
+ /* Set of attributes to match. */
+{
+ XftPattern *pattern;
+ int weight, slant;
+ UnixFtFont *fontPtr;
+
+#if DEBUG_FONTSEL
+ printf("TkpGetFontFromAttributes %s-%d %d %d\n", faPtr->family,
+ faPtr->size, faPtr->weight, faPtr->slant);
+#endif /* DEBUG_FONTSEL */
+ pattern = XftPatternCreate();
+ if (faPtr->family) {
+ XftPatternAddString(pattern, XFT_FAMILY, faPtr->family);
+ }
+ if (faPtr->size > 0) {
+ XftPatternAddDouble(pattern, XFT_SIZE, (double)faPtr->size);
+ } else if (faPtr->size < 0) {
+ XftPatternAddInteger(pattern, XFT_PIXEL_SIZE, -faPtr->size);
+ } else {
+ XftPatternAddDouble(pattern, XFT_SIZE, 12.0);
+ }
+ switch (faPtr->weight) {
+ case TK_FW_NORMAL:
+ default:
+ weight = XFT_WEIGHT_MEDIUM;
+ break;
+ case TK_FW_BOLD:
+ weight = XFT_WEIGHT_BOLD;
+ break;
+ }
+ XftPatternAddInteger(pattern, XFT_WEIGHT, weight);
+ switch (faPtr->slant) {
+ case TK_FS_ROMAN:
+ default:
+ slant = XFT_SLANT_ROMAN;
+ break;
+ case TK_FS_ITALIC:
+ slant = XFT_SLANT_ITALIC;
+ break;
+ case TK_FS_OBLIQUE:
+ slant = XFT_SLANT_OBLIQUE;
+ break;
+ }
+ XftPatternAddInteger(pattern, XFT_SLANT, slant);
+
+ fontPtr = (UnixFtFont *) tkFontPtr;
+ if (fontPtr != NULL) {
+ FinishedWithFont(fontPtr);
+ }
+ fontPtr = InitFont(tkwin, pattern, fontPtr);
+
+ /*
+ * Hack to work around issues with weird issues with Xft/Xrender
+ * connection. For details, see comp.lang.tcl thread starting from
+ * <adcc99ed-c73e-4efc-bb5d-e57a57a051e8@l35g2000pra.googlegroups.com>
+ */
+
+ if (!fontPtr) {
+ XftPatternAddBool(pattern, XFT_RENDER, FcFalse);
+ fontPtr = InitFont(tkwin, pattern, fontPtr);
+ }
+
+ if (!fontPtr) {
+ FcPatternDestroy(pattern);
+ return NULL;
+ }
+
+ fontPtr->font.fa.underline = faPtr->underline;
+ fontPtr->font.fa.overstrike = faPtr->overstrike;
+ return &fontPtr->font;
+}
+
+void
+TkpDeleteFont(
+ TkFont *tkFontPtr) /* Token of font to be deleted. */
+{
+ UnixFtFont *fontPtr = (UnixFtFont *) tkFontPtr;
+
+ FinishedWithFont(fontPtr);
+ /* XXX tkUnixFont.c doesn't free tkFontPtr... */
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * TkpGetFontFamilies --
+ *
+ * Return information about the font families that are available on the
+ * display of the given window.
+ *
+ * Results:
+ * Modifies interp's result object to hold a list of all the available
+ * font families.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+void
+TkpGetFontFamilies(
+ Tcl_Interp *interp, /* Interp to hold result. */
+ Tk_Window tkwin) /* For display to query. */
+{
+ Tcl_Obj *resultPtr;
+ XftFontSet *list;
+ int i;
+
+ resultPtr = Tcl_NewListObj(0, NULL);
+
+ list = XftListFonts(Tk_Display(tkwin), Tk_ScreenNumber(tkwin),
+ (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)
+ {
+ Tcl_Obj *strPtr = Tcl_NewStringObj(family, -1);
+ Tcl_ListObjAppendElement(NULL, resultPtr, strPtr);
+ }
+ }
+ XftFontSetDestroy(list);
+
+ Tcl_SetObjResult(interp, resultPtr);
+}
+
+/*
+ *-------------------------------------------------------------------------
+ *
+ * TkpGetSubFonts --
+ *
+ * Called by [testfont subfonts] in the Tk testing package.
+ *
+ * Results:
+ * Sets interp's result to a list of the faces used by tkfont
+ *
+ *-------------------------------------------------------------------------
+ */
+
+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);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkpGetFontAttrsForChar --
+ *
+ * Retrieve the font attributes of the actual font used to render a given
+ * character.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TkpGetFontAttrsForChar(
+ Tk_Window tkwin, /* Window on the font's display */
+ Tk_Font tkfont, /* Font to query */
+ Tcl_UniChar c, /* Character of interest */
+ TkFontAttributes *faPtr) /* Output: Font attributes */
+{
+ UnixFtFont *fontPtr = (UnixFtFont *) tkfont;
+ /* Structure describing the logical font */
+ FcChar32 ucs4 = (FcChar32) c;
+ /* UCS-4 character to map */
+ XftFont *ftFont = GetFont(fontPtr, ucs4);
+ /* Actual font used to render the character */
+
+ GetTkFontAttributes(ftFont, faPtr);
+ faPtr->underline = fontPtr->font.fa.underline;
+ faPtr->overstrike = fontPtr->font.fa.overstrike;
+}
+
+int
+Tk_MeasureChars(
+ Tk_Font tkfont, /* Font in which characters will be drawn. */
+ CONST char *source, /* UTF-8 string to be displayed. Need not be
+ * '\0' terminated. */
+ int numBytes, /* Maximum number of bytes to consider from
+ * source string. */
+ int maxLength, /* If >= 0, maxLength specifies the longest
+ * permissible line length in pixels; don't
+ * consider any character that would cross
+ * this x-position. If < 0, then line length
+ * is unbounded and the flags argument is
+ * ignored. */
+ int flags, /* Various flag bits OR-ed together:
+ * TK_PARTIAL_OK means include the last char
+ * which only partially fit on this line.
+ * TK_WHOLE_WORDS means stop on a word
+ * boundary, if possible. TK_AT_LEAST_ONE
+ * means return at least one character even if
+ * no characters fit. */
+ int *lengthPtr) /* Filled with x-location just after the
+ * terminating character. */
+{
+ UnixFtFont *fontPtr = (UnixFtFont *) tkfont;
+ XftFont *ftFont;
+ FcChar32 c;
+ XGlyphInfo extents;
+ int clen, curX, newX, curByte, newByte, sawNonSpace;
+ int termByte = 0, termX = 0;
+#if DEBUG_FONTSEL
+ char string[256];
+ int len = 0;
+#endif /* DEBUG_FONTSEL */
+
+ curX = 0;
+ curByte = 0;
+ sawNonSpace = 0;
+ while (numBytes > 0) {
+ Tcl_UniChar unichar;
+
+ clen = Tcl_UtfToUniChar(source, &unichar);
+ c = (FcChar32)unichar;
+
+ if (clen <= 0) {
+ /*
+ * This can't happen (but see #1185640)
+ */
+
+ *lengthPtr = curX;
+ return curByte;
+ }
+
+ source += clen;
+ numBytes -= clen;
+ if (c < 256 && isspace(c)) { /* I18N: ??? */
+ if (sawNonSpace) {
+ termByte = curByte;
+ termX = curX;
+ sawNonSpace = 0;
+ }
+ } else {
+ sawNonSpace = 1;
+ }
+
+#if DEBUG_FONTSEL
+ string[len++] = (char) c;
+#endif /* DEBUG_FONTSEL */
+ ftFont = GetFont(fontPtr, c);
+
+ XftTextExtents32(fontPtr->display, ftFont, &c, 1, &extents);
+
+ newX = curX + extents.xOff;
+ newByte = curByte + clen;
+ if (maxLength >= 0 && newX > maxLength) {
+ if (flags & TK_PARTIAL_OK ||
+ (flags & TK_AT_LEAST_ONE && curByte == 0)) {
+ curX = newX;
+ curByte = newByte;
+ } else if (flags & TK_WHOLE_WORDS && termX != 0) {
+ curX = termX;
+ curByte = termByte;
+ }
+ break;
+ }
+
+ curX = newX;
+ curByte = newByte;
+ }
+#if DEBUG_FONTSEL
+ string[len] = '\0';
+ printf("MeasureChars %s length %d bytes %d\n", string, curX, curByte);
+#endif /* DEBUG_FONTSEL */
+ *lengthPtr = curX;
+ return curByte;
+}
+
+int
+TkpMeasureCharsInContext(
+ Tk_Font tkfont,
+ CONST char *source,
+ int numBytes,
+ int rangeStart,
+ int rangeLength,
+ int maxLength,
+ int flags,
+ int *lengthPtr)
+{
+ (void) numBytes; /*unused*/
+
+ return Tk_MeasureChars(tkfont, source + rangeStart, rangeLength,
+ maxLength, flags, lengthPtr);
+}
+
+#define NUM_SPEC 1024
+
+void
+Tk_DrawChars(
+ 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. */
+ int x, int y) /* Coordinates at which to place origin of
+ * string when drawing. */
+{
+ const int maxCoord = 0x7FFF;/* Xft coordinates are 16 bit values */
+ UnixFtFont *fontPtr = (UnixFtFont *) tkfont;
+ XGCValues values;
+ XColor xcolor;
+ int clen, nspec, xStart = x;
+ XftGlyphFontSpec specs[NUM_SPEC];
+ XGlyphInfo metrics;
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
+ Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
+
+ 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, (ClientData) 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;
+ }
+ if (tsdPtr->clipRegion != None) {
+ XftDrawSetClip(fontPtr->ftDraw, tsdPtr->clipRegion);
+ }
+ nspec = 0;
+ while (numBytes > 0 && x <= maxCoord && y <= maxCoord) {
+ XftFont *ftFont;
+ FcChar32 c;
+
+ clen = FcUtf8ToUcs4((FcChar8 *) source, &c, numBytes);
+ if (clen <= 0) {
+ /*
+ * This should not happen, but it can.
+ */
+
+ goto doUnderlineStrikeout;
+ }
+ source += clen;
+ numBytes -= clen;
+
+ ftFont = GetFont(fontPtr, c);
+ if (ftFont) {
+ specs[nspec].font = ftFont;
+ specs[nspec].glyph = XftCharIndex(fontPtr->display, ftFont, c);
+ specs[nspec].x = x;
+ specs[nspec].y = y;
+ XftGlyphExtents(fontPtr->display, ftFont, &specs[nspec].glyph, 1,
+ &metrics);
+ x += metrics.xOff;
+ y += metrics.yOff;
+ nspec++;
+ if (nspec == NUM_SPEC) {
+ XftDrawGlyphFontSpec(fontPtr->ftDraw, &fontPtr->color,
+ specs, nspec);
+ nspec = 0;
+ }
+ }
+ }
+ if (nspec) {
+ XftDrawGlyphFontSpec(fontPtr->ftDraw, &fontPtr->color, specs, nspec);
+ }
+ if (tsdPtr->clipRegion != None) {
+ XftDrawSetClip(fontPtr->ftDraw, None);
+ }
+
+ doUnderlineStrikeout:
+ if (fontPtr->font.fa.underline != 0) {
+ XFillRectangle(display, drawable, gc, xStart,
+ y + fontPtr->font.underlinePos, (unsigned) (x - xStart),
+ (unsigned) fontPtr->font.underlineHeight);
+ }
+ if (fontPtr->font.fa.overstrike != 0) {
+ y -= fontPtr->font.fm.descent + (fontPtr->font.fm.ascent) / 10;
+ XFillRectangle(display, drawable, gc, xStart, y,
+ (unsigned) (x - xStart),
+ (unsigned) fontPtr->font.underlineHeight);
+ }
+}
+
+void
+TkUnixSetXftClipRegion(
+ TkRegion clipRegion) /* The clipping region to install. */
+{
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
+ Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
+
+ tsdPtr->clipRegion = (Region) clipRegion;
+}