From 037fc862b0dd4535accf7b69a8c0112355bd04b1 Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Sat, 3 Mar 2007 02:53:41 +0000 Subject: [PATCH] pango is now mandatory.. lots of cleanups to the pango code, which was a very nice base to start from. thanks to whomever wrote that for us.. put some of the pango variables into the various render structs so that they don't need to be created all the time. put the pango context inside our RrInstance so that it can be properly freed at shutdown. removed xft dependencies all through the code and the build system also. who knows if this will break compiling for some poor souls. i guess we'll find out, won't we! --- Makefile.am | 7 +- configure.ac | 30 +---- render/font.c | 320 +++++++++++++++------------------------------- render/font.h | 16 +-- render/instance.c | 4 + render/instance.h | 2 + render/render.h | 3 +- 7 files changed, 121 insertions(+), 261 deletions(-) diff --git a/Makefile.am b/Makefile.am index 2c2ba020..fc415ba4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -34,13 +34,12 @@ bin_PROGRAMS = \ ## render ## render_rendertest_CPPFLAGS = \ - $(XFT_CFLAGS) \ + $(PANGO_CFLAGS) \ $(GLIB_CFLAGS) \ -DG_LOG_DOMAIN=\"RenderTest\" render_rendertest_LDADD = \ parser/libobparser.la \ render/libobrender.la \ - $(XFT_LIBS) \ $(GLIB_LIBS) \ $(PANGO_LIBS) \ $(XML_LIBS) \ @@ -49,7 +48,6 @@ render_rendertest_SOURCES = render/test.c render_libobrender_la_CPPFLAGS = \ $(X_CFLAGS) \ - $(XFT_CFLAGS) \ $(GLIB_CFLAGS) \ $(XML_CFLAGS) \ $(PANGO_CFLAGS) \ @@ -60,7 +58,6 @@ render_libobrender_la_LDFLAGS = \ render_libobrender_la_LIBADD = \ parser/libobparser.la \ $(X_LIBS) \ - $(XFT_LIBS) \ $(PANGO_LIBS) \ $(GLIB_LIBS) \ $(XML_LIBS) @@ -108,7 +105,7 @@ parser_libobparser_la_SOURCES = \ openbox_openbox_CPPFLAGS = \ $(X_CFLAGS) \ $(SM_CFLAGS) \ - $(XFT_CFLAGS) \ + $(PANGO_CFLAGS) \ $(GLIB_CFLAGS) \ $(LIBSN_CFLAGS) \ $(XML_CFLAGS) \ diff --git a/configure.ac b/configure.ac index f55eb0b0..09159bb1 100644 --- a/configure.ac +++ b/configure.ac @@ -74,32 +74,9 @@ PKG_CHECK_MODULES([GLIB], [glib-2.0]) AC_SUBST(GLIB_CFLAGS) AC_SUBST(GLIB_LIBS) -AC_ARG_ENABLE(pango, - AC_HELP_STRING( - [--disable-pango], - [disable the pango library [[default=enabled]]] - ), - [enable_pango=$enableval], - [enable_pango=yes] -) - -if test "$enable_pango" = yes; then -PKG_CHECK_MODULES([PANGO], [pango pangoxft], - [ - AC_DEFINE(USE_PANGO, [1], [Use Pango]) - AC_SUBST(PANGO_CFLAGS) - AC_SUBST(PANGO_LIBS) - pango_found=yes - ], - pango_found=no -) -else - pango_found=no -fi - -PKG_CHECK_MODULES(XFT, [xft]) -AC_SUBST(XFT_CFLAGS) -AC_SUBST(XFT_LIBS) +PKG_CHECK_MODULES(PANGO, [pango pangoxft]) +AC_SUBST(PANGO_CFLAGS) +AC_SUBST(PANGO_LIBS) PKG_CHECK_MODULES(XML, [libxml-2.0]) AC_SUBST(XML_CFLAGS) @@ -155,7 +132,6 @@ AC_OUTPUT AC_MSG_RESULT AC_MSG_RESULT([Compiling with these options: - Pango... $pango_found Startup Notification... $sn_found Session Management... $SM ]) diff --git a/render/font.c b/render/font.c index 14b9ea14..a88df51f 100644 --- a/render/font.c +++ b/render/font.c @@ -23,19 +23,13 @@ #include "mask.h" #include "theme.h" #include "geom.h" +#include "instance.h" #include "gettext.h" -#include #include #include #include -#ifdef USE_PANGO #include -#endif - -#define ELIPSES "..." -#define ELIPSES_LENGTH(font) \ - (font->elipses_length + (font->shadow ? font->offset : 0)) #define OB_SHADOW "shadow" #define OB_SHADOW_OFFSET "shadowoffset" @@ -47,9 +41,6 @@ FcObjectType objs[] = { { OB_SHADOW_ALPHA, FcTypeInteger } }; -#ifdef USE_PANGO -static PangoContext *context; -#endif static gboolean started = FALSE; static void font_startup(void) @@ -59,25 +50,29 @@ static void font_startup(void) exit(EXIT_FAILURE); } -#ifdef USE_PANGO - g_type_init(); - /* these will never be freed, but we will need - * them until we shut down anyway */ - context = pango_xft_get_context(RrDisplay(NULL), RrScreen(NULL)); -#endif /* USE_PANGO */ /* Here we are teaching xft about the shadow, shadowoffset & shadowtint */ FcNameRegisterObjectTypes(objs, (sizeof(objs) / sizeof(objs[0]))); } -static void measure_font(RrFont *f) +static void measure_font(const RrInstance *inst, RrFont *f) { - /* xOff, yOff is the normal spacing to the next glyph. */ - XGlyphInfo info; - - /* measure an elipses */ - XftTextExtentsUtf8(RrDisplay(f->inst), f->xftfont, - (FcChar8*)ELIPSES, strlen(ELIPSES), &info); - f->elipses_length = (signed) info.xOff; + PangoFontMetrics *metrics; + gchar *locale, *p; + + /* get the default language from the locale + (based on gtk_get_default_language in gtkmain.c) */ + locale = g_strdup(setlocale(LC_CTYPE, NULL)); + if ((p = strchr(locale, '.'))) *p = '\0'; /* strip off the . */ + if ((p = strchr(locale, '@'))) *p = '\0'; /* strip off the @ */ + + /* measure the ascent and descent */ + metrics = pango_context_get_metrics(inst->pango, f->font_desc, + pango_language_from_string(locale)); + f->ascent = pango_font_metrics_get_ascent(metrics); + f->descent = pango_font_metrics_get_descent(metrics); + pango_font_metrics_unref(metrics); + + g_free(locale); } static RrFont *openfont(const RrInstance *inst, gchar *fontstring) @@ -85,100 +80,78 @@ static RrFont *openfont(const RrInstance *inst, gchar *fontstring) /* This function is called for each font in the theme file. */ /* It returns a pointer to a RrFont struct after filling it. */ RrFont *out; - FcPattern *pat, *match; - XftFont *font; - FcResult res; + FcPattern *pat; gint tint; -#ifdef USE_PANGO - guchar *tmp_string = NULL; - gint tmp_int; -#endif /* USE_PANGO */ + gchar *sval; + gint ival; if (!(pat = XftNameParse(fontstring))) return NULL; - match = XftFontMatch(RrDisplay(inst), RrScreen(inst), pat, &res); - FcPatternDestroy(pat); - if (!match) - return NULL; - out = g_new(RrFont, 1); out->inst = inst; -#ifdef USE_PANGO - out->pango_font_description = pango_font_description_new(); - - if (FcPatternGetString(match, "family", 0, &tmp_string) != - FcResultTypeMismatch) { - pango_font_description_set_family(out->pango_font_description, - (gchar *)tmp_string); - tmp_string = NULL; - } - if (FcPatternGetString(match, "style", 0, &tmp_string) != - FcResultTypeMismatch) { - /* Bold ? */ - if (!g_ascii_strcasecmp("bold", (gchar *)tmp_string)) { - pango_font_description_set_weight(out->pango_font_description, + out->font_desc = pango_font_description_new(); + out->layout = pango_layout_new(inst->pango); + + /* get the data from the parsed xft string */ + + /* get the family */ + if (FcPatternGetString(pat, "family", 0, + (FcChar8**)&sval) == FcResultMatch) + pango_font_description_set_family(out->font_desc, sval); + + /* get the weight */ + if (FcPatternGetInteger(pat, "weight", 0, &ival) == FcResultMatch) { + if (ival == FC_WEIGHT_LIGHT) + pango_font_description_set_weight(out->font_desc, + PANGO_WEIGHT_LIGHT); + else if (ival == FC_WEIGHT_DEMIBOLD) + pango_font_description_set_weight(out->font_desc, + PANGO_WEIGHT_SEMIBOLD); + else if (ival == FC_WEIGHT_BOLD) + pango_font_description_set_weight(out->font_desc, PANGO_WEIGHT_BOLD); - } - /* Italic ? */ - else if (!g_ascii_strcasecmp("italic", (gchar *)tmp_string)) { - pango_font_description_set_style(out->pango_font_description, - PANGO_STYLE_ITALIC); - } - tmp_string = NULL; + else if (ival == FC_WEIGHT_BLACK) + pango_font_description_set_weight(out->font_desc, + PANGO_WEIGHT_ULTRABOLD); } - if (FcPatternGetInteger(match, "pixelsize", 0, &tmp_int) != - FcResultTypeMismatch) { - pango_font_description_set_absolute_size(out->pango_font_description, - tmp_int*PANGO_SCALE); + if (FcPatternGetInteger(pat, "slant", 0, &ival) == FcResultMatch) { + if (ival == FC_SLANT_ITALIC) + pango_font_description_set_style(out->font_desc, + PANGO_STYLE_ITALIC); + else if (ival == FC_SLANT_OBLIQUE) + pango_font_description_set_style(out->font_desc, + PANGO_STYLE_OBLIQUE); } - /* based on gtkmain.c gtk_get_default_language() */ - { - gchar *locale, *p; - PangoFontMetrics *metrics; - - locale = g_strdup(setlocale(LC_CTYPE, NULL)); - if ((p = strchr(locale, '.'))) - *p = '\0'; - if ((p = strchr(locale, '@'))) - *p = '\0'; - metrics = - pango_context_get_metrics(context, out->pango_font_description, - pango_language_from_string(locale)); - out->pango_ascent = pango_font_metrics_get_ascent(metrics); - out->pango_descent = pango_font_metrics_get_descent(metrics); - g_free(locale); - pango_font_metrics_unref(metrics); - } -#endif /* USE_PANGO */ + /* get the size */ + if (FcPatternGetInteger(pat, "size", 0, &ival) == FcResultMatch) + pango_font_description_set_size(out->font_desc, ival * PANGO_SCALE); + else if (FcPatternGetInteger(pat, "pixelsize", 0, &ival) == FcResultMatch) + pango_font_description_set_absolute_size(out->font_desc, + ival * PANGO_SCALE); - if (FcPatternGetBool(match, OB_SHADOW, 0, &out->shadow) != FcResultMatch) + if (FcPatternGetBool(pat, OB_SHADOW, 0, &out->shadow) != FcResultMatch) out->shadow = FALSE; - if (FcPatternGetInteger(match, OB_SHADOW_OFFSET, 0, &out->offset) != + if (FcPatternGetInteger(pat, OB_SHADOW_OFFSET, 0, &out->offset) != FcResultMatch) out->offset = 1; - if (FcPatternGetInteger(match, OB_SHADOW_ALPHA, 0, &tint) != FcResultMatch) + if (FcPatternGetInteger(pat, OB_SHADOW_ALPHA, 0, &tint) != FcResultMatch) tint = 25; if (tint > 100) tint = 100; else if (tint < -100) tint = -100; out->tint = tint; - font = XftFontOpenPattern(RrDisplay(inst), match); - if (!font) { - FcPatternDestroy(match); - g_free(out); - return NULL; - } else - out->xftfont = font; + /* setup the layout */ + pango_layout_set_font_description(out->layout, out->font_desc); + pango_layout_set_single_paragraph_mode(out->layout, TRUE); + pango_layout_set_ellipsize(out->layout, PANGO_ELLIPSIZE_MIDDLE); -#ifdef USE_PANGO - /* FcPatternDestroy(match); */ -#endif /* USE_PANGO */ - measure_font(out); + /* get the ascent and descent */ + measure_font(inst, out); return out; } @@ -207,10 +180,8 @@ RrFont *RrFontOpen(const RrInstance *inst, gchar *fontstring) void RrFontClose(RrFont *f) { if (f) { -#ifdef USE_PANGO - pango_font_description_free(f->pango_font_description); -#endif - XftFontClose(RrDisplay(f->inst), f->xftfont); + g_object_unref(f->layout); + pango_font_description_free(f->font_desc); g_free(f); } } @@ -218,56 +189,29 @@ void RrFontClose(RrFont *f) static void font_measure_full(const RrFont *f, const gchar *str, gint *x, gint *y) { -#ifdef USE_PANGO - PangoLayout *pl; PangoRectangle rect; - pl = pango_layout_new (context); - pango_layout_set_text(pl, str, -1); - pango_layout_set_font_description(pl, f->pango_font_description); - pango_layout_set_single_paragraph_mode(pl, TRUE); - pango_layout_get_pixel_extents(pl, NULL, &rect); + + pango_layout_set_text(f->layout, str, -1); + pango_layout_set_width(f->layout, -1); + pango_layout_get_pixel_extents(f->layout, NULL, &rect); *x = rect.width + (f->shadow ? ABS(f->offset) : 0); *y = rect.height + (f->shadow ? ABS(f->offset) : 0); - g_object_unref(pl); - -#else - XGlyphInfo info; - - XftTextExtentsUtf8(RrDisplay(f->inst), f->xftfont, - (const FcChar8*)str, strlen(str), &info); - - *x = (signed) info.xOff + (f->shadow ? ABS(f->offset) : 0); - *y = info.height + (f->shadow ? ABS(f->offset) : 0); -#endif /* USE_PANGO */ } RrSize *RrFontMeasureString(const RrFont *f, const gchar *str) { RrSize *size; size = g_new(RrSize, 1); - font_measure_full (f, str, &size->width, &size->height); + font_measure_full(f, str, &size->width, &size->height); return size; } gint RrFontHeight(const RrFont *f) { -#ifdef USE_PANGO - return (f->pango_ascent - + f->pango_descent - ) / PANGO_SCALE + - (f->shadow ? f->offset : 0); -#else - return f->xftfont->ascent + f->xftfont->descent + - (f->shadow ? f->offset : 0); -#endif + return (f->ascent + f->descent) / PANGO_SCALE + + (f->shadow ? f->offset : 0); } -gint RrFontMaxCharWidth(const RrFont *f) -{ - return (signed) f->xftfont->max_advance_width; -} - -#ifdef USE_PANGO static inline int font_calculate_baseline(RrFont *f, gint height) { /* For my own reference: @@ -283,84 +227,41 @@ static inline int font_calculate_baseline(RrFont *f, gint height) * ^space/2 | * V_________v */ - int asc = f->pango_ascent; - int ascdesc = asc + f->pango_descent; - int space = height * PANGO_SCALE - ascdesc; - int baseline = space / 2 + asc; - return baseline / PANGO_SCALE; + return (((height * PANGO_SCALE) /* height of the space in pango units */ + - (f->ascent + f->descent)) /* minus space taken up by text */ + / 2 /* divided by two -> half of the empty space (this is the top + of the text) */ + + f->ascent) /* now move down to the baseline */ + / PANGO_SCALE; /* back to pixels */ } -#endif void RrFontDraw(XftDraw *d, RrTextureText *t, RrRect *area) { gint x,y,w,h; XftColor c; - GString *text; gint mw; -#ifndef USE_PANGO - gint mh; - size_t l; - gboolean shortened = FALSE; -#else - PangoLayout *pl; PangoRectangle rect; - pl = pango_layout_new (context); -#endif /* USE_PANGO */ - - /* center vertically - * for xft we pass the top edge of the text for positioning... */ -#ifndef USE_PANGO - y = area->y + - (area->height - RrFontHeight(t->font)) / 2; -#else - /* but for pango we pass the baseline, since different fonts have - * different top edges. It looks stupid when the baseline of "normal" - * text jumps up and down when a "strange" character is just added - * to the end of the text */ + /* center the text vertically + We do this centering based on the 'baseline' since different fonts have + different top edges. It looks bad when the whole string is moved when 1 + character from a non-default language is included in the string */ y = area->y + font_calculate_baseline(t->font, area->height); -#endif + /* the +2 and -4 leave a small blank edge on the sides */ x = area->x + 2; w = area->width - 4; h = area->height; - text = g_string_new(t->string); -#ifndef USE_PANGO - l = g_utf8_strlen(text->str, -1); - font_measure_full(t->font, text->str, &mw, &mh); - while (l && mw > area->width) { - shortened = TRUE; - /* remove a character from the middle */ - text = g_string_erase(text, l-- / 2, 1); - /* if the elipses are too large, don't show them at all */ - if (ELIPSES_LENGTH(t->font) > area->width) - shortened = FALSE; - font_measure_full(t->font, text->str, &mw, &mh); - mw += ELIPSES_LENGTH(t->font); - } - if (shortened) { - text = g_string_insert(text, (l + 1) / 2, ELIPSES); - l += 3; - } - if (!l) return; - - l = strlen(text->str); /* number of bytes */ - -#else - pango_layout_set_text(pl, text->str, -1); - pango_layout_set_font_description(pl, t->font->pango_font_description); - pango_layout_set_single_paragraph_mode(pl, TRUE); - pango_layout_set_width(pl, w * PANGO_SCALE); - pango_layout_set_ellipsize(pl, PANGO_ELLIPSIZE_MIDDLE); - /* This doesn't work with layout_line() of course */ -/* pango_layout_set_alignment(pl, (PangoAlignment)(t->justify)); */ - pango_layout_get_pixel_extents(pl, NULL, &rect); - mw = rect.width; + pango_layout_set_text(t->font->layout, t->string, -1); + pango_layout_set_width(t->font->layout, w * PANGO_SCALE); -#endif /* USE_PANGO */ + pango_layout_get_pixel_extents(t->font->layout, NULL, &rect); + mw = rect.width; + /* pango_layout_set_alignment doesn't work with + pango_xft_render_layout_line */ switch (t->justify) { case RR_JUSTIFY_LEFT: break; @@ -388,37 +289,22 @@ void RrFontDraw(XftDraw *d, RrTextureText *t, RrRect *area) c.pixel = WhitePixel(RrDisplay(t->font->inst), RrScreen(t->font->inst)); } -#ifndef USE_PANGO - XftDrawStringUtf8(d, &c, t->font->xftfont, x + t->font->offset, - t->font->xftfont->ascent + y + t->font->offset, - (FcChar8*)text->str, l); -#else /* USE_PANGO */ /* see below... */ - pango_xft_render_layout_line(d, &c, pango_layout_get_line(pl, 0), - (x + t->font->offset) * PANGO_SCALE, - (y + t->font->offset) * PANGO_SCALE); -#endif /* USE_PANGO */ + pango_xft_render_layout_line + (d, &c, pango_layout_get_line(t->font->layout, 0), + (x + t->font->offset) * PANGO_SCALE, + (y + t->font->offset) * PANGO_SCALE); } + c.color.red = t->color->r | t->color->r << 8; c.color.green = t->color->g | t->color->g << 8; c.color.blue = t->color->b | t->color->b << 8; c.color.alpha = 0xff | 0xff << 8; /* fully opaque text */ c.pixel = t->color->pixel; -#ifndef USE_PANGO - XftDrawStringUtf8(d, &c, t->font->xftfont, x, - t->font->xftfont->ascent + y, - (FcChar8*)text->str, l); -#else /* USE_PANGO */ - /* layout_line() bases y on the baseline, while layout() bases y on the - * top of the ink layout. We want the baseline to always be in the same - * place, thusly, we use layout_line() - * The actual line doesn't need to be freed (per the pango docs) */ - pango_xft_render_layout_line(d, &c, pango_layout_get_line(pl, 0), - x * PANGO_SCALE, y * PANGO_SCALE); - g_object_unref(pl); -#endif - - g_string_free(text, TRUE); - return; + /* layout_line() uses y to specify the baseline + The line doesn't need to be freed, it's a part of the layout */ + pango_xft_render_layout_line + (d, &c, pango_layout_get_line(t->font->layout, 0), + x * PANGO_SCALE, y * PANGO_SCALE); } diff --git a/render/font.h b/render/font.h index 19417db2..a0686605 100644 --- a/render/font.h +++ b/render/font.h @@ -21,26 +21,22 @@ #define __font_h #include "render.h" #include "geom.h" -#ifdef USE_PANGO #include -#include -#endif /* USE_PANGO */ struct _RrFont { const RrInstance *inst; - XftFont *xftfont; - gint elipses_length; + PangoFontDescription *font_desc; + PangoLayout *layout; /*!< Used for measuring and rendering strings */ + gint ascent; /*!< The font's ascent in pango-units */ + gint descent; /*!< The font's descent in pango-units */ + gint elipses_length; /*!< This one is in pixels, yay */ gint shadow; gchar tint; gint offset; -#ifdef USE_PANGO - PangoFontDescription *pango_font_description; - gint pango_ascent; - gint pango_descent; -#endif /* USE_PANGO */ }; RrFont *RrFontOpen(const RrInstance *inst, gchar *fontstring); void RrFontClose(RrFont *f); void RrFontDraw(XftDraw *d, RrTextureText *t, RrRect *position); + #endif /* __font_h */ diff --git a/render/instance.c b/render/instance.c index 386c87a3..02e68040 100644 --- a/render/instance.c +++ b/render/instance.c @@ -57,6 +57,8 @@ void print_refs(gint id) RrInstance* RrInstanceNew (Display *display, gint screen) { + g_type_init(); /* supposedly needed for pango but seems to work without */ + definst = g_new (RrInstance, 1); definst->display = display; definst->screen = screen; @@ -64,6 +66,7 @@ RrInstance* RrInstanceNew (Display *display, gint screen) definst->depth = DefaultDepth(display, screen); definst->visual = DefaultVisual(display, screen); definst->colormap = DefaultColormap(display, screen); + definst->pango = pango_xft_get_context(display, screen); definst->pseudo_colors = NULL; @@ -210,6 +213,7 @@ void RrInstanceFree (RrInstance *inst) if (inst == definst) definst = NULL; g_free(inst->pseudo_colors); g_hash_table_destroy(inst->color_hash); + g_object_unref(inst->pango); } } diff --git a/render/instance.h b/render/instance.h index 21bd535f..8a15f423 100644 --- a/render/instance.h +++ b/render/instance.h @@ -21,6 +21,7 @@ #include #include +#include struct _RrInstance { Display *display; @@ -29,6 +30,7 @@ struct _RrInstance { Visual *visual; gint depth; Colormap colormap; + PangoContext *pango; gint red_offset; gint green_offset; diff --git a/render/render.h b/render/render.h index ac1394cf..da34a6a8 100644 --- a/render/render.h +++ b/render/render.h @@ -25,8 +25,7 @@ #include "version.h" #include /* some platforms dont include this as needed for Xft */ -#define _XFT_NO_COMPAT_ /* no Xft 1 API */ -#include +#include #include G_BEGIN_DECLS -- 2.45.2