+++ /dev/null
-/*
- * 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;
- XftFont *ft0Font;
- FcPattern *source;
- FcCharSet *charset;
- double angle;
-} 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;
-\f
-/*
- * 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);
-}
-\f
-static XftFont *
-GetFont(
- UnixFtFont *fontPtr,
- 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;
- }
- }
- if (i == fontPtr->nfaces) {
- i = 0;
- }
- } else {
- i = 0;
- }
- 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;
- XftFont *ftFont;
-
- /*
- * Initialize the matrix manually so this can compile with HP-UX cc
- * (which does not allow non-constant structure initializers). [Bug
- * 2978410]
- */
-
- mat.xx = mat.yy = c;
- mat.xy = -(mat.yx = s);
-
- 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:
- */
-
- ftFont = XftFontOpen(fontPtr->display, fontPtr->screen,
- 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.
- */
-
- Tcl_Panic("Cannot find a usable font");
- }
-
- 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 (angle==0.0? fontPtr->faces[i].ft0Font : fontPtr->faces[i].ftFont);
-}
-\f
-/*
- *---------------------------------------------------------------------------
- *
- * GetTkFontAttributes --
- * Fill in TkFontAttributes from an XftFont.
- */
-
-static void
-GetTkFontAttributes(
- XftFont *ftFont,
- TkFontAttributes *faPtr)
-{
- const char *family = "Unknown";
- const char *const *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;
-}
-\f
-/*
- *---------------------------------------------------------------------------
- *
- * 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;
-}
-\f
-/*
- *---------------------------------------------------------------------------
- *
- * 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, iWidth;
-
- if (!fontPtr) {
- fontPtr = 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(fontPtr);
- return NULL;
- }
-
- fontPtr->fontset = set;
- fontPtr->pattern = pattern;
- fontPtr->faces = 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].ft0Font = 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->faces[i].angle = 0.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, 0.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;
-
- 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;
-}
-\f
-static void
-FinishedWithFont(
- UnixFtFont *fontPtr)
-{
- Display *display = fontPtr->display;
- int i;
- 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(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);
-}
-\f
-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;
-}
-\f
-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;
-}
-\f
-void
-TkpDeleteFont(
- TkFont *tkFontPtr) /* Token of font to be deleted. */
-{
- UnixFtFont *fontPtr = (UnixFtFont *) tkFontPtr;
-
- FinishedWithFont(fontPtr);
- /* XXX tkUnixFont.c doesn't free tkFontPtr... */
-}
-\f
-/*
- *---------------------------------------------------------------------------
- *
- * 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);
-}
-\f
-/*
- *-------------------------------------------------------------------------
- *
- * 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;
- const char *family = "Unknown";
- const char *const *familyPtr = &family;
- const char *foundry = "Unknown";
- const char *const *foundryPtr = &foundry;
- const char *encoding = "Unknown";
- const char *const *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);
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * 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, 0.0);
- /* Actual font used to render the character */
-
- GetTkFontAttributes(ftFont, faPtr);
- faPtr->underline = fontPtr->font.fa.underline;
- faPtr->overstrike = fontPtr->font.fa.overstrike;
-}
-\f
-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, 0.0);
-
- 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;
-}
-\f
-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);
-}
-\f
-#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, 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, 0.0);
- 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);
- }
-
- doUnderlineStrikeout:
- if (tsdPtr->clipRegion != None) {
- XftDrawSetClip(fontPtr->ftDraw, None);
- }
- 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);
- }
-}
-\f
-/*
- *---------------------------------------------------------------------------
- *
- * TkDrawAngledChars --
- *
- * Draw some characters at an angle. This would be simple code, except
- * Xft has bugs with cumulative errors in character positioning which are
- * caused by trying to perform all calculations internally with integers.
- * So we have to do the work ourselves with floating-point math.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Target drawable is updated.
- *
- *---------------------------------------------------------------------------
- */
-
-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);
- }
- }
- }
-}
-\f
-void
-TkUnixSetXftClipRegion(
- TkRegion clipRegion) /* The clipping region to install. */
-{
- ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
- Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
-
- tsdPtr->clipRegion = (Region) clipRegion;
-}
-\f
-/*
- * Local Variables:
- * c-basic-offset: 4
- * fill-column: 78
- * End:
- */