--- Begin Message ---
Package: tk8.4
Version: 8.4.9-1
Severity: wishlist
Tags: patch
tk8.4 can look rather ugly without anti-aliasing these days. The
upcoming 8.5 version will include XFT capabilities. However, there
exists a patch for the 8.3er version, which I managed to apply to
tk8.4 with minor changes. It complies and works with XFT afterwards,
so the patch seems to me rather safe and straightforward. I'll attach
it to the bug report, please consider applying it, if you also think
it's safe.
-- System Information:
Debian Release: 3.1
Architecture: i386 (i686)
Kernel: Linux 2.6.9-1-k7
Locale: LANG=ru_RU.UTF-8, LC_CTYPE=ru_RU.UTF-8 (charmap=UTF-8)
Versions of packages tk8.4 depends on:
ii libc6 2.3.2.ds1-19ubuntu3 GNU C Library: Shared libraries an
ii libfontconfig1 2.2.3-4 generic font configuration library
ii libfreetype6 2.1.7-2.3 FreeType 2 font engine, shared lib
ii libx11-6 6.8.1-1ubuntu8 X Window System protocol client li
ii libxft2 2.1.2-6 FreeType-based font drawing librar
ii libxrender1 0.9.0-0ubuntu4 X Rendering Extension client libra
ii tcl8.4 8.4.7-1ubuntu1 Tcl (the Tool Command Language) v8
ii xlibs 6.8.1-1ubuntu8 X Window System client libraries m
ii zlib1g 1:1.2.2-4ubuntu1 compression library - runtime
-- no debconf information
diff -Nru tk8.4-8.4.9/unix/Makefile.in tk8.4-8.4.9-patched/unix/Makefile.in
--- tk8.4-8.4.9/unix/Makefile.in 2004-12-30 08:58:48 +0100
+++ tk8.4-8.4.9-patched/unix/Makefile.in 2004-12-28 12:52:31 +0100
@@ -129,7 +129,7 @@
# Linker switch(es) to use to link with the X11 library archive (the
# configure script will try to set this value automatically, but you
# can override it).
-X11_LIB_SWITCHES = @XLIBSW@
+X11_LIB_SWITCHES = @XLIBSW@ `freetype-config --libs` `xft-config --libs`
# To turn off the security checks that disallow incoming sends when
@@ -278,7 +278,7 @@
CC_SWITCHES_NO_STUBS = ${CFLAGS} ${CFLAGS_WARNING} ${SHLIB_CFLAGS} \
-I${UNIX_DIR} -I${GENERIC_DIR} \
--I${BMAP_DIR} -I${TCL_GENERIC_DIR} ${X11_INCLUDES} \
+-I${BMAP_DIR} -I${TCL_GENERIC_DIR} ${X11_INCLUDES} `freetype-config --cflags`
`xft-config --cflags` \
${AC_FLAGS} ${PROTO_FLAGS} \
${SECURITY_FLAGS} ${MEM_DEBUG_FLAGS} ${KEYSYM_FLAGS} ${NO_DEPRECATED_FLAGS}
@@ -286,7 +286,7 @@
DEPEND_SWITCHES = ${CFLAGS} -I${UNIX_DIR} -I${GENERIC_DIR} \
-I${BMAP_DIR} \
--I${TCL_GENERIC_DIR} ${X11_INCLUDES} \
+-I${TCL_GENERIC_DIR} ${X11_INCLUDES} `freetype-config --cflags` `xft-config
--cflags` \
${AC_FLAGS} ${PROTO_FLAGS} ${SECURITY_FLAGS} ${MEM_DEBUG_FLAGS} \
${KEYSYM_FLAGS}
@@ -309,7 +309,7 @@
UNIXOBJS = tkUnix.o tkUnix3d.o tkUnixButton.o tkUnixColor.o tkUnixConfig.o \
tkUnixCursor.o tkUnixDraw.o tkUnixEmbed.o tkUnixEvent.o \
- tkUnixFocus.o tkUnixFont.o tkUnixInit.o tkUnixKey.o tkUnixMenu.o \
+ tkUnixFocus.o tkUnixRFont.o tkUnixInit.o tkUnixKey.o tkUnixMenu.o \
tkUnixMenubu.o tkUnixScale.o tkUnixScrlbr.o tkUnixSelect.o \
tkUnixSend.o tkUnixWm.o tkUnixXId.o tkStubInit.o tkStubLib.o
@@ -373,7 +373,7 @@
$(UNIX_DIR)/tkUnixDraw.c \
$(UNIX_DIR)/tkUnixEmbed.c $(UNIX_DIR)/tkUnixEvent.c \
$(UNIX_DIR)/tkUnixFocus.c \
- $(UNIX_DIR)/tkUnixFont.c $(UNIX_DIR)/tkUnixInit.c \
+ $(UNIX_DIR)/tkUnixRFont.c $(UNIX_DIR)/tkUnixInit.c \
$(UNIX_DIR)/tkUnixKey.c \
$(UNIX_DIR)/tkUnixMenu.c $(UNIX_DIR)/tkUnixMenubu.c \
$(UNIX_DIR)/tkUnixScale.c $(UNIX_DIR)/tkUnixScrlbr.c \
@@ -940,8 +940,8 @@
tkUnixFocus.o: $(UNIX_DIR)/tkUnixFocus.c
$(CC) -c $(CC_SWITCHES) $(UNIX_DIR)/tkUnixFocus.c
-tkUnixFont.o: $(UNIX_DIR)/tkUnixFont.c
- $(CC) -c $(CC_SWITCHES) $(UNIX_DIR)/tkUnixFont.c
+tkUnixFont.o: $(UNIX_DIR)/tkUnixRFont.c
+ $(CC) -c $(CC_SWITCHES) $(UNIX_DIR)/tkUnixRFont.c
tkUnixInit.o: $(UNIX_DIR)/tkUnixInit.c $(GENERIC_DIR)/tkInitScript.h
tkConfig.sh
$(CC) -c $(CC_SWITCHES) -DTK_LIBRARY=\"${TK_LIBRARY}\" \
diff -Nru tk8.4-8.4.9/unix/tkUnixRFont.c tk8.4-8.4.9-patched/unix/tkUnixRFont.c
--- tk8.4-8.4.9/unix/tkUnixRFont.c 1970-01-01 01:00:00 +0100
+++ tk8.4-8.4.9-patched/unix/tkUnixRFont.c 2004-12-28 12:50:32 +0100
@@ -0,0 +1,643 @@
+/*
+ * 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.
+ *
+ * RCS: @(#) $Id: tkUnixRFont.c,v 1.6 2003/11/17 23:48:47 dkf Exp $
+ */
+
+#include "tkUnixInt.h"
+#include "tkFont.h"
+#include <X11/Xft/Xft.h>
+#include <ctype.h>
+
+typedef struct _UnixFtFace {
+ XftFont *ftFont;
+ FcPattern *source;
+ FcCharSet *charset;
+} UnixFtFace;
+
+typedef struct _UnixFtFont {
+ TkFont font; /* Stuff used by generic font package. Must
+ * be first in structure. */
+ UnixFtFace *faces;
+ int nfaces;
+ FcCharSet *charset;
+ FcPattern *pattern;
+
+ Display *display;
+ int screen;
+ XftDraw *ftDraw;
+ Drawable drawable;
+ XftColor color;
+} UnixFtFont;
+
+void
+TkpFontPkgInit(mainPtr)
+ TkMainInfo *mainPtr; /* The application being created. */
+{
+}
+
+static XftFont *
+GetFont(fontPtr, ucs4)
+ 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;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * 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(tkwin, pattern, fontPtr)
+ Tk_Window tkwin;
+ FcPattern *pattern;
+ UnixFtFont *fontPtr;
+{
+ TkFontAttributes *faPtr;
+ TkFontMetrics *fmPtr;
+ char *family;
+ int weight, slant, spacing, i;
+ double size;
+ FcFontSet *set;
+ FcCharSet *charset;
+ FcResult result;
+ XftFont *ftFont;
+
+ if (!fontPtr) {
+ fontPtr = (UnixFtFont *) ckalloc(sizeof(UnixFtFont));
+ }
+ if (!fontPtr) {
+ return NULL; /* Never called? */
+ }
+
+ FcConfigSubstitute(0, pattern, FcMatchPattern);
+ XftDefaultSubstitute(Tk_Display(tkwin), Tk_ScreenNumber(tkwin), pattern);
+
+ /*
+ * Generate the list of fonts
+ */
+ set = FcFontSort(0, pattern, FcTrue, &charset, &result);
+
+ if (!set) {
+ FcPatternDestroy(pattern);
+ ckfree((char *) fontPtr);
+ return NULL;
+ }
+
+ fontPtr->charset = charset;
+ fontPtr->pattern = pattern;
+
+ fontPtr->faces = (UnixFtFace *) ckalloc(set->nfont * sizeof(UnixFtFace));
+ if (!fontPtr->faces) {
+ FcFontSetDestroy(set);
+ FcCharSetDestroy(charset);
+ FcPatternDestroy(pattern);
+ ckfree((char *) fontPtr);
+ return NULL;
+ }
+ 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->font.fid = XLoadFont(Tk_Display(tkwin), "fixed");
+ fontPtr->display = Tk_Display(tkwin);
+ fontPtr->screen = Tk_ScreenNumber(tkwin);
+ fontPtr->ftDraw = 0;
+ fontPtr->drawable = 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;
+
+ ftFont = GetFont(fontPtr, 0);
+
+ /*
+ * Build the Tk font structure
+ */
+ if (XftPatternGetString(ftFont->pattern, XFT_FAMILY, 0,
+ &family) != XftResultMatch) {
+ family = "Unknown";
+ }
+
+ if (XftPatternGetInteger(ftFont->pattern, XFT_WEIGHT, 0,
+ &weight) != XftResultMatch) {
+ weight = XFT_WEIGHT_MEDIUM;
+ }
+ if (weight <= XFT_WEIGHT_MEDIUM) {
+ weight = TK_FW_NORMAL;
+ } else {
+ weight = TK_FW_BOLD;
+ }
+
+ if (XftPatternGetInteger(ftFont->pattern, XFT_SLANT, 0,
+ &slant) != XftResultMatch) {
+ slant = XFT_SLANT_ROMAN;
+ }
+ if (slant <= XFT_SLANT_ROMAN) {
+ slant = TK_FS_ROMAN;
+ } else {
+ slant = TK_FS_ITALIC;
+ }
+
+ if (XftPatternGetDouble(ftFont->pattern, XFT_SIZE, 0,
+ &size) != XftResultMatch) {
+ size = 12.0;
+ }
+
+ if (XftPatternGetInteger(ftFont->pattern, XFT_SPACING, 0,
+ &spacing) != XftResultMatch) {
+ spacing = XFT_PROPORTIONAL;
+ }
+ if (spacing == XFT_PROPORTIONAL) {
+ spacing = 0;
+ } else {
+ spacing = 1;
+ }
+#if DEBUG_FONTSEL
+ printf("family %s size %g weight %d slant %d\n",
+ family, size, weight, slant);
+#endif
+
+ faPtr = &fontPtr->font.fa;
+ faPtr->family = family;
+ faPtr->size = (int) size;
+ faPtr->weight = weight;
+ faPtr->slant = slant;
+ faPtr->underline = 0;
+ faPtr->overstrike = 0;
+
+ fmPtr = &fontPtr->font.fm;
+ fmPtr->ascent = ftFont->ascent;
+ fmPtr->descent = ftFont->descent;
+ fmPtr->maxWidth = ftFont->max_advance_width;
+ fmPtr->fixed = spacing;
+
+ return fontPtr;
+}
+
+static void
+FiniFont(fontPtr)
+ UnixFtFont *fontPtr;
+{
+ Display *display = fontPtr->display;
+ Tk_ErrorHandler handler;
+ int i;
+
+ handler = Tk_CreateErrorHandler(display, -1, -1, -1,
+ (Tk_ErrorProc *) 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].source) {
+ FcPatternDestroy(fontPtr->faces[i].source);
+ }
+ if (fontPtr->faces[i].charset) {
+ FcCharSetDestroy(fontPtr->faces[i].charset);
+ }
+ }
+ if (fontPtr->ftDraw) {
+ XftDrawDestroy(fontPtr->ftDraw);
+ }
+ if (fontPtr->font.fid) {
+ XUnloadFont(fontPtr->display, fontPtr->font.fid);
+ }
+ Tk_DeleteErrorHandler(handler);
+}
+
+TkFont *
+TkpGetNativeFont(tkwin, name)
+ 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
+
+ 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) {
+ return NULL;
+ }
+ return &fontPtr->font;
+}
+
+TkFont *
+TkpGetFontFromAttributes(tkFontPtr, tkwin, faPtr)
+ 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
+ pattern = XftPatternCreate();
+ if (faPtr->family) {
+ XftPatternAddString(pattern, XFT_FAMILY, faPtr->family);
+ }
+ if (faPtr->size > 0) {
+ XftPatternAddInteger(pattern, XFT_SIZE, faPtr->size);
+ } else if (faPtr->size < 0) {
+ XftPatternAddInteger(pattern, XFT_PIXEL_SIZE, -faPtr->size);
+ } else {
+ XftPatternAddInteger(pattern, XFT_SIZE, 12);
+ }
+ 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) {
+ FiniFont(fontPtr);
+ }
+ fontPtr = InitFont(tkwin, pattern, fontPtr);
+ if (!fontPtr) {
+ return NULL;
+ }
+ return &fontPtr->font;
+}
+
+void
+TkpDeleteFont(tkFontPtr)
+ TkFont *tkFontPtr; /* Token of font to be deleted. */
+{
+ UnixFtFont *fontPtr = (UnixFtFont *) tkFontPtr;
+
+ FiniFont(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(interp, tkwin)
+ Tcl_Interp *interp; /* Interp to hold result. */
+ Tk_Window tkwin; /* For display to query. */
+{
+ Tcl_Obj *resultPtr, *strPtr;
+ XftFontSet *list;
+ int i;
+ char *family;
+
+ resultPtr = Tcl_NewListObj(0, NULL);
+
+ list = XftListFonts(Tk_Display(tkwin), Tk_ScreenNumber(tkwin), 0,
+ XFT_FAMILY, 0);
+ for (i = 0; i < list->nfont; i++) {
+ if (XftPatternGetString(list->fonts[i], XFT_FAMILY, 0,
+ &family) == XftResultMatch) {
+ strPtr = Tcl_NewStringObj(Tk_GetUid(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(interp, tkfont)
+ Tcl_Interp *interp;
+ Tk_Font tkfont;
+{
+ Tcl_Obj *objv[3], *listPtr, *resultPtr;
+ UnixFtFont *fontPtr = (UnixFtFont *) tkfont;
+ FcPattern *pattern;
+ char *family, *foundry, *encoding;
+ int i;
+
+ resultPtr = Tcl_NewListObj(0, NULL);
+
+ for (i = 0; i < fontPtr->nfaces ; ++i) {
+ pattern = FcFontRenderPrepare(0, fontPtr->pattern,
+ fontPtr->faces[i].source);
+
+ if (XftPatternGetString(pattern, XFT_FAMILY, 0,
+ &family) != XftResultMatch) {
+ family = "Unknown";
+ }
+ if (XftPatternGetString(pattern, XFT_FOUNDRY, 0,
+ &foundry) != XftResultMatch) {
+ foundry = "Unknown";
+ }
+ if (XftPatternGetString(pattern, XFT_ENCODING, 0,
+ &encoding) != XftResultMatch) {
+ encoding = "Unknown";
+ }
+ 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);
+}
+
+int
+Tk_MeasureChars(tkfont, source, numBytes, maxLength, flags, lengthPtr)
+ 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;
+ int clen;
+ XGlyphInfo extents;
+ int curX, newX;
+ int termByte = 0, termX = 0;
+ int curByte, newByte, sawNonSpace;
+#if 0
+ char string[256];
+ int len = 0;
+#endif
+
+ curX = 0;
+ curByte = 0;
+ sawNonSpace = 0;
+ while (numBytes > 0) {
+ clen = FcUtf8ToUcs4((FcChar8 *) source, &c, numBytes);
+
+ if (clen <= 0) {
+ /*
+ * This should not happen, but it can, due to bugs in Tcl
+ * (i.e., [encoding convertfrom identity]).
+ */
+ *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 0
+ string[len++] = (char) c;
+#endif
+ 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 0
+ string[len] = '\0';
+ printf("MeasureChars %s length %d bytes %d\n", string, curX, curByte);
+#endif
+ *lengthPtr = curX;
+ return curByte;
+}
+
+#define NUM_SPEC 1024
+
+void
+Tk_DrawChars(display, drawable, gc, tkfont, source, numBytes, x, y)
+ 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, y; /* Coordinates at which to place origin of
+ * string when drawing. */
+{
+ UnixFtFont *fontPtr = (UnixFtFont *) tkfont;
+ XGCValues values;
+ XColor xcolor;
+ int clen;
+ XftGlyphFontSpec specs[NUM_SPEC];
+ int nspec;
+ XGlyphInfo metrics;
+
+ if (fontPtr->ftDraw == 0) {
+#if 0
+ printf("Switch to drawable 0x%x\n", drawable);
+#endif
+ fontPtr->ftDraw = XftDrawCreate(display, drawable,
+ DefaultVisual(display, fontPtr->screen),
+ DefaultColormap(display, fontPtr->screen));
+ fontPtr->drawable = drawable;
+ } else {
+ Tk_ErrorHandler handler;
+
+ handler = Tk_CreateErrorHandler(display, -1, -1, -1,
+ (Tk_ErrorProc *) NULL, (ClientData) NULL);
+ XftDrawChange(fontPtr->ftDraw, drawable);
+ fontPtr->drawable = 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) {
+ 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);
+ 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);
+ }
+}
--- End Message ---