From 59105341bce12b2ec009ff953facbb7f7b10e85f Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Tue, 5 Jan 2010 11:58:12 +0000 Subject: [PATCH] text: Store the markup attributes separately Previously when the markup property is set it would generate an attribute list from the markup and then merge it with the attributes from the attribute property and store it as the effective attributes. The markup attributes and the marked up text would then be forgotten. This breaks if the application then later changes the attributes property because it would try to regenerate the effective attributes from the markup text but the stored text no longer contains any markup. If the original markup text happened to contain entities like '<' they would end up causing parse errors because they would be converted to the actual symbols. To fix this the attributes from the markup are now stored independently from the effective attributes. The effective attributes are now regenerated if either set of attributes changes right before a layout is created. http://bugzilla.openedhand.com/show_bug.cgi?id=1940 --- clutter/clutter-text.c | 134 +++++++++++++++++++++++++---------------- 1 file changed, 82 insertions(+), 52 deletions(-) diff --git a/clutter/clutter-text.c b/clutter/clutter-text.c index 9925d903d..4cf56b5ba 100644 --- a/clutter/clutter-text.c +++ b/clutter/clutter-text.c @@ -112,8 +112,18 @@ struct _ClutterTextPrivate LayoutCache cached_layouts[N_CACHED_LAYOUTS]; guint cache_age; + /* These are the attributes set by the attributes property */ PangoAttrList *attrs; + /* These are the attributes derived from the text when the + use-markup property is set */ + PangoAttrList *markup_attrs; + /* This is the combination of the above two lists. It is set to NULL + whenever either of them changes and then regenerated by merging + the two lists whenever a layout is needed */ PangoAttrList *effective_attrs; + /* These are the attributes for the preedit string. These are merged + with the effective attributes into a temporary list before + creating a layout */ PangoAttrList *preedit_attrs; guint alignment : 2; @@ -287,6 +297,52 @@ clutter_text_get_display_text (ClutterText *self) } } +static void +clutter_text_ensure_effective_attributes (ClutterText *self) +{ + ClutterTextPrivate *priv = self->priv; + + /* If we already have the effective attributes then we don't need to + do anything */ + if (priv->effective_attrs == NULL) + { + if (priv->attrs) + { + /* If there are no markup attributes then we can just use + these attributes directly */ + if (priv->markup_attrs == NULL) + priv->effective_attrs = pango_attr_list_ref (priv->attrs); + else + { + /* Otherwise we need to merge the two lists */ + PangoAttrIterator *iter; + GSList *attributes, *l; + + priv->effective_attrs = pango_attr_list_copy (priv->markup_attrs); + + iter = pango_attr_list_get_iterator (priv->attrs); + do + { + attributes = pango_attr_iterator_get_attrs (iter); + + for (l = attributes; l != NULL; l = l->next) + { + PangoAttribute *attr = l->data; + + pango_attr_list_insert (priv->effective_attrs, attr); + } + + g_slist_free (attributes); + } + while (pango_attr_iterator_next (iter)); + } + } + else if (priv->markup_attrs) + /* We can just use the markup attributes directly */ + priv->effective_attrs = pango_attr_list_ref (priv->markup_attrs); + } +} + static PangoLayout * clutter_text_create_layout_no_cache (ClutterText *text, gfloat allocation_width, @@ -333,8 +389,15 @@ clutter_text_create_layout_no_cache (ClutterText *text, else pango_layout_set_text (layout, contents, contents_len); - if (!priv->editable && priv->effective_attrs) - pango_layout_set_attributes (layout, priv->effective_attrs); + if (!priv->editable) + { + /* This will merge the markup attributes and the attributes + property if needed */ + clutter_text_ensure_effective_attributes (text); + + if (priv->effective_attrs) + pango_layout_set_attributes (layout, priv->effective_attrs); + } pango_layout_set_alignment (layout, priv->alignment); pango_layout_set_single_paragraph_mode (layout, priv->single_line_mode); @@ -749,39 +812,6 @@ clutter_text_delete_selection (ClutterText *self) return TRUE; } -static void -clutter_text_merge_attributes (ClutterText *self) -{ - ClutterTextPrivate *priv = self->priv; - PangoAttrIterator *iter; - GSList *attributes, *l; - - if (!priv->attrs) - return; - - if (!priv->effective_attrs) - { - priv->effective_attrs = pango_attr_list_ref (priv->attrs); - return; - } - - iter = pango_attr_list_get_iterator (priv->attrs); - do - { - attributes = pango_attr_iterator_get_attrs (iter); - - for (l = attributes; l != NULL; l = l->next) - { - PangoAttribute *attr = l->data; - - pango_attr_list_insert (priv->effective_attrs, attr); - } - - g_slist_free (attributes); - } - while (pango_attr_iterator_next (iter)); -} - static inline void clutter_text_set_text_internal (ClutterText *self, const gchar *text) @@ -885,15 +915,18 @@ clutter_text_set_markup_internal (ClutterText *self, g_free (text); } - if (attrs) + /* Store the new markup attributes */ + if (priv->markup_attrs) + pango_attr_list_unref (priv->markup_attrs); + priv->markup_attrs = attrs; + + /* Clear the effective attributes so they will be regenerated when a + layout is created */ + if (priv->effective_attrs) { - if (priv->effective_attrs) - pango_attr_list_unref (priv->effective_attrs); - - priv->effective_attrs = attrs; + pango_attr_list_unref (priv->effective_attrs); + priv->effective_attrs = NULL; } - - clutter_text_merge_attributes (self); } static void @@ -1146,6 +1179,8 @@ clutter_text_finalize (GObject *gobject) if (priv->attrs) pango_attr_list_unref (priv->attrs); + if (priv->markup_attrs) + pango_attr_list_unref (priv->markup_attrs); if (priv->effective_attrs) pango_attr_list_unref (priv->effective_attrs); if (priv->preedit_attrs) @@ -3858,18 +3893,13 @@ clutter_text_set_attributes (ClutterText *self, priv->attrs = attrs; - if (!priv->use_markup) + /* Clear the effective attributes so they will be regenerated when a + layout is created */ + if (priv->effective_attrs) { - if (attrs) - pango_attr_list_ref (attrs); - - if (priv->effective_attrs) - pango_attr_list_unref (priv->effective_attrs); - - priv->effective_attrs = attrs; + pango_attr_list_unref (priv->effective_attrs); + priv->effective_attrs = NULL; } - else - clutter_text_set_markup_internal (self, priv->text); clutter_text_dirty_cache (self);