summaryrefslogtreecommitdiff
path: root/trunk/pango/pango-attributes.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/pango/pango-attributes.c')
-rw-r--r--trunk/pango/pango-attributes.c1986
1 files changed, 1986 insertions, 0 deletions
diff --git a/trunk/pango/pango-attributes.c b/trunk/pango/pango-attributes.c
new file mode 100644
index 00000000..e054b14d
--- /dev/null
+++ b/trunk/pango/pango-attributes.c
@@ -0,0 +1,1986 @@
+/* Pango
+ * pango-attributes.c: Attributed text
+ *
+ * Copyright (C) 2000-2002 Red Hat Software
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+#include <string.h>
+
+#include "pango-attributes.h"
+#include "pango-impl-utils.h"
+
+struct _PangoAttrList
+{
+ guint ref_count;
+ GSList *attributes;
+ GSList *attributes_tail;
+};
+
+struct _PangoAttrIterator
+{
+ GSList *next_attribute;
+ GList *attribute_stack;
+ guint start_index;
+ guint end_index;
+};
+
+static PangoAttribute *pango_attr_color_new (const PangoAttrClass *klass,
+ guint16 red,
+ guint16 green,
+ guint16 blue);
+static PangoAttribute *pango_attr_string_new (const PangoAttrClass *klass,
+ const char *str);
+static PangoAttribute *pango_attr_int_new (const PangoAttrClass *klass,
+ int value);
+static PangoAttribute *pango_attr_float_new (const PangoAttrClass *klass,
+ double value);
+static PangoAttribute *pango_attr_size_new_internal (int size,
+ gboolean absolute);
+
+
+/**
+ * pango_attr_type_register:
+ * @name: an identifier for the type (currently unused.)
+ *
+ * Allocate a new attribute type ID.
+ *
+ * Return value: the new type ID.
+ **/
+PangoAttrType
+pango_attr_type_register (const gchar *name)
+{
+ static guint current_type = 0x1000000;
+
+ return current_type++;
+}
+
+/**
+ * pango_attribute_copy:
+ * @attr: a #PangoAttribute
+ *
+ * Make a copy of an attribute.
+ *
+ * Return value: the newly allocated #PangoAttribute, which should be
+ * freed with pango_attribute_destroy().
+ **/
+PangoAttribute *
+pango_attribute_copy (const PangoAttribute *attr)
+{
+ PangoAttribute *result;
+
+ g_return_val_if_fail (attr != NULL, NULL);
+
+ result = attr->klass->copy (attr);
+ result->start_index = attr->start_index;
+ result->end_index = attr->end_index;
+
+ return result;
+}
+
+/**
+ * pango_attribute_destroy:
+ * @attr: a #PangoAttribute.
+ *
+ * Destroy a #PangoAttribute and free all associated memory.
+ **/
+void
+pango_attribute_destroy (PangoAttribute *attr)
+{
+ g_return_if_fail (attr != NULL);
+
+ attr->klass->destroy (attr);
+}
+
+/**
+ * pango_attribute_equal:
+ * @attr1: a #PangoAttribute
+ * @attr2: another #PangoAttribute
+ *
+ * Compare two attributes for equality. This compares only the
+ * actual value of the two attributes and not the ranges that the
+ * attributes apply to.
+ *
+ * Return value: %TRUE if the two attributes have the same value.
+ **/
+gboolean
+pango_attribute_equal (const PangoAttribute *attr1,
+ const PangoAttribute *attr2)
+{
+ g_return_val_if_fail (attr1 != NULL, FALSE);
+ g_return_val_if_fail (attr2 != NULL, FALSE);
+
+ if (attr1->klass->type != attr2->klass->type)
+ return FALSE;
+
+ return attr1->klass->equal (attr1, attr2);
+}
+
+static PangoAttribute *
+pango_attr_string_copy (const PangoAttribute *attr)
+{
+ return pango_attr_string_new (attr->klass, ((PangoAttrString *)attr)->value);
+}
+
+static void
+pango_attr_string_destroy (PangoAttribute *attr)
+{
+ PangoAttrString *sattr = (PangoAttrString *)attr;
+
+ g_free (sattr->value);
+ g_slice_free (PangoAttrString, sattr);
+}
+
+static gboolean
+pango_attr_string_equal (const PangoAttribute *attr1,
+ const PangoAttribute *attr2)
+{
+ return strcmp (((PangoAttrString *)attr1)->value, ((PangoAttrString *)attr2)->value) == 0;
+}
+
+static PangoAttribute *
+pango_attr_string_new (const PangoAttrClass *klass,
+ const char *str)
+{
+ PangoAttrString *result = g_slice_new (PangoAttrString);
+
+ result->attr.klass = klass;
+ result->value = g_strdup (str);
+
+ return (PangoAttribute *)result;
+}
+
+/**
+ * pango_attr_family_new:
+ * @family: the family or comma separated list of families
+ *
+ * Create a new font family attribute.
+ *
+ * Return value: the newly allocated #PangoAttribute, which should be
+ * freed with pango_attribute_destroy().
+ **/
+PangoAttribute *
+pango_attr_family_new (const char *family)
+{
+ static const PangoAttrClass klass = {
+ PANGO_ATTR_FAMILY,
+ pango_attr_string_copy,
+ pango_attr_string_destroy,
+ pango_attr_string_equal
+ };
+
+ g_return_val_if_fail (family != NULL, NULL);
+
+ return pango_attr_string_new (&klass, family);
+}
+
+static PangoAttribute *
+pango_attr_language_copy (const PangoAttribute *attr)
+{
+ return pango_attr_language_new (((PangoAttrLanguage *)attr)->value);
+}
+
+static void
+pango_attr_language_destroy (PangoAttribute *attr)
+{
+ PangoAttrLanguage *lattr = (PangoAttrLanguage *)attr;
+
+ g_slice_free (PangoAttrLanguage, lattr);
+}
+
+static gboolean
+pango_attr_language_equal (const PangoAttribute *attr1,
+ const PangoAttribute *attr2)
+{
+ return ((PangoAttrLanguage *)attr1)->value == ((PangoAttrLanguage *)attr2)->value;
+}
+
+/**
+ * pango_attr_language_new:
+ * @language: language tag
+ *
+ * Create a new language tag attribute.
+ *
+ * Return value: the newly allocated #PangoAttribute, which should be
+ * freed with pango_attribute_destroy().
+ **/
+PangoAttribute *
+pango_attr_language_new (PangoLanguage *language)
+{
+ PangoAttrLanguage *result;
+
+ static const PangoAttrClass klass = {
+ PANGO_ATTR_LANGUAGE,
+ pango_attr_language_copy,
+ pango_attr_language_destroy,
+ pango_attr_language_equal
+ };
+
+ g_return_val_if_fail (language != NULL, NULL);
+
+ result = g_slice_new (PangoAttrLanguage);
+
+ result->attr.klass = &klass;
+ result->value = language;
+
+ return (PangoAttribute *)result;
+}
+
+static PangoAttribute *
+pango_attr_color_copy (const PangoAttribute *attr)
+{
+ const PangoAttrColor *color_attr = (PangoAttrColor *)attr;
+
+ return pango_attr_color_new (attr->klass,
+ color_attr->color.red,
+ color_attr->color.green,
+ color_attr->color.blue);
+}
+
+static void
+pango_attr_color_destroy (PangoAttribute *attr)
+{
+ PangoAttrColor *cattr = (PangoAttrColor *)attr;
+
+ g_slice_free (PangoAttrColor, cattr);
+}
+
+static gboolean
+pango_attr_color_equal (const PangoAttribute *attr1,
+ const PangoAttribute *attr2)
+{
+ const PangoAttrColor *color_attr1 = (const PangoAttrColor *)attr1;
+ const PangoAttrColor *color_attr2 = (const PangoAttrColor *)attr2;
+
+ return (color_attr1->color.red == color_attr2->color.red &&
+ color_attr1->color.blue == color_attr2->color.blue &&
+ color_attr1->color.green == color_attr2->color.green);
+}
+
+static PangoAttribute *
+pango_attr_color_new (const PangoAttrClass *klass,
+ guint16 red,
+ guint16 green,
+ guint16 blue)
+{
+ PangoAttrColor *result = g_slice_new (PangoAttrColor);
+ result->attr.klass = klass;
+ result->color.red = red;
+ result->color.green = green;
+ result->color.blue = blue;
+
+ return (PangoAttribute *)result;
+}
+
+/**
+ * pango_attr_foreground_new:
+ * @red: the red value (ranging from 0 to 65535)
+ * @green: the green value
+ * @blue: the blue value
+ *
+ * Create a new foreground color attribute.
+ *
+ * Return value: the newly allocated #PangoAttribute, which should be
+ * freed with pango_attribute_destroy().
+ **/
+PangoAttribute *
+pango_attr_foreground_new (guint16 red,
+ guint16 green,
+ guint16 blue)
+{
+ static const PangoAttrClass klass = {
+ PANGO_ATTR_FOREGROUND,
+ pango_attr_color_copy,
+ pango_attr_color_destroy,
+ pango_attr_color_equal
+ };
+
+ return pango_attr_color_new (&klass, red, green, blue);
+}
+
+/**
+ * pango_attr_background_new:
+ * @red: the red value (ranging from 0 to 65535)
+ * @green: the green value
+ * @blue: the blue value
+ *
+ * Create a new background color attribute.
+ *
+ * Return value: the newly allocated #PangoAttribute, which should be
+ * freed with pango_attribute_destroy().
+ **/
+PangoAttribute *
+pango_attr_background_new (guint16 red,
+ guint16 green,
+ guint16 blue)
+{
+ static const PangoAttrClass klass = {
+ PANGO_ATTR_BACKGROUND,
+ pango_attr_color_copy,
+ pango_attr_color_destroy,
+ pango_attr_color_equal
+ };
+
+ return pango_attr_color_new (&klass, red, green, blue);
+}
+
+static PangoAttribute *
+pango_attr_int_copy (const PangoAttribute *attr)
+{
+ const PangoAttrInt *int_attr = (PangoAttrInt *)attr;
+
+ return pango_attr_int_new (attr->klass, int_attr->value);
+}
+
+static void
+pango_attr_int_destroy (PangoAttribute *attr)
+{
+ PangoAttrInt *iattr = (PangoAttrInt *)attr;
+
+ g_slice_free (PangoAttrInt, iattr);
+}
+
+static gboolean
+pango_attr_int_equal (const PangoAttribute *attr1,
+ const PangoAttribute *attr2)
+{
+ const PangoAttrInt *int_attr1 = (const PangoAttrInt *)attr1;
+ const PangoAttrInt *int_attr2 = (const PangoAttrInt *)attr2;
+
+ return (int_attr1->value == int_attr2->value);
+}
+
+static PangoAttribute *
+pango_attr_int_new (const PangoAttrClass *klass,
+ int value)
+{
+ PangoAttrInt *result = g_slice_new (PangoAttrInt);
+ result->attr.klass = klass;
+ result->value = value;
+
+ return (PangoAttribute *)result;
+}
+
+static PangoAttribute *
+pango_attr_float_copy (const PangoAttribute *attr)
+{
+ const PangoAttrFloat *float_attr = (PangoAttrFloat *)attr;
+
+ return pango_attr_float_new (attr->klass, float_attr->value);
+}
+
+static void
+pango_attr_float_destroy (PangoAttribute *attr)
+{
+ PangoAttrFloat *fattr = (PangoAttrFloat *)attr;
+
+ g_slice_free (PangoAttrFloat, fattr);
+}
+
+static gboolean
+pango_attr_float_equal (const PangoAttribute *attr1,
+ const PangoAttribute *attr2)
+{
+ const PangoAttrFloat *float_attr1 = (const PangoAttrFloat *)attr1;
+ const PangoAttrFloat *float_attr2 = (const PangoAttrFloat *)attr2;
+
+ return (float_attr1->value == float_attr2->value);
+}
+
+static PangoAttribute*
+pango_attr_float_new (const PangoAttrClass *klass,
+ double value)
+{
+ PangoAttrFloat *result = g_slice_new (PangoAttrFloat);
+ result->attr.klass = klass;
+ result->value = value;
+
+ return (PangoAttribute *)result;
+}
+
+static PangoAttribute *
+pango_attr_size_copy (const PangoAttribute *attr)
+{
+ const PangoAttrSize *size_attr = (PangoAttrSize *)attr;
+
+ if (attr->klass->type == PANGO_ATTR_ABSOLUTE_SIZE)
+ return pango_attr_size_new_absolute (size_attr->size);
+ else
+ return pango_attr_size_new (size_attr->size);
+}
+
+static void
+pango_attr_size_destroy (PangoAttribute *attr)
+{
+ PangoAttrSize *sattr = (PangoAttrSize *)attr;
+
+ g_slice_free (PangoAttrSize, sattr);
+}
+
+static gboolean
+pango_attr_size_equal (const PangoAttribute *attr1,
+ const PangoAttribute *attr2)
+{
+ const PangoAttrSize *size_attr1 = (const PangoAttrSize *)attr1;
+ const PangoAttrSize *size_attr2 = (const PangoAttrSize *)attr2;
+
+ return size_attr1->size == size_attr2->size;
+}
+
+static PangoAttribute *
+pango_attr_size_new_internal (int size,
+ gboolean absolute)
+{
+ PangoAttrSize *result;
+
+ static const PangoAttrClass klass = {
+ PANGO_ATTR_SIZE,
+ pango_attr_size_copy,
+ pango_attr_size_destroy,
+ pango_attr_size_equal
+ };
+ static const PangoAttrClass absolute_klass = {
+ PANGO_ATTR_ABSOLUTE_SIZE,
+ pango_attr_size_copy,
+ pango_attr_size_destroy,
+ pango_attr_size_equal
+ };
+
+ result = g_slice_new (PangoAttrSize);
+ result->attr.klass = absolute ? &absolute_klass : &klass;
+ result->size = size;
+ result->absolute = absolute;
+
+ return (PangoAttribute *)result;
+}
+
+/**
+ * pango_attr_size_new:
+ * @size: the font size, in %PANGO_SCALE<!-- -->ths of a point.
+ *
+ * Create a new font-size attribute in fractional points.
+ *
+ * Return value: the newly allocated #PangoAttribute, which should be
+ * freed with pango_attribute_destroy().
+ **/
+PangoAttribute *
+pango_attr_size_new (int size)
+{
+ return pango_attr_size_new_internal (size, FALSE);
+}
+
+/**
+ * pango_attr_size_new_absolute:
+ * @size: the font size, in %PANGO_SCALE<!-- -->ths of a device unit.
+ *
+ * Create a new font-size attribute in device units.
+ *
+ * Return value: the newly allocated #PangoAttribute, which should be
+ * freed with pango_attribute_destroy().
+ *
+ * Since: 1.8
+ **/
+PangoAttribute *
+pango_attr_size_new_absolute (int size)
+{
+ return pango_attr_size_new_internal (size, TRUE);
+}
+
+/**
+ * pango_attr_style_new:
+ * @style: the slant style
+ *
+ * Create a new font slant style attribute.
+ *
+ * Return value: the newly allocated #PangoAttribute, which should be
+ * freed with pango_attribute_destroy().
+ **/
+PangoAttribute *
+pango_attr_style_new (PangoStyle style)
+{
+ static const PangoAttrClass klass = {
+ PANGO_ATTR_STYLE,
+ pango_attr_int_copy,
+ pango_attr_int_destroy,
+ pango_attr_int_equal
+ };
+
+ return pango_attr_int_new (&klass, (int)style);
+}
+
+/**
+ * pango_attr_weight_new:
+ * @weight: the weight
+ *
+ * Create a new font weight attribute.
+ *
+ * Return value: the newly allocated #PangoAttribute, which should be
+ * freed with pango_attribute_destroy().
+ **/
+PangoAttribute *
+pango_attr_weight_new (PangoWeight weight)
+{
+ static const PangoAttrClass klass = {
+ PANGO_ATTR_WEIGHT,
+ pango_attr_int_copy,
+ pango_attr_int_destroy,
+ pango_attr_int_equal
+ };
+
+ return pango_attr_int_new (&klass, (int)weight);
+}
+
+/**
+ * pango_attr_variant_new:
+ * @variant: the variant
+ *
+ * Create a new font variant attribute (normal or small caps)
+ *
+ * Return value: the newly allocated #PangoAttribute, which should be
+ * freed with pango_attribute_destroy().
+ **/
+PangoAttribute *
+pango_attr_variant_new (PangoVariant variant)
+{
+ static const PangoAttrClass klass = {
+ PANGO_ATTR_VARIANT,
+ pango_attr_int_copy,
+ pango_attr_int_destroy,
+ pango_attr_int_equal
+ };
+
+ return pango_attr_int_new (&klass, (int)variant);
+}
+
+/**
+ * pango_attr_stretch_new:
+ * @stretch: the stretch
+ *
+ * Create a new font stretch attribute
+ *
+ * Return value: the newly allocated #PangoAttribute, which should be
+ * freed with pango_attribute_destroy().
+ **/
+PangoAttribute *
+pango_attr_stretch_new (PangoStretch stretch)
+{
+ static const PangoAttrClass klass = {
+ PANGO_ATTR_STRETCH,
+ pango_attr_int_copy,
+ pango_attr_int_destroy,
+ pango_attr_int_equal
+ };
+
+ return pango_attr_int_new (&klass, (int)stretch);
+}
+
+static PangoAttribute *
+pango_attr_font_desc_copy (const PangoAttribute *attr)
+{
+ const PangoAttrFontDesc *desc_attr = (const PangoAttrFontDesc *)attr;
+
+ return pango_attr_font_desc_new (desc_attr->desc);
+}
+
+static void
+pango_attr_font_desc_destroy (PangoAttribute *attr)
+{
+ PangoAttrFontDesc *desc_attr = (PangoAttrFontDesc *)attr;
+
+ pango_font_description_free (desc_attr->desc);
+ g_slice_free (PangoAttrFontDesc, desc_attr);
+}
+
+static gboolean
+pango_attr_font_desc_equal (const PangoAttribute *attr1,
+ const PangoAttribute *attr2)
+{
+ const PangoAttrFontDesc *desc_attr1 = (const PangoAttrFontDesc *)attr1;
+ const PangoAttrFontDesc *desc_attr2 = (const PangoAttrFontDesc *)attr2;
+
+ return pango_font_description_get_set_fields (desc_attr1->desc) ==
+ pango_font_description_get_set_fields (desc_attr2->desc) &&
+ pango_font_description_equal (desc_attr1->desc, desc_attr2->desc);
+}
+
+/**
+ * pango_attr_font_desc_new:
+ * @desc: the font description
+ *
+ * Create a new font description attribute. This attribute
+ * allows setting family, style, weight, variant, stretch,
+ * and size simultaneously.
+ *
+ * Return value: the newly allocated #PangoAttribute, which should be
+ * freed with pango_attribute_destroy().
+ **/
+PangoAttribute *
+pango_attr_font_desc_new (const PangoFontDescription *desc)
+{
+ static const PangoAttrClass klass = {
+ PANGO_ATTR_FONT_DESC,
+ pango_attr_font_desc_copy,
+ pango_attr_font_desc_destroy,
+ pango_attr_font_desc_equal
+ };
+
+ PangoAttrFontDesc *result = g_slice_new (PangoAttrFontDesc);
+ result->attr.klass = &klass;
+ result->desc = pango_font_description_copy (desc);
+
+ return (PangoAttribute *)result;
+}
+
+
+/**
+ * pango_attr_underline_new:
+ * @underline: the underline style.
+ *
+ * Create a new underline-style attribute.
+ *
+ * Return value: the newly allocated #PangoAttribute, which should be
+ * freed with pango_attribute_destroy().
+ **/
+PangoAttribute *
+pango_attr_underline_new (PangoUnderline underline)
+{
+ static const PangoAttrClass klass = {
+ PANGO_ATTR_UNDERLINE,
+ pango_attr_int_copy,
+ pango_attr_int_destroy,
+ pango_attr_int_equal
+ };
+
+ return pango_attr_int_new (&klass, (int)underline);
+}
+
+/**
+ * pango_attr_underline_color_new:
+ * @red: the red value (ranging from 0 to 65535)
+ * @green: the green value
+ * @blue: the blue value
+ *
+ * Create a new underline color attribute. This attribute
+ * modifies the color of underlines. If not set, underlines
+ * will use the foreground color.
+ *
+ * Return value: the newly allocated #PangoAttribute, which should be
+ * freed with pango_attribute_destroy().
+ *
+ * Since: 1.8
+ **/
+PangoAttribute *
+pango_attr_underline_color_new (guint16 red,
+ guint16 green,
+ guint16 blue)
+{
+ static const PangoAttrClass klass = {
+ PANGO_ATTR_UNDERLINE_COLOR,
+ pango_attr_color_copy,
+ pango_attr_color_destroy,
+ pango_attr_color_equal
+ };
+
+ return pango_attr_color_new (&klass, red, green, blue);
+}
+
+/**
+ * pango_attr_strikethrough_new:
+ * @strikethrough: %TRUE if the text should be struck-through.
+ *
+ * Create a new strike-through attribute.
+ *
+ * Return value: the newly allocated #PangoAttribute, which should be
+ * freed with pango_attribute_destroy().
+ **/
+PangoAttribute *
+pango_attr_strikethrough_new (gboolean strikethrough)
+{
+ static const PangoAttrClass klass = {
+ PANGO_ATTR_STRIKETHROUGH,
+ pango_attr_int_copy,
+ pango_attr_int_destroy,
+ pango_attr_int_equal
+ };
+
+ return pango_attr_int_new (&klass, (int)strikethrough);
+}
+
+/**
+ * pango_attr_strikethrough_color_new:
+ * @red: the red value (ranging from 0 to 65535)
+ * @green: the green value
+ * @blue: the blue value
+ *
+ * Create a new strikethrough color attribute. This attribute
+ * modifies the color of strikethrough lines. If not set, strikethrough
+ * lines will use the foreground color.
+ *
+ * Return value: the newly allocated #PangoAttribute, which should be
+ * freed with pango_attribute_destroy().
+ *
+ * Since: 1.8
+ **/
+PangoAttribute *
+pango_attr_strikethrough_color_new (guint16 red,
+ guint16 green,
+ guint16 blue)
+{
+ static const PangoAttrClass klass = {
+ PANGO_ATTR_STRIKETHROUGH_COLOR,
+ pango_attr_color_copy,
+ pango_attr_color_destroy,
+ pango_attr_color_equal
+ };
+
+ return pango_attr_color_new (&klass, red, green, blue);
+}
+
+/**
+ * pango_attr_rise_new:
+ * @rise: the amount that the text should be displaced vertically,
+ * in Pango units. Positive values displace the text upwards.
+ *
+ * Create a new baseline displacement attribute.
+ *
+ * Return value: the newly allocated #PangoAttribute, which should be
+ * freed with pango_attribute_destroy().
+ **/
+PangoAttribute *
+pango_attr_rise_new (int rise)
+{
+ static const PangoAttrClass klass = {
+ PANGO_ATTR_RISE,
+ pango_attr_int_copy,
+ pango_attr_int_destroy,
+ pango_attr_int_equal
+ };
+
+ return pango_attr_int_new (&klass, (int)rise);
+}
+
+/**
+ * pango_attr_scale_new:
+ * @scale_factor: factor to scale the font
+ *
+ * Create a new font size scale attribute. The base font for the
+ * affected text will have its size multiplied by @scale_factor.
+ *
+ * Return value: the newly allocated #PangoAttribute, which should be
+ * freed with pango_attribute_destroy().
+ **/
+PangoAttribute*
+pango_attr_scale_new (double scale_factor)
+{
+ static const PangoAttrClass klass = {
+ PANGO_ATTR_SCALE,
+ pango_attr_float_copy,
+ pango_attr_float_destroy,
+ pango_attr_float_equal
+ };
+
+ return pango_attr_float_new (&klass, scale_factor);
+}
+
+/**
+ * pango_attr_fallback_new:
+ * @enable_fallback: %TRUE if we should fall back on other fonts
+ * for characters the active font is missing.
+ *
+ * Create a new font fallback attribute.
+ *
+ * If fallback is disabled, characters will only be used from the
+ * closest matching font on the system. No fallback will be done to
+ * other fonts on the system that might contain the characters in the
+ * text.
+ *
+ * Return value: the newly allocated #PangoAttribute, which should be
+ * freed with pango_attribute_destroy().
+ *
+ * Since: 1.4
+ **/
+PangoAttribute *
+pango_attr_fallback_new (gboolean enable_fallback)
+{
+ static const PangoAttrClass klass = {
+ PANGO_ATTR_FALLBACK,
+ pango_attr_int_copy,
+ pango_attr_int_destroy,
+ pango_attr_int_equal,
+ };
+
+ return pango_attr_int_new (&klass, (int)enable_fallback);
+}
+
+/**
+ * pango_attr_letter_spacing_new:
+ * @letter_spacing: amount of extra space to add between graphemes
+ * of the text, in Pango units.
+ *
+ * Create a new letter-spacing attribute.
+ *
+ * Return value: the newly allocated #PangoAttribute, which should be
+ * freed with pango_attribute_destroy().
+ *
+ * Since: 1.6
+ **/
+PangoAttribute *
+pango_attr_letter_spacing_new (int letter_spacing)
+{
+ static const PangoAttrClass klass = {
+ PANGO_ATTR_LETTER_SPACING,
+ pango_attr_int_copy,
+ pango_attr_int_destroy,
+ pango_attr_int_equal
+ };
+
+ return pango_attr_int_new (&klass, letter_spacing);
+}
+
+static PangoAttribute *
+pango_attr_shape_copy (const PangoAttribute *attr)
+{
+ const PangoAttrShape *shape_attr = (PangoAttrShape *)attr;
+ gpointer data;
+
+ if (shape_attr->copy_func)
+ data = shape_attr->copy_func (shape_attr->data);
+ else
+ data = shape_attr->data;
+
+ return pango_attr_shape_new_with_data (&shape_attr->ink_rect, &shape_attr->logical_rect,
+ data, shape_attr->copy_func, shape_attr->destroy_func);
+}
+
+static void
+pango_attr_shape_destroy (PangoAttribute *attr)
+{
+ PangoAttrShape *shape_attr = (PangoAttrShape *)attr;
+
+ if (shape_attr->destroy_func)
+ shape_attr->destroy_func (shape_attr->data);
+
+ g_slice_free (PangoAttrShape, shape_attr);
+}
+
+static gboolean
+pango_attr_shape_equal (const PangoAttribute *attr1,
+ const PangoAttribute *attr2)
+{
+ const PangoAttrShape *shape_attr1 = (const PangoAttrShape *)attr1;
+ const PangoAttrShape *shape_attr2 = (const PangoAttrShape *)attr2;
+
+ return (shape_attr1->logical_rect.x == shape_attr2->logical_rect.x &&
+ shape_attr1->logical_rect.y == shape_attr2->logical_rect.y &&
+ shape_attr1->logical_rect.width == shape_attr2->logical_rect.width &&
+ shape_attr1->logical_rect.height == shape_attr2->logical_rect.height &&
+ shape_attr1->ink_rect.x == shape_attr2->ink_rect.x &&
+ shape_attr1->ink_rect.y == shape_attr2->ink_rect.y &&
+ shape_attr1->ink_rect.width == shape_attr2->ink_rect.width &&
+ shape_attr1->ink_rect.height == shape_attr2->ink_rect.height &&
+ shape_attr1->data == shape_attr2->data);
+}
+
+/**
+ * pango_attr_shape_new_with_data:
+ * @ink_rect: ink rectangle to assign to each character
+ * @logical_rect: logical rectangle to assign to each character
+ * @data: user data pointer
+ * @copy_func: function to copy @data when the attribute
+ * is copied. If %NULL, @data is simply copied
+ * as a pointer.
+ * @destroy_func: function to free @data when the attribute
+ * is freed, or %NULL
+ *
+ * Like pango_attr_shape_new(), but a user data pointer is also
+ * provided; this pointer can be accessed when later
+ * rendering the glyph.
+ *
+ * Return value: the newly allocated #PangoAttribute, which should be
+ * freed with pango_attribute_destroy().
+ *
+ * Since: 1.8
+ **/
+PangoAttribute *
+pango_attr_shape_new_with_data (const PangoRectangle *ink_rect,
+ const PangoRectangle *logical_rect,
+ gpointer data,
+ PangoAttrDataCopyFunc copy_func,
+ GDestroyNotify destroy_func)
+{
+ static const PangoAttrClass klass = {
+ PANGO_ATTR_SHAPE,
+ pango_attr_shape_copy,
+ pango_attr_shape_destroy,
+ pango_attr_shape_equal
+ };
+
+ PangoAttrShape *result;
+
+ g_return_val_if_fail (ink_rect != NULL, NULL);
+ g_return_val_if_fail (logical_rect != NULL, NULL);
+
+ result = g_slice_new (PangoAttrShape);
+ result->attr.klass = &klass;
+ result->ink_rect = *ink_rect;
+ result->logical_rect = *logical_rect;
+ result->data = data;
+ result->copy_func = copy_func;
+ result->destroy_func = destroy_func;
+
+ return (PangoAttribute *)result;
+}
+
+/**
+ * pango_attr_shape_new:
+ * @ink_rect: ink rectangle to assign to each character
+ * @logical_rect: logical rectangle to assign to each character
+ *
+ * Create a new shape attribute. A shape is used to impose a
+ * particular ink and logical rectangle on the result of shaping a
+ * particular glyph. This might be used, for instance, for
+ * embedding a picture or a widget inside a #PangoLayout.
+ *
+ * Return value: the newly allocated #PangoAttribute, which should be
+ * freed with pango_attribute_destroy().
+ **/
+PangoAttribute *
+pango_attr_shape_new (const PangoRectangle *ink_rect,
+ const PangoRectangle *logical_rect)
+{
+ g_return_val_if_fail (ink_rect != NULL, NULL);
+ g_return_val_if_fail (logical_rect != NULL, NULL);
+
+ return pango_attr_shape_new_with_data (ink_rect, logical_rect,
+ NULL, NULL, NULL);
+}
+
+/**
+ * pango_attr_gravity_new:
+ * @gravity: the gravity value; should not be %PANGO_GRAVITY_AUTO.
+ *
+ * Create a new gravity attribute.
+ *
+ * Return value: the newly allocated #PangoAttribute, which should be
+ * freed with pango_attribute_destroy().
+ *
+ * Since: 1.16
+ **/
+PangoAttribute *
+pango_attr_gravity_new (PangoGravity gravity)
+{
+ static const PangoAttrClass klass = {
+ PANGO_ATTR_GRAVITY,
+ pango_attr_int_copy,
+ pango_attr_int_destroy,
+ pango_attr_int_equal
+ };
+
+ g_return_val_if_fail (gravity != PANGO_GRAVITY_AUTO, NULL);
+
+ return pango_attr_int_new (&klass, (int)gravity);
+}
+
+/**
+ * pango_attr_gravity_hint_new:
+ * @hint: the gravity hint value.
+ *
+ * Create a new gravity hint attribute.
+ *
+ * Return value: the newly allocated #PangoAttribute, which should be
+ * freed with pango_attribute_destroy().
+ *
+ * Since: 1.16
+ **/
+PangoAttribute *
+pango_attr_gravity_hint_new (PangoGravityHint hint)
+{
+ static const PangoAttrClass klass = {
+ PANGO_ATTR_GRAVITY_HINT,
+ pango_attr_int_copy,
+ pango_attr_int_destroy,
+ pango_attr_int_equal
+ };
+
+ return pango_attr_int_new (&klass, (int)hint);
+}
+
+
+/*
+ * Attribute List
+ */
+
+GType
+pango_attr_list_get_type (void)
+{
+ static GType our_type = 0;
+
+ if (G_UNLIKELY (our_type == 0))
+ our_type = g_boxed_type_register_static (I_("PangoAttrList"),
+ (GBoxedCopyFunc) pango_attr_list_copy,
+ (GBoxedFreeFunc) pango_attr_list_unref);
+
+ return our_type;
+}
+
+/**
+ * pango_attr_list_new:
+ *
+ * Create a new empty attribute list with a reference count of one.
+ *
+ * Return value: the newly allocated #PangoAttrList, which should
+ * be freed with pango_attr_list_unref().
+ **/
+PangoAttrList *
+pango_attr_list_new (void)
+{
+ PangoAttrList *list = g_slice_new (PangoAttrList);
+
+ list->ref_count = 1;
+ list->attributes = NULL;
+ list->attributes_tail = NULL;
+
+ return list;
+}
+
+/**
+ * pango_attr_list_ref:
+ * @list: a #PangoAttrList
+ *
+ * Increase the reference count of the given attribute list by one.
+ *
+ * Return value: The attribute list passed in
+ *
+ * Since: 1.10
+ **/
+PangoAttrList *
+pango_attr_list_ref (PangoAttrList *list)
+{
+ g_return_val_if_fail (list != NULL, NULL);
+
+ list->ref_count++;
+
+ return list;
+}
+
+/**
+ * pango_attr_list_unref:
+ * @list: a #PangoAttrList
+ *
+ * Decrease the reference count of the given attribute list by one.
+ * If the result is zero, free the attribute list and the attributes
+ * it contains.
+ **/
+void
+pango_attr_list_unref (PangoAttrList *list)
+{
+ GSList *tmp_list;
+
+ g_return_if_fail (list != NULL);
+ g_return_if_fail (list->ref_count > 0);
+
+ list->ref_count--;
+ if (list->ref_count == 0)
+ {
+ tmp_list = list->attributes;
+ while (tmp_list)
+ {
+ PangoAttribute *attr = tmp_list->data;
+ tmp_list = tmp_list->next;
+
+ attr->klass->destroy (attr);
+ }
+
+ g_slist_free (list->attributes);
+
+ g_slice_free (PangoAttrList, list);
+ }
+}
+
+/**
+ * pango_attr_list_copy:
+ * @list: a #PangoAttrList
+ *
+ * Copy @list and return an identical new list.
+ *
+ * Return value: the newly allocated #PangoAttrList, with a
+ * reference count of one, which should
+ * be freed with pango_attr_list_unref().
+ **/
+PangoAttrList *
+pango_attr_list_copy (PangoAttrList *list)
+{
+ PangoAttrList *new;
+ GSList *iter;
+ GSList *new_attrs;
+
+ g_return_val_if_fail (list != NULL, NULL);
+
+ new = pango_attr_list_new ();
+
+ iter = list->attributes;
+ new_attrs = NULL;
+ while (iter != NULL)
+ {
+ new_attrs = g_slist_prepend (new_attrs,
+ pango_attribute_copy (iter->data));
+
+ iter = g_slist_next (iter);
+ }
+
+ /* we're going to reverse the nodes, so head becomes tail */
+ new->attributes_tail = new_attrs;
+ new->attributes = g_slist_reverse (new_attrs);
+
+ return new;
+}
+
+static void
+pango_attr_list_insert_internal (PangoAttrList *list,
+ PangoAttribute *attr,
+ gboolean before)
+{
+ GSList *tmp_list, *prev, *link;
+ guint start_index = attr->start_index;
+
+ if (!list->attributes)
+ {
+ list->attributes = g_slist_prepend (NULL, attr);
+ list->attributes_tail = list->attributes;
+ }
+ else if (((PangoAttribute *)list->attributes_tail->data)->start_index < start_index ||
+ (!before && ((PangoAttribute *)list->attributes_tail->data)->start_index == start_index))
+ {
+ g_slist_append (list->attributes_tail, attr);
+ list->attributes_tail = list->attributes_tail->next;
+ g_assert (list->attributes_tail);
+ }
+ else
+ {
+ prev = NULL;
+ tmp_list = list->attributes;
+ while (1)
+ {
+ PangoAttribute *tmp_attr = tmp_list->data;
+
+ if (tmp_attr->start_index > start_index ||
+ (before && tmp_attr->start_index == start_index))
+ {
+ link = g_slist_alloc ();
+ link->next = tmp_list;
+ link->data = attr;
+
+ if (prev)
+ prev->next = link;
+ else
+ list->attributes = link;
+
+ if (!tmp_list)
+ list->attributes_tail = link;
+
+ break;
+ }
+
+ prev = tmp_list;
+ tmp_list = tmp_list->next;
+ }
+ }
+}
+
+/**
+ * pango_attr_list_insert:
+ * @list: a #PangoAttrList
+ * @attr: the attribute to insert. Ownership of this value is
+ * assumed by the list.
+ *
+ * Insert the given attribute into the #PangoAttrList. It will
+ * be inserted after all other attributes with a matching
+ * @start_index.
+ **/
+void
+pango_attr_list_insert (PangoAttrList *list,
+ PangoAttribute *attr)
+{
+ g_return_if_fail (list != NULL);
+ g_return_if_fail (attr != NULL);
+
+ pango_attr_list_insert_internal (list, attr, FALSE);
+}
+
+/**
+ * pango_attr_list_insert_before:
+ * @list: a #PangoAttrList
+ * @attr: the attribute to insert. Ownership of this value is
+ * assumed by the list.
+ *
+ * Insert the given attribute into the #PangoAttrList. It will
+ * be inserted before all other attributes with a matching
+ * @start_index.
+ **/
+void
+pango_attr_list_insert_before (PangoAttrList *list,
+ PangoAttribute *attr)
+{
+ g_return_if_fail (list != NULL);
+ g_return_if_fail (attr != NULL);
+
+ pango_attr_list_insert_internal (list, attr, TRUE);
+}
+
+/**
+ * pango_attr_list_change:
+ * @list: a #PangoAttrList
+ * @attr: the attribute to insert. Ownership of this value is
+ * assumed by the list.
+ *
+ * Insert the given attribute into the #PangoAttrList. It will
+ * replace any attributes of the same type on that segment
+ * and be merged with any adjoining attributes that are identical.
+ *
+ * This function is slower than pango_attr_list_insert() for
+ * creating a attribute list in order (potentially much slower
+ * for large lists). However, pango_attr_list_insert() is not
+ * suitable for continually changing a set of attributes
+ * since it never removes or combines existing attributes.
+ **/
+void
+pango_attr_list_change (PangoAttrList *list,
+ PangoAttribute *attr)
+{
+ GSList *tmp_list, *prev, *link;
+ guint start_index = attr->start_index;
+ guint end_index = attr->end_index;
+
+ g_return_if_fail (list != NULL);
+
+ if (start_index == end_index) /* empty, nothing to do */
+ {
+ pango_attribute_destroy (attr);
+ return;
+ }
+
+ tmp_list = list->attributes;
+ prev = NULL;
+ while (1)
+ {
+ PangoAttribute *tmp_attr;
+
+ if (!tmp_list ||
+ ((PangoAttribute *)tmp_list->data)->start_index > start_index)
+ {
+ /* We need to insert a new attribute
+ */
+ link = g_slist_alloc ();
+ link->next = tmp_list;
+ link->data = attr;
+
+ if (prev)
+ prev->next = link;
+ else
+ list->attributes = link;
+
+ if (!tmp_list)
+ list->attributes_tail = link;
+
+ prev = link;
+ tmp_list = prev->next;
+ break;
+ }
+
+ tmp_attr = tmp_list->data;
+
+ if (tmp_attr->klass->type == attr->klass->type &&
+ tmp_attr->end_index >= start_index)
+ {
+ /* We overlap with an existing attribute */
+ if (pango_attribute_equal (tmp_attr, attr))
+ {
+ /* We can merge the new attribute with this attribute
+ */
+ if (tmp_attr->end_index >= end_index)
+ {
+ /* We are totally overlapping the previous attribute.
+ * No action is needed.
+ */
+ pango_attribute_destroy (attr);
+ return;
+ }
+ tmp_attr->end_index = end_index;
+ pango_attribute_destroy (attr);
+
+ attr = tmp_attr;
+
+ prev = tmp_list;
+ tmp_list = tmp_list->next;
+
+ break;
+ }
+ else
+ {
+ /* Split, truncate, or remove the old attribute
+ */
+ if (tmp_attr->end_index > attr->end_index)
+ {
+ PangoAttribute *end_attr = pango_attribute_copy (tmp_attr);
+
+ end_attr->start_index = attr->end_index;
+ pango_attr_list_insert (list, end_attr);
+ }
+
+ if (tmp_attr->start_index == attr->start_index)
+ {
+ pango_attribute_destroy (tmp_attr);
+ tmp_list->data = attr;
+
+ prev = tmp_list;
+ tmp_list = tmp_list->next;
+ break;
+ }
+ else
+ {
+ tmp_attr->end_index = attr->start_index;
+ }
+ }
+ }
+ prev = tmp_list;
+ tmp_list = tmp_list->next;
+ }
+ /* At this point, prev points to the list node with attr in it,
+ * tmp_list points to prev->next.
+ */
+
+ g_assert (prev->data == attr);
+ g_assert (prev->next == tmp_list);
+
+ /* We now have the range inserted into the list one way or the
+ * other. Fix up the remainder
+ */
+ while (tmp_list)
+ {
+ PangoAttribute *tmp_attr = tmp_list->data;
+
+ if (tmp_attr->start_index > end_index)
+ break;
+ else if (tmp_attr->klass->type == attr->klass->type)
+ {
+ if (tmp_attr->end_index <= attr->end_index ||
+ pango_attribute_equal (tmp_attr, attr))
+ {
+ /* We can merge the new attribute with this attribute.
+ */
+ attr->end_index = MAX (end_index, tmp_attr->end_index);
+
+ pango_attribute_destroy (tmp_attr);
+ prev->next = tmp_list->next;
+
+ if (!prev->next)
+ list->attributes_tail = prev;
+
+ g_slist_free_1 (tmp_list);
+ tmp_list = prev->next;
+
+ continue;
+ }
+ else
+ {
+ /* Trim the start of this attribute that it begins at the end
+ * of the new attribute. This may involve moving
+ * it in the list to maintain the required non-decreasing
+ * order of start indices
+ */
+ GSList *tmp_list2;
+ GSList *prev2;
+
+ tmp_attr->start_index = attr->end_index;
+
+ tmp_list2 = tmp_list->next;
+ prev2 = tmp_list;
+
+ while (tmp_list2)
+ {
+ PangoAttribute *tmp_attr2 = tmp_list2->data;
+
+ if (tmp_attr2->start_index >= tmp_attr->start_index)
+ break;
+
+ prev2 = tmp_list2;
+ tmp_list2 = tmp_list2->next;
+ }
+
+ /* Now remove and insert before tmp_list2. We'll
+ * hit this attribute again later, but that's harmless.
+ */
+ if (prev2 != tmp_list)
+ {
+ GSList *old_next = tmp_list->next;
+
+ prev->next = old_next;
+ prev2->next = tmp_list;
+ tmp_list->next = tmp_list2;
+
+ if (!tmp_list->next)
+ list->attributes_tail = tmp_list;
+
+ tmp_list = old_next;
+
+ continue;
+ }
+ }
+ }
+
+ prev = tmp_list;
+ tmp_list = tmp_list->next;
+ }
+}
+
+/**
+ * pango_attr_list_splice:
+ * @list: a #PangoAttrList
+ * @other: another #PangoAttrList
+ * @pos: the position in @list at which to insert @other
+ * @len: the length of the spliced segment. (Note that this
+ * must be specified since the attributes in @other
+ * may only be present at some subsection of this range)
+ *
+ * This function opens up a hole in @list, fills it in with attributes from
+ * the left, and then merges @other on top of the hole.
+ *
+ * This operation is equivalent to stretching every attribute
+ * that applies at position @pos in @list by an amount @len,
+ * and then calling pango_attr_list_change() with a copy
+ * of each attribute in @other in sequence (offset in position by @pos).
+ *
+ * This operation proves useful for, for instance, inserting
+ * a pre-edit string in the middle of an edit buffer.
+ **/
+void
+pango_attr_list_splice (PangoAttrList *list,
+ PangoAttrList *other,
+ gint pos,
+ gint len)
+{
+ GSList *tmp_list;
+ guint upos, ulen;
+
+ g_return_if_fail (list != NULL);
+ g_return_if_fail (other != NULL);
+ g_return_if_fail (pos >= 0);
+ g_return_if_fail (len >= 0);
+
+ upos = (guint)pos;
+ ulen = (guint)len;
+
+/* This definition only works when a and b are unsigned; overflow
+ * isn't defined in the C standard for signed integers
+ */
+#define CLAMP_ADD(a,b) (((a) + (b) < (a)) ? G_MAXUINT : (a) + (b))
+
+ tmp_list = list->attributes;
+ while (tmp_list)
+ {
+ PangoAttribute *attr = tmp_list->data;
+
+ if (attr->start_index <= upos)
+ {
+ if (attr->end_index > upos)
+ attr->end_index = CLAMP_ADD (attr->end_index, ulen);
+ }
+ else
+ {
+ /* This could result in a zero length attribute if it
+ * gets squashed up against G_MAXUINT, but deleting such
+ * an element could (in theory) suprise the caller, so
+ * we don't delete it.
+ */
+ attr->start_index = CLAMP_ADD (attr->start_index, ulen);
+ attr->end_index = CLAMP_ADD (attr->end_index, ulen);
+ }
+
+ tmp_list = tmp_list->next;
+ }
+
+ tmp_list = other->attributes;
+ while (tmp_list)
+ {
+ PangoAttribute *attr = pango_attribute_copy (tmp_list->data);
+ attr->start_index = CLAMP_ADD (attr->start_index, upos);
+ attr->end_index = CLAMP_ADD (attr->end_index, upos);
+
+ /* Same as above, the attribute could be squashed to zero-length; here
+ * pango_attr_list_change() will take care of deleting it.
+ */
+ pango_attr_list_change (list, attr);
+
+ tmp_list = tmp_list->next;
+ }
+#undef CLAMP_ADD
+}
+
+/**
+ * pango_attr_list_get_iterator:
+ * @list: a #PangoAttrList
+ *
+ * Create a iterator initialized to the beginning of the list.
+ * @list must not be modified until this iterator is freed.
+ *
+ * Return value: the newly allocated #PangoAttrIterator, which should
+ * be freed with pango_attr_iterator_destroy().
+ **/
+PangoAttrIterator *
+pango_attr_list_get_iterator (PangoAttrList *list)
+{
+ PangoAttrIterator *iterator;
+
+ g_return_val_if_fail (list != NULL, NULL);
+
+ iterator = g_slice_new (PangoAttrIterator);
+ iterator->next_attribute = list->attributes;
+ iterator->attribute_stack = NULL;
+
+ iterator->start_index = 0;
+ iterator->end_index = 0;
+
+ if (!pango_attr_iterator_next (iterator))
+ iterator->end_index = G_MAXUINT;
+
+ return iterator;
+}
+
+/**
+ * pango_attr_iterator_range:
+ * @iterator: a #PangoAttrIterator
+ * @start: location to store the start of the range
+ * @end: location to store the end of the range
+ *
+ * Get the range of the current segment. Note that the
+ * stored return values are signed, not unsigned like
+ * the values in #PangoAttribute. To deal with this API
+ * oversight, stored return values that wouldn't fit into
+ * a signed integer are clamped to %G_MAXINT.
+ **/
+void
+pango_attr_iterator_range (PangoAttrIterator *iterator,
+ gint *start,
+ gint *end)
+{
+ g_return_if_fail (iterator != NULL);
+
+ if (start)
+ *start = MIN (iterator->start_index, G_MAXINT);
+ if (end)
+ *end = MIN (iterator->end_index, G_MAXINT);
+}
+
+/**
+ * pango_attr_iterator_next:
+ * @iterator: a #PangoAttrIterator
+ *
+ * Advance the iterator until the next change of style.
+ *
+ * Return value: %FALSE if the iterator is at the end of the list, otherwise %TRUE
+ **/
+gboolean
+pango_attr_iterator_next (PangoAttrIterator *iterator)
+{
+ GList *tmp_list;
+
+ g_return_val_if_fail (iterator != NULL, FALSE);
+
+ if (!iterator->next_attribute && !iterator->attribute_stack)
+ return FALSE;
+
+ iterator->start_index = iterator->end_index;
+ iterator->end_index = G_MAXUINT;
+
+ tmp_list = iterator->attribute_stack;
+ while (tmp_list)
+ {
+ GList *next = tmp_list->next;
+ PangoAttribute *attr = tmp_list->data;
+
+ if (attr->end_index == iterator->start_index)
+ {
+ iterator->attribute_stack = g_list_remove_link (iterator->attribute_stack, tmp_list);
+ g_list_free_1 (tmp_list);
+ }
+ else
+ {
+ iterator->end_index = MIN (iterator->end_index, attr->end_index);
+ }
+
+ tmp_list = next;
+ }
+
+ while (iterator->next_attribute &&
+ ((PangoAttribute *)iterator->next_attribute->data)->start_index == iterator->start_index)
+ {
+ if (((PangoAttribute *)iterator->next_attribute->data)->end_index > iterator->start_index)
+ {
+ iterator->attribute_stack = g_list_prepend (iterator->attribute_stack, iterator->next_attribute->data);
+ iterator->end_index = MIN (iterator->end_index, ((PangoAttribute *)iterator->next_attribute->data)->end_index);
+ }
+ iterator->next_attribute = iterator->next_attribute->next;
+ }
+
+ if (iterator->next_attribute)
+ iterator->end_index = MIN (iterator->end_index, ((PangoAttribute *)iterator->next_attribute->data)->start_index);
+
+ return TRUE;
+}
+
+/**
+ * pango_attr_iterator_copy:
+ * @iterator: a #PangoAttrIterator.
+ *
+ * Copy a #PangoAttrIterator
+ *
+ * Return value: the newly allocated #PangoAttrIterator, which should
+ * be freed with pango_attr_iterator_destroy().
+ **/
+PangoAttrIterator *
+pango_attr_iterator_copy (PangoAttrIterator *iterator)
+{
+ PangoAttrIterator *copy;
+
+ g_return_val_if_fail (iterator != NULL, NULL);
+
+ copy = g_slice_new (PangoAttrIterator);
+
+ *copy = *iterator;
+
+ copy->attribute_stack = g_list_copy (iterator->attribute_stack);
+
+ return copy;
+}
+
+/**
+ * pango_attr_iterator_destroy:
+ * @iterator: a #PangoAttrIterator.
+ *
+ * Destroy a #PangoAttrIterator and free all associated memory.
+ **/
+void
+pango_attr_iterator_destroy (PangoAttrIterator *iterator)
+{
+ g_return_if_fail (iterator != NULL);
+
+ g_list_free (iterator->attribute_stack);
+ g_slice_free (PangoAttrIterator, iterator);
+}
+
+/**
+ * pango_attr_iterator_get:
+ * @iterator: a #PangoAttrIterator
+ * @type: the type of attribute to find.
+ *
+ * Find the current attribute of a particular type at the iterator
+ * location. When multiple attributes of the same type overlap,
+ * the attribute whose range starts closest to the current location
+ * is used.
+ *
+ * Return value: the current attribute of the given type, or %NULL
+ * if no attribute of that type applies to the current
+ * location.
+ **/
+PangoAttribute *
+pango_attr_iterator_get (PangoAttrIterator *iterator,
+ PangoAttrType type)
+{
+ GList *tmp_list;
+
+ g_return_val_if_fail (iterator != NULL, NULL);
+
+ tmp_list = iterator->attribute_stack;
+ while (tmp_list)
+ {
+ PangoAttribute *attr = tmp_list->data;
+
+ if (attr->klass->type == type)
+ return attr;
+
+ tmp_list = tmp_list->next;
+ }
+
+ return NULL;
+}
+
+/**
+ * pango_attr_iterator_get_font:
+ * @iterator: a #PangoAttrIterator
+ * @desc: a #PangoFontDescription to fill in with the current values.
+ * The family name in this structure will be set using
+ * pango_font_description_set_family_static() using values from
+ * an attribute in the #PangoAttrList associated with the iterator,
+ * so if you plan to keep it around, you must call:
+ * <literal>pango_font_description_set_family (desc, pango_font_description_get_family (desc))</literal>.
+ * @language: if non-%NULL, location to store language tag for item, or %NULL
+ * if none is found.
+ * @extra_attrs: if non-%NULL, location in which to store a list of non-font
+ * attributes at the the current position; only the highest priority
+ * value of each attribute will be added to this list. In order
+ * to free this value, you must call pango_attribute_destroy() on
+ * each member.
+ *
+ * Get the font and other attributes at the current iterator position.
+ **/
+void
+pango_attr_iterator_get_font (PangoAttrIterator *iterator,
+ PangoFontDescription *desc,
+ PangoLanguage **language,
+ GSList **extra_attrs)
+{
+ GList *tmp_list1;
+ GSList *tmp_list2;
+
+ PangoFontMask mask = 0;
+ gboolean have_language = FALSE;
+ gdouble scale = 0;
+ gboolean have_scale = FALSE;
+
+ g_return_if_fail (iterator != NULL);
+ g_return_if_fail (desc != NULL);
+
+ if (language)
+ *language = NULL;
+
+ if (extra_attrs)
+ *extra_attrs = NULL;
+
+ tmp_list1 = iterator->attribute_stack;
+ while (tmp_list1)
+ {
+ PangoAttribute *attr = tmp_list1->data;
+ tmp_list1 = tmp_list1->next;
+
+ switch (attr->klass->type)
+ {
+ case PANGO_ATTR_FONT_DESC:
+ {
+ PangoFontMask new_mask = pango_font_description_get_set_fields (((PangoAttrFontDesc *)attr)->desc) & ~mask;
+ mask |= new_mask;
+ pango_font_description_unset_fields (desc, new_mask);
+ pango_font_description_merge_static (desc, ((PangoAttrFontDesc *)attr)->desc, FALSE);
+
+ break;
+ }
+ case PANGO_ATTR_FAMILY:
+ if (!(mask & PANGO_FONT_MASK_FAMILY))
+ {
+ mask |= PANGO_FONT_MASK_FAMILY;
+ pango_font_description_set_family (desc, ((PangoAttrString *)attr)->value);
+ }
+ break;
+ case PANGO_ATTR_STYLE:
+ if (!(mask & PANGO_FONT_MASK_STYLE))
+ {
+ mask |= PANGO_FONT_MASK_STYLE;
+ pango_font_description_set_style (desc, ((PangoAttrInt *)attr)->value);
+ }
+ break;
+ case PANGO_ATTR_VARIANT:
+ if (!(mask & PANGO_FONT_MASK_VARIANT))
+ {
+ mask |= PANGO_FONT_MASK_VARIANT;
+ pango_font_description_set_variant (desc, ((PangoAttrInt *)attr)->value);
+ }
+ break;
+ case PANGO_ATTR_WEIGHT:
+ if (!(mask & PANGO_FONT_MASK_WEIGHT))
+ {
+ mask |= PANGO_FONT_MASK_WEIGHT;
+ pango_font_description_set_weight (desc, ((PangoAttrInt *)attr)->value);
+ }
+ break;
+ case PANGO_ATTR_STRETCH:
+ if (!(mask & PANGO_FONT_MASK_STRETCH))
+ {
+ mask |= PANGO_FONT_MASK_STRETCH;
+ pango_font_description_set_stretch (desc, ((PangoAttrInt *)attr)->value);
+ }
+ break;
+ case PANGO_ATTR_SIZE:
+ if (!(mask & PANGO_FONT_MASK_SIZE))
+ {
+ mask |= PANGO_FONT_MASK_SIZE;
+ pango_font_description_set_size (desc, ((PangoAttrSize *)attr)->size);
+ }
+ break;
+ case PANGO_ATTR_ABSOLUTE_SIZE:
+ if (!(mask & PANGO_FONT_MASK_SIZE))
+ {
+ mask |= PANGO_FONT_MASK_SIZE;
+ pango_font_description_set_absolute_size (desc, ((PangoAttrSize *)attr)->size);
+ }
+ break;
+ case PANGO_ATTR_SCALE:
+ if (!have_scale)
+ {
+ have_scale = TRUE;
+ scale = ((PangoAttrFloat *)attr)->value;
+ }
+ break;
+ case PANGO_ATTR_LANGUAGE:
+ if (language)
+ {
+ if (!have_language)
+ {
+ have_language = TRUE;
+ *language = ((PangoAttrLanguage *)attr)->value;
+ }
+ }
+ break;
+ default:
+ if (extra_attrs)
+ {
+ gboolean found = FALSE;
+
+ tmp_list2 = *extra_attrs;
+ while (tmp_list2)
+ {
+ PangoAttribute *old_attr = tmp_list2->data;
+ if (attr->klass->type == old_attr->klass->type)
+ {
+ found = TRUE;
+ break;
+ }
+
+ tmp_list2 = tmp_list2->next;
+ }
+
+ if (!found)
+ *extra_attrs = g_slist_prepend (*extra_attrs, pango_attribute_copy (attr));
+ }
+ }
+ }
+
+ if (have_scale)
+ pango_font_description_set_size (desc, scale * pango_font_description_get_size (desc));
+
+}
+
+/**
+ * pango_attr_list_filter:
+ * @list: a #PangoAttrList
+ * @func: callback function; returns %TRUE if an attribute
+ * should be filtered out.
+ * @data: Data to be passed to @func
+ *
+ * Given a #PangoAttrList and callback function, removes any elements
+ * of @list for which @func returns %TRUE and inserts them into
+ * a new list.
+ *
+ * Return value: the new #PangoAttrList or %NULL if
+ * no attributes of the given types were found.
+ *
+ * Since: 1.2
+ **/
+PangoAttrList *
+pango_attr_list_filter (PangoAttrList *list,
+ PangoAttrFilterFunc func,
+ gpointer data)
+
+{
+ PangoAttrList *new = NULL;
+ GSList *tmp_list;
+ GSList *prev;
+
+ g_return_val_if_fail (list != NULL, NULL);
+
+ tmp_list = list->attributes;
+ prev = NULL;
+ while (tmp_list)
+ {
+ GSList *next = tmp_list->next;
+ PangoAttribute *tmp_attr = tmp_list->data;
+
+ if ((*func) (tmp_attr, data))
+ {
+ if (!tmp_list->next)
+ list->attributes_tail = prev;
+
+ if (prev)
+ prev->next = tmp_list->next;
+ else
+ list->attributes = tmp_list->next;
+
+ tmp_list->next = NULL;
+
+ if (!new)
+ {
+ new = pango_attr_list_new ();
+ new->attributes = new->attributes_tail = tmp_list;
+ }
+ else
+ {
+ new->attributes_tail->next = tmp_list;
+ new->attributes_tail = tmp_list;
+ }
+
+ goto next_attr;
+ }
+
+ prev = tmp_list;
+
+ next_attr:
+ tmp_list = next;
+ }
+
+ return new;
+}
+
+/**
+ * pango_attr_iterator_get_attrs:
+ * @iterator: a #PangoAttrIterator
+ *
+ * Gets a list of all attributes at the current position of the
+ * iterator.
+ *
+ * Return value: a list of all attributes for the current range.
+ * To free this value, call pango_attribute_destroy() on
+ * each value and g_slist_free() on the list.
+ *
+ * Since: 1.2
+ **/
+GSList *
+pango_attr_iterator_get_attrs (PangoAttrIterator *iterator)
+{
+ GSList *attrs = NULL;
+ GList *tmp_list;
+
+ for (tmp_list = iterator->attribute_stack; tmp_list; tmp_list = tmp_list->next)
+ {
+ PangoAttribute *attr = tmp_list->data;
+ GSList *tmp_list2;
+ gboolean found = FALSE;
+
+ for (tmp_list2 = attrs; tmp_list2; tmp_list2 = tmp_list2->next)
+ {
+ PangoAttribute *old_attr = tmp_list2->data;
+ if (attr->klass->type == old_attr->klass->type)
+ {
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (!found)
+ attrs = g_slist_prepend (attrs, pango_attribute_copy (attr));
+ }
+
+ return attrs;
+}