summaryrefslogtreecommitdiffstats
path: root/unix
diff options
context:
space:
mode:
authordkf <donal.k.fellows@manchester.ac.uk>2008-11-22 18:08:51 (GMT)
committerdkf <donal.k.fellows@manchester.ac.uk>2008-11-22 18:08:51 (GMT)
commit08d210474dcf15c239160ca885bd7799ac618787 (patch)
treea79e10925b1fe14d042ef56ea012b2e1e56407de /unix
parent76c04ee36744e2a988a33f9d8ccb9d3b7e2359c2 (diff)
downloadtk-08d210474dcf15c239160ca885bd7799ac618787.zip
tk-08d210474dcf15c239160ca885bd7799ac618787.tar.gz
tk-08d210474dcf15c239160ca885bd7799ac618787.tar.bz2
TIP#119 implementation. [Patch 1611359]
Diffstat (limited to 'unix')
-rw-r--r--unix/tkUnixFont.c283
-rw-r--r--unix/tkUnixRFont.c292
2 files changed, 537 insertions, 38 deletions
diff --git a/unix/tkUnixFont.c b/unix/tkUnixFont.c
index 405b19c..b069cd9 100644
--- a/unix/tkUnixFont.c
+++ b/unix/tkUnixFont.c
@@ -9,7 +9,7 @@
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tkUnixFont.c,v 1.38 2008/11/05 22:20:59 nijtmans Exp $
+ * RCS: @(#) $Id: tkUnixFont.c,v 1.39 2008/11/22 18:08:51 dkf Exp $
*/
#include "tkUnixInt.h"
@@ -139,9 +139,9 @@ typedef struct UnixFont {
*/
typedef struct EncodingAlias {
- const char *realName; /* The real name of the encoding to load if
+ const char *realName; /* The real name of the encoding to load if
* the provided name matched the pattern. */
- const char *aliasPattern; /* Pattern for encoding name, of the form that
+ const char *aliasPattern; /* Pattern for encoding name, of the form that
* is acceptable to Tcl_StringMatch. */
} EncodingAlias;
@@ -3018,6 +3018,283 @@ GetEncodingAlias(
return name;
}
+static inline XImage *
+GetImageOfText(
+ Display *display, /* Display on which to draw. */
+ Drawable drawable, /* Window or pixmap in which to draw. */
+ Tk_Font tkfont, /* Font in which characters will be drawn. */
+ 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 *realWidthPtr, int *realHeightPtr)
+{
+ int width, height;
+ TkFont *fontPtr = (TkFont *) tkfont;
+ Pixmap bitmap;
+ GC bitmapGC;
+ XGCValues values;
+ XImage *image;
+
+ (void) Tk_MeasureChars(tkfont, source, numBytes, -1, 0, &width);
+ height = fontPtr->fm.ascent + fontPtr->fm.descent;
+
+ bitmap = Tk_GetPixmap(display, drawable, width, height, 1);
+ values.graphics_exposures = False;
+ values.foreground = BlackPixel(display, DefaultScreen(display));
+ bitmapGC = XCreateGC(display, bitmap, GCGraphicsExposures|GCForeground,
+ &values);
+ XFillRectangle(display, bitmap, bitmapGC, 0, 0, width, height);
+
+ values.font = Tk_FontId(tkfont);
+ values.foreground = WhitePixel(display, DefaultScreen(display));
+ values.background = BlackPixel(display, DefaultScreen(display));
+ XChangeGC(display, bitmapGC, GCFont|GCForeground|GCBackground, &values);
+ Tk_DrawChars(display, bitmap, bitmapGC, tkfont, source, numBytes, 0,
+ fontPtr->fm.ascent);
+ XFreeGC(display, bitmapGC);
+
+ image = XGetImage(display, bitmap, 0, 0, width, height, AllPlanes,
+ ZPixmap);
+ Tk_FreePixmap(display, bitmap);
+
+ *realWidthPtr = width;
+ *realHeightPtr = height;
+ return image;
+}
+
+static inline XImage *
+InitDestImage(
+ Display *display,
+ Drawable drawable,
+ int width,
+ int height,
+ Pixmap *bitmapPtr)
+{
+ Pixmap bitmap;
+ XImage *image;
+ GC bitmapGC;
+ XGCValues values;
+
+ bitmap = Tk_GetPixmap(display, drawable, width, height, 1);
+ values.graphics_exposures = False;
+ values.foreground = BlackPixel(display, DefaultScreen(display));
+ bitmapGC = XCreateGC(display, bitmap, GCGraphicsExposures|GCForeground,
+ &values);
+ XFillRectangle(display, bitmap, bitmapGC, 0, 0, width, height);
+ XFreeGC(display, bitmapGC);
+
+ image = XGetImage(display, bitmap, 0, 0, width, height, AllPlanes,
+ ZPixmap);
+ *bitmapPtr = bitmap;
+ return image;
+}
+
+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,
+ double angle)
+{
+ if (angle == 0.0) {
+ Tk_DrawChars(display, drawable, gc, tkfont, source, numBytes, x, y);
+ } else {
+ double sinA = sin(angle * PI/180.0), cosA = cos(angle * PI/180.0);
+ int bufHeight, bufWidth, srcWidth, srcHeight, i, j, dx, dy;
+ Pixmap buf;
+ XImage *srcImage = GetImageOfText(display, drawable, tkfont, source,
+ numBytes, &srcWidth, &srcHeight);
+ XImage *dstImage;
+ enum {Q0=1,R1,Q1,R2,Q2,R3,Q3} quadrant;
+ GC bwgc, cpgc;
+ XGCValues values;
+ int ascent = ((TkFont *) tkfont)->fm.ascent;
+
+ /*
+ * First, work out what quadrant we are operating in. We also handle
+ * the rectilinear rotations as special cases. Conceptually, there's
+ * also R0 (angle == 0.0) but that has been already handled as a
+ * special case above.
+ *
+ * R1
+ * Q1 | Q0
+ * |
+ * R2 ----+---- R0
+ * |
+ * Q2 | Q3
+ * R3
+ */
+
+ if (angle < 90.0) {
+ quadrant = Q0;
+ } else if (angle == 90.0) {
+ quadrant = R1;
+ } else if (angle < 180.0) {
+ quadrant = Q1;
+ } else if (angle == 180.0) {
+ quadrant = R2;
+ } else if (angle < 270.0) {
+ quadrant = Q2;
+ } else if (angle == 270.0) {
+ quadrant = R3;
+ } else {
+ quadrant = Q3;
+ }
+
+ if (srcImage == NULL) {
+ return;
+ }
+ bufWidth = srcWidth*fabs(cosA) + srcHeight*fabs(sinA);
+ bufHeight = srcHeight*fabs(cosA) + srcWidth*fabs(sinA);
+ dstImage = InitDestImage(display, drawable, bufWidth,bufHeight, &buf);
+ if (dstImage == NULL) {
+ Tk_FreePixmap(display, buf);
+ XDestroyImage(srcImage);
+ return;
+ }
+
+ /*
+ * Do the rotation, setting or resetting pixels in the destination
+ * image dependent on whether the corresponding pixel (after rotation
+ * to source image space) is set.
+ */
+
+ for (i=0 ; i<srcWidth ; i++) {
+ for (j=0 ; j<srcHeight ; j++) {
+ switch (quadrant) {
+ case Q0:
+ dx = floor(i*cosA + j*sinA + 0.5);
+ dy = floor(j*cosA + (srcWidth - i)*sinA + 0.5);
+ break;
+ case R1:
+ dx = j;
+ dy = srcWidth - i;
+ break;
+ case Q1:
+ dx = floor((i - srcWidth)*cosA + j*sinA + 0.5);
+ dy = floor((srcWidth-i)*sinA + (j-srcHeight)*cosA + 0.5);
+ break;
+ case R2:
+ dx = srcWidth - i;
+ dy = srcHeight - j;
+ break;
+ case Q2:
+ dx = floor((i-srcWidth)*cosA + (j-srcHeight)*sinA + 0.5);
+ dy = floor((j - srcHeight)*cosA - i*sinA + 0.5);
+ break;
+ case R3:
+ dx = srcHeight - j;
+ dy = i;
+ break;
+ default:
+ dx = floor(i*cosA + (j - srcHeight)*sinA + 0.5);
+ dy = floor(j*cosA - i*sinA + 0.5);
+ }
+
+ if (dx < 0 || dy < 0 || dx >= bufWidth || dy >= bufHeight) {
+ continue;
+ }
+ XPutPixel(dstImage, dx, dy,
+ XGetPixel(dstImage,dx,dy) | XGetPixel(srcImage,i,j));
+ }
+ }
+ XDestroyImage(srcImage);
+
+ /*
+ * Schlep the data back to the Xserver.
+ */
+
+ values.function = GXcopy;
+ values.foreground = WhitePixel(display, DefaultScreen(display));
+ values.background = BlackPixel(display, DefaultScreen(display));
+ bwgc = XCreateGC(display, buf, GCFunction|GCForeground|GCBackground,
+ &values);
+ XPutImage(display, buf, bwgc, dstImage, 0,0, 0,0, bufWidth,bufHeight);
+ XFreeGC(display, bwgc);
+ XDestroyImage(dstImage);
+
+ /*
+ * Calculate where we want to draw the text.
+ */
+
+ switch (quadrant) {
+ case Q0:
+ dx = x;
+ dy = y - srcWidth*sinA;
+ break;
+ case R1:
+ dx = x;
+ dy = y - srcWidth;
+ break;
+ case Q1:
+ dx = x + srcWidth*cosA;
+ dy = y + srcHeight*cosA - srcWidth*sinA;
+ break;
+ case R2:
+ dx = x - srcWidth;
+ dy = y - srcHeight;
+ break;
+ case Q2:
+ dx = x + srcWidth*cosA + srcHeight*sinA;
+ dy = y + srcHeight*cosA;
+ break;
+ case R3:
+ dx = x - srcHeight;
+ dy = y;
+ break;
+ default:
+ dx = x + srcHeight*sinA;
+ dy = y;
+ }
+
+ /*
+ * Apply a correction to deal with the fact that we aren't told to
+ * draw from our top-left corner but rather from the left-end of our
+ * baseline.
+ */
+
+ dx -= ascent*sinA;
+ dy -= ascent*cosA;
+
+ /*
+ * Transfer the text to the screen. This is done by using it as a mask
+ * and then drawing through that mask with the original drawing color.
+ */
+
+ values.function = GXcopy;
+ values.fill_style = FillSolid;
+ values.clip_mask = buf;
+ values.clip_x_origin = dx;
+ values.clip_y_origin = dy;
+ cpgc = XCreateGC(display, drawable,
+ GCFunction|GCFillStyle|GCClipMask|GCClipXOrigin|GCClipYOrigin,
+ &values);
+ XCopyGC(display, gc, GCForeground, cpgc);
+ XFillRectangle(display, drawable, cpgc, dx, dy, bufWidth,
+ bufHeight);
+ XFreeGC(display, cpgc);
+
+ Tk_FreePixmap(display, buf);
+ return;
+ }
+}
+
/*
* Local Variables:
* mode: c
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:
+ */