diff options
author | dkf <donal.k.fellows@manchester.ac.uk> | 2008-11-22 18:08:51 (GMT) |
---|---|---|
committer | dkf <donal.k.fellows@manchester.ac.uk> | 2008-11-22 18:08:51 (GMT) |
commit | 08d210474dcf15c239160ca885bd7799ac618787 (patch) | |
tree | a79e10925b1fe14d042ef56ea012b2e1e56407de /unix | |
parent | 76c04ee36744e2a988a33f9d8ccb9d3b7e2359c2 (diff) | |
download | tk-08d210474dcf15c239160ca885bd7799ac618787.zip tk-08d210474dcf15c239160ca885bd7799ac618787.tar.gz tk-08d210474dcf15c239160ca885bd7799ac618787.tar.bz2 |
TIP#119 implementation. [Patch 1611359]
Diffstat (limited to 'unix')
-rw-r--r-- | unix/tkUnixFont.c | 283 | ||||
-rw-r--r-- | unix/tkUnixRFont.c | 292 |
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: + */ |