allow font rendering to use multiple lines

This commit is contained in:
Dana Jansens 2008-02-06 22:12:54 -05:00
parent a01ece1353
commit 9e3ce4efed
3 changed files with 88 additions and 25 deletions

View file

@ -108,7 +108,6 @@ RrFont *RrFontOpen(const RrInstance *inst, const gchar *name, gint size,
/* setup the layout */ /* setup the layout */
pango_layout_set_font_description(out->layout, out->font_desc); pango_layout_set_font_description(out->layout, out->font_desc);
pango_layout_set_single_paragraph_mode(out->layout, TRUE);
pango_layout_set_wrap(out->layout, PANGO_WRAP_WORD_CHAR); pango_layout_set_wrap(out->layout, PANGO_WRAP_WORD_CHAR);
/* get the ascent and descent */ /* get the ascent and descent */
@ -141,13 +140,20 @@ void RrFontClose(RrFont *f)
static void font_measure_full(const RrFont *f, const gchar *str, static void font_measure_full(const RrFont *f, const gchar *str,
gint *x, gint *y, gint shadow_x, gint shadow_y, gint *x, gint *y, gint shadow_x, gint shadow_y,
gint maxwidth) gboolean flow, gint maxwidth)
{ {
PangoRectangle rect; PangoRectangle rect;
pango_layout_set_text(f->layout, str, -1); pango_layout_set_text(f->layout, str, -1);
pango_layout_set_width(f->layout, if (flow) {
(maxwidth <= 0 ? -1 : maxwidth * PANGO_SCALE)); pango_layout_set_single_paragraph_mode(f->layout, FALSE);
pango_layout_set_width(f->layout, maxwidth * PANGO_SCALE);
}
else {
/* single line mode */
pango_layout_set_single_paragraph_mode(f->layout, TRUE);
pango_layout_set_width(f->layout, -1);
}
/* pango_layout_get_pixel_extents lies! this is the right way to get the /* pango_layout_get_pixel_extents lies! this is the right way to get the
size of the text's area */ size of the text's area */
@ -166,12 +172,16 @@ static void font_measure_full(const RrFont *f, const gchar *str,
} }
RrSize *RrFontMeasureString(const RrFont *f, const gchar *str, RrSize *RrFontMeasureString(const RrFont *f, const gchar *str,
gint shadow_x, gint shadow_y, gint maxwidth) gint shadow_x, gint shadow_y,
gboolean flow, gint maxwidth)
{ {
RrSize *size; RrSize *size;
g_assert(!flow || maxwidth > 0);
size = g_new(RrSize, 1); size = g_new(RrSize, 1);
font_measure_full(f, str, &size->width, &size->height, shadow_x, shadow_y, font_measure_full(f, str, &size->width, &size->height, shadow_x, shadow_y,
maxwidth); flow, maxwidth);
return size; return size;
} }
@ -212,16 +222,22 @@ void RrFontDraw(XftDraw *d, RrTextureText *t, RrRect *area)
PangoAttrList *attrlist; PangoAttrList *attrlist;
PangoEllipsizeMode ell; PangoEllipsizeMode ell;
g_assert(!t->flow || t->maxwidth > 0);
y = area->y;
if (!t->flow)
/* center the text vertically /* center the text vertically
We do this centering based on the 'baseline' since different fonts have We do this centering based on the 'baseline' since different fonts
different top edges. It looks bad when the whole string is moved when 1 have different top edges. It looks bad when the whole string is
character from a non-default language is included in the string */ moved when 1 character from a non-default language is included in
y = area->y + the string */
font_calculate_baseline(t->font, area->height); y += font_calculate_baseline(t->font, area->height);
/* the +2 and -4 leave a small blank edge on the sides */ /* the +2 and -4 leave a small blank edge on the sides */
x = area->x + 2; x = area->x + 2;
w = area->width - 4; w = area->width;
if (t->flow) w = MAX(w, t->maxwidth);
w -= 4;
h = area->height; h = area->height;
switch (t->ellipsize) { switch (t->ellipsize) {
@ -242,6 +258,7 @@ void RrFontDraw(XftDraw *d, RrTextureText *t, RrRect *area)
pango_layout_set_text(t->font->layout, t->string, -1); pango_layout_set_text(t->font->layout, t->string, -1);
pango_layout_set_width(t->font->layout, w * PANGO_SCALE); pango_layout_set_width(t->font->layout, w * PANGO_SCALE);
pango_layout_set_ellipsize(t->font->layout, ell); pango_layout_set_ellipsize(t->font->layout, ell);
pango_layout_set_single_paragraph_mode(t->font->layout, !t->flow);
/* * * end of setting up the layout * * */ /* * * end of setting up the layout * * */
@ -269,11 +286,24 @@ void RrFontDraw(XftDraw *d, RrTextureText *t, RrRect *area)
c.pixel = t->shadow_color->pixel; c.pixel = t->shadow_color->pixel;
/* see below... */ /* see below... */
if (!t->flow) {
pango_xft_render_layout_line pango_xft_render_layout_line
(d, &c, pango_layout_get_line(t->font->layout, 0), (d, &c,
#if PANGO_VERSION_MAJOR > 1 || \
(PANGO_VERSION_MAJOR == 1 && PANGO_VERSION_MINOR >= 16)
pango_layout_get_line_readonly(t->font->layout, 0),
#else
pango_layout_get_line(t->font->layout, 0),
#endif
(x + t->shadow_offset_x) * PANGO_SCALE, (x + t->shadow_offset_x) * PANGO_SCALE,
(y + t->shadow_offset_y) * PANGO_SCALE); (y + t->shadow_offset_y) * PANGO_SCALE);
} }
else {
pango_xft_render_layout(d, &c, t->font->layout,
(x + t->shadow_offset_x) * PANGO_SCALE,
(y + t->shadow_offset_y) * PANGO_SCALE);
}
}
c.color.red = t->color->r | t->color->r << 8; c.color.red = t->color->r | t->color->r << 8;
c.color.green = t->color->g | t->color->g << 8; c.color.green = t->color->g | t->color->g << 8;
@ -299,9 +329,23 @@ void RrFontDraw(XftDraw *d, RrTextureText *t, RrRect *area)
/* layout_line() uses y to specify the baseline /* layout_line() uses y to specify the baseline
The line doesn't need to be freed, it's a part of the layout */ The line doesn't need to be freed, it's a part of the layout */
if (!t->flow) {
pango_xft_render_layout_line pango_xft_render_layout_line
(d, &c, pango_layout_get_line(t->font->layout, 0), (d, &c,
x * PANGO_SCALE, y * PANGO_SCALE); #if PANGO_VERSION_MAJOR > 1 || \
(PANGO_VERSION_MAJOR == 1 && PANGO_VERSION_MINOR >= 16)
pango_layout_get_line_readonly(t->font->layout, 0),
#else
pango_layout_get_line(t->font->layout, 0),
#endif
x * PANGO_SCALE,
y * PANGO_SCALE);
}
else {
pango_xft_render_layout(d, &c, t->font->layout,
x * PANGO_SCALE,
y * PANGO_SCALE);
}
if (t->shortcut) { if (t->shortcut) {
t->font->shortcut_underline->start_index = 0; t->font->shortcut_underline->start_index = 0;

View file

@ -180,8 +180,6 @@ RrAppearance *RrAppearanceNew(const RrInstance *inst, gint numtex)
void RrAppearanceRemoveTextures(RrAppearance *a) void RrAppearanceRemoveTextures(RrAppearance *a)
{ {
gint i;
g_free(a->texture); g_free(a->texture);
a->textures = 0; a->textures = 0;
} }
@ -387,6 +385,7 @@ gint RrMinWidth(RrAppearance *a)
a->texture[i].data.text.string, a->texture[i].data.text.string,
a->texture[i].data.text.shadow_offset_x, a->texture[i].data.text.shadow_offset_x,
a->texture[i].data.text.shadow_offset_y, a->texture[i].data.text.shadow_offset_y,
a->texture[i].data.text.flow,
a->texture[i].data.text.maxwidth); a->texture[i].data.text.maxwidth);
w = MAX(w, m->width); w = MAX(w, m->width);
g_free(m); g_free(m);
@ -413,6 +412,7 @@ gint RrMinHeight(RrAppearance *a)
{ {
gint i; gint i;
gint l, t, r, b; gint l, t, r, b;
RrSize *m;
gint h = 0; gint h = 0;
for (i = 0; i < a->textures; ++i) { for (i = 0; i < a->textures; ++i) {
@ -423,7 +423,23 @@ gint RrMinHeight(RrAppearance *a)
h = MAX(h, a->texture[i].data.mask.mask->height); h = MAX(h, a->texture[i].data.mask.mask->height);
break; break;
case RR_TEXTURE_TEXT: case RR_TEXTURE_TEXT:
h += MAX(h, RrFontHeight(a->texture[i].data.text.font, if (a->texture[i].data.text.flow) {
g_assert(a->texture[i].data.text.string != NULL);
m = RrFontMeasureString
(a->texture[i].data.text.font,
a->texture[i].data.text.string,
a->texture[i].data.text.shadow_offset_x,
a->texture[i].data.text.shadow_offset_y,
a->texture[i].data.text.flow,
a->texture[i].data.text.maxwidth);
h += MAX(h, m->height);
g_free(m);
}
else
h += MAX(h,
RrFontHeight
(a->texture[i].data.text.font,
a->texture[i].data.text.shadow_offset_y)); a->texture[i].data.text.shadow_offset_y));
break; break;
case RR_TEXTURE_RGBA: case RR_TEXTURE_RGBA:

View file

@ -141,6 +141,7 @@ struct _RrTextureText {
gboolean shortcut; /*!< Underline a character */ gboolean shortcut; /*!< Underline a character */
guint shortcut_pos; /*!< Position in bytes of the character to underline */ guint shortcut_pos; /*!< Position in bytes of the character to underline */
RrEllipsizeMode ellipsize; RrEllipsizeMode ellipsize;
gboolean flow; /* allow multiple lines. must set maxwidth below */
gint maxwidth; gint maxwidth;
}; };
@ -254,7 +255,7 @@ RrFont *RrFontOpenDefault (const RrInstance *inst);
void RrFontClose (RrFont *f); void RrFontClose (RrFont *f);
RrSize *RrFontMeasureString (const RrFont *f, const gchar *str, RrSize *RrFontMeasureString (const RrFont *f, const gchar *str,
gint shadow_offset_x, gint shadow_offset_y, gint shadow_offset_x, gint shadow_offset_y,
gint maxwidth); gboolean flow, gint maxwidth);
gint RrFontHeight (const RrFont *f, gint shadow_offset_y); gint RrFontHeight (const RrFont *f, gint shadow_offset_y);
gint RrFontMaxCharWidth (const RrFont *f); gint RrFontMaxCharWidth (const RrFont *f);
@ -265,6 +266,8 @@ Pixmap RrPaintPixmap (RrAppearance *a, gint w, gint h);
void RrPaint (RrAppearance *a, Window win, gint w, gint h); void RrPaint (RrAppearance *a, Window win, gint w, gint h);
void RrMinSize (RrAppearance *a, gint *w, gint *h); void RrMinSize (RrAppearance *a, gint *w, gint *h);
gint RrMinWidth (RrAppearance *a); gint RrMinWidth (RrAppearance *a);
/* For text textures, if flow is TRUE, then the string must be set before
calling this, otherwise it doesn't need to be */
gint RrMinHeight (RrAppearance *a); gint RrMinHeight (RrAppearance *a);
void RrMargins (RrAppearance *a, gint *l, gint *t, gint *r, gint *b); void RrMargins (RrAppearance *a, gint *l, gint *t, gint *r, gint *b);