From d7ce56bb465735599de825d1545999999aa11125 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Tue, 16 Dec 2008 14:02:05 +0000 Subject: [PATCH 1/2] Support pango_layout_set_height() in ClutterText This is the port of the patch attached to bug 1266: ClutterLabel support for pango_layout_set_height() to the ClutterText actor. This patch adds support for the pango_layout_set_height() function inside the layout creation and caching, so that setting the height of a ClutterText will make PangoLayout try to fill out the given height before ellipsizing the contents of the ClutterText actor. The original patch is from Havoc Pennington. This commit ports the patch to ClutterText and applies a small change to the height computation pointed out by Behdad Esfahbod on GNOME's Bugzilla: http://bugzilla.gnome.org/show_bug.cgi?id=560931 That the layout heights when doing a size request should be set to be G_MAXINT instead of -1. Unfortunately, the patch seems to break the conformance suite when setting the ellipsization on the layout. --- clutter/clutter-text.c | 163 ++++++++++++++++++++++++++--------------- 1 file changed, 103 insertions(+), 60 deletions(-) diff --git a/clutter/clutter-text.c b/clutter/clutter-text.c index 4d70c2fc5..20c6bbe68 100644 --- a/clutter/clutter-text.c +++ b/clutter/clutter-text.c @@ -57,7 +57,7 @@ #include "clutter-private.h" #include "clutter-units.h" -#include "cogl-pango.h" +#include "pango/cogl-pango.h" #define DEFAULT_FONT_NAME "Sans 10" @@ -93,13 +93,16 @@ struct _LayoutCache */ PangoLayout *layout; - /* The width that used to generate this layout */ - ClutterUnit width; + /* The width that was used to generate this layout */ + ClutterUnit width; + + /* The height that was used to generate this layout */ + ClutterUnit height; /* A number representing the age of this cache (so that when a * new layout is needed the last used cache is replaced) */ - guint age; + guint age; }; struct _ClutterTextPrivate @@ -247,7 +250,8 @@ clutter_text_clear_selection (ClutterText *self) static PangoLayout * clutter_text_create_layout_no_cache (ClutterText *text, - ClutterUnit allocation_width) + ClutterUnit allocation_width, + ClutterUnit allocation_height) { ClutterTextPrivate *priv = text->priv; PangoLayout *layout; @@ -300,45 +304,65 @@ clutter_text_create_layout_no_cache (ClutterText *text, pango_layout_set_markup (layout, priv->text, -1); } - if (allocation_width > 0 && - (priv->ellipsize != PANGO_ELLIPSIZE_NONE || priv->wrap)) + /* Cases, assuming ellipsize != NONE on actor: + * + * Width request: ellipsization can be set or not on layout, + * doesn't matter. + * + * Height request: ellipsization must never be set on layout + * if wrap=true, because we need to measure the wrapped + * height. It must always be set if wrap=false. + * + * Allocate: ellipsization must always be set. + * + * See http://bugzilla.gnome.org/show_bug.cgi?id=560931 + */ + if (priv->ellipsize != PANGO_ELLIPSIZE_NONE) { - int layout_width, layout_height; - - pango_layout_get_size (layout, &layout_width, &layout_height); - - /* No need to set ellipsize or wrap if we already have enough - * space, since we don't want to make the layout wider than it - * would be otherwise. - */ - - if (CLUTTER_UNITS_FROM_PANGO_UNIT (layout_width) > allocation_width) - { - if (priv->ellipsize != PANGO_ELLIPSIZE_NONE) - { - gint width; - - width = allocation_width > 0 - ? CLUTTER_UNITS_TO_PANGO_UNIT (allocation_width) - : -1; - - pango_layout_set_ellipsize (layout, priv->ellipsize); - pango_layout_set_width (layout, width); - } - else if (priv->wrap) - { - gint width; - - width = allocation_width > 0 - ? CLUTTER_UNITS_TO_PANGO_UNIT (allocation_width) - : -1; - - pango_layout_set_wrap (layout, priv->wrap_mode); - pango_layout_set_width (layout, width); - } - } + if (allocation_height < 0 && priv->wrap) + ; /* must not set ellipsization on wrap=true height request */ + else + pango_layout_set_ellipsize (layout, priv->ellipsize); } + if (priv->wrap) + pango_layout_set_wrap (layout, priv->wrap_mode); + + if (allocation_width > 0) + { + gint width; + + width = allocation_width > 0 + ? CLUTTER_UNITS_FROM_PANGO_UNIT (allocation_width) + : -1; + + pango_layout_set_width (layout, width); + } + + /* Pango only uses height if ellipsization is enabled, so don't set + * height if ellipsize isn't set. Pango implicitly enables wrapping + * if height is set, so don't set height if wrapping is disabled. + * In other words, only set height if we want to both wrap then + * ellipsize. + * + * See http://bugzilla.gnome.org/show_bug.cgi?id=560931 if this + * seems odd. + */ + if (allocation_height > 0 && + priv->wrap && + priv->ellipsize != PANGO_ELLIPSIZE_NONE) + { + gint height; + + height = allocation_height > 0 + ? CLUTTER_UNITS_TO_PANGO_UNIT (allocation_height) + : -1; + + pango_layout_set_height (layout, height); + } + else + pango_layout_set_height (layout, G_MAXINT); + return layout; } @@ -362,6 +386,7 @@ clutter_text_dirty_cache (ClutterText *text) * clutter_text_create_layout: * @text: a #ClutterText * @allocation_width: the allocation width + * @allocation_height: the allocation height * * Like clutter_text_create_layout_no_cache(), but will also ensure * the glyphs cache. If a previously cached layout generated using the @@ -370,15 +395,17 @@ clutter_text_dirty_cache (ClutterText *text) */ static PangoLayout * clutter_text_create_layout (ClutterText *text, - ClutterUnit allocation_width) + ClutterUnit allocation_width, + ClutterUnit allocation_height) { ClutterTextPrivate *priv = text->priv; LayoutCache *oldest_cache = priv->cached_layouts; gboolean found_free_cache = FALSE; int i; - /* Search for a cached layout with the same width and keep track of - the oldest one */ + /* Search for a cached layout with the same width and keep + * track of the oldest one + */ for (i = 0; i < N_CACHED_LAYOUTS; i++) { if (priv->cached_layouts[i].layout == NULL) @@ -387,13 +414,16 @@ clutter_text_create_layout (ClutterText *text, found_free_cache = TRUE; oldest_cache = priv->cached_layouts + i; } - /* If this cached layout is using the same width then we can - just return that directly */ - else if (priv->cached_layouts[i].width == allocation_width) + else if (priv->cached_layouts[i].width == allocation_width && + priv->cached_layouts[i].height == allocation_height) { - CLUTTER_NOTE (ACTOR, "ClutterText: %p: cache hit for width %i", + /* If this cached layout is using the same size then we can + * just return that directly + */ + CLUTTER_NOTE (ACTOR, "ClutterText: %p: cache hit for size %i x %i", text, - CLUTTER_UNITS_TO_DEVICE (allocation_width)); + CLUTTER_UNITS_TO_DEVICE (allocation_width), + CLUTTER_UNITS_TO_DEVICE (allocation_height)); return priv->cached_layouts[i].layout; } @@ -404,9 +434,10 @@ clutter_text_create_layout (ClutterText *text, } } - CLUTTER_NOTE (ACTOR, "ClutterText: %p: cache miss for width %i", + CLUTTER_NOTE (ACTOR, "ClutterText: %p: cache miss for size %i x %i", text, - CLUTTER_UNITS_TO_DEVICE (allocation_width)); + CLUTTER_UNITS_TO_DEVICE (allocation_width), + CLUTTER_UNITS_TO_DEVICE (allocation_height)); /* If we make it here then we didn't have a cached version so we need to recreate the layout */ @@ -414,13 +445,16 @@ clutter_text_create_layout (ClutterText *text, g_object_unref (oldest_cache->layout); oldest_cache->layout = - clutter_text_create_layout_no_cache (text, allocation_width); + clutter_text_create_layout_no_cache (text, + allocation_width, + allocation_height); cogl_pango_ensure_glyph_cache_for_layout (oldest_cache->layout); /* Mark the 'time' this cache was created and advance the time */ oldest_cache->age = priv->cache_age++; oldest_cache->width = allocation_width; + oldest_cache->height = allocation_height; return oldest_cache->layout; } @@ -1035,7 +1069,9 @@ clutter_text_paint (ClutterActor *self) CLUTTER_NOTE (PAINT, "painting text (text:`%s')", priv->text); clutter_actor_get_allocation_box (self, &alloc); - layout = clutter_text_create_layout (text, alloc.x2 - alloc.x1); + layout = clutter_text_create_layout (text, + alloc.x2 - alloc.x1, + alloc.y2 - alloc.y1); real_opacity = clutter_actor_get_paint_opacity (self) * priv->text_color.alpha @@ -1062,7 +1098,7 @@ clutter_text_get_preferred_width (ClutterActor *self, gint logical_width; ClutterUnit layout_width; - layout = clutter_text_create_layout (text, -1); + layout = clutter_text_create_layout (text, -1, -1); pango_layout_get_extents (layout, NULL, &logical_rect); @@ -1111,7 +1147,7 @@ clutter_text_get_preferred_height (ClutterActor *self, gint logical_height; ClutterUnit layout_height; - layout = clutter_text_create_layout (text, for_width); + layout = clutter_text_create_layout (text, for_width, -1); pango_layout_get_extents (layout, NULL, &logical_rect); @@ -1124,7 +1160,12 @@ clutter_text_get_preferred_height (ClutterActor *self, layout_height = CLUTTER_UNITS_FROM_PANGO_UNIT (logical_height); if (min_height_p) - *min_height_p = layout_height; + { + if (text->priv->ellipsize) + *min_height_p = -1; + else + *min_height_p = layout_height; + } if (natural_height_p) *natural_height_p = layout_height; @@ -1142,7 +1183,9 @@ clutter_text_allocate (ClutterActor *self, /* Ensure that there is a cached layout with the right width so * that we don't need to create the text during the paint run */ - clutter_text_create_layout (text, box->x2 - box->x1); + clutter_text_create_layout (text, + box->x2 - box->x1, + box->y2 - box->y1); parent_class = CLUTTER_ACTOR_CLASS (clutter_text_parent_class); parent_class->allocate (self, box, origin_changed); @@ -2707,13 +2750,13 @@ clutter_text_set_text (ClutterText *self, PangoLayout * clutter_text_get_layout (ClutterText *self) { - ClutterUnit width; + ClutterUnit width, height; g_return_val_if_fail (CLUTTER_IS_TEXT (self), NULL); - width = clutter_actor_get_widthu (CLUTTER_ACTOR (self)); + clutter_actor_get_sizeu (CLUTTER_ACTOR (self), &width, &height); - return clutter_text_create_layout (self, width); + return clutter_text_create_layout (self, width, height); } /** From fbd9c59c7cb7901ec208d05416454a68c7329cfd Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Wed, 15 Apr 2009 14:46:45 +0100 Subject: [PATCH 2/2] [clutter-text] Fix ellipsizing Ellipsizing was effectively broken for two reasons. There was a typo in the code to set the width so it always ended up being some massive value. If no height should be set on the layout it was being set to G_MAXINT. Setting a height greater than 0 enables wrapping which so ellipsizing is not performed. It should be left at the default of -1 instead. --- clutter/clutter-text.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/clutter/clutter-text.c b/clutter/clutter-text.c index 20c6bbe68..3d57f4c31 100644 --- a/clutter/clutter-text.c +++ b/clutter/clutter-text.c @@ -333,7 +333,7 @@ clutter_text_create_layout_no_cache (ClutterText *text, gint width; width = allocation_width > 0 - ? CLUTTER_UNITS_FROM_PANGO_UNIT (allocation_width) + ? CLUTTER_UNITS_TO_PANGO_UNIT (allocation_width) : -1; pango_layout_set_width (layout, width); @@ -360,8 +360,6 @@ clutter_text_create_layout_no_cache (ClutterText *text, pango_layout_set_height (layout, height); } - else - pango_layout_set_height (layout, G_MAXINT); return layout; }