Esempio n. 1
0
/* Cleanup memory allocation
 */
static void
free_state (EllipsizeState *state)
{
  if (state->line_start_attr)
    pango_attr_iterator_destroy (state->line_start_attr);
  if (state->gap_start_attr)
    pango_attr_iterator_destroy (state->gap_start_attr);
  g_free (state->run_info);
}
Esempio n. 2
0
/* Updates the shaping of the ellipsis if necessary when we move the
 * position of the start of the gap.
 *
 * The shaping of the ellipsis is determined by two things:
 *
 * - The font attributes applied to the first character in the gap
 * - Whether the first character in the gap is wide or not. If the
 *   first character is wide, then we assume that we are ellipsizing
 *   East-Asian text, so prefer a mid-line ellipsizes to a baseline
 *   ellipsis, since that's typical practice for Chinese/Japanese/Korean.
 */
static void
update_ellipsis_shape (EllipsizeState *state)
{
  gboolean recompute = FALSE;
  gunichar start_wc;
  gboolean is_cjk;

  /* Unfortunately, we can only advance PangoAttrIterator forward; so each
   * time we back up we need to go forward to find the new position. To make
   * this not utterly slow, we cache an iterator at the start of the line
   */
  if (!state->line_start_attr)
    {
      state->line_start_attr = pango_attr_list_get_iterator (state->attrs);
      advance_iterator_to (state->line_start_attr, state->run_info[0].run->item->offset);
    }

  if (state->gap_start_attr)
    {
      /* See if the current attribute range contains the new start position
       */
      int start, end;
      
      pango_attr_iterator_range (state->gap_start_attr, &start, &end);

      if (state->gap_start_iter.run_iter.start_index < start)
	{
	  pango_attr_iterator_destroy (state->gap_start_attr);
	  state->gap_start_attr = NULL;
	}
    }

  /* Check whether we need to recompute the ellipsis because of new font attributes
   */
  if (!state->gap_start_attr)
    {
      state->gap_start_attr = pango_attr_iterator_copy (state->line_start_attr);
      advance_iterator_to (state->gap_start_attr,
			   state->run_info[state->gap_start_iter.run_index].run->item->offset);
      
      recompute = TRUE;
    }

  /* Check whether we need to recompute the ellipsis because we switch from CJK to not
   * or vice-versa
   */
  start_wc = g_utf8_get_char (state->layout->text + state->gap_start_iter.run_iter.start_index);
  is_cjk = g_unichar_iswide (start_wc);

  if (is_cjk != state->ellipsis_is_cjk)
    {
      state->ellipsis_is_cjk = is_cjk;
      recompute = TRUE;
    }

  if (recompute)
    shape_ellipsis (state);
}
Esempio n. 3
0
PangoAttrList *
go_pango_translate_attributes (PangoAttrList *attrs)
{
	PangoAttrList *n_attrs, *filtered;

	if (attrs == NULL)
		return NULL;

	n_attrs = pango_attr_list_copy (attrs);
	filtered = pango_attr_list_filter (n_attrs, filter_func, NULL);

	if (filtered == NULL) {
		pango_attr_list_unref (n_attrs);
		return attrs;
	} else {
		PangoAttrIterator *iter, *f_iter;
		f_iter = pango_attr_list_get_iterator (filtered);
		do {
			gint f_range_start, f_range_end;
			gint range_start, range_end;
			/* We need to restart everytime since we are changing n_attrs */
			iter = pango_attr_list_get_iterator (n_attrs);
			pango_attr_iterator_range (f_iter, &f_range_start,
						   &f_range_end);
			pango_attr_iterator_range (iter, &range_start,
						   &range_end);
			while (range_end <= f_range_start) {
				if (!pango_attr_iterator_next (iter))
					break;
				pango_attr_iterator_range (iter, &range_start,
						   &range_end);
			}
			/* Now range_end > f_range_start >= range_start */
			go_pango_translate_here (iter, f_iter, n_attrs);
			pango_attr_iterator_destroy (iter);
		} while (pango_attr_iterator_next (f_iter));
		pango_attr_iterator_destroy (f_iter);
	}
	pango_attr_list_unref (filtered);
	return n_attrs;
}
Esempio n. 4
0
static GSList *
attrs_at_byte (PangoAttrList *alist, gint bytepos)
{
	PangoAttrIterator *iter = pango_attr_list_get_iterator (alist);
	GSList *attrs = NULL;

	do {
		gint start, end;
		pango_attr_iterator_range (iter, &start, &end);
		if (start <= bytepos && bytepos < end) {
			attrs = pango_attr_iterator_get_attrs (iter);
			break;
		}
	} while (pango_attr_iterator_next (iter));
	pango_attr_iterator_destroy (iter);

	return attrs;
}
Esempio n. 5
0
char *
go_pango_attrs_to_markup (PangoAttrList *attrs, char const *text)
{
	PangoAttrIterator * iter;
	int handled = 0;
	int from, to;
	int len;
	GString *gstr;

	if (text == NULL)
		return NULL;
	if (attrs == NULL || go_pango_attr_list_is_empty (attrs))
		return g_strdup (text);

	len = strlen (text);
	gstr = g_string_sized_new (len + 1);

	iter = pango_attr_list_get_iterator (attrs);
	do {
		GSList *list, *l;
		int spans = 0;

		pango_attr_iterator_range (iter, &from, &to);
		to = (to > len) ? len : to;       /* Since "to" can be really big! */
		from = (from > len) ? len : from; /* Since "from" can also be really big! */
		if (from > handled)
			g_string_append_len (gstr, text + handled, from - handled);
		list = pango_attr_iterator_get_attrs (iter);
		for (l = list; l != NULL; l = l->next)
			spans += go_pango_attr_as_markup_string (l->data, gstr);
		g_slist_free (list);
		if (to > from)
			g_string_append_len (gstr, text + from, to - from);
		while (spans-- > 0)
			g_string_append (gstr, "</span>");
		handled = to;
	} while (pango_attr_iterator_next (iter));

	pango_attr_iterator_destroy (iter);

	return g_string_free (gstr, FALSE);
}
Esempio n. 6
0
static void
html_new_markup (GsfOutput *output, const PangoAttrList *markup, char const *text,
		 html_version_t version)
{
	int handled = 0;
	PangoAttrIterator * iter;
	int from, to;
	int len = strlen (text);
	GString *closure = g_string_new ("");

	iter = pango_attr_list_get_iterator ((PangoAttrList *) markup);

	do {
		GSList *list, *l;

		g_string_erase (closure, 0, -1);
		pango_attr_iterator_range (iter, &from, &to);
		from = (from > len) ? len : from; /* Since "from" can be really big! */
		to = (to > len) ? len : to;       /* Since "to" can be really big!   */
		if (from > handled)
			cb_html_add_chars (output, text + handled, from - handled);
		list = pango_attr_iterator_get_attrs (iter);
		for (l = list; l != NULL; l = l->next) {
			char const *result = cb_html_attrs_as_string (output, l->data, version);
			if (result != NULL)
				g_string_prepend (closure, result);
		}
		g_slist_free (list);
		if (to > from)
			cb_html_add_chars (output, text + from, to - from);
		gsf_output_puts (output, closure->str);
		handled = to;
	} while (pango_attr_iterator_next (iter));

	g_string_free (closure, TRUE);
	pango_attr_iterator_destroy (iter);

	return;
}
Esempio n. 7
0
static void
dump_attrs (PangoAttrList *attrs, GString *string)
{
  PangoAttrIterator *iter;

  iter = pango_attr_list_get_iterator (attrs);
  do {
    gint start, end;
    GSList *list, *l;

    pango_attr_iterator_range (iter, &start, &end);
    g_string_append_printf (string, "range %d %d\n", start, end);
    list = pango_attr_iterator_get_attrs (iter);
    for (l = list; l; l = l->next)
      {
        PangoAttribute *attr = l->data;
        print_attr (attr, string);
      }
    g_slist_free_full (list, (GDestroyNotify)pango_attribute_destroy);
  } while (pango_attr_iterator_next (iter));

  pango_attr_iterator_destroy (iter);
}
Esempio n. 8
0
void
go_load_pango_attributes_into_buffer (PangoAttrList  *markup, GtkTextBuffer *buffer, gchar const *str)
{
	PangoAttrIterator * iter;
	PangoAttrList  *copied_markup;
	PangoAttrList  *our_markup;

	if (markup == NULL)
		return;

/* For some styles we create named tags. The names are taken from the Pango enums */

	copied_markup = pango_attr_list_copy (markup);
	our_markup = pango_attr_list_filter (copied_markup,
					     go_load_pango_attributes_into_buffer_named_filter,
					     NULL);
	pango_attr_list_unref (copied_markup);
	if (our_markup != NULL) {
		iter = pango_attr_list_get_iterator (our_markup);

		do {
			GSList *attr = pango_attr_iterator_get_attrs (iter);
			if (attr != NULL) {
				GSList *ptr;
				gint start, end;
				GtkTextIter start_iter, end_iter;
				char const *name;

				pango_attr_iterator_range (iter, &start, &end);
				start = go_load_pango_byte_to_char (str, start);
				end = go_load_pango_byte_to_char (str, end);
				gtk_text_buffer_get_iter_at_offset (buffer, &start_iter, start);
				gtk_text_buffer_get_iter_at_offset (buffer, &end_iter, end);

				for (ptr = attr; ptr != NULL; ptr = ptr->next) {
					PangoAttribute *attribute = ptr->data;
					GtkTextTag *tag;
					int val;

					switch (attribute->klass->type) {
					case PANGO_ATTR_STYLE:
						name = (((PangoAttrInt *)attribute)->value
							== PANGO_STYLE_NORMAL)
							? "PANGO_STYLE_NORMAL" :
							"PANGO_STYLE_ITALIC";
						tag = gtk_text_tag_table_lookup
							(gtk_text_buffer_get_tag_table (buffer),
							 name);
						gtk_text_buffer_apply_tag (buffer, tag,
									   &start_iter, &end_iter);
						break;
					case PANGO_ATTR_STRIKETHROUGH:
						name = (((PangoAttrInt *)attribute)->value) ?
							"PANGO_STRIKETHROUGH_TRUE" :
							"PANGO_STRIKETHROUGH_FALSE";
						tag = gtk_text_tag_table_lookup
							(gtk_text_buffer_get_tag_table (buffer),
							 name);
						gtk_text_buffer_apply_tag (buffer, tag,
									   &start_iter, &end_iter);
						break;
					case PANGO_ATTR_UNDERLINE:
						val = ((PangoAttrInt *)attribute)->value;
						if (val == PANGO_UNDERLINE_NONE)
							gtk_text_buffer_apply_tag_by_name (buffer,"PANGO_UNDERLINE_NONE",
											   &start_iter, &end_iter);
						else if (val == PANGO_UNDERLINE_SINGLE)
							gtk_text_buffer_apply_tag_by_name (buffer,"PANGO_UNDERLINE_SINGLE",
											   &start_iter, &end_iter);
						else if (val == PANGO_UNDERLINE_DOUBLE)
							gtk_text_buffer_apply_tag_by_name (buffer,"PANGO_UNDERLINE_DOUBLE",
											   &start_iter, &end_iter);
						else if (val == PANGO_UNDERLINE_LOW)
							gtk_text_buffer_apply_tag_by_name (buffer,"PANGO_UNDERLINE_LOW",
											   &start_iter, &end_iter);
						else if (val == PANGO_UNDERLINE_ERROR)
							gtk_text_buffer_apply_tag_by_name (buffer,"PANGO_UNDERLINE_ERROR",
											   &start_iter, &end_iter);
						break;
					case PANGO_ATTR_WEIGHT:
						val = ((PangoAttrInt *)attribute)->value;
						if (val < (PANGO_WEIGHT_THIN + PANGO_WEIGHT_ULTRALIGHT)/2)
							gtk_text_buffer_apply_tag_by_name (buffer,"PANGO_WEIGHT_THIN",
											   &start_iter, &end_iter);
						else if (val < (PANGO_WEIGHT_ULTRALIGHT + PANGO_WEIGHT_LIGHT)/2)
							gtk_text_buffer_apply_tag_by_name (buffer,"PANGO_WEIGHT_ULTRALIGHT",
											   &start_iter, &end_iter);
						else if (val < (PANGO_WEIGHT_LIGHT + PANGO_WEIGHT_BOOK)/2)
							gtk_text_buffer_apply_tag_by_name (buffer,"PANGO_WEIGHT_LIGHT",
											   &start_iter, &end_iter);
						else if (val < (PANGO_WEIGHT_BOOK + PANGO_WEIGHT_NORMAL)/2)
							gtk_text_buffer_apply_tag_by_name (buffer,"PANGO_WEIGHT_BOOK",
											   &start_iter, &end_iter);
						else if (val < (PANGO_WEIGHT_NORMAL + PANGO_WEIGHT_MEDIUM)/2)
							gtk_text_buffer_apply_tag_by_name (buffer,"PANGO_WEIGHT_NORMAL",
											   &start_iter, &end_iter);
						else if (val < (PANGO_WEIGHT_MEDIUM + PANGO_WEIGHT_SEMIBOLD)/2)
							gtk_text_buffer_apply_tag_by_name (buffer,"PANGO_WEIGHT_MEDIUM",
											   &start_iter, &end_iter);
						else if (val < (PANGO_WEIGHT_SEMIBOLD + PANGO_WEIGHT_BOLD)/2)
							gtk_text_buffer_apply_tag_by_name (buffer,"PANGO_WEIGHT_SEMIBOLD",
											   &start_iter, &end_iter);
						else if (val < (PANGO_WEIGHT_BOLD + PANGO_WEIGHT_ULTRABOLD)/2)
							gtk_text_buffer_apply_tag_by_name (buffer,"PANGO_WEIGHT_BOLD",
											   &start_iter, &end_iter);
						else if (val < (PANGO_WEIGHT_ULTRABOLD + PANGO_WEIGHT_HEAVY)/2)
							gtk_text_buffer_apply_tag_by_name (buffer,"PANGO_WEIGHT_ULTRABOLD",
											   &start_iter, &end_iter);
						else if (val < (PANGO_WEIGHT_HEAVY + PANGO_WEIGHT_ULTRAHEAVY)/2)
							gtk_text_buffer_apply_tag_by_name (buffer,"PANGO_WEIGHT_HEAVY",
											   &start_iter, &end_iter);
						else gtk_text_buffer_apply_tag_by_name (buffer,"PANGO_WEIGHT_ULTRAHEAVY",
											&start_iter, &end_iter);
						break;
					default:
						break;
					}
				}
				g_slist_free_full (attr, (GDestroyNotify)pango_attribute_destroy);
			}
		} while (pango_attr_iterator_next (iter));
		pango_attr_iterator_destroy (iter);
		pango_attr_list_unref (our_markup);
	}

/* For other styles (that are not at true/false type styles) we use unnamed styles */

	copied_markup = pango_attr_list_copy (markup);
	our_markup = pango_attr_list_filter (copied_markup,
					     go_load_pango_attributes_into_buffer_filter,
					     NULL);
	pango_attr_list_unref (copied_markup);
	if (our_markup != NULL) {
		iter = pango_attr_list_get_iterator (our_markup);

		do {
			GSList *attr = pango_attr_iterator_get_attrs (iter);
			if (attr != NULL) {
				char *string;
				GSList *ptr;
				gint start, end;
				GtkTextIter start_iter, end_iter;
				GtkTextTag *tag = gtk_text_buffer_create_tag (buffer, NULL, NULL);
				for (ptr = attr; ptr != NULL; ptr = ptr->next) {
					PangoAttribute *attribute = ptr->data;
					switch (attribute->klass->type) {
					case PANGO_ATTR_FOREGROUND:
						string = pango_color_to_string
							(&((PangoAttrColor *)attribute)->color);
						g_object_set (G_OBJECT (tag),
							      "foreground", string,
							      "foreground-set", TRUE,
							      NULL);
						g_free (string);
						break;
					case PANGO_ATTR_RISE:
						g_object_set (G_OBJECT (tag),
							      "rise",
							      ((PangoAttrInt *)attribute)->value,
							      "rise-set", TRUE,
							      NULL);
						break;
					default:
						break;
					}
				}
				pango_attr_iterator_range (iter, &start, &end);
				start = go_load_pango_byte_to_char (str, start);
				end = go_load_pango_byte_to_char (str, end);
				gtk_text_buffer_get_iter_at_offset (buffer, &start_iter, start);
				gtk_text_buffer_get_iter_at_offset (buffer, &end_iter, end);
				gtk_text_buffer_apply_tag (buffer, tag, &start_iter, &end_iter);
				g_slist_free_full (attr, (GDestroyNotify)pango_attribute_destroy);
			}
		} while (pango_attr_iterator_next (iter));
		pango_attr_iterator_destroy (iter);
		pango_attr_list_unref (our_markup);
	}
}
Esempio n. 9
0
static AtkAttributeSet *
get_run_attributes (PangoAttrList   *attrs,
		    const gchar     *text,
		    gint             offset,
		    gint            *start_offset,
		    gint            *end_offset)
{
	AtkAttributeSet   *atk_attr_set = NULL;
	PangoAttrString   *pango_string;
	PangoAttrInt      *pango_int;
	PangoAttrColor    *pango_color;
	PangoAttrIterator *iter;
	gint               i, start, end;
	gboolean           has_attrs = FALSE;
	glong              text_length;
	gchar             *attr_value;

	text_length = g_utf8_strlen (text, -1);
	if (offset < 0 || offset >= text_length)
		return NULL;

	/* Check if there are attributes for the offset,
	 * and set the attributes range if positive */
	iter = pango_attr_list_get_iterator (attrs);
	i = g_utf8_offset_to_pointer (text, offset) - text;

	do {
		pango_attr_iterator_range (iter, &start, &end);
		if (i >= start && i < end) {
			*start_offset = g_utf8_pointer_to_offset (text, text + start);
			if (end == G_MAXINT) /* Last iterator */
				end = text_length;
			*end_offset = g_utf8_pointer_to_offset (text, text + end);
			 has_attrs = TRUE;
		}
	} while (!has_attrs && pango_attr_iterator_next (iter));

	if (!has_attrs) {
		pango_attr_iterator_destroy (iter);
		return NULL;
	}

	/* Create the AtkAttributeSet from the Pango attributes */
	pango_string = (PangoAttrString *) pango_attr_iterator_get (iter, PANGO_ATTR_FAMILY);
	if (pango_string) {
		attr_value = g_strdup (pango_string->value);
		atk_attr_set = add_attribute (atk_attr_set, ATK_TEXT_ATTR_FAMILY_NAME, attr_value);
	}

	pango_int = (PangoAttrInt *) pango_attr_iterator_get (iter, PANGO_ATTR_SIZE);
	if (pango_int) {
		attr_value = g_strdup_printf ("%i", pango_int->value / PANGO_SCALE);
		atk_attr_set = add_attribute (atk_attr_set, ATK_TEXT_ATTR_SIZE, attr_value);
	}

	pango_int = (PangoAttrInt *) pango_attr_iterator_get (iter, PANGO_ATTR_UNDERLINE);
	if (pango_int) {
		atk_attr_set = add_attribute (atk_attr_set,
					      ATK_TEXT_ATTR_UNDERLINE,
					      g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_UNDERLINE,
										      pango_int->value)));
	}

	pango_color = (PangoAttrColor *) pango_attr_iterator_get (iter, PANGO_ATTR_FOREGROUND);
	if (pango_color) {
		attr_value = g_strdup_printf ("%u,%u,%u",
					      pango_color->color.red,
					      pango_color->color.green,
					      pango_color->color.blue);
		atk_attr_set = add_attribute (atk_attr_set, ATK_TEXT_ATTR_FG_COLOR, attr_value);
	}

	pango_attr_iterator_destroy (iter);

	return atk_attr_set;
}
Esempio n. 10
0
/**
 * gail_misc_layout_get_run_attributes:
 * @attrib_set: The #AtkAttributeSet to add the attribute to
 * @layout: The PangoLayout from which the attributes will be obtained
 * @text: The text 
 * @offset: The offset at which the attributes are required
 * @start_offset: The start offset of the current run
 * @end_offset: The end offset of the current run
 *
 * Adds the attributes for the run starting at offset to the specified
 * attribute set.
 *
 * Returns: A pointer to the #AtkAttributeSet.
 **/
AtkAttributeSet* 
gail_misc_layout_get_run_attributes (AtkAttributeSet *attrib_set,
                                     PangoLayout     *layout,
                                     const gchar     *text,
                                     gint            offset,
                                     gint            *start_offset,
                                     gint            *end_offset)
{
  PangoAttrIterator *iter;
  PangoAttrList *attr;  
  PangoAttrString *pango_string;
  PangoAttrInt *pango_int;
  PangoAttrColor *pango_color;
  PangoAttrLanguage *pango_lang;
  PangoAttrFloat *pango_float;
  gint index, start_index, end_index;
  gboolean is_next = TRUE;
  gchar *value = NULL;
  glong len;

  len = g_utf8_strlen (text, -1);
  /* Grab the attributes of the PangoLayout, if any */
  if ((attr = pango_layout_get_attributes (layout)) == NULL)
    {
      *start_offset = 0;
      *end_offset = len;
      return attrib_set;
    }
  iter = pango_attr_list_get_iterator (attr);
  /* Get invariant range offsets */
  /* If offset out of range, set offset in range */
  if (offset > len)
    offset = len;
  else if (offset < 0)
    offset = 0;

  index = g_utf8_offset_to_pointer (text, offset) - text;
  pango_attr_iterator_range (iter, &start_index, &end_index);
  while (is_next)
    {
      if (index >= start_index && index < end_index)
        {
          *start_offset = g_utf8_pointer_to_offset (text, 
                                                    text + start_index);  
          if (end_index == G_MAXINT)
          /* Last iterator */
            end_index = len;
      
          *end_offset = g_utf8_pointer_to_offset (text, 
                                                  text + end_index);  
          break;
        }  
      is_next = pango_attr_iterator_next (iter);
      pango_attr_iterator_range (iter, &start_index, &end_index);
    }
  /* Get attributes */
  if ((pango_string = (PangoAttrString*) pango_attr_iterator_get (iter, 
                                   PANGO_ATTR_FAMILY)) != NULL)
    {
      value = g_strdup_printf("%s", pango_string->value);
      attrib_set = gail_misc_add_attribute (attrib_set, 
                                            ATK_TEXT_ATTR_FAMILY_NAME, 
                                            value);
    } 
  if ((pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, 
                                   PANGO_ATTR_STYLE)) != NULL)
    {
      attrib_set = gail_misc_add_attribute (attrib_set, 
                                            ATK_TEXT_ATTR_STYLE, 
      g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_STYLE, pango_int->value)));
    } 
  if ((pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, 
                                   PANGO_ATTR_WEIGHT)) != NULL)
    {
      value = g_strdup_printf("%i", pango_int->value);
      attrib_set = gail_misc_add_attribute (attrib_set, 
                                            ATK_TEXT_ATTR_WEIGHT, 
                                            value);
    } 
  if ((pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, 
                                   PANGO_ATTR_VARIANT)) != NULL)
    {
      attrib_set = gail_misc_add_attribute (attrib_set, 
                                            ATK_TEXT_ATTR_VARIANT, 
       g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_VARIANT, pango_int->value)));
    } 
  if ((pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, 
                                   PANGO_ATTR_STRETCH)) != NULL)
    {
      attrib_set = gail_misc_add_attribute (attrib_set, 
                                            ATK_TEXT_ATTR_STRETCH, 
       g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_STRETCH, pango_int->value)));
    } 
  if ((pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, 
                                   PANGO_ATTR_SIZE)) != NULL)
    {
      value = g_strdup_printf("%i", pango_int->value / PANGO_SCALE);
      attrib_set = gail_misc_add_attribute (attrib_set, 
                                            ATK_TEXT_ATTR_SIZE,
                                            value);
    } 
  if ((pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, 
                                   PANGO_ATTR_UNDERLINE)) != NULL)
    {
      attrib_set = gail_misc_add_attribute (attrib_set, 
                                            ATK_TEXT_ATTR_UNDERLINE, 
       g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_UNDERLINE, pango_int->value)));
    } 
  if ((pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, 
                                   PANGO_ATTR_STRIKETHROUGH)) != NULL)
    {
      attrib_set = gail_misc_add_attribute (attrib_set, 
                                            ATK_TEXT_ATTR_STRIKETHROUGH, 
       g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_STRIKETHROUGH, pango_int->value)));
    } 
  if ((pango_int = (PangoAttrInt*) pango_attr_iterator_get (iter, 
                                   PANGO_ATTR_RISE)) != NULL)
    {
      value = g_strdup_printf("%i", pango_int->value);
      attrib_set = gail_misc_add_attribute (attrib_set, 
                                            ATK_TEXT_ATTR_RISE,
                                            value);
    } 
  if ((pango_lang = (PangoAttrLanguage*) pango_attr_iterator_get (iter, 
                                   PANGO_ATTR_LANGUAGE)) != NULL)
    {
      value = g_strdup( pango_language_to_string( pango_lang->value));
      attrib_set = gail_misc_add_attribute (attrib_set, 
                                            ATK_TEXT_ATTR_LANGUAGE, 
                                            value);
    } 
  if ((pango_float = (PangoAttrFloat*) pango_attr_iterator_get (iter, 
                                   PANGO_ATTR_SCALE)) != NULL)
    {
      value = g_strdup_printf("%g", pango_float->value);
      attrib_set = gail_misc_add_attribute (attrib_set, 
                                            ATK_TEXT_ATTR_SCALE, 
                                            value);
    } 
  if ((pango_color = (PangoAttrColor*) pango_attr_iterator_get (iter, 
                                    PANGO_ATTR_FOREGROUND)) != NULL)
    {
      value = g_strdup_printf ("%u,%u,%u", 
                               pango_color->color.red, 
                               pango_color->color.green, 
                               pango_color->color.blue);
      attrib_set = gail_misc_add_attribute (attrib_set, 
                                            ATK_TEXT_ATTR_FG_COLOR, 
                                            value);
    } 
  if ((pango_color = (PangoAttrColor*) pango_attr_iterator_get (iter, 
                                     PANGO_ATTR_BACKGROUND)) != NULL)
    {
      value = g_strdup_printf ("%u,%u,%u", 
                               pango_color->color.red, 
                               pango_color->color.green, 
                               pango_color->color.blue);
      attrib_set = gail_misc_add_attribute (attrib_set, 
                                            ATK_TEXT_ATTR_BG_COLOR, 
                                            value);
    } 
  pango_attr_iterator_destroy (iter);
  return attrib_set;
}
static void
gtk_text_buffer_insert_markup(GtkTextBuffer * buffer, GtkTextIter * iter,
			      const gchar * markup)
{
    PangoAttrIterator *paiter;
    PangoAttrList *attrlist;
    GtkTextMark *mark;
    GError *error = NULL;
    gchar *text;

    g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer));
    g_return_if_fail(markup != NULL);

    if (*markup == '\000')
	return;

    /* invalid */
    if (!pango_parse_markup(markup, -1, 0, &attrlist, &text, NULL, &error)) {
	g_warning("Invalid markup string: %s", error->message);
	g_error_free(error);
	return;
    }

    /* trivial, no markup */
    if (attrlist == NULL) {
	gtk_text_buffer_insert(buffer, iter, text, -1);
	g_free(text);
	return;
    }

    /* create mark with right gravity */
    mark = gtk_text_buffer_create_mark(buffer, NULL, iter, FALSE);
    paiter = pango_attr_list_get_iterator(attrlist);

    do {
	PangoAttribute *attr;
	GtkTextTag *tag;
	GtkTextTag *tag_para;
	gint start, end;

	pango_attr_iterator_range(paiter, &start, &end);

	if (end == G_MAXINT)	/* last chunk */
	    end = start - 1;	/* resulting in -1 to be passed to _insert */

	tag = gtk_text_tag_new(NULL);

	if ((attr = pango_attr_iterator_get(paiter, PANGO_ATTR_LANGUAGE)))
	    g_object_set(tag, "language",
			 pango_language_to_string(((PangoAttrLanguage *)
						   attr)->value), NULL);

	if ((attr = pango_attr_iterator_get(paiter, PANGO_ATTR_FAMILY)))
	    g_object_set(tag, "family", ((PangoAttrString *) attr)->value,
			 NULL);

	if ((attr = pango_attr_iterator_get(paiter, PANGO_ATTR_STYLE)))
	    g_object_set(tag, "style", ((PangoAttrInt *) attr)->value,
			 NULL);

	if ((attr = pango_attr_iterator_get(paiter, PANGO_ATTR_WEIGHT)))
	    g_object_set(tag, "weight", ((PangoAttrInt *) attr)->value,
			 NULL);

	if ((attr = pango_attr_iterator_get(paiter, PANGO_ATTR_VARIANT)))
	    g_object_set(tag, "variant", ((PangoAttrInt *) attr)->value,
			 NULL);

	if ((attr = pango_attr_iterator_get(paiter, PANGO_ATTR_STRETCH)))
	    g_object_set(tag, "stretch", ((PangoAttrInt *) attr)->value,
			 NULL);

	if ((attr = pango_attr_iterator_get(paiter, PANGO_ATTR_SIZE)))
	    g_object_set(tag, "size", ((PangoAttrInt *) attr)->value,
			 NULL);

	if ((attr = pango_attr_iterator_get(paiter, PANGO_ATTR_FONT_DESC)))
	    g_object_set(tag, "font-desc",
			 ((PangoAttrFontDesc *) attr)->desc, NULL);

	if ((attr =
	     pango_attr_iterator_get(paiter, PANGO_ATTR_FOREGROUND))) {
	    GdkColor col = { 0,
		((PangoAttrColor *) attr)->color.red,
		((PangoAttrColor *) attr)->color.green,
		((PangoAttrColor *) attr)->color.blue
	    };

	    g_object_set(tag, "foreground-gdk", &col, NULL);
	}

	if ((attr =
	     pango_attr_iterator_get(paiter, PANGO_ATTR_BACKGROUND))) {
	    GdkColor col = { 0,
		((PangoAttrColor *) attr)->color.red,
		((PangoAttrColor *) attr)->color.green,
		((PangoAttrColor *) attr)->color.blue
	    };

	    g_object_set(tag, "background-gdk", &col, NULL);
	}

	if ((attr = pango_attr_iterator_get(paiter, PANGO_ATTR_UNDERLINE)))
	    g_object_set(tag, "underline", ((PangoAttrInt *) attr)->value,
			 NULL);

	if ((attr =
	     pango_attr_iterator_get(paiter, PANGO_ATTR_STRIKETHROUGH)))
	    g_object_set(tag, "strikethrough",
			 (gboolean) (((PangoAttrInt *) attr)->value != 0),
			 NULL);

	if ((attr = pango_attr_iterator_get(paiter, PANGO_ATTR_RISE)))
	    g_object_set(tag, "rise", ((PangoAttrInt *) attr)->value,
			 NULL);

	if ((attr = pango_attr_iterator_get(paiter, PANGO_ATTR_SCALE)))
	    g_object_set(tag, "scale", ((PangoAttrFloat *) attr)->value,
			 NULL);

	gtk_text_tag_table_add(gtk_text_buffer_get_tag_table(buffer), tag);

	tag_para =
	    gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table
				      (buffer), "para");
	gtk_text_buffer_insert_with_tags(buffer, iter, text + start,
					 end - start, tag, tag_para, NULL);

	/* mark had right gravity, so it should be
	 *      at the end of the inserted text now */
	gtk_text_buffer_get_iter_at_mark(buffer, iter, mark);
    } while (pango_attr_iterator_next(paiter));

    gtk_text_buffer_delete_mark(buffer, mark);
    pango_attr_iterator_destroy(paiter);
    pango_attr_list_unref(attrlist);
    g_free(text);
}