From fde697af64aae8450b540fb7eeb4f0f19aa3f005 Mon Sep 17 00:00:00 2001 From: dkf Date: Tue, 12 Jun 2012 08:29:27 +0000 Subject: Fix text clipping when working with the Xft-based renderer. --- ChangeLog | 8 ++++++++ generic/tkInt.h | 3 +++ generic/ttk/ttkEntry.c | 13 ++++++++++++- generic/ttk/ttkLabel.c | 13 ++++++++++++- unix/tkUnixRFont.c | 28 ++++++++++++++++++++++++++++ 5 files changed, 63 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7ac76d5..c5bee52 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2012-06-12 Donal K. Fellows + + * unix/tkUnixRFont.c (Tk_DrawChars, TkUnixSetXftClipRegion): Add some + * generic/ttk/ttkEntry.c (EntryDisplay): special magic to make the + * generic/ttk/ttkLabel.c (TextDraw): text clipping work right with the + Xft-based renderer (which doesn't use the standard Tk GC except to + supply the color). + 2012-06-11 Donal K. Fellows * generic/ttk/ttkLabel.c (TextDraw): [Bug 3294450]: Get the clipping diff --git a/generic/tkInt.h b/generic/tkInt.h index b152a7a..a95adf8 100644 --- a/generic/tkInt.h +++ b/generic/tkInt.h @@ -1186,6 +1186,9 @@ MODULE_SCOPE Status TkParseColor (Display * display, Colormap map, CONST char* spec, XColor * colorPtr); #endif +#ifdef HAVE_XFT +MODULE_SCOPE void TkUnixSetXftClipRegion(Region clipRegion); +#endif /* * Unsupported commands. diff --git a/generic/ttk/ttkEntry.c b/generic/ttk/ttkEntry.c index e5d0ef2..a3d0179 100644 --- a/generic/ttk/ttkEntry.c +++ b/generic/ttk/ttkEntry.c @@ -1221,7 +1221,8 @@ static void EntryDisplay(void *clientData, Drawable d) } } - /* Initialize the clip region: + /* Initialize the clip region. Note that Xft does _not_ derive its + * clipping area from the GC, so we have to supply that by other means. */ rect.x = textarea.x; @@ -1230,6 +1231,9 @@ static void EntryDisplay(void *clientData, Drawable d) rect.height = textarea.height; clipRegion = TkCreateRegion(); TkUnionRectWithRegion(&rect, clipRegion, clipRegion); +#ifdef HAVE_XFT + TkUnixSetXftClipRegion(clipRegion); +#endif /* Draw cursor: */ @@ -1272,6 +1276,13 @@ static void EntryDisplay(void *clientData, Drawable d) selFirst, selLast); Tk_FreeGC(Tk_Display(tkwin), gc); } + + /* Drop the region. Note that we have to manually remove the reference to + * it from the Xft guts (if they're being used). + */ +#ifdef HAVE_XFT + TkUnixSetXftClipRegion(None); +#endif TkDestroyRegion(clipRegion); } diff --git a/generic/ttk/ttkLabel.c b/generic/ttk/ttkLabel.c index df6a686..52782ea 100644 --- a/generic/ttk/ttkLabel.c +++ b/generic/ttk/ttkLabel.c @@ -131,6 +131,7 @@ static void TextDraw(TextElement *text, Tk_Window tkwin, Drawable d, Ttk_Box b) XGCValues gcValues; GC gc1, gc2; Tk_Anchor anchor = TK_ANCHOR_CENTER; + TkRegion clipRegion = NULL; gcValues.font = Tk_FontId(text->tkfont); gcValues.foreground = color->pixel; @@ -148,9 +149,9 @@ static void TextDraw(TextElement *text, Tk_Window tkwin, Drawable d, Ttk_Box b) * Clip text if it's too wide: */ if (b.width < text->width) { - TkRegion clipRegion = TkCreateRegion(); XRectangle rect; + clipRegion = TkCreateRegion(); rect.x = b.x; rect.y = b.y; rect.width = b.width + (text->embossed ? 1 : 0); @@ -158,7 +159,11 @@ static void TextDraw(TextElement *text, Tk_Window tkwin, Drawable d, Ttk_Box b) TkUnionRectWithRegion(&rect, clipRegion, clipRegion); TkSetRegion(Tk_Display(tkwin), gc1, clipRegion); TkSetRegion(Tk_Display(tkwin), gc2, clipRegion); +#ifdef HAVE_XFT + TkUnixSetXftClipRegion(clipRegion); +#else TkDestroyRegion(clipRegion); +#endif } if (text->embossed) { @@ -180,6 +185,12 @@ static void TextDraw(TextElement *text, Tk_Window tkwin, Drawable d, Ttk_Box b) Tk_FreeGC(Tk_Display(tkwin), gc1); Tk_FreeGC(Tk_Display(tkwin), gc2); +#ifdef HAVE_XFT + if (clipRegion != NULL) { + TkUnixSetXftClipRegion(None); + TkDestroyRegion(clipRegion); + } +#endif } static void TextElementSize( diff --git a/unix/tkUnixRFont.c b/unix/tkUnixRFont.c index 134bb45..deecceb 100644 --- a/unix/tkUnixRFont.c +++ b/unix/tkUnixRFont.c @@ -33,6 +33,16 @@ typedef struct { 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; /* * Package initialization: @@ -712,6 +722,8 @@ Tk_DrawChars( 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 @@ -738,6 +750,9 @@ Tk_DrawChars( 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; @@ -775,6 +790,9 @@ Tk_DrawChars( if (nspec) { XftDrawGlyphFontSpec(fontPtr->ftDraw, &fontPtr->color, specs, nspec); } + if (tsdPtr->clipRegion != None) { + XftDrawSetClip(fontPtr->ftDraw, None); + } doUnderlineStrikeout: if (fontPtr->font.fa.underline != 0) { @@ -789,3 +807,13 @@ Tk_DrawChars( (unsigned) fontPtr->font.underlineHeight); } } + +void +TkUnixSetXftClipRegion( + Region clipRegion) /* The clipping region to install. */ +{ + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + + tsdPtr->clipRegion = clipRegion; +} -- cgit v0.12