static void xftfont_text_extents (struct font *font, unsigned int *code, int nglyphs, struct font_metrics *metrics) { struct xftfont_info *xftfont_info = (struct xftfont_info *) font; XGlyphInfo extents; block_input (); XftGlyphExtents (xftfont_info->display, xftfont_info->xftfont, code, nglyphs, &extents); unblock_input (); metrics->lbearing = - extents.x; metrics->rbearing = - extents.x + extents.width; metrics->width = extents.xOff; metrics->ascent = extents.y; metrics->descent = extents.height - extents.y; }
static int xftfont_text_extents (struct font *font, unsigned int *code, int nglyphs, struct font_metrics *metrics) { struct xftfont_info *xftfont_info = (struct xftfont_info *) font; XGlyphInfo extents; BLOCK_INPUT; XftGlyphExtents (xftfont_info->display, xftfont_info->xftfont, code, nglyphs, &extents); UNBLOCK_INPUT; if (metrics) { metrics->lbearing = - extents.x; metrics->rbearing = - extents.x + extents.width; metrics->width = extents.xOff; metrics->ascent = extents.y; metrics->descent = extents.height - extents.y; } return extents.xOff; }
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; XftGlyphFontSpec specs[NUM_SPEC]; XGlyphInfo metrics; 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; } 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. */ 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); } }
void TkDrawAngledChars( 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; int xStart = x, yStart = y; ThreadSpecificData *tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); #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; } if (tsdPtr->clipRegion != None) { XftDrawSetClip(fontPtr->ftDraw, tsdPtr->clipRegion); } 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. */ goto doUnderlineStrikeout; } 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 = ROUND16(x); originY = ROUND16(y); 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; } if (tsdPtr->clipRegion != None) { XftDrawSetClip(fontPtr->ftDraw, tsdPtr->clipRegion); } 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. */ goto doUnderlineStrikeout; } 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 = ROUND16(x); specs[nspec].y = ROUND16(y); 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 */ doUnderlineStrikeout: if (tsdPtr->clipRegion != None) { XftDrawSetClip(fontPtr->ftDraw, None); } if (fontPtr->font.fa.underline || fontPtr->font.fa.overstrike) { XPoint points[5]; double width = (x - xStart) * cosA + (yStart - y) * sinA; double barHeight = fontPtr->font.underlineHeight; double dy = fontPtr->font.underlinePos; if (fontPtr->font.fa.underline != 0) { if (fontPtr->font.underlineHeight == 1) { dy++; } points[0].x = xStart + ROUND16(dy*sinA); points[0].y = yStart + ROUND16(dy*cosA); points[1].x = xStart + ROUND16(dy*sinA + width*cosA); points[1].y = yStart + ROUND16(dy*cosA - width*sinA); if (fontPtr->font.underlineHeight == 1) { XDrawLines(display, drawable, gc, points, 2, CoordModeOrigin); } else { points[2].x = xStart + ROUND16(dy*sinA + width*cosA + barHeight*sinA); points[2].y = yStart + ROUND16(dy*cosA - width*sinA + barHeight*cosA); points[3].x = xStart + ROUND16(dy*sinA + barHeight*sinA); points[3].y = yStart + ROUND16(dy*cosA + barHeight*cosA); points[4].x = points[0].x; points[4].y = points[0].y; XFillPolygon(display, drawable, gc, points, 5, Complex, CoordModeOrigin); XDrawLines(display, drawable, gc, points, 5, CoordModeOrigin); } } if (fontPtr->font.fa.overstrike != 0) { dy = -fontPtr->font.fm.descent - (fontPtr->font.fm.ascent) / 10; points[0].x = xStart + ROUND16(dy*sinA); points[0].y = yStart + ROUND16(dy*cosA); points[1].x = xStart + ROUND16(dy*sinA + width*cosA); points[1].y = yStart + ROUND16(dy*cosA - width*sinA); if (fontPtr->font.underlineHeight == 1) { XDrawLines(display, drawable, gc, points, 2, CoordModeOrigin); } else { points[2].x = xStart + ROUND16(dy*sinA + width*cosA + barHeight*sinA); points[2].y = yStart + ROUND16(dy*cosA - width*sinA + barHeight*cosA); points[3].x = xStart + ROUND16(dy*sinA + barHeight*sinA); points[3].y = yStart + ROUND16(dy*cosA + barHeight*cosA); points[4].x = points[0].x; points[4].y = points[0].y; XFillPolygon(display, drawable, gc, points, 5, Complex, CoordModeOrigin); XDrawLines(display, drawable, gc, points, 5, CoordModeOrigin); } } } }