allow font rendering to use multiple lines
authorDana Jansens <danakj@orodu.net>
Thu, 7 Feb 2008 03:12:54 +0000 (22:12 -0500)
committerDana Jansens <danakj@orodu.net>
Thu, 14 Feb 2008 19:24:07 +0000 (14:24 -0500)
render/font.c
render/render.c
render/render.h

index 29d4821..2f06c73 100644 (file)
@@ -108,7 +108,6 @@ RrFont *RrFontOpen(const RrInstance *inst, const gchar *name, gint size,
 
     /* setup the layout */
     pango_layout_set_font_description(out->layout, out->font_desc);
 
     /* 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_wrap(out->layout, PANGO_WRAP_WORD_CHAR);
 
     /* get the ascent and descent */
     pango_layout_set_wrap(out->layout, PANGO_WRAP_WORD_CHAR);
 
     /* get the ascent and descent */
@@ -141,13 +140,20 @@ void RrFontClose(RrFont *f)
 
 static void font_measure_full(const RrFont *f, const gchar *str,
                               gint *x, gint *y, gint shadow_x, gint shadow_y,
 
 static void font_measure_full(const RrFont *f, const gchar *str,
                               gint *x, gint *y, gint shadow_x, gint shadow_y,
-                              gint maxwidth)
+                              gboolean flow, gint maxwidth)
 {
     PangoRectangle rect;
 
     pango_layout_set_text(f->layout, str, -1);
 {
     PangoRectangle rect;
 
     pango_layout_set_text(f->layout, str, -1);
-    pango_layout_set_width(f->layout,
-                           (maxwidth <= 0 ? -1 : maxwidth * PANGO_SCALE));
+    if (flow) {
+        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
        size of the text's area */
 
     /* pango_layout_get_pixel_extents lies! this is the right way to get the
        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);
     font_measure_full(f, str, &size->width, &size->height, shadow_x, shadow_y,
     size = g_new(RrSize, 1);
     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;
     PangoEllipsizeMode ell;
 
     PangoAttrList *attrlist;
     PangoEllipsizeMode ell;
 
-    /* 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);
+    g_assert(!t->flow || t->maxwidth > 0);
+
+    y = area->y;
+    if (!t->flow)
+        /* 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 += font_calculate_baseline(t->font, area->height);
 
     /* the +2 and -4 leave a small blank edge on the sides */
     x = area->x + 2;
 
     /* the +2 and -4 leave a small blank edge on the sides */
     x = area->x + 2;
-    w = area->width - 4;
+    w = area->width;
+    if (t->flow) w = MAX(w, t->maxwidth);
+    w -= 4;
     h = area->height;
 
     switch (t->ellipsize) {
     h = area->height;
 
     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_width(t->font->layout, w * PANGO_SCALE);
     pango_layout_set_ellipsize(t->font->layout, ell);
     pango_layout_set_text(t->font->layout, t->string, -1);
     pango_layout_set_width(t->font->layout, w * PANGO_SCALE);
     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 * * */
 
@@ -280,10 +297,23 @@ void RrFontDraw(XftDraw *d, RrTextureText *t, RrRect *area)
         c.pixel = t->shadow_color->pixel;
 
         /* see below... */
         c.pixel = t->shadow_color->pixel;
 
         /* see below... */
-        pango_xft_render_layout_line
-            (d, &c, pango_layout_get_line(t->font->layout, 0),
-             (x + t->shadow_offset_x) * PANGO_SCALE,
-             (y + t->shadow_offset_y) * PANGO_SCALE);
+        if (!t->flow) {
+            pango_xft_render_layout_line
+                (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,
+                 (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;
@@ -310,9 +340,23 @@ void RrFontDraw(XftDraw *d, RrTextureText *t, RrRect *area)
 
     /* layout_line() uses y to specify the baseline
        The line doesn't need to be freed, it's a part of the layout */
 
     /* 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);
+    if (!t->flow) {
+        pango_xft_render_layout_line
+            (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 * PANGO_SCALE,
+             y * PANGO_SCALE);
+    }
+    else {
+        pango_xft_render_layout(d, &c, t->font->layout,
+                                x * PANGO_SCALE,
+                                y * PANGO_SCALE);
+    }
 
     if (t->shortcut) {
         t->font->shortcut_underline->start_index = 0;
 
     if (t->shortcut) {
         t->font->shortcut_underline->start_index = 0;
index 2147df0..75dead1 100644 (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);
     a->textures = 0;
 }
     g_free(a->texture);
     a->textures = 0;
 }
@@ -387,6 +385,7 @@ gint RrMinWidth(RrAppearance *a)
                                     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.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);
             w = MAX(w, m->width);
             g_free(m);
                                     a->texture[i].data.text.maxwidth);
             w = MAX(w, m->width);
             g_free(m);
@@ -413,6 +412,7 @@ gint RrMinHeight(RrAppearance *a)
 {
     gint i;
     gint l, t, r, b;
 {
     gint i;
     gint l, t, r, b;
+    RrSize *m;
     gint h = 0;
 
     for (i = 0; i < a->textures; ++i) {
     gint h = 0;
 
     for (i = 0; i < a->textures; ++i) {
@@ -423,8 +423,24 @@ gint RrMinHeight(RrAppearance *a)
             h = MAX(h, a->texture[i].data.mask.mask->height);
             break;
         case RR_TEXTURE_TEXT:
             h = MAX(h, a->texture[i].data.mask.mask->height);
             break;
         case RR_TEXTURE_TEXT:
-            h += MAX(h, RrFontHeight(a->texture[i].data.text.font,
-                                     a->texture[i].data.text.shadow_offset_y));
+            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));
             break;
         case RR_TEXTURE_RGBA:
             h += MAX(h, a->texture[i].data.rgba.height);
             break;
         case RR_TEXTURE_RGBA:
             h += MAX(h, a->texture[i].data.rgba.height);
index c812c31..0034ad4 100644 (file)
@@ -141,6 +141,7 @@ struct _RrTextureText {
     gboolean shortcut; /*!< Underline a character */
     guint shortcut_pos; /*!< Position in bytes of the character to underline */
     RrEllipsizeMode ellipsize;
     gboolean shortcut; /*!< Underline a character */
     guint shortcut_pos; /*!< Position in bytes of the character to underline */
     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);
 RrSize *RrFontMeasureString (const RrFont *f, const gchar *str,
                              gint shadow_offset_x, gint shadow_offset_y,
 void    RrFontClose         (RrFont *f);
 RrSize *RrFontMeasureString (const RrFont *f, const gchar *str,
                              gint shadow_offset_x, gint shadow_offset_y,
-                             gint maxwidth);
+                             gboolean flow, gint maxwidth);
 gint    RrFontHeight        (const RrFont *f, gint shadow_offset_y);
 gint    RrFontMaxCharWidth  (const RrFont *f);
 
 gint    RrFontHeight        (const RrFont *f, gint shadow_offset_y);
 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   RrMinSize     (RrAppearance *a, gint *w, gint *h);
 gint   RrMinWidth    (RrAppearance *a);
 void   RrPaint       (RrAppearance *a, Window win, gint w, gint h);
 void   RrMinSize     (RrAppearance *a, gint *w, gint *h);
 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);
 void   RrMargins     (RrAppearance *a, gint *l, gint *t, gint *r, gint *b);
 
 gint   RrMinHeight   (RrAppearance *a);
 void   RrMargins     (RrAppearance *a, gint *l, gint *t, gint *r, gint *b);