summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordkf <donal.k.fellows@manchester.ac.uk>2009-10-10 17:42:50 (GMT)
committerdkf <donal.k.fellows@manchester.ac.uk>2009-10-10 17:42:50 (GMT)
commit49df46a2bf9d2a9e8254aab31eeafa5f957d4dcf (patch)
treecc55f4b952ce33eb8e00878156d1e2cb2f2f367d
parentba31530899c4dd81a94eef9d7b3b8c000fa7e869 (diff)
downloadtk-49df46a2bf9d2a9e8254aab31eeafa5f957d4dcf.zip
tk-49df46a2bf9d2a9e8254aab31eeafa5f957d4dcf.tar.gz
tk-49df46a2bf9d2a9e8254aab31eeafa5f957d4dcf.tar.bz2
[Bug 1961455]: Draw underlines and overstrikes when using Xft.
-rw-r--r--ChangeLog9
-rw-r--r--generic/tkFont.c11
-rw-r--r--unix/tkUnixRFont.c125
3 files changed, 135 insertions, 10 deletions
diff --git a/ChangeLog b/ChangeLog
index 4a95f15..2814c4e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2009-10-10 Donal K. Fellows <dkf@users.sf.net>
+
+ * unix/tkUnixRFont.c (InitFont, TkpGetFontFromAttributes)
+ (Tk_DrawChars, TkpDrawAngledChars): [Bug 1961455]: Draw underlines and
+ overstrikes when using Xft for font rendering.
+
+ * generic/tkFont.c (TkDrawAngledTextLayout): Optimize the zero-angle
+ case better.
+
2009-10-08 Donal K. Fellows <dkf@users.sf.net>
* library/iconlist.tcl (Create): [Patch 2870648]: Corrected cursor
diff --git a/generic/tkFont.c b/generic/tkFont.c
index bd65379..47852ca 100644
--- a/generic/tkFont.c
+++ b/generic/tkFont.c
@@ -10,7 +10,7 @@
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tkFont.c,v 1.58 2009/09/10 12:16:37 dkf Exp $
+ * RCS: @(#) $Id: tkFont.c,v 1.59 2009/10/10 17:42:50 dkf Exp $
*/
#include "tkInt.h"
@@ -2376,8 +2376,13 @@ TkDrawAngledTextLayout(
lastByte = Tcl_UtfAtIndex(chunkPtr->start, numDisplayChars);
dx = cosA * (chunkPtr->x + drawX) + sinA * (chunkPtr->y);
dy = -sinA * (chunkPtr->x + drawX) + cosA * (chunkPtr->y);
- TkpDrawAngledChars(display, drawable, gc, layoutPtr->tkfont,
- firstByte, lastByte - firstByte, x+dx, y+dy, angle);
+ if (angle == 0.0) {
+ Tk_DrawChars(display, drawable, gc, layoutPtr->tkfont,
+ firstByte, lastByte - firstByte, x + dx, y + dy);
+ } else {
+ TkpDrawAngledChars(display, drawable, gc, layoutPtr->tkfont,
+ firstByte, lastByte - firstByte, x+dx, y+dy, angle);
+ }
}
firstChar -= chunkPtr->numChars;
lastChar -= chunkPtr->numChars;
diff --git a/unix/tkUnixRFont.c b/unix/tkUnixRFont.c
index e1c7e75..5e62ffa 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.29 2009/09/09 22:47:36 dkf Exp $
+ * RCS: @(#) $Id: tkUnixRFont.c,v 1.30 2009/10/10 17:42:50 dkf Exp $
*/
#include "tkUnixInt.h"
@@ -16,6 +16,8 @@
#include <X11/Xft/Xft.h>
#include <ctype.h>
+#define ROUND16(x) ((short)((x) + 0.5))
+
typedef struct {
XftFont *ftFont;
XftFont *ft0Font;
@@ -37,7 +39,6 @@ typedef struct {
XftDraw *ftDraw;
XftColor color;
} UnixFtFont;
-
/*
* Package initialization:
@@ -229,7 +230,7 @@ InitFont(
FcCharSet *charset;
FcResult result;
XftFont *ftFont;
- int i;
+ int i, iWidth;
if (!fontPtr) {
fontPtr = (UnixFtFont *) ckalloc(sizeof(UnixFtFont));
@@ -288,6 +289,43 @@ InitFont(
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;
}
@@ -434,6 +472,9 @@ TkpGetFontFromAttributes(
FcPatternDestroy(pattern);
return NULL;
}
+
+ fontPtr->font.fa.underline = faPtr->underline;
+ fontPtr->font.fa.overstrike = faPtr->overstrike;
return &fontPtr->font;
}
@@ -705,7 +746,7 @@ Tk_DrawChars(
UnixFtFont *fontPtr = (UnixFtFont *) tkfont;
XGCValues values;
XColor xcolor;
- int clen, nspec;
+ int clen, nspec, xStart = x;
XftGlyphFontSpec specs[NUM_SPEC];
XGlyphInfo metrics;
@@ -745,7 +786,7 @@ Tk_DrawChars(
* This should not happen, but it can.
*/
- return;
+ goto doUnderlineStrikeout;
}
source += clen;
numBytes -= clen;
@@ -771,6 +812,19 @@ Tk_DrawChars(
if (nspec) {
XftDrawGlyphFontSpec(fontPtr->ftDraw, &fontPtr->color, specs, nspec);
}
+
+ doUnderlineStrikeout:
+ 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);
+ }
}
void
@@ -797,6 +851,7 @@ TkpDrawAngledChars(
UnixFtFont *fontPtr = (UnixFtFont *) tkfont;
XGCValues values;
XColor xcolor;
+ int xStart = x, yStart = y;
#ifdef XFT_HAS_FIXED_ROTATED_PLACEMENT
int clen, nglyph;
FT_UInt glyphs[NUM_SPEC];
@@ -846,7 +901,7 @@ TkpDrawAngledChars(
* This should not happen, but it can.
*/
- return;
+ goto doUnderlineStrikeout;
}
source += clen;
numBytes -= clen;
@@ -928,7 +983,7 @@ TkpDrawAngledChars(
* This should not happen, but it can.
*/
- return;
+ goto doUnderlineStrikeout;
}
source += clen;
numBytes -= clen;
@@ -956,6 +1011,62 @@ TkpDrawAngledChars(
XftDrawGlyphFontSpec(fontPtr->ftDraw, &fontPtr->color, specs, nspec);
}
#endif /* XFT_HAS_FIXED_ROTATED_PLACEMENT */
+
+ doUnderlineStrikeout:
+ 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);
+ }
+ }
+ }
}
/*