[pango/pango2: 119/135] Split pango-attributes.[hc]




commit 6fc426dbc79ac24793d2346b43a0c3f7c774100a
Author: Matthias Clasen <mclasen redhat com>
Date:   Sat Feb 5 19:18:57 2022 +0100

    Split pango-attributes.[hc]
    
    Split pango-attributes.[hc] into separate files for
    PangoAttribute, PangoAttrList, PangoAttrIterator, and
    the predefined attribute types.

 pango/break.c                       |   36 +-
 pango/ellipsize.c                   |    6 +-
 pango/itemize.c                     |    2 +-
 pango/meson.build                   |    6 +
 pango/pango-attr-iterator-private.h |   38 +
 pango/pango-attr-iterator.c         |  518 ++++++++
 pango/pango-attr-iterator.h         |   68 +
 pango/pango-attr-list-private.h     |   35 +
 pango/pango-attr-list.c             | 1285 +++++++++++++++++++
 pango/pango-attr-list.h             |  114 ++
 pango/pango-attr-private.h          |   24 +
 pango/pango-attr.c                  |  540 ++++++++
 pango/pango-attr.h                  |  214 ++++
 pango/pango-attributes-private.h    |   55 +-
 pango/pango-attributes.c            | 2369 +----------------------------------
 pango/pango-attributes.h            |  546 +++-----
 pango/pango-glyph-item.c            |    7 +-
 pango/pango-item.h                  |    3 +-
 pango/pango-line-breaker.c          |   14 +-
 pango/pango-line.c                  |    5 +-
 pango/pango-markup.h                |    2 +-
 pango/pango.h                       |    3 +
 pango/serializer.c                  |    3 +-
 23 files changed, 3093 insertions(+), 2800 deletions(-)
---
diff --git a/pango/break.c b/pango/break.c
index bc8e4da6..dbfc88fc 100644
--- a/pango/break.c
+++ b/pango/break.c
@@ -24,7 +24,9 @@
 #include "pango-break.h"
 #include "pango-script-private.h"
 #include "pango-emoji-private.h"
-#include "pango-attributes-private.h"
+#include "pango-attributes.h"
+#include "pango-attr-list-private.h"
+#include "pango-attr-iterator-private.h"
 #include "pango-break-table.h"
 #include "pango-impl-utils.h"
 #include <string.h>
@@ -1786,7 +1788,7 @@ handle_allow_breaks (const char    *text,
   PangoAttrIterator iter;
   gboolean tailored = FALSE;
 
-  _pango_attr_list_get_iterator (attrs, &iter);
+  pango_attr_list_init_iterator (attrs, &iter);
 
   do
     {
@@ -1822,7 +1824,7 @@ handle_allow_breaks (const char    *text,
     }
   while (pango_attr_iterator_next (&iter));
 
-  _pango_attr_iterator_destroy (&iter);
+  pango_attr_iterator_clear (&iter);
 
   return tailored;
 }
@@ -1839,7 +1841,7 @@ handle_words (const char    *text,
   PangoAttrIterator iter;
   gboolean tailored = FALSE;
 
-  _pango_attr_list_get_iterator (attrs, &iter);
+  pango_attr_list_init_iterator (attrs, &iter);
 
   do
     {
@@ -1928,7 +1930,7 @@ handle_words (const char    *text,
     }
   while (pango_attr_iterator_next (&iter));
 
-  _pango_attr_iterator_destroy (&iter);
+  pango_attr_iterator_clear (&iter);
 
   return tailored;
 }
@@ -1944,7 +1946,7 @@ handle_sentences (const char    *text,
   PangoAttrIterator iter;
   gboolean tailored = FALSE;
 
-  _pango_attr_list_get_iterator (attrs, &iter);
+  pango_attr_list_init_iterator (attrs, &iter);
 
   do
     {
@@ -2016,7 +2018,7 @@ handle_sentences (const char    *text,
     }
   while (pango_attr_iterator_next (&iter));
 
-  _pango_attr_iterator_destroy (&iter);
+  pango_attr_iterator_clear (&iter);
 
   return tailored;
 }
@@ -2032,7 +2034,7 @@ handle_hyphens (const char    *text,
   PangoAttrIterator iter;
   gboolean tailored = FALSE;
 
-  _pango_attr_list_get_iterator (attrs, &iter);
+  pango_attr_list_init_iterator (attrs, &iter);
 
   do {
     const PangoAttribute *attr = pango_attr_iterator_get (&iter, PANGO_ATTR_INSERT_HYPHENS);
@@ -2065,7 +2067,7 @@ handle_hyphens (const char    *text,
       }
   } while (pango_attr_iterator_next (&iter));
 
-  _pango_attr_iterator_destroy (&iter);
+  pango_attr_iterator_clear (&iter);
 
   return tailored;
 }
@@ -2085,10 +2087,10 @@ break_attrs (const char   *text,
   GSList *l;
   gboolean tailored = FALSE;
 
-  _pango_attr_list_init (&allow_breaks);
-  _pango_attr_list_init (&words);
-  _pango_attr_list_init (&sentences);
-  _pango_attr_list_init (&hyphens);
+  pango_attr_list_init (&allow_breaks);
+  pango_attr_list_init (&words);
+  pango_attr_list_init (&sentences);
+  pango_attr_list_init (&hyphens);
 
   for (l = attributes; l; l = l->next)
     {
@@ -2116,10 +2118,10 @@ break_attrs (const char   *text,
   tailored |= handle_allow_breaks (text, length, &allow_breaks, offset,
                                    log_attrs, log_attrs_len);
 
-  _pango_attr_list_destroy (&allow_breaks);
-  _pango_attr_list_destroy (&words);
-  _pango_attr_list_destroy (&sentences);
-  _pango_attr_list_destroy (&hyphens);
+  pango_attr_list_destroy (&allow_breaks);
+  pango_attr_list_destroy (&words);
+  pango_attr_list_destroy (&sentences);
+  pango_attr_list_destroy (&hyphens);
 
   return tailored;
 }
diff --git a/pango/ellipsize.c b/pango/ellipsize.c
index 35bb5953..9f68c6e9 100644
--- a/pango/ellipsize.c
+++ b/pango/ellipsize.c
@@ -25,6 +25,8 @@
 #include "pango-glyph-item.h"
 #include "pango-font-private.h"
 #include "pango-attributes-private.h"
+#include "pango-attr-list-private.h"
+#include "pango-attr-iterator-private.h"
 #include "pango-impl-utils.h"
 #include "pango-line-private.h"
 
@@ -321,7 +323,7 @@ shape_ellipsis (EllipsizeState *state)
   int len;
   int i;
 
-  _pango_attr_list_init (&attrs);
+  pango_attr_list_init (&attrs);
 
   /* Create/reset state->ellipsis_run
    */
@@ -387,7 +389,7 @@ shape_ellipsis (EllipsizeState *state)
       item = itemize_text (state, ellipsis_text, &attrs);
     }
 
-  _pango_attr_list_destroy (&attrs);
+  pango_attr_list_destroy (&attrs);
 
   state->ellipsis_run->item = item;
 
diff --git a/pango/itemize.c b/pango/itemize.c
index 2c5235fa..9ca97738 100644
--- a/pango/itemize.c
+++ b/pango/itemize.c
@@ -31,7 +31,7 @@
 #include "pango-fontmap-private.h"
 #include "pango-script-private.h"
 #include "pango-emoji-private.h"
-#include "pango-attributes-private.h"
+#include "pango-attr-iterator-private.h"
 #include "pango-item-private.h"
 
 #include <hb-ot.h>
diff --git a/pango/meson.build b/pango/meson.build
index cc0dc468..21d40b19 100644
--- a/pango/meson.build
+++ b/pango/meson.build
@@ -3,6 +3,9 @@ pango_sources = [
   'ellipsize.c',
   'glyphstring.c',
   'itemize.c',
+  'pango-attr.c',
+  'pango-attr-list.c',
+  'pango-attr-iterator.c',
   'pango-attributes.c',
   'pango-bidi-type.c',
   'pango-color.c',
@@ -52,6 +55,9 @@ pango_sources = [
 
 pango_headers = [
   'pango.h',
+  'pango-attr.h',
+  'pango-attr-list.h',
+  'pango-attr-iterator.h',
   'pango-attributes.h',
   'pango-break.h',
   'pango-color.h',
diff --git a/pango/pango-attr-iterator-private.h b/pango/pango-attr-iterator-private.h
new file mode 100644
index 00000000..b229cbad
--- /dev/null
+++ b/pango/pango-attr-iterator-private.h
@@ -0,0 +1,38 @@
+/* Pango
+ * pango-attributes-private.h: Internal structures of PangoLayout
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <pango/pango-attr-iterator.h>
+
+struct _PangoAttrIterator
+{
+  GPtrArray *attrs; /* From the list */
+  guint n_attrs; /* Copied from the list */
+
+  GPtrArray *attribute_stack;
+
+  guint attr_index;
+  guint start_index;
+  guint end_index;
+};
+
+void     pango_attr_iterator_clear    (PangoAttrIterator *iterator);
+gboolean pango_attr_iterator_advance  (PangoAttrIterator *iterator,
+                                       int                index);
diff --git a/pango/pango-attr-iterator.c b/pango/pango-attr-iterator.c
new file mode 100644
index 00000000..e940d5a1
--- /dev/null
+++ b/pango/pango-attr-iterator.c
@@ -0,0 +1,518 @@
+/* Pango
+ * pango-attr-iterator.c: Attribute iterator
+ *
+ * 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-attr-iterator-private.h"
+#include "pango-attr-list-private.h"
+#include "pango-attr-private.h"
+#include "pango-impl-utils.h"
+
+
+G_DEFINE_BOXED_TYPE (PangoAttrIterator,
+                     pango_attr_iterator,
+                     pango_attr_iterator_copy,
+                     pango_attr_iterator_destroy)
+
+/* {{{ Private API */
+
+void
+pango_attr_list_init_iterator (PangoAttrList     *list,
+                               PangoAttrIterator *iterator)
+{
+  iterator->attribute_stack = NULL;
+  iterator->attrs = list->attributes;
+  iterator->n_attrs = iterator->attrs ? iterator->attrs->len : 0;
+
+  iterator->attr_index = 0;
+  iterator->start_index = 0;
+  iterator->end_index = 0;
+
+  if (!pango_attr_iterator_next (iterator))
+    iterator->end_index = G_MAXUINT;
+}
+
+void
+pango_attr_iterator_clear (PangoAttrIterator *iterator)
+{
+  if (iterator->attribute_stack)
+    g_ptr_array_free (iterator->attribute_stack, TRUE);
+}
+
+gboolean
+pango_attr_iterator_advance (PangoAttrIterator *iterator,
+                             int                index)
+{
+  int start_range, end_range;
+
+  pango_attr_iterator_range (iterator, &start_range, &end_range);
+
+  while (index >= end_range)
+    {
+      if (!pango_attr_iterator_next (iterator))
+        return FALSE;
+      pango_attr_iterator_range (iterator, &start_range, &end_range);
+    }
+
+  if (start_range > index)
+    g_warning ("pango_attr_iterator_advance(): iterator had already "
+               "moved beyond the index");
+
+  return TRUE;
+}
+
+/* }}} */
+/* {{{ Public API */
+
+/**
+ * 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: (transfer full): the newly allocated
+ *   `PangoAttrIterator`, which should be freed with
+ *   [method@Pango.AttrIterator.destroy]
+ */
+PangoAttrIterator *
+pango_attr_list_get_iterator (PangoAttrList  *list)
+{
+  PangoAttrIterator *iterator;
+
+  g_return_val_if_fail (list != NULL, NULL);
+
+  iterator = g_slice_new (PangoAttrIterator);
+  pango_attr_list_init_iterator (list, iterator);
+
+  return iterator;
+}
+
+/**
+ * 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);
+
+  pango_attr_iterator_clear (iterator);
+  g_slice_free (PangoAttrIterator, iterator);
+}
+
+/**
+ * pango_attr_iterator_copy:
+ * @iterator: a `PangoAttrIterator`
+ *
+ * Copy a `PangoAttrIterator`.
+ *
+ * Return value: (transfer full): the newly allocated
+ *   `PangoAttrIterator`, which should be freed with
+ *   [method@Pango.AttrIterator.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;
+
+  if (iterator->attribute_stack)
+    copy->attribute_stack = g_ptr_array_copy (iterator->attribute_stack, NULL, NULL);
+  else
+    copy->attribute_stack = NULL;
+
+  return copy;
+}
+
+/**
+ * pango_attr_iterator_range:
+ * @iterator: a PangoAttrIterator
+ * @start: (out): location to store the start of the range
+ * @end: (out): 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)
+{
+  int i;
+
+  g_return_val_if_fail (iterator != NULL, FALSE);
+
+  if (iterator->attr_index >= iterator->n_attrs &&
+      (!iterator->attribute_stack || iterator->attribute_stack->len == 0))
+    return FALSE;
+
+  iterator->start_index = iterator->end_index;
+  iterator->end_index = G_MAXUINT;
+
+  if (iterator->attribute_stack)
+    {
+      for (i = iterator->attribute_stack->len - 1; i>= 0; i--)
+        {
+          const PangoAttribute *attr = g_ptr_array_index (iterator->attribute_stack, i);
+
+          if (attr->end_index == iterator->start_index)
+            g_ptr_array_remove_index (iterator->attribute_stack, i); /* Can't use index_fast :( */
+          else
+            iterator->end_index = MIN (iterator->end_index, attr->end_index);
+        }
+    }
+
+  while (1)
+    {
+      PangoAttribute *attr;
+
+      if (iterator->attr_index >= iterator->n_attrs)
+        break;
+
+      attr = g_ptr_array_index (iterator->attrs, iterator->attr_index);
+
+      if (attr->start_index != iterator->start_index)
+        break;
+
+      if (attr->end_index > iterator->start_index)
+        {
+          if (G_UNLIKELY (!iterator->attribute_stack))
+            iterator->attribute_stack = g_ptr_array_new ();
+
+          g_ptr_array_add (iterator->attribute_stack, attr);
+
+          iterator->end_index = MIN (iterator->end_index, attr->end_index);
+        }
+
+      iterator->attr_index++; /* NEXT! */
+    }
+
+  if (iterator->attr_index < iterator->n_attrs)
+      {
+      PangoAttribute *attr = g_ptr_array_index (iterator->attrs, iterator->attr_index);
+
+      iterator->end_index = MIN (iterator->end_index, attr->start_index);
+    }
+
+  return TRUE;
+}
+
+/**
+ * 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: (nullable) (transfer none): 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,
+                         guint              type)
+{
+  int i;
+
+  g_return_val_if_fail (iterator != NULL, NULL);
+
+  if (!iterator->attribute_stack)
+    return NULL;
+
+  for (i = iterator->attribute_stack->len - 1; i>= 0; i--)
+    {
+      PangoAttribute *attr = g_ptr_array_index (iterator->attribute_stack, i);
+
+      if (attr->type == type)
+        return attr;
+    }
+
+  return NULL;
+}
+
+/**
+ * pango_attr_iterator_get_font:
+ * @iterator: a `PangoAttrIterator`
+ * @desc: (out caller-allocates): a `PangoFontDescription` to fill in with the current
+ *   values. The family name in this structure will be set using
+ *   [method@Pango.FontDescription.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:
+ *   `pango_font_description_set_family (desc, pango_font_description_get_family (desc))`.
+ * @language: (out) (optional): location to store language tag
+ *   for item, or %NULL if none is found.
+ * @extra_attrs: (out) (optional) (element-type Pango.Attribute) (transfer full):
+ *   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
+ *   [method@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)
+{
+  PangoFontMask mask = 0;
+  gboolean have_language = FALSE;
+  gdouble scale = 0;
+  gboolean have_scale = FALSE;
+  int i;
+
+  g_return_if_fail (iterator != NULL);
+  g_return_if_fail (desc != NULL);
+
+  if (language)
+    *language = NULL;
+
+  if (extra_attrs)
+    *extra_attrs = NULL;
+
+  if (!iterator->attribute_stack)
+    return;
+
+  for (i = iterator->attribute_stack->len - 1; i >= 0; i--)
+    {
+      const PangoAttribute *attr = g_ptr_array_index (iterator->attribute_stack, i);
+
+      switch ((int) attr->type)
+        {
+        case PANGO_ATTR_FONT_DESC:
+          {
+            PangoFontMask new_mask = pango_font_description_get_set_fields (attr->font_value) & ~mask;
+            mask |= new_mask;
+            pango_font_description_unset_fields (desc, new_mask);
+            pango_font_description_merge_static (desc, attr->font_value, FALSE);
+
+            break;
+          }
+        case PANGO_ATTR_FAMILY:
+          if (!(mask & PANGO_FONT_MASK_FAMILY))
+            {
+              mask |= PANGO_FONT_MASK_FAMILY;
+              pango_font_description_set_family (desc, attr->str_value);
+            }
+          break;
+        case PANGO_ATTR_STYLE:
+          if (!(mask & PANGO_FONT_MASK_STYLE))
+            {
+              mask |= PANGO_FONT_MASK_STYLE;
+              pango_font_description_set_style (desc, attr->int_value);
+            }
+          break;
+        case PANGO_ATTR_VARIANT:
+          if (!(mask & PANGO_FONT_MASK_VARIANT))
+            {
+              mask |= PANGO_FONT_MASK_VARIANT;
+              pango_font_description_set_variant (desc, attr->int_value);
+            }
+          break;
+        case PANGO_ATTR_WEIGHT:
+          if (!(mask & PANGO_FONT_MASK_WEIGHT))
+            {
+              mask |= PANGO_FONT_MASK_WEIGHT;
+              pango_font_description_set_weight (desc, attr->int_value);
+            }
+          break;
+        case PANGO_ATTR_STRETCH:
+          if (!(mask & PANGO_FONT_MASK_STRETCH))
+            {
+              mask |= PANGO_FONT_MASK_STRETCH;
+              pango_font_description_set_stretch (desc, attr->int_value);
+            }
+          break;
+        case PANGO_ATTR_SIZE:
+          if (!(mask & PANGO_FONT_MASK_SIZE))
+            {
+              mask |= PANGO_FONT_MASK_SIZE;
+              pango_font_description_set_size (desc, attr->int_value);
+            }
+          break;
+        case PANGO_ATTR_ABSOLUTE_SIZE:
+          if (!(mask & PANGO_FONT_MASK_SIZE))
+            {
+              mask |= PANGO_FONT_MASK_SIZE;
+              pango_font_description_set_absolute_size (desc, attr->int_value);
+            }
+          break;
+        case PANGO_ATTR_SCALE:
+          if (!have_scale)
+            {
+              have_scale = TRUE;
+              scale = attr->double_value;
+            }
+          break;
+        case PANGO_ATTR_LANGUAGE:
+          if (language)
+            {
+              if (!have_language)
+                {
+                  have_language = TRUE;
+                  *language = attr->lang_value;
+                }
+            }
+          break;
+        default:
+          if (extra_attrs)
+            {
+              gboolean found = FALSE;
+
+              /* Hack: special-case FONT_FEATURES, BASELINE_SHIFT and FONT_SCALE.
+               * We don't want these to accumulate, not override each other,
+               * so we never merge them.
+               * This needs to be handled more systematically.
+               */
+              if (attr->type != PANGO_ATTR_FONT_FEATURES &&
+                  attr->type != PANGO_ATTR_BASELINE_SHIFT &&
+                  attr->type != PANGO_ATTR_FONT_SCALE)
+                {
+                  GSList *tmp_list = *extra_attrs;
+                  while (tmp_list)
+                    {
+                      PangoAttribute *old_attr = tmp_list->data;
+                      if (attr->type == old_attr->type)
+                        {
+                          found = TRUE;
+                          break;
+                        }
+
+                      tmp_list = tmp_list->next;
+                    }
+                }
+
+              if (!found)
+                *extra_attrs = g_slist_prepend (*extra_attrs, pango_attribute_copy (attr));
+            }
+        }
+    }
+
+  if (have_scale)
+    {
+      /* We need to use a local variable to ensure that the compiler won't
+       * implicitly cast it to integer while the result is kept in registers,
+       * leading to a wrong approximation in i386 (with 387 FPU)
+       */
+      volatile double size = scale * pango_font_description_get_size (desc);
+
+      if (pango_font_description_get_size_is_absolute (desc))
+        pango_font_description_set_absolute_size (desc, size);
+      else
+        pango_font_description_set_size (desc, size);
+    }
+}
+
+/**
+ * pango_attr_iterator_get_attrs:
+ * @iterator: a `PangoAttrIterator`
+ *
+ * Gets a list of all attributes at the current position of the
+ * iterator.
+ *
+ * Return value: (element-type Pango.Attribute) (transfer full):
+ *   a list of all attributes for the current range. To free
+ *   this value, call [method@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;
+  int i;
+
+  if (!iterator->attribute_stack ||
+      iterator->attribute_stack->len == 0)
+    return NULL;
+
+  for (i = iterator->attribute_stack->len - 1; i >= 0; i--)
+    {
+      PangoAttribute *attr = g_ptr_array_index (iterator->attribute_stack, i);
+      GSList *tmp_list2;
+      gboolean found = FALSE;
+
+      if (attr->type != PANGO_ATTR_FONT_DESC &&
+          attr->type != PANGO_ATTR_BASELINE_SHIFT &&
+          attr->type != PANGO_ATTR_FONT_SCALE)
+        for (tmp_list2 = attrs; tmp_list2; tmp_list2 = tmp_list2->next)
+          {
+            PangoAttribute *old_attr = tmp_list2->data;
+            if (attr->type == old_attr->type)
+              {
+                found = TRUE;
+                break;
+              }
+          }
+
+      if (!found)
+        attrs = g_slist_prepend (attrs, pango_attribute_copy (attr));
+    }
+
+  return attrs;
+}
+
+/* }}} */
+
+/* vim:set foldmethod=marker expandtab: */
diff --git a/pango/pango-attr-iterator.h b/pango/pango-attr-iterator.h
new file mode 100644
index 00000000..d805cb92
--- /dev/null
+++ b/pango/pango-attr-iterator.h
@@ -0,0 +1,68 @@
+/* Pango
+ * pango-attr-list.h: Attribute lists
+ *
+ * Copyright (C) 2000 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.
+ */
+
+#pragma once
+
+#include <pango/pango-attr-list.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+
+/**
+ * PangoAttrIterator:
+ *
+ * A `PangoAttrIterator` is used to iterate through a `PangoAttrList`.
+ *
+ * A new iterator is created with [method@Pango.AttrList.get_iterator].
+ * Once the iterator is created, it can be advanced through the style
+ * changes in the text using [method Pango AttrIterator next]. At each
+ * style change, the range of the current style segment and the attributes
+ * currently in effect can be queried.
+ */
+
+PANGO_AVAILABLE_IN_1_44
+GType                   pango_attr_iterator_get_type    (void) G_GNUC_CONST;
+
+PANGO_AVAILABLE_IN_ALL
+void                    pango_attr_iterator_range       (PangoAttrIterator     *iterator,
+                                                         int                   *start,
+                                                         int                   *end);
+PANGO_AVAILABLE_IN_ALL
+gboolean                pango_attr_iterator_next        (PangoAttrIterator     *iterator);
+PANGO_AVAILABLE_IN_ALL
+PangoAttrIterator *     pango_attr_iterator_copy        (PangoAttrIterator     *iterator);
+PANGO_AVAILABLE_IN_ALL
+void                    pango_attr_iterator_destroy     (PangoAttrIterator     *iterator);
+PANGO_AVAILABLE_IN_ALL
+PangoAttribute *        pango_attr_iterator_get         (PangoAttrIterator     *iterator,
+                                                         guint                  type);
+PANGO_AVAILABLE_IN_ALL
+void                    pango_attr_iterator_get_font    (PangoAttrIterator     *iterator,
+                                                         PangoFontDescription  *desc,
+                                                         PangoLanguage        **language,
+                                                         GSList               **extra_attrs);
+PANGO_AVAILABLE_IN_1_2
+GSList *                pango_attr_iterator_get_attrs   (PangoAttrIterator     *iterator);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(PangoAttrIterator, pango_attr_iterator_destroy)
+
+G_END_DECLS
diff --git a/pango/pango-attr-list-private.h b/pango/pango-attr-list-private.h
new file mode 100644
index 00000000..fcd9e0f6
--- /dev/null
+++ b/pango/pango-attr-list-private.h
@@ -0,0 +1,35 @@
+/* Pango
+ * pango-attributes-private.h: Internal structures of PangoLayout
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <pango/pango-attr-list.h>
+
+struct _PangoAttrList
+{
+  guint ref_count;
+  GPtrArray *attributes;
+};
+
+void     pango_attr_list_init           (PangoAttrList       *list);
+void     pango_attr_list_destroy        (PangoAttrList       *list);
+gboolean pango_attr_list_has_attributes (const PangoAttrList *list);
+
+void     pango_attr_list_init_iterator  (PangoAttrList       *list,
+                                         PangoAttrIterator   *iterator);
diff --git a/pango/pango-attr-list.c b/pango/pango-attr-list.c
new file mode 100644
index 00000000..2615ddf1
--- /dev/null
+++ b/pango/pango-attr-list.c
@@ -0,0 +1,1285 @@
+/* Pango
+ * pango-attr-list.c: Attribute lists
+ *
+ * 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-attr-list-private.h"
+#include "pango-attr-private.h"
+#include "pango-impl-utils.h"
+
+
+G_DEFINE_BOXED_TYPE (PangoAttrList, pango_attr_list,
+                     pango_attr_list_copy,
+                     pango_attr_list_unref);
+
+/* {{{ Utilities */
+
+static void
+pango_attr_list_insert_internal (PangoAttrList  *list,
+                                 PangoAttribute *attr,
+                                 gboolean        before)
+{
+  const guint start_index = attr->start_index;
+  PangoAttribute *last_attr;
+
+  if (G_UNLIKELY (!list->attributes))
+    list->attributes = g_ptr_array_new ();
+
+  if (list->attributes->len == 0)
+    {
+      g_ptr_array_add (list->attributes, attr);
+      return;
+    }
+
+  g_assert (list->attributes->len > 0);
+
+  last_attr = g_ptr_array_index (list->attributes, list->attributes->len - 1);
+
+  if (last_attr->start_index < start_index ||
+      (!before && last_attr->start_index == start_index))
+    {
+      g_ptr_array_add (list->attributes, attr);
+    }
+  else
+    {
+      guint i, p;
+
+      for (i = 0, p = list->attributes->len; i < p; i++)
+        {
+          PangoAttribute *cur = g_ptr_array_index (list->attributes, i);
+
+          if (cur->start_index > start_index ||
+              (before && cur->start_index == start_index))
+            {
+              g_ptr_array_insert (list->attributes, i, attr);
+              break;
+            }
+        }
+    }
+}
+
+/* }}} */
+/* {{{ Private API */
+
+void
+pango_attr_list_init (PangoAttrList *list)
+{
+  list->ref_count = 1;
+  list->attributes = NULL;
+}
+
+void
+pango_attr_list_destroy (PangoAttrList *list)
+{
+  if (!list->attributes)
+    return;
+
+  g_ptr_array_free (list->attributes, TRUE);
+}
+
+gboolean
+pango_attr_list_has_attributes (const PangoAttrList *list)
+{
+  return list && list->attributes != NULL && list->attributes->len > 0;
+}
+
+/* }}} */
+/* {{{ Public API */
+
+/**
+ * pango_attr_list_new:
+ *
+ * Create a new empty attribute list with a reference
+ * count of one.
+ *
+ * Return value: (transfer full): the newly allocated
+ *   `PangoAttrList`, which should be freed with
+ *   [method@Pango.AttrList.unref]
+ */
+PangoAttrList *
+pango_attr_list_new (void)
+{
+  PangoAttrList *list = g_slice_new (PangoAttrList);
+
+  pango_attr_list_init (list);
+
+  return list;
+}
+
+/**
+ * pango_attr_list_ref:
+ * @list: (nullable): 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)
+{
+  if (list == NULL)
+    return NULL;
+
+  g_atomic_int_inc ((int *) &list->ref_count);
+
+  return list;
+}
+
+/**
+ * pango_attr_list_unref:
+ * @list: (nullable): 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)
+{
+  if (list == NULL)
+    return;
+
+  g_return_if_fail (list->ref_count > 0);
+
+  if (g_atomic_int_dec_and_test ((int *) &list->ref_count))
+    {
+      pango_attr_list_destroy (list);
+      g_slice_free (PangoAttrList, list);
+    }
+}
+
+/**
+ * pango_attr_list_copy:
+ * @list: (nullable): a `PangoAttrList`
+ *
+ * Copy @list and return an identical new list.
+ *
+ * Return value: (nullable): the newly allocated
+ *   `PangoAttrList`, with a reference count of one,
+ *   which should be freed with [method@Pango.AttrList.unref].
+ *   Returns %NULL if @list was %NULL.
+ */
+PangoAttrList *
+pango_attr_list_copy (PangoAttrList *list)
+{
+  PangoAttrList *new;
+
+  if (list == NULL)
+    return NULL;
+
+  new = pango_attr_list_new ();
+  if (!list->attributes || list->attributes->len == 0)
+    return new;
+
+  new->attributes = g_ptr_array_copy (list->attributes, (GCopyFunc)pango_attribute_copy, NULL);
+
+  return new;
+}
+
+/**
+ * pango_attr_list_insert:
+ * @list: a `PangoAttrList`
+ * @attr: (transfer full): the attribute to insert
+ *
+ * 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: (transfer full): the attribute to insert
+ *
+ * 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: (transfer full): the attribute to insert
+ *
+ * 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 [method@Pango.AttrList.insert]
+ * for creating an attribute list in order (potentially
+ * much slower for large lists). However,
+ * [method@Pango.AttrList.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)
+{
+  guint i, p;
+  guint start_index = attr->start_index;
+  guint end_index = attr->end_index;
+  gboolean inserted;
+
+  g_return_if_fail (list != NULL);
+
+  if (start_index == end_index) /* empty, nothing to do */
+    {
+      pango_attribute_destroy (attr);
+      return;
+    }
+
+  if (!list->attributes || list->attributes->len == 0)
+    {
+      pango_attr_list_insert (list, attr);
+      return;
+    }
+
+  inserted = FALSE;
+  for (i = 0, p = list->attributes->len; i < p; i++)
+    {
+      PangoAttribute *tmp_attr = g_ptr_array_index (list->attributes, i);
+
+      if (tmp_attr->start_index > start_index)
+        {
+          g_ptr_array_insert (list->attributes, i, attr);
+          inserted = TRUE;
+          break;
+        }
+
+      if (tmp_attr->type != attr->type)
+        continue;
+
+      if (tmp_attr->end_index < start_index)
+        continue; /* This attr does not overlap with the new one */
+
+      g_assert (tmp_attr->start_index <= start_index);
+      g_assert (tmp_attr->end_index >= start_index);
+
+      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;
+          inserted = TRUE;
+          break;
+        }
+      else
+        {
+          /* Split, truncate, or remove the old attribute
+           */
+          if (tmp_attr->end_index > end_index)
+            {
+              PangoAttribute *end_attr = pango_attribute_copy (tmp_attr);
+
+              end_attr->start_index = end_index;
+              pango_attr_list_insert (list, end_attr);
+            }
+
+          if (tmp_attr->start_index == start_index)
+            {
+              pango_attribute_destroy (tmp_attr);
+              g_ptr_array_remove_index (list->attributes, i);
+              break;
+            }
+          else
+            {
+              tmp_attr->end_index = start_index;
+            }
+        }
+    }
+
+  if (!inserted)
+    /* we didn't insert attr yet */
+    pango_attr_list_insert (list, attr);
+
+  /* We now have the range inserted into the list one way or the
+   * other. Fix up the remainder
+   */
+  /* Attention: No i = 0 here. */
+  for (i = i + 1, p = list->attributes->len; i < p; i++)
+    {
+      PangoAttribute *tmp_attr = g_ptr_array_index (list->attributes, i);
+
+      if (tmp_attr->start_index > end_index)
+        break;
+
+      if (tmp_attr->type != attr->type)
+        continue;
+
+      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);
+          g_ptr_array_remove_index (list->attributes, i);
+          i--;
+          p--;
+          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.
+           */
+          int k, m;
+
+          tmp_attr->start_index = attr->end_index;
+
+          for (k = i + 1, m = list->attributes->len; k < m; k++)
+            {
+              PangoAttribute *tmp_attr2 = g_ptr_array_index (list->attributes, k);
+
+              if (tmp_attr2->start_index >= tmp_attr->start_index)
+                break;
+            }
+        }
+    }
+}
+
+/**
+ * pango_attr_list_update:
+ * @list: a `PangoAttrList`
+ * @pos: the position of the change
+ * @remove: the number of removed bytes
+ * @add: the number of added bytes
+ *
+ * Update indices of attributes in @list for a change in the
+ * text they refer to.
+ *
+ * The change that this function applies is removing @remove
+ * bytes at position @pos and inserting @add bytes instead.
+ *
+ * Attributes that fall entirely in the (@pos, @pos + @remove)
+ * range are removed.
+ *
+ * Attributes that start or end inside the (@pos, @pos + @remove)
+ * range are shortened to reflect the removal.
+ *
+ * Attributes start and end positions are updated if they are
+ * behind @pos + @remove.
+ *
+ * Since: 1.44
+ */
+void
+pango_attr_list_update (PangoAttrList *list,
+                        int             pos,
+                        int             remove,
+                        int             add)
+{
+  guint i, p;
+
+  g_return_if_fail (pos >= 0);
+  g_return_if_fail (remove >= 0);
+  g_return_if_fail (add >= 0);
+
+  if (list->attributes)
+    for (i = 0, p = list->attributes->len; i < p; i++)
+      {
+        PangoAttribute *attr = g_ptr_array_index (list->attributes, i);
+
+        if (attr->start_index >= pos &&
+          attr->end_index < pos + remove)
+          {
+            pango_attribute_destroy (attr);
+            g_ptr_array_remove_index (list->attributes, i);
+            i--; /* Look at this index again */
+            p--;
+            continue;
+          }
+
+        if (attr->start_index != PANGO_ATTR_INDEX_FROM_TEXT_BEGINNING)
+          {
+            if (attr->start_index >= pos &&
+                attr->start_index < pos + remove)
+              {
+                attr->start_index = pos + add;
+              }
+            else if (attr->start_index >= pos + remove)
+              {
+                attr->start_index += add - remove;
+              }
+          }
+
+        if (attr->end_index != PANGO_ATTR_INDEX_TO_TEXT_END)
+          {
+            if (attr->end_index >= pos &&
+                attr->end_index < pos + remove)
+              {
+                attr->end_index = pos;
+              }
+            else if (attr->end_index >= pos + remove)
+              {
+                if (add > remove &&
+                    G_MAXUINT - attr->end_index < add - remove)
+                  attr->end_index = G_MAXUINT;
+                else
+                  attr->end_index += add - remove;
+              }
+          }
+      }
+}
+
+/**
+ * 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 [method@Pango.AttrList.change] with a copy
+ * of each attribute in @other in sequence (offset in position
+ * by @pos, and limited in length to @len).
+ *
+ * This operation proves useful for, for instance, inserting
+ * a pre-edit string in the middle of an edit buffer.
+ *
+ * For backwards compatibility, the function behaves differently
+ * when @len is 0. In this case, the attributes from @other are
+ * not imited to @len, and are just overlayed on top of @list.
+ *
+ * This mode is useful for merging two lists of attributes together.
+ */
+void
+pango_attr_list_splice (PangoAttrList *list,
+                        PangoAttrList *other,
+                        gint           pos,
+                        gint           len)
+{
+  guint i, p;
+  guint upos, ulen;
+  guint end;
+
+  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))
+
+  end = CLAMP_ADD (upos, ulen);
+
+  if (list->attributes)
+    for (i = 0, p = list->attributes->len; i < p; i++)
+      {
+        PangoAttribute *attr = g_ptr_array_index (list->attributes, i);;
+
+        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);
+         }
+      }
+
+  if (!other->attributes || other->attributes->len == 0)
+    return;
+
+  for (i = 0, p = other->attributes->len; i < p; i++)
+    {
+      PangoAttribute *attr = pango_attribute_copy (g_ptr_array_index (other->attributes, i));
+      if (ulen > 0)
+        {
+          attr->start_index = MIN (CLAMP_ADD (attr->start_index, upos), end);
+          attr->end_index = MIN (CLAMP_ADD (attr->end_index, upos), end);
+        }
+      else
+        {
+          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);
+    }
+#undef CLAMP_ADD
+}
+
+/**
+ * pango_attr_list_get_attributes:
+ * @list: a `PangoAttrList`
+ *
+ * Gets a list of all attributes in @list.
+ *
+ * Return value: (element-type Pango.Attribute) (transfer full):
+ *   a list of all attributes in @list. To free this value,
+ *   call [method@Pango.Attribute.destroy] on each value and
+ *   g_slist_free() on the list.
+ *
+ * Since: 1.44
+ */
+GSList *
+pango_attr_list_get_attributes (PangoAttrList *list)
+{
+  GSList *result = NULL;
+  guint i, p;
+
+  g_return_val_if_fail (list != NULL, NULL);
+
+  if (!list->attributes || list->attributes->len == 0)
+    return NULL;
+
+  for (i = 0, p = list->attributes->len; i < p; i++)
+    {
+      PangoAttribute *attr = g_ptr_array_index (list->attributes, i);
+
+      result = g_slist_prepend (result, pango_attribute_copy (attr));
+    }
+
+  return g_slist_reverse (result);
+}
+
+/**
+ * pango_attr_list_equal:
+ * @list: a `PangoAttrList`
+ * @other_list: the other `PangoAttrList`
+ *
+ * Checks whether @list and @other_list contain the same
+ * attributes and whether those attributes apply to the
+ * same ranges.
+ *
+ * Beware that this will return wrong values if any list
+ * contains duplicates.
+ *
+ * Return value: %TRUE if the lists are equal, %FALSE if
+ *   they aren't
+ *
+ * Since: 1.46
+ */
+gboolean
+pango_attr_list_equal (PangoAttrList *list,
+                       PangoAttrList *other_list)
+{
+  GPtrArray *attrs, *other_attrs;
+  guint64 skip_bitmask = 0;
+  guint i;
+
+  if (list == other_list)
+    return TRUE;
+
+  if (list == NULL || other_list == NULL)
+    return FALSE;
+
+  if (list->attributes == NULL || other_list->attributes == NULL)
+    return list->attributes == other_list->attributes;
+
+  attrs = list->attributes;
+  other_attrs = other_list->attributes;
+
+  if (attrs->len != other_attrs->len)
+    return FALSE;
+
+  for (i = 0; i < attrs->len; i++)
+    {
+      PangoAttribute *attr = g_ptr_array_index (attrs, i);
+      gboolean attr_equal = FALSE;
+      guint other_attr_index;
+
+      for (other_attr_index = 0; other_attr_index < other_attrs->len; other_attr_index++)
+        {
+          PangoAttribute *other_attr = g_ptr_array_index (other_attrs, other_attr_index);
+          guint64 other_attr_bitmask = other_attr_index < 64 ? 1 << other_attr_index : 0;
+
+          if ((skip_bitmask & other_attr_bitmask) != 0)
+            continue;
+
+          if (attr->start_index == other_attr->start_index &&
+              attr->end_index == other_attr->end_index &&
+              pango_attribute_equal (attr, other_attr))
+            {
+              skip_bitmask |= other_attr_bitmask;
+              attr_equal = TRUE;
+              break;
+            }
+
+        }
+
+      if (!attr_equal)
+        return FALSE;
+    }
+
+  return TRUE;
+}
+
+/**
+ * pango_attr_list_filter:
+ * @list: a `PangoAttrList`
+ * @func: (scope call) (closure data): callback function;
+ *   returns %TRUE if an attribute should be filtered out
+ * @data: (closure): 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: (transfer full) (nullable): 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;
+  guint i, p;
+
+  g_return_val_if_fail (list != NULL, NULL);
+
+  if (!list->attributes || list->attributes->len == 0)
+    return NULL;
+
+  for (i = 0, p = list->attributes->len; i < p; i++)
+    {
+      PangoAttribute *tmp_attr = g_ptr_array_index (list->attributes, i);
+
+      if ((*func) (tmp_attr, data))
+        {
+          g_ptr_array_remove_index (list->attributes, i);
+          i--; /* Need to look at this index again */
+          p--;
+
+          if (G_UNLIKELY (!new))
+            {
+              new = pango_attr_list_new ();
+              new->attributes = g_ptr_array_new ();
+            }
+
+          g_ptr_array_add (new->attributes, tmp_attr);
+        }
+    }
+
+  return new;
+}
+
+/* }}} */
+/* {{{ Serialization */
+
+/* We serialize attribute lists to strings. The format
+ * is a comma-separated list of the attributes in the order
+ * in which they are in the list, with each attribute having
+ * this format:
+ *
+ * START END NICK VALUE
+ *
+ * Values that can contain a comma, such as font descriptions
+ * are quoted with "".
+ */
+
+static GType
+get_attr_value_type (PangoAttrType type)
+{
+  switch ((int)type)
+    {
+    case PANGO_ATTR_STYLE: return PANGO_TYPE_STYLE;
+    case PANGO_ATTR_WEIGHT: return PANGO_TYPE_WEIGHT;
+    case PANGO_ATTR_VARIANT: return PANGO_TYPE_VARIANT;
+    case PANGO_ATTR_STRETCH: return PANGO_TYPE_STRETCH;
+    case PANGO_ATTR_GRAVITY: return PANGO_TYPE_GRAVITY;
+    case PANGO_ATTR_GRAVITY_HINT: return PANGO_TYPE_GRAVITY_HINT;
+    case PANGO_ATTR_UNDERLINE: return PANGO_TYPE_UNDERLINE;
+    case PANGO_ATTR_OVERLINE: return PANGO_TYPE_OVERLINE;
+    case PANGO_ATTR_BASELINE_SHIFT: return PANGO_TYPE_BASELINE_SHIFT;
+    case PANGO_ATTR_FONT_SCALE: return PANGO_TYPE_FONT_SCALE;
+    case PANGO_ATTR_TEXT_TRANSFORM: return PANGO_TYPE_TEXT_TRANSFORM;
+    default: return G_TYPE_INVALID;
+    }
+}
+
+static void
+append_enum_value (GString *str,
+                   GType    type,
+                   int      value)
+{
+  GEnumClass *enum_class;
+  GEnumValue *enum_value;
+
+  enum_class = g_type_class_ref (type);
+  enum_value = g_enum_get_value (enum_class, value);
+  g_type_class_unref (enum_class);
+
+  if (enum_value)
+    g_string_append_printf (str, " %s", enum_value->value_nick);
+  else
+    g_string_append_printf (str, " %d", value);
+}
+
+static void
+attr_print (GString        *str,
+            PangoAttribute *attr)
+{
+  const char *name;
+
+  name = pango_attr_type_get_name (attr->type);
+  if (!name)
+    return;
+
+  g_string_append_printf (str, "%u %u %s", attr->start_index, attr->end_index, name);
+
+  switch (PANGO_ATTR_VALUE_TYPE (attr))
+    {
+    case PANGO_ATTR_VALUE_INT:
+      if (attr->type == PANGO_ATTR_WEIGHT ||
+          attr->type == PANGO_ATTR_STYLE ||
+          attr->type == PANGO_ATTR_STRETCH ||
+          attr->type == PANGO_ATTR_VARIANT ||
+          attr->type == PANGO_ATTR_GRAVITY ||
+          attr->type == PANGO_ATTR_GRAVITY_HINT ||
+          attr->type == PANGO_ATTR_UNDERLINE ||
+          attr->type == PANGO_ATTR_OVERLINE ||
+          attr->type == PANGO_ATTR_BASELINE_SHIFT ||
+          attr->type == PANGO_ATTR_FONT_SCALE ||
+          attr->type == PANGO_ATTR_TEXT_TRANSFORM)
+        append_enum_value (str, get_attr_value_type (attr->type), attr->int_value);
+      else
+        g_string_append_printf (str, " %d", attr->int_value);
+      break;
+
+    case PANGO_ATTR_VALUE_BOOLEAN:
+      g_string_append (str, attr->int_value ? " true" : " false");
+      break;
+
+    case PANGO_ATTR_VALUE_STRING:
+      g_string_append_printf (str, " \"%s\"", attr->str_value);
+      break;
+
+    case PANGO_ATTR_VALUE_LANGUAGE:
+      g_string_append_printf (str, " %s", pango_language_to_string (attr->lang_value));
+      break;
+
+    case PANGO_ATTR_VALUE_FLOAT:
+      {
+        char buf[20];
+        g_ascii_formatd (buf, 20, "%f", attr->double_value);
+        g_string_append_printf (str, " %s", buf);
+      }
+      break;
+
+    case PANGO_ATTR_VALUE_FONT_DESC:
+      {
+        char *s = pango_font_description_to_string (attr->font_value);
+        g_string_append_printf (str, " \"%s\"", s);
+        g_free (s);
+      }
+      break;
+
+    case PANGO_ATTR_VALUE_COLOR:
+      {
+        char *s = pango_color_to_string (&attr->color_value);
+        g_string_append_printf (str, " %s", s);
+        g_free (s);
+      }
+      break;
+
+    case PANGO_ATTR_VALUE_POINTER:
+      {
+        char *s = pango_attr_value_serialize (attr);
+        g_string_append_printf (str, " %s", s);
+        g_free (s);
+      }
+      break;
+
+    default:
+      g_assert_not_reached ();
+    }
+}
+
+/**
+ * pango_attr_list_to_string:
+ * @list: a `PangoAttrList`
+ *
+ * Serializes a `PangoAttrList` to a string.
+ *
+ * No guarantees are made about the format of the string,
+ * it may change between Pango versions.
+ *
+ * The intended use of this function is testing and
+ * debugging. The format is not meant as a permanent
+ * storage format.
+ *
+ * Returns: (transfer full): a newly allocated string
+ * Since: 1.50
+ */
+char *
+pango_attr_list_to_string (PangoAttrList *list)
+{
+  GString *s;
+
+  s = g_string_new ("");
+
+  if (list->attributes)
+    for (int i = 0; i < list->attributes->len; i++)
+      {
+        PangoAttribute *attr = g_ptr_array_index (list->attributes, i);
+
+        if (i > 0)
+          g_string_append (s, "\n");
+        attr_print (s, attr);
+      }
+
+  return g_string_free (s, FALSE);
+}
+
+static PangoAttrType
+get_attr_type_by_nick (const char *nick,
+                       int         len)
+{
+  GEnumClass *enum_class;
+
+  enum_class = g_type_class_ref (pango_attr_type_get_type ());
+  for (GEnumValue *ev = enum_class->values; ev->value_name; ev++)
+    {
+      if (ev->value_nick && strncmp (ev->value_nick, nick, len) == 0)
+        {
+          g_type_class_unref (enum_class);
+          return (PangoAttrType) ev->value;
+        }
+    }
+
+  g_type_class_unref (enum_class);
+  return PANGO_ATTR_INVALID;
+}
+
+static int
+get_attr_value (PangoAttrType  type,
+                const char    *str,
+                int            len)
+{
+  GEnumClass *enum_class;
+  char *endp;
+  int value;
+
+  enum_class = g_type_class_ref (get_attr_value_type (type));
+  for (GEnumValue *ev = enum_class->values; ev->value_name; ev++)
+    {
+      if (ev->value_nick && strncmp (ev->value_nick, str, len) == 0)
+        {
+          g_type_class_unref (enum_class);
+          return ev->value;
+        }
+    }
+  g_type_class_unref (enum_class);
+
+  value = g_ascii_strtoll (str, &endp, 10);
+  if (endp - str == len)
+    return value;
+
+  return -1;
+}
+
+static gboolean
+is_valid_end_char (char c)
+{
+  return c == ',' || c == '\n' || c == '\0';
+}
+
+/**
+ * pango_attr_list_from_string:
+ * @text: a string
+ *
+ * Deserializes a `PangoAttrList` from a string.
+ *
+ * This is the counterpart to [method@Pango.AttrList.to_string].
+ * See that functions for details about the format.
+ *
+ * Returns: (transfer full) (nullable): a new `PangoAttrList`
+ * Since: 1.50
+ */
+PangoAttrList *
+pango_attr_list_from_string (const char *text)
+{
+  PangoAttrList *list;
+  const char *p;
+
+  g_return_val_if_fail (text != NULL, NULL);
+
+  list = pango_attr_list_new ();
+
+  if (*text == '\0')
+    return list;
+
+  list->attributes = g_ptr_array_new ();
+
+  p = text + strspn (text, " \t\n");
+  while (*p)
+    {
+      char *endp;
+      gint64 start_index;
+      gint64 end_index;
+      char *str;
+      PangoAttrType attr_type;
+      PangoAttribute *attr;
+      PangoLanguage *lang;
+      gint64 integer;
+      PangoFontDescription *desc;
+      PangoColor color;
+      double num;
+
+      start_index = g_ascii_strtoll (p, &endp, 10);
+      if (*endp != ' ')
+        goto fail;
+
+      p = endp + strspn (endp, " ");
+      if (!*p)
+        goto fail;
+
+      end_index = g_ascii_strtoll (p, &endp, 10);
+      if (*endp != ' ')
+        goto fail;
+
+      p = endp + strspn (endp, " ");
+
+      endp = (char *)p + strcspn (p, " ");
+      attr_type = get_attr_type_by_nick (p, endp - p);
+
+      p = endp + strspn (endp, " ");
+      if (*p == '\0')
+        goto fail;
+
+#define INT_ATTR(name,type) \
+          integer = g_ascii_strtoll (p, &endp, 10); \
+          if (!is_valid_end_char (*endp)) goto fail; \
+          attr = pango_attr_##name##_new ((type)integer);
+
+#define BOOLEAN_ATTR(name,type) \
+          if (strncmp (p, "true", strlen ("true")) == 0) \
+            { \
+              integer = 1; \
+              endp = (char *)(p + strlen ("true")); \
+            } \
+          else if (strncmp (p, "false", strlen ("false")) == 0) \
+            { \
+              integer = 0; \
+              endp = (char *)(p + strlen ("false")); \
+            } \
+          else \
+            integer = g_ascii_strtoll (p, &endp, 10); \
+          if (!is_valid_end_char (*endp)) goto fail; \
+          attr = pango_attr_##name##_new ((type)integer);
+
+#define ENUM_ATTR(name, type, min, max) \
+          endp = (char *)p + strcspn (p, ",\n"); \
+          integer = get_attr_value (attr_type, p, endp - p); \
+          attr = pango_attr_##name##_new ((type) CLAMP (integer, min, max));
+
+#define FLOAT_ATTR(name) \
+          num = g_ascii_strtod (p, &endp); \
+          if (!is_valid_end_char (*endp)) goto fail; \
+          attr = pango_attr_##name##_new ((float)num);
+
+#define COLOR_ATTR(name) \
+          endp = (char *)p + strcspn (p, ",\n"); \
+          if (!is_valid_end_char (*endp)) goto fail; \
+          str = g_strndup (p, endp - p); \
+          if (!pango_color_parse (&color, str)) \
+            { \
+              g_free (str); \
+              goto fail; \
+            } \
+          attr = pango_attr_##name##_new (color.red, color.green, color.blue); \
+          g_free (str);
+
+      switch (attr_type)
+        {
+        case PANGO_ATTR_INVALID:
+          pango_attr_list_unref (list);
+          return NULL;
+
+        case PANGO_ATTR_LANGUAGE:
+          endp = (char *)p + strcspn (p, ",\n");
+          if (!is_valid_end_char (*endp)) goto fail;
+          str = g_strndup (p, endp - p);
+          lang = pango_language_from_string (str);
+          attr = pango_attr_language_new (lang);
+          g_free (str);
+          break;
+
+        case PANGO_ATTR_FAMILY:
+          p++;
+          endp = strchr (p, '"');
+          if (!endp) goto fail;
+          str = g_strndup (p, endp - p);
+          attr = pango_attr_family_new (str);
+          g_free (str);
+          endp++;
+          if (!is_valid_end_char (*endp)) goto fail;
+          break;
+
+        case PANGO_ATTR_STYLE:
+          ENUM_ATTR(style, PangoStyle, PANGO_STYLE_NORMAL, PANGO_STYLE_ITALIC);
+          break;
+
+        case PANGO_ATTR_WEIGHT:
+          ENUM_ATTR(weight, PangoWeight, PANGO_WEIGHT_THIN, PANGO_WEIGHT_ULTRAHEAVY);
+          break;
+
+        case PANGO_ATTR_VARIANT:
+          ENUM_ATTR(variant, PangoVariant, PANGO_VARIANT_NORMAL, PANGO_VARIANT_TITLE_CAPS);
+          break;
+
+        case PANGO_ATTR_STRETCH:
+          ENUM_ATTR(stretch, PangoStretch, PANGO_STRETCH_ULTRA_CONDENSED, PANGO_STRETCH_ULTRA_EXPANDED);
+          break;
+
+        case PANGO_ATTR_SIZE:
+          INT_ATTR(size, int);
+          break;
+
+        case PANGO_ATTR_FONT_DESC:
+          p++;
+          endp = strchr (p, '"');
+          if (!endp) goto fail;
+          str = g_strndup (p, endp - p);
+          desc = pango_font_description_from_string (str);
+          attr = pango_attr_font_desc_new (desc);
+          pango_font_description_free (desc);
+          g_free (str);
+          endp++;
+          if (!is_valid_end_char (*endp)) goto fail;
+          break;
+
+        case PANGO_ATTR_FOREGROUND:
+          COLOR_ATTR(foreground);
+          break;
+
+        case PANGO_ATTR_BACKGROUND:
+          COLOR_ATTR(background);
+          break;
+
+        case PANGO_ATTR_UNDERLINE:
+          ENUM_ATTR(underline, PangoUnderline, PANGO_UNDERLINE_NONE, PANGO_UNDERLINE_ERROR_LINE);
+          break;
+
+        case PANGO_ATTR_STRIKETHROUGH:
+          BOOLEAN_ATTR(strikethrough, gboolean);
+          break;
+
+        case PANGO_ATTR_RISE:
+          INT_ATTR(rise, int);
+          break;
+
+        case PANGO_ATTR_SCALE:
+          FLOAT_ATTR(scale);
+          break;
+
+        case PANGO_ATTR_FALLBACK:
+          BOOLEAN_ATTR(fallback, gboolean);
+          break;
+
+        case PANGO_ATTR_LETTER_SPACING:
+          INT_ATTR(letter_spacing, int);
+          break;
+
+        case PANGO_ATTR_UNDERLINE_COLOR:
+          COLOR_ATTR(underline_color);
+          break;
+
+        case PANGO_ATTR_STRIKETHROUGH_COLOR:
+          COLOR_ATTR(strikethrough_color);
+          break;
+
+        case PANGO_ATTR_ABSOLUTE_SIZE:
+          integer = g_ascii_strtoll (p, &endp, 10);
+          if (!is_valid_end_char (*endp)) goto fail;
+          attr = pango_attr_size_new_absolute (integer);
+          break;
+
+        case PANGO_ATTR_GRAVITY:
+          ENUM_ATTR(gravity, PangoGravity, PANGO_GRAVITY_SOUTH, PANGO_GRAVITY_WEST);
+          break;
+
+        case PANGO_ATTR_FONT_FEATURES:
+          p++;
+          endp = strchr (p, '"');
+          if (!endp) goto fail;
+          str = g_strndup (p, endp - p);
+          attr = pango_attr_font_features_new (str);
+          g_free (str);
+          endp++;
+          if (!is_valid_end_char (*endp)) goto fail;
+          break;
+
+        case PANGO_ATTR_GRAVITY_HINT:
+          ENUM_ATTR(gravity_hint, PangoGravityHint, PANGO_GRAVITY_HINT_NATURAL, PANGO_GRAVITY_HINT_LINE);
+          break;
+
+        case PANGO_ATTR_FOREGROUND_ALPHA:
+          INT_ATTR(foreground_alpha, int);
+          break;
+
+        case PANGO_ATTR_BACKGROUND_ALPHA:
+          INT_ATTR(background_alpha, int);
+          break;
+
+        case PANGO_ATTR_ALLOW_BREAKS:
+          BOOLEAN_ATTR(allow_breaks, gboolean);
+          break;
+
+        case PANGO_ATTR_SHOW:
+          INT_ATTR(show, PangoShowFlags);
+          break;
+
+        case PANGO_ATTR_INSERT_HYPHENS:
+          BOOLEAN_ATTR(insert_hyphens, gboolean);
+          break;
+
+        case PANGO_ATTR_OVERLINE:
+          ENUM_ATTR(overline, PangoOverline, PANGO_OVERLINE_NONE, PANGO_OVERLINE_SINGLE);
+          break;
+
+        case PANGO_ATTR_OVERLINE_COLOR:
+          COLOR_ATTR(overline_color);
+          break;
+
+        case PANGO_ATTR_LINE_HEIGHT:
+          FLOAT_ATTR(line_height);
+          break;
+
+        case PANGO_ATTR_ABSOLUTE_LINE_HEIGHT:
+          integer = g_ascii_strtoll (p, &endp, 10);
+          if (!is_valid_end_char (*endp)) goto fail;
+          attr = pango_attr_line_height_new_absolute (integer);
+          break;
+
+        case PANGO_ATTR_TEXT_TRANSFORM:
+          ENUM_ATTR(text_transform, PangoTextTransform, PANGO_TEXT_TRANSFORM_NONE, 
PANGO_TEXT_TRANSFORM_CAPITALIZE);
+          break;
+
+        case PANGO_ATTR_WORD:
+          integer = g_ascii_strtoll (p, &endp, 10);
+          if (!is_valid_end_char (*endp)) goto fail;
+          attr = pango_attr_word_new ();
+          break;
+
+        case PANGO_ATTR_SENTENCE:
+          integer = g_ascii_strtoll (p, &endp, 10);
+          if (!is_valid_end_char (*endp)) goto fail;
+          attr = pango_attr_sentence_new ();
+          break;
+
+        case PANGO_ATTR_BASELINE_SHIFT:
+          ENUM_ATTR(baseline_shift, PangoBaselineShift, 0, G_MAXINT);
+          break;
+
+        case PANGO_ATTR_FONT_SCALE:
+          ENUM_ATTR(font_scale, PangoFontScale, PANGO_FONT_SCALE_NONE, PANGO_FONT_SCALE_SMALL_CAPS);
+          break;
+
+        default:
+          g_assert_not_reached ();
+        }
+
+      attr->start_index = (guint)start_index;
+      attr->end_index = (guint)end_index;
+      g_ptr_array_add (list->attributes, attr);
+
+      p = endp;
+      if (*p)
+        {
+          if (*p == ',')
+            p++;
+          p += strspn (p, " \n");
+        }
+    }
+
+  goto success;
+
+fail:
+  pango_attr_list_unref (list);
+  list = NULL;
+
+success:
+  return list;
+}
+
+/* }}} */
+
+/* vim:set foldmethod=marker expandtab: */
diff --git a/pango/pango-attr-list.h b/pango/pango-attr-list.h
new file mode 100644
index 00000000..ad1a0fb1
--- /dev/null
+++ b/pango/pango-attr-list.h
@@ -0,0 +1,114 @@
+/* Pango
+ * pango-attr-list.h: Attribute lists
+ *
+ * Copyright (C) 2000 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.
+ */
+
+#pragma once
+
+#include <pango/pango-attributes.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _PangoAttrList     PangoAttrList;
+typedef struct _PangoAttrIterator PangoAttrIterator;
+
+#define PANGO_TYPE_ATTR_LIST pango_attr_list_get_type ()
+
+/**
+ * PangoAttrList:
+ *
+ * A `PangoAttrList` represents a list of attributes that apply to a section
+ * of text.
+ *
+ * The attributes in a `PangoAttrList` are, in general, allowed to overlap in
+ * an arbitrary fashion. However, if the attributes are manipulated only through
+ * [method@Pango.AttrList.change], the overlap between properties will meet
+ * stricter criteria.
+ */
+
+PANGO_AVAILABLE_IN_ALL
+GType                   pango_attr_list_get_type        (void) G_GNUC_CONST;
+
+PANGO_AVAILABLE_IN_ALL
+PangoAttrList *         pango_attr_list_new             (void);
+PANGO_AVAILABLE_IN_1_10
+PangoAttrList *         pango_attr_list_ref             (PangoAttrList         *list);
+PANGO_AVAILABLE_IN_ALL
+void                    pango_attr_list_unref           (PangoAttrList         *list);
+PANGO_AVAILABLE_IN_ALL
+PangoAttrList *         pango_attr_list_copy            (PangoAttrList         *list);
+PANGO_AVAILABLE_IN_ALL
+void                    pango_attr_list_insert          (PangoAttrList         *list,
+                                                         PangoAttribute        *attr);
+PANGO_AVAILABLE_IN_ALL
+void                    pango_attr_list_insert_before   (PangoAttrList         *list,
+                                                         PangoAttribute        *attr);
+PANGO_AVAILABLE_IN_ALL
+void                    pango_attr_list_change          (PangoAttrList         *list,
+                                                         PangoAttribute        *attr);
+PANGO_AVAILABLE_IN_ALL
+void                    pango_attr_list_splice          (PangoAttrList         *list,
+                                                         PangoAttrList         *other,
+                                                         int                    pos,
+                                                         int                    len);
+PANGO_AVAILABLE_IN_1_44
+void                    pango_attr_list_update          (PangoAttrList         *list,
+                                                         int                    pos,
+                                                         int                    remove,
+                                                         int                    add);
+
+/**
+ * PangoAttrFilterFunc:
+ * @attribute: a Pango attribute
+ * @user_data: user data passed to the function
+ *
+ * Type of a function filtering a list of attributes.
+ *
+ * Return value: `TRUE` if the attribute should be selected for
+ *   filtering, `FALSE` otherwise.
+ */
+typedef gboolean (*PangoAttrFilterFunc) (PangoAttribute *attribute,
+                                         gpointer        user_data);
+
+PANGO_AVAILABLE_IN_1_2
+PangoAttrList *         pango_attr_list_filter          (PangoAttrList         *list,
+                                                         PangoAttrFilterFunc    func,
+                                                         gpointer               data);
+
+PANGO_AVAILABLE_IN_1_44
+GSList *                pango_attr_list_get_attributes  (PangoAttrList         *list);
+
+PANGO_AVAILABLE_IN_1_46
+gboolean                pango_attr_list_equal           (PangoAttrList         *list,
+                                                         PangoAttrList         *other_list);
+
+PANGO_AVAILABLE_IN_1_50
+char *                  pango_attr_list_to_string       (PangoAttrList         *list);
+PANGO_AVAILABLE_IN_1_50
+PangoAttrList *         pango_attr_list_from_string     (const char            *text);
+
+PANGO_AVAILABLE_IN_ALL
+PangoAttrIterator *     pango_attr_list_get_iterator    (PangoAttrList         *list);
+
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(PangoAttrList, pango_attr_list_unref)
+
+G_END_DECLS
diff --git a/pango/pango-attr-private.h b/pango/pango-attr-private.h
new file mode 100644
index 00000000..6e068931
--- /dev/null
+++ b/pango/pango-attr-private.h
@@ -0,0 +1,24 @@
+/* Pango
+ * pango-attributes-private.h: Internal structures of PangoLayout
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <pango/pango-attr.h>
+
+char *    pango_attr_value_serialize   (PangoAttribute    *attr);
diff --git a/pango/pango-attr.c b/pango/pango-attr.c
new file mode 100644
index 00000000..0314bdcf
--- /dev/null
+++ b/pango/pango-attr.c
@@ -0,0 +1,540 @@
+/* Pango
+ * pango-attr.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-attr-private.h"
+#include "pango-impl-utils.h"
+
+
+/* {{{ Generic attribute code */
+
+G_LOCK_DEFINE_STATIC (attr_type);
+static GArray *attr_type;
+
+#define MIN_CUSTOM 1000
+
+typedef struct _PangoAttrClass PangoAttrClass;
+
+struct _PangoAttrClass {
+  guint type;
+  const char *name;
+  PangoAttrDataCopyFunc copy;
+  GDestroyNotify destroy;
+  GEqualFunc equal;
+  PangoAttrDataSerializeFunc serialize;
+};
+
+static const char *
+get_attr_type_nick (PangoAttrType type)
+{
+  GEnumClass *enum_class;
+  GEnumValue *enum_value;
+
+  enum_class = g_type_class_ref (pango_attr_type_get_type ());
+  enum_value = g_enum_get_value (enum_class, type);
+  g_type_class_unref (enum_class);
+
+  return enum_value->value_nick;
+}
+
+/**
+ * pango_attr_type_register:
+ * @copy: function to copy the data of an attribute
+ *   of this type
+ * @destroy: function to free the data of an attribute
+ *   of this type
+ * @equal: function to compare the data of two attributes
+ *   of this type
+ * @name: (nullable): an identifier for the type
+ * @serialize: (nullable): function to serialize the data
+ *   of an attribute of this type
+ *
+ * Register a new attribute type.
+ *
+ * The attribute type name can be accessed later
+ * by using [func@Pango.AttrType.get_name].
+ *
+ * If @name and to @serialize are provided, they will be used
+ * to serialize attributes of this type.
+ *
+ * To create attributes with the new type, use [func@Pango.attr_custom_new].
+ *
+ * Return value: the attribute type ID
+ */
+guint
+pango_attr_type_register (PangoAttrDataCopyFunc       copy,
+                          GDestroyNotify              destroy,
+                          GEqualFunc                  equal,
+                          const char                 *name,
+                          PangoAttrDataSerializeFunc  serialize)
+{
+  static guint current_id = MIN_CUSTOM; /* MT-safe */
+  PangoAttrClass class;
+
+  G_LOCK (attr_type);
+
+  class.type = PANGO_ATTR_VALUE_POINTER | (current_id << 8);
+  current_id++;
+
+  class.copy = copy;
+  class.destroy = destroy;
+  class.equal = equal;
+  class.serialize = serialize;
+
+  if (name)
+    class.name = g_intern_string (name);
+
+  if (attr_type == NULL)
+    attr_type = g_array_new (FALSE, FALSE, sizeof (PangoAttrClass));
+
+  g_array_append_val (attr_type, class);
+
+  G_UNLOCK (attr_type);
+
+  return class.type;
+}
+
+/**
+ * pango_attr_type_get_name:
+ * @type: an attribute type ID to fetch the name for
+ *
+ * Fetches the attribute type name.
+ *
+ * The attribute type name is the string passed in
+ * when registering the type using
+ * [func@Pango.AttrType.register].
+ *
+ * The returned value is an interned string (see
+ * g_intern_string() for what that means) that should
+ * not be modified or freed.
+ *
+ * Return value: (nullable): the type ID name (which
+ *   may be %NULL), or %NULL if @type is a built-in Pango
+ *   attribute type or invalid.
+ *
+ * Since: 1.22
+ */
+const char *
+pango_attr_type_get_name (guint type)
+{
+  const char *result = NULL;
+
+  if ((type >> 8) < MIN_CUSTOM)
+    return get_attr_type_nick (type);
+
+  G_LOCK (attr_type);
+
+  for (int i = 0; i < attr_type->len; i++)
+    {
+      PangoAttrClass *class = &g_array_index (attr_type, PangoAttrClass, i);
+      if (class->type == type)
+        {
+          result = class->name;
+          break;
+        }
+    }
+
+  G_UNLOCK (attr_type);
+
+  return result;
+}
+
+/**
+ * pango_attribute_copy:
+ * @attr: a `PangoAttribute`
+ *
+ * Make a copy of an attribute.
+ *
+ * Return value: (transfer full): the newly allocated
+ *   `PangoAttribute`, which should be freed with
+ *   [method@Pango.Attribute.destroy].
+ */
+PangoAttribute *
+pango_attribute_copy (const PangoAttribute *attr)
+{
+  PangoAttribute *result;
+
+  g_return_val_if_fail (attr != NULL, NULL);
+
+  result = g_slice_dup (PangoAttribute, attr);
+
+  switch (PANGO_ATTR_VALUE_TYPE (attr))
+    {
+    case PANGO_ATTR_VALUE_STRING:
+      result->str_value = g_strdup (attr->str_value);
+      break;
+
+    case PANGO_ATTR_VALUE_FONT_DESC:
+      result->font_value = pango_font_description_copy (attr->font_value);
+      break;
+
+    case PANGO_ATTR_VALUE_POINTER:
+      {
+        PangoAttrDataCopyFunc copy = NULL;
+
+        G_LOCK (attr_type);
+
+        g_assert (attr_type != NULL);
+
+        for (int i = 0; i < attr_type->len; i++)
+          {
+            PangoAttrClass *class = &g_array_index (attr_type, PangoAttrClass, i);
+            if (class->type == attr->type)
+              {
+                copy = class->copy;
+                break;
+              }
+          }
+
+        G_UNLOCK (attr_type);
+
+        g_assert (copy != NULL);
+
+        result->pointer_value = copy (attr->pointer_value);
+      }
+      break;
+
+    case PANGO_ATTR_VALUE_INT:
+    case PANGO_ATTR_VALUE_BOOLEAN:
+    case PANGO_ATTR_VALUE_FLOAT:
+    case PANGO_ATTR_VALUE_COLOR:
+    case PANGO_ATTR_VALUE_LANGUAGE:
+    default: ;
+    }
+
+  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);
+
+  switch (PANGO_ATTR_VALUE_TYPE (attr))
+    {
+    case PANGO_ATTR_VALUE_STRING:
+      g_free (attr->str_value);
+      break;
+
+    case PANGO_ATTR_VALUE_FONT_DESC:
+      pango_font_description_free (attr->font_value);
+      break;
+
+    case PANGO_ATTR_VALUE_POINTER:
+      {
+        GDestroyNotify destroy = NULL;
+
+        G_LOCK (attr_type);
+
+        g_assert (attr_type != NULL);
+
+        for (int i = 0; i < attr_type->len; i++)
+          {
+            PangoAttrClass *class = &g_array_index (attr_type, PangoAttrClass, i);
+            if (class->type == attr->type)
+              {
+                destroy = class->destroy;
+                break;
+              }
+          }
+
+        G_UNLOCK (attr_type);
+
+        g_assert (destroy != NULL);
+
+        destroy (attr->pointer_value);
+      }
+      break;
+
+    case PANGO_ATTR_VALUE_INT:
+    case PANGO_ATTR_VALUE_BOOLEAN:
+    case PANGO_ATTR_VALUE_FLOAT:
+    case PANGO_ATTR_VALUE_COLOR:
+    case PANGO_ATTR_VALUE_LANGUAGE:
+    default: ;
+    }
+
+  g_slice_free (PangoAttribute, attr);
+}
+
+G_DEFINE_BOXED_TYPE (PangoAttribute, pango_attribute,
+                     pango_attribute_copy,
+                     pango_attribute_destroy);
+
+/**
+ * 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->type != attr2->type)
+    return FALSE;
+
+  switch (PANGO_ATTR_VALUE_TYPE (attr1))
+    {
+    case PANGO_ATTR_VALUE_STRING:
+      return strcmp (attr1->str_value, attr2->str_value) == 0;
+
+    case PANGO_ATTR_VALUE_INT:
+      return attr1->int_value == attr2->int_value;
+
+    case PANGO_ATTR_VALUE_BOOLEAN:
+      return attr1->boolean_value == attr2->boolean_value;
+
+    case PANGO_ATTR_VALUE_FLOAT:
+      return attr1->double_value == attr2->double_value;
+
+    case PANGO_ATTR_VALUE_COLOR:
+      return memcmp (&attr1->color_value, &attr2->color_value, sizeof (PangoColor)) == 0;
+
+    case PANGO_ATTR_VALUE_LANGUAGE:
+      return attr1->lang_value == attr2->lang_value;
+
+    case PANGO_ATTR_VALUE_FONT_DESC:
+      return pango_font_description_equal (attr1->font_value, attr2->font_value);
+
+    case PANGO_ATTR_VALUE_POINTER:
+      {
+        GEqualFunc equal = NULL;
+
+        G_LOCK (attr_type);
+
+        g_assert (attr_type != NULL);
+
+        for (int i = 0; i < attr_type->len; i++)
+          {
+            PangoAttrClass *class = &g_array_index (attr_type, PangoAttrClass, i);
+            if (class->type == attr1->type)
+              {
+                equal = class->equal;
+                break;
+              }
+          }
+
+        G_UNLOCK (attr_type);
+
+        g_assert (equal != NULL);
+
+        return equal (attr1->pointer_value, attr2->pointer_value);
+      }
+
+    default:
+      g_assert_not_reached ();
+    }
+}
+
+/**
+ * pango_attr_custom_new:
+ * @type: the attribute type
+ * @user_data: data for the attribute
+ *
+ * Creates a new attribute for the given type.
+ *
+ * The type must have been registered with [func@Pango.register_attr_type]
+ * before. @user_data will be copied with the copy function that
+ * was given when the type was registered.
+ *
+ * Return value: (transfer full): the newly allocated
+ *   `PangoAttribute`, which should be freed with
+ *   [method@Pango.Attribute.destroy]
+ */
+PangoAttribute *
+pango_attr_custom_new (guint    type,
+                       gpointer user_data)
+{
+  PangoAttribute *attr;
+  PangoAttrDataCopyFunc copy = NULL;
+
+  g_return_val_if_fail (PANGO_ATTR_TYPE_VALUE_TYPE (type) == PANGO_ATTR_VALUE_POINTER, NULL);
+
+  G_LOCK (attr_type);
+
+  g_assert (attr_type != NULL);
+
+  for (int i = 0; i < attr_type->len; i++)
+    {
+      PangoAttrClass *class = &g_array_index (attr_type, PangoAttrClass, i);
+      if (class->type == type)
+        {
+          copy = class->copy;
+          break;
+        }
+    }
+
+  g_assert (copy != NULL);
+
+  G_UNLOCK (attr_type);
+
+  attr = g_slice_new (PangoAttribute);
+  attr->type = type;
+  attr->start_index = PANGO_ATTR_INDEX_FROM_TEXT_BEGINNING;
+  attr->end_index = PANGO_ATTR_INDEX_TO_TEXT_END;
+  attr->pointer_value = copy (user_data);
+
+  return attr;
+}
+
+/* }}} */
+/* {{{ Private API */
+
+char *
+pango_attr_value_serialize (PangoAttribute *attr)
+{
+  PangoAttrDataSerializeFunc serialize = NULL;
+
+  G_LOCK (attr_type);
+
+  g_assert (attr_type != NULL);
+
+  for (int i = 0; i < attr_type->len; i++)
+    {
+      PangoAttrClass *class = &g_array_index (attr_type, PangoAttrClass, i);
+      if (class->type == attr->type)
+        {
+          serialize = class->serialize;
+          break;
+        }
+    }
+
+  G_UNLOCK (attr_type);
+
+  if (serialize)
+    return serialize (attr->pointer_value);
+
+  return NULL;
+}
+
+/* }}} */
+/* {{{ Binding Helpers */
+
+gboolean
+pango_attribute_get_string (PangoAttribute   *attribute,
+                            const char      **value)
+{
+  if (PANGO_ATTR_VALUE_TYPE (attribute) != PANGO_ATTR_VALUE_STRING)
+    return FALSE;
+
+  *value = attribute->str_value;
+  return TRUE;
+}
+
+gboolean
+pango_attribute_get_language (PangoAttribute  *attribute,
+                              PangoLanguage  **value)
+{
+  if (PANGO_ATTR_VALUE_TYPE (attribute) != PANGO_ATTR_VALUE_LANGUAGE)
+    return FALSE;
+
+  *value = attribute->lang_value;
+  return TRUE;
+}
+
+gboolean
+pango_attribute_get_int (PangoAttribute *attribute,
+                         int            *value)
+{
+  if (PANGO_ATTR_VALUE_TYPE (attribute) != PANGO_ATTR_VALUE_INT)
+    return FALSE;
+
+  *value = attribute->int_value;
+  return TRUE;
+}
+
+gboolean
+pango_attribute_get_boolean (PangoAttribute *attribute,
+                             int            *value)
+{
+  if (PANGO_ATTR_VALUE_TYPE (attribute) != PANGO_ATTR_VALUE_BOOLEAN)
+    return FALSE;
+
+  *value = attribute->boolean_value;
+  return TRUE;
+}
+
+gboolean
+pango_attribute_get_float (PangoAttribute *attribute,
+                           double         *value)
+{
+  if (PANGO_ATTR_VALUE_TYPE (attribute) != PANGO_ATTR_VALUE_FLOAT)
+    return FALSE;
+
+  *value = attribute->double_value;
+  return TRUE;
+}
+
+gboolean
+pango_attribute_get_color (PangoAttribute *attribute,
+                           PangoColor     *value)
+{
+  if (PANGO_ATTR_VALUE_TYPE (attribute) != PANGO_ATTR_VALUE_COLOR)
+    return FALSE;
+
+  *value = attribute->color_value;
+  return TRUE;
+}
+
+gboolean
+pango_attribute_get_font_desc (PangoAttribute        *attribute,
+                               PangoFontDescription **value)
+{
+  if (PANGO_ATTR_VALUE_TYPE (attribute) != PANGO_ATTR_VALUE_FONT_DESC)
+    return FALSE;
+
+  *value = attribute->font_value;
+  return TRUE;
+}
+
+gboolean
+pango_attribute_get_custom (PangoAttribute *attribute,
+                            gpointer       *value)
+{
+  if (PANGO_ATTR_VALUE_TYPE (attribute) != PANGO_ATTR_VALUE_POINTER)
+    return FALSE;
+
+  *value = attribute->pointer_value;
+  return TRUE;
+}
+
+/* }}} */
+
+/* vim:set foldmethod=marker expandtab: */
diff --git a/pango/pango-attr.h b/pango/pango-attr.h
new file mode 100644
index 00000000..53d4536e
--- /dev/null
+++ b/pango/pango-attr.h
@@ -0,0 +1,214 @@
+/* Pango
+ * pango-attributes.h: Attributed text
+ *
+ * Copyright (C) 2000 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.
+ */
+
+#pragma once
+
+#include <pango/pango-font.h>
+#include <pango/pango-color.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _PangoAttribute PangoAttribute;
+
+/**
+ * PangoAttrValueType:
+ * @PANGO_ATTR_VALUE_STRING: a string
+ * @PANGO_ATTR_VALUE_INT: an integer
+ * @PANGO_ATTR_VALUE_BOOLEAN: a boolean
+ * @PANGO_ATTR_VALUE_FLOAT: a floating point number
+ * @PANGO_ATTR_VALUE_COLOR: a `PangoColor`
+ * @PANGO_ATTR_VALUE_LANGUAGE: a `PangoLanguage`
+ * @PANGO_ATTR_VALUE_FONT_DESC: a `PangoFontDescription`
+ * @PANGO_ATTR_VALUE_POINTER: a generic pointer
+ *
+ * The `PangoAttrValueType` enumeration describes the various types
+ * of values that a `PangoAttribute` can contain.
+ *
+ * The `PangoAttrValueType` of a `PangoAttribute` is part of its type,
+ * and can be obtained with `PANGO_ATTR_VALUE_TYPE()`.
+ */
+typedef enum
+{
+  PANGO_ATTR_VALUE_STRING,
+  PANGO_ATTR_VALUE_INT,
+  PANGO_ATTR_VALUE_BOOLEAN,
+  PANGO_ATTR_VALUE_FLOAT,
+  PANGO_ATTR_VALUE_COLOR,
+  PANGO_ATTR_VALUE_LANGUAGE,
+  PANGO_ATTR_VALUE_FONT_DESC,
+  PANGO_ATTR_VALUE_POINTER
+} PangoAttrValueType;
+
+/**
+ * PANGO_ATTR_TYPE_VALUE_TYPE:
+ * @type: an attribute type
+ *
+ * Extracts the `PangoAttrValueType` from an attribute type.
+ */
+#define PANGO_ATTR_TYPE_VALUE_TYPE(type) ((PangoAttrValueType)((type) & 0xff))
+
+/**
+ * PANGO_ATTR_VALUE_TYPE:
+ * @attr: a `PangoAttribute`
+ *
+ * Obtains the `PangoAttrValueType of a `PangoAttribute`.
+ */
+#define PANGO_ATTR_VALUE_TYPE(attr) PANGO_ATTR_TYPE_VALUE_TYPE ((attr)->type)
+
+/**
+ * PANGO_ATTR_INDEX_FROM_TEXT_BEGINNING:
+ *
+ * Value for @start_index in `PangoAttribute` that indicates
+ * the beginning of the text.
+ *
+ * Since: 1.24
+ */
+#define PANGO_ATTR_INDEX_FROM_TEXT_BEGINNING ((guint)0)
+
+/**
+ * PANGO_ATTR_INDEX_TO_TEXT_END: (value 4294967295)
+ *
+ * Value for @end_index in `PangoAttribute` that indicates
+ * the end of the text.
+ *
+ * Since: 1.24
+ */
+#define PANGO_ATTR_INDEX_TO_TEXT_END ((guint)(G_MAXUINT + 0))
+
+/**
+ * PangoAttribute:
+ * @klass: the class structure holding information about the type of the attribute
+ * @start_index: the start index of the range (in bytes).
+ * @end_index: end index of the range (in bytes). The character at this index
+ *   is not included in the range.
+ * @str_value: the string value
+ * @int_value: the integer value
+ * @boolean_value: the boolean value
+ * @double_value: the double value
+ * @color_value: the `PangoColor` value
+ * @lang_value: the `PangoLanguage` value
+ * @font_value: the `PangoFontDescription` value
+ * @pointer_value: a custom value
+ *
+ * The `PangoAttribute` structure contains information for a single
+ * attribute.
+ *
+ * The common portion of the attribute holds the range to which
+ * the value in the type-specific part of the attribute applies.
+ * By default, an attribute will have an all-inclusive range of
+ * [0,%G_MAXUINT].
+ *
+ * Which of the values is used depends on the value type of the
+ * attribute, which can be obtained with `PANGO_ATTR_VALUE_TYPE()`.
+ */
+struct _PangoAttribute
+{
+  guint type;
+  guint start_index;
+  guint end_index;
+  union {
+    char *str_value;
+    int  int_value;
+    gboolean boolean_value;
+    double double_value;
+    PangoColor color_value;
+    PangoLanguage *lang_value;
+    PangoFontDescription *font_value;
+    gpointer pointer_value;
+  };
+};
+
+/**
+ * PangoAttrDataCopyFunc:
+ * @value: value to copy
+ *
+ * Type of a function that can duplicate the value of an attribute.
+ *
+ * Return value: new copy of @value.
+ **/
+typedef gpointer (*PangoAttrDataCopyFunc) (gconstpointer value);
+
+/**
+ * PangoAttrDataSerializeFunc:
+ * @value: value to serialize
+ *
+ * Type of a function that can serialize the value of an attribute.
+ *
+ * Return value: a newly allocated string holding the serialization of @value
+ */
+typedef char * (*PangoAttrDataSerializeFunc) (gconstpointer value);
+
+PANGO_AVAILABLE_IN_ALL
+GType                   pango_attribute_get_type                (void) G_GNUC_CONST;
+
+PANGO_AVAILABLE_IN_ALL
+guint                   pango_attr_type_register                (PangoAttrDataCopyFunc       copy,
+                                                                 GDestroyNotify              destroy,
+                                                                 GEqualFunc                  equal,
+                                                                 const char                 *name,
+                                                                 PangoAttrDataSerializeFunc  serialize);
+
+PANGO_AVAILABLE_IN_1_22
+const char *            pango_attr_type_get_name                (guint                       type) 
G_GNUC_CONST;
+PANGO_AVAILABLE_IN_ALL
+PangoAttribute *        pango_attribute_copy                    (const PangoAttribute       *attr);
+PANGO_AVAILABLE_IN_ALL
+void                    pango_attribute_destroy                 (PangoAttribute             *attr);
+PANGO_AVAILABLE_IN_ALL
+gboolean                pango_attribute_equal                   (const PangoAttribute       *attr1,
+                                                                 const PangoAttribute       *attr2) 
G_GNUC_PURE;
+
+PANGO_AVAILABLE_IN_ALL
+PangoAttribute *        pango_attr_custom_new                   (guint                       type,
+                                                                 gpointer                     user_data);
+
+PANGO_AVAILABLE_IN_ALL
+gboolean                pango_attribute_get_string              (PangoAttribute              *attribute,
+                                                                 const char                 **value);
+PANGO_AVAILABLE_IN_ALL
+gboolean                pango_attribute_get_language            (PangoAttribute              *attribute,
+                                                                 PangoLanguage              **value);
+PANGO_AVAILABLE_IN_ALL
+gboolean                pango_attribute_get_int                 (PangoAttribute              *attribute,
+                                                                 int                         *value);
+PANGO_AVAILABLE_IN_ALL
+gboolean                pango_attribute_get_boolean             (PangoAttribute              *attribute,
+                                                                 gboolean                    *value);
+PANGO_AVAILABLE_IN_ALL
+gboolean                pango_attribute_get_float               (PangoAttribute              *attribute,
+                                                                 double                      *value);
+PANGO_AVAILABLE_IN_ALL
+gboolean                pango_attribute_get_color               (PangoAttribute              *attribute,
+                                                                 PangoColor                  *value);
+PANGO_AVAILABLE_IN_ALL
+gboolean                pango_attribute_get_font_desc           (PangoAttribute              *attribute,
+                                                                 PangoFontDescription       **value);
+
+PANGO_AVAILABLE_IN_ALL
+gboolean                pango_attribute_get_custom              (PangoAttribute              *attribute,
+                                                                 gpointer                    *value);
+
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(PangoAttribute, pango_attribute_destroy)
+
+G_END_DECLS
diff --git a/pango/pango-attributes-private.h b/pango/pango-attributes-private.h
index c52cd4da..8301b86d 100644
--- a/pango/pango-attributes-private.h
+++ b/pango/pango-attributes-private.h
@@ -1,60 +1,13 @@
-/* Pango
- * pango-attributes-private.h: Internal structures of PangoLayout
- *
- * 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.
- */
+#pragma once
 
-#ifndef __PANGO_ATTRIBUTES_PRIVATE_H__
-#define __PANGO_ATTRIBUTES_PRIVATE_H__
-
-struct _PangoAttrIterator
-{
-  GPtrArray *attrs; /* From the list */
-  guint n_attrs; /* Copied from the list */
-
-  GPtrArray *attribute_stack;
-
-  guint attr_index;
-  guint start_index;
-  guint end_index;
-};
-
-struct _PangoAttrList
-{
-  guint ref_count;
-  GPtrArray *attributes;
-};
-
-char *    pango_attr_value_serialize   (PangoAttribute    *attr);
-void     _pango_attr_list_init         (PangoAttrList     *list);
-void     _pango_attr_list_destroy      (PangoAttrList     *list);
-gboolean _pango_attr_list_has_attributes (const PangoAttrList *list);
-
-void     _pango_attr_list_get_iterator (PangoAttrList     *list,
-                                        PangoAttrIterator *iterator);
-
-void     _pango_attr_iterator_destroy  (PangoAttrIterator *iterator);
-gboolean  pango_attr_iterator_advance  (PangoAttrIterator *iterator,
-                                        int                index);
+#include "pango-attributes.h"
 
+G_BEGIN_DECLS
 
 gboolean pango_attribute_affects_itemization    (PangoAttribute *attr,
                                                  gpointer        data);
 gboolean pango_attribute_affects_break_or_shape (PangoAttribute *attr,
                                                  gpointer        data);
 
-#endif
 
+G_END_DECLS
diff --git a/pango/pango-attributes.c b/pango/pango-attributes.c
index 54a8978a..ee46829a 100644
--- a/pango/pango-attributes.c
+++ b/pango/pango-attributes.c
@@ -22,347 +22,11 @@
 #include "config.h"
 #include <string.h>
 
-#include "pango-attributes.h"
 #include "pango-attributes-private.h"
+#include "pango-attr-private.h"
 #include "pango-impl-utils.h"
 
-
-/* {{{ Generic attribute code */
-
-G_LOCK_DEFINE_STATIC (attr_type);
-static GArray *attr_type;
-
-#define MIN_CUSTOM 1000
-
-typedef struct _PangoAttrClass PangoAttrClass;
-
-struct _PangoAttrClass {
-  PangoAttrType type;
-  const char *name;
-  PangoAttrDataCopyFunc copy;
-  GDestroyNotify destroy;
-  GEqualFunc equal;
-  PangoAttrDataSerializeFunc serialize;
-};
-
-static const char *
-get_attr_type_nick (PangoAttrType type)
-{
-  GEnumClass *enum_class;
-  GEnumValue *enum_value;
-
-  enum_class = g_type_class_ref (pango_attr_type_get_type ());
-  enum_value = g_enum_get_value (enum_class, type);
-  g_type_class_unref (enum_class);
-
-  return enum_value->value_nick;
-}
-
-/**
- * pango_attr_type_register:
- * @copy: function to copy the data of an attribute
- *   of this type
- * @destroy: function to free the data of an attribute
- *   of this type
- * @equal: function to compare the data of two attributes
- *   of this type
- * @name: (nullable): an identifier for the type
- * @serialize: (nullable): function to serialize the data
- *   of an attribute of this type
- *
- * Allocate a new attribute type ID.
- *
- * The attribute type name can be accessed later
- * by using [func@Pango.AttrType.get_name].
- *
- * If @name and to @serialize are provided, they will be used
- * to serialize attributes of this type.
- *
- * Return value: the new type ID.
- */
-PangoAttrType
-pango_attr_type_register (PangoAttrDataCopyFunc       copy,
-                          GDestroyNotify              destroy,
-                          GEqualFunc                  equal,
-                          const char                 *name,
-                          PangoAttrDataSerializeFunc  serialize)
-{
-  static guint current_id = MIN_CUSTOM; /* MT-safe */
-  PangoAttrClass class;
-
-  G_LOCK (attr_type);
-
-  class.type = PANGO_ATTR_VALUE_POINTER | (current_id << 8);
-  current_id++;
-
-  class.copy = copy;
-  class.destroy = destroy;
-  class.equal = equal;
-  class.serialize = serialize;
-
-  if (name)
-    class.name = g_intern_string (name);
-
-  if (attr_type == NULL)
-    attr_type = g_array_new (FALSE, FALSE, sizeof (PangoAttrClass));
-
-  g_array_append_val (attr_type, class);
-
-  G_UNLOCK (attr_type);
-
-  return class.type;
-}
-
-/**
- * pango_attr_type_get_name:
- * @type: an attribute type ID to fetch the name for
- *
- * Fetches the attribute type name.
- *
- * The attribute type name is the string passed in
- * when registering the type using
- * [func@Pango.AttrType.register].
- *
- * The returned value is an interned string (see
- * g_intern_string() for what that means) that should
- * not be modified or freed.
- *
- * Return value: (nullable): the type ID name (which
- *   may be %NULL), or %NULL if @type is a built-in Pango
- *   attribute type or invalid.
- *
- * Since: 1.22
- */
-const char *
-pango_attr_type_get_name (PangoAttrType type)
-{
-  const char *result = NULL;
-
-  if ((type >> 8) < MIN_CUSTOM)
-    return get_attr_type_nick (type);
-
-  G_LOCK (attr_type);
-
-  for (int i = 0; i < attr_type->len; i++)
-    {
-      PangoAttrClass *class = &g_array_index (attr_type, PangoAttrClass, i);
-      if (class->type == type)
-        {
-          result = class->name;
-          break;
-        }
-    }
-
-  G_UNLOCK (attr_type);
-
-  return result;
-}
-
-/**
- * pango_attribute_copy:
- * @attr: a `PangoAttribute`
- *
- * Make a copy of an attribute.
- *
- * Return value: (transfer full): the newly allocated
- *   `PangoAttribute`, which should be freed with
- *   [method@Pango.Attribute.destroy].
- */
-PangoAttribute *
-pango_attribute_copy (const PangoAttribute *attr)
-{
-  PangoAttribute *result;
-
-  g_return_val_if_fail (attr != NULL, NULL);
-
-  result = g_slice_dup (PangoAttribute, attr);
-
-  switch (PANGO_ATTR_VALUE_TYPE (attr))
-    {
-    case PANGO_ATTR_VALUE_STRING:
-      result->str_value = g_strdup (attr->str_value);
-      break;
-
-    case PANGO_ATTR_VALUE_FONT_DESC:
-      result->font_value = pango_font_description_copy (attr->font_value);
-      break;
-
-    case PANGO_ATTR_VALUE_POINTER:
-      {
-        PangoAttrDataCopyFunc copy = NULL;
-
-        G_LOCK (attr_type);
-
-        g_assert (attr_type != NULL);
-
-        for (int i = 0; i < attr_type->len; i++)
-          {
-            PangoAttrClass *class = &g_array_index (attr_type, PangoAttrClass, i);
-            if (class->type == attr->type)
-              {
-                copy = class->copy;
-                break;
-              }
-          }
-
-        G_UNLOCK (attr_type);
-
-        g_assert (copy != NULL);
-
-        result->pointer_value = copy (attr->pointer_value);
-      }
-      break;
-
-    case PANGO_ATTR_VALUE_INT:
-    case PANGO_ATTR_VALUE_BOOLEAN:
-    case PANGO_ATTR_VALUE_FLOAT:
-    case PANGO_ATTR_VALUE_COLOR:
-    case PANGO_ATTR_VALUE_LANGUAGE:
-    default: ;
-    }
-
-  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);
-
-  switch (PANGO_ATTR_VALUE_TYPE (attr))
-    {
-    case PANGO_ATTR_VALUE_STRING:
-      g_free (attr->str_value);
-      break;
-
-    case PANGO_ATTR_VALUE_FONT_DESC:
-      pango_font_description_free (attr->font_value);
-      break;
-
-    case PANGO_ATTR_VALUE_POINTER:
-      {
-        GDestroyNotify destroy = NULL;
-
-        G_LOCK (attr_type);
-
-        g_assert (attr_type != NULL);
-
-        for (int i = 0; i < attr_type->len; i++)
-          {
-            PangoAttrClass *class = &g_array_index (attr_type, PangoAttrClass, i);
-            if (class->type == attr->type)
-              {
-                destroy = class->destroy;
-                break;
-              }
-          }
-
-        G_UNLOCK (attr_type);
-
-        g_assert (destroy != NULL);
-
-        destroy (attr->pointer_value);
-      }
-      break;
-
-    case PANGO_ATTR_VALUE_INT:
-    case PANGO_ATTR_VALUE_BOOLEAN:
-    case PANGO_ATTR_VALUE_FLOAT:
-    case PANGO_ATTR_VALUE_COLOR:
-    case PANGO_ATTR_VALUE_LANGUAGE:
-    default: ;
-    }
-
-  g_slice_free (PangoAttribute, attr);
-}
-
-G_DEFINE_BOXED_TYPE (PangoAttribute, pango_attribute,
-                     pango_attribute_copy,
-                     pango_attribute_destroy);
-
-/**
- * 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->type != attr2->type)
-    return FALSE;
-
-  switch (PANGO_ATTR_VALUE_TYPE (attr1))
-    {
-    case PANGO_ATTR_VALUE_STRING:
-      return strcmp (attr1->str_value, attr2->str_value) == 0;
-
-    case PANGO_ATTR_VALUE_INT:
-      return attr1->int_value == attr2->int_value;
-
-    case PANGO_ATTR_VALUE_BOOLEAN:
-      return attr1->boolean_value == attr2->boolean_value;
-
-    case PANGO_ATTR_VALUE_FLOAT:
-      return attr1->double_value == attr2->double_value;
-
-    case PANGO_ATTR_VALUE_COLOR:
-      return memcmp (&attr1->color_value, &attr2->color_value, sizeof (PangoColor)) == 0;
-
-    case PANGO_ATTR_VALUE_LANGUAGE:
-      return attr1->lang_value == attr2->lang_value;
-
-    case PANGO_ATTR_VALUE_FONT_DESC:
-      return pango_font_description_equal (attr1->font_value, attr2->font_value);
-
-    case PANGO_ATTR_VALUE_POINTER:
-      {
-        GEqualFunc equal = NULL;
-
-        G_LOCK (attr_type);
-
-        g_assert (attr_type != NULL);
-
-        for (int i = 0; i < attr_type->len; i++)
-          {
-            PangoAttrClass *class = &g_array_index (attr_type, PangoAttrClass, i);
-            if (class->type == attr1->type)
-              {
-                equal = class->equal;
-                break;
-              }
-          }
-
-        G_UNLOCK (attr_type);
-
-        g_assert (equal != NULL);
-
-        return equal (attr1->pointer_value, attr2->pointer_value);
-      }
-
-    default:
-      g_assert_not_reached ();
-    }
-}
-
-/* {{{ Builtin Attribute value types */
+/* {{{ Attribute value types */
 
 static inline PangoAttribute *
 pango_attr_init (PangoAttrType type)
@@ -377,7 +41,7 @@ pango_attr_init (PangoAttrType type)
   return attr;
 }
 
-static PangoAttribute *
+static inline PangoAttribute *
 pango_attr_string_new (PangoAttrType  type,
                        const char    *value)
 {
@@ -391,7 +55,7 @@ pango_attr_string_new (PangoAttrType  type,
   return attr;
 }
 
-static PangoAttribute *
+static inline PangoAttribute *
 pango_attr_int_new (PangoAttrType type,
                     int           value)
 {
@@ -405,7 +69,7 @@ pango_attr_int_new (PangoAttrType type,
   return attr;
 }
 
-static PangoAttribute *
+static inline PangoAttribute *
 pango_attr_boolean_new (PangoAttrType type,
                         gboolean      value)
 {
@@ -419,7 +83,7 @@ pango_attr_boolean_new (PangoAttrType type,
   return attr;
 }
 
-static PangoAttribute *
+static inline PangoAttribute *
 pango_attr_float_new (PangoAttrType type,
                       double        value)
 {
@@ -433,7 +97,7 @@ pango_attr_float_new (PangoAttrType type,
   return attr;
 }
 
-static PangoAttribute *
+static inline PangoAttribute *
 pango_attr_color_new (PangoAttrType type,
                       guint16       red,
                       guint16       green,
@@ -451,7 +115,7 @@ pango_attr_color_new (PangoAttrType type,
   return attr;
 }
 
-static PangoAttribute *
+static inline PangoAttribute *
 pango_attr_lang_new (PangoAttrType  type,
                      PangoLanguage *value)
 {
@@ -465,7 +129,7 @@ pango_attr_lang_new (PangoAttrType  type,
   return attr;
 }
 
-static PangoAttribute *
+static inline PangoAttribute *
 pango_attr_font_description_new (PangoAttrType               type,
                                  const PangoFontDescription *value)
 {
@@ -478,97 +142,9 @@ pango_attr_font_description_new (PangoAttrType               type,
 
   return attr;
 }
-/* }}} */
-/* }}} */
-/* {{{ Private API */
-
-char *
-pango_attr_value_serialize (PangoAttribute *attr)
-{
-  PangoAttrDataSerializeFunc serialize = NULL;
-
-  G_LOCK (attr_type);
-
-  g_assert (attr_type != NULL);
-
-  for (int i = 0; i < attr_type->len; i++)
-    {
-      PangoAttrClass *class = &g_array_index (attr_type, PangoAttrClass, i);
-      if (class->type == attr->type)
-        {
-          serialize = class->serialize;
-          break;
-        }
-    }
-
-  G_UNLOCK (attr_type);
-
-  if (serialize)
-    return serialize (attr->pointer_value);
-
-  return NULL;
-}
-
-/* }}} */
-/* {{{ Private API */
-
-gboolean
-pango_attribute_affects_itemization (PangoAttribute *attr,
-                                     gpointer        data)
-{
-  switch ((int)attr->type)
-    {
-    /* These affect font selection */
-    case PANGO_ATTR_LANGUAGE:
-    case PANGO_ATTR_FAMILY:
-    case PANGO_ATTR_STYLE:
-    case PANGO_ATTR_WEIGHT:
-    case PANGO_ATTR_VARIANT:
-    case PANGO_ATTR_STRETCH:
-    case PANGO_ATTR_SIZE:
-    case PANGO_ATTR_FONT_DESC:
-    case PANGO_ATTR_SCALE:
-    case PANGO_ATTR_FALLBACK:
-    case PANGO_ATTR_ABSOLUTE_SIZE:
-    case PANGO_ATTR_GRAVITY:
-    case PANGO_ATTR_GRAVITY_HINT:
-    case PANGO_ATTR_FONT_SCALE:
-    /* These need to be constant across runs */
-    case PANGO_ATTR_LETTER_SPACING:
-    case PANGO_ATTR_RISE:
-    case PANGO_ATTR_BASELINE_SHIFT:
-    case PANGO_ATTR_LINE_HEIGHT:
-    case PANGO_ATTR_ABSOLUTE_LINE_HEIGHT:
-    case PANGO_ATTR_TEXT_TRANSFORM:
-      return TRUE;
-    default:
-      return FALSE;
-    }
-}
-
-gboolean
-pango_attribute_affects_break_or_shape (PangoAttribute *attr,
-                                        gpointer        data)
-{
-  switch ((int)attr->type)
-    {
-    /* Affects breaks */
-    case PANGO_ATTR_ALLOW_BREAKS:
-    case PANGO_ATTR_WORD:
-    case PANGO_ATTR_SENTENCE:
-    case PANGO_ATTR_PARAGRAPH:
-    /* Affects shaping */
-    case PANGO_ATTR_INSERT_HYPHENS:
-    case PANGO_ATTR_FONT_FEATURES:
-    case PANGO_ATTR_SHOW:
-      return TRUE;
-    default:
-      return FALSE;
-    }
-}
 
 /* }}} */
-/* {{{ Public API */
+/* {{{ Attribute types */
 
 /**
  * pango_attr_family_new:
@@ -1305,1893 +881,64 @@ pango_attr_text_transform_new (PangoTextTransform transform)
   return pango_attr_int_new (PANGO_ATTR_TEXT_TRANSFORM, transform);
 }
 
-/**
- * pango_attr_custom_new:
- * @type: the attribute type
- * @user_data: data for the attribute
- *
- * Creates a new attribute for the given type.
- *
- * The type must have been registered with [func@Pango.register_attr_type]
- * before. @user_data will be copied with the copy function that
- * was given when the type was registered.
- *
- * Return value: (transfer full): the newly allocated
- *   `PangoAttribute`, which should be freed with
- *   [method@Pango.Attribute.destroy]
- */
-PangoAttribute *
-pango_attr_custom_new (PangoAttrType type,
-                       gpointer      user_data)
-{
-  PangoAttrClass *class = NULL;
-  PangoAttribute *attr;
-
-  g_return_val_if_fail (PANGO_ATTR_TYPE_VALUE_TYPE (type) == PANGO_ATTR_VALUE_POINTER, NULL);
-
-  G_LOCK (attr_type);
-
-  g_assert (attr_type != NULL);
-
-  for (int i = 0; i < attr_type->len; i++)
-    {
-      PangoAttrClass *c = &g_array_index (attr_type, PangoAttrClass, i);
-      if (c->type == type)
-        {
-          class = c;
-          break;
-        }
-    }
-
-  g_assert (class != NULL);
-
-  G_UNLOCK (attr_type);
-
-  attr = pango_attr_init (type);
-  attr->pointer_value = class->copy (user_data);
-
-  return attr;
-}
-
 /* }}} */
-/* {{{ Binding Helpers */
-
-gboolean
-pango_attribute_get_string (PangoAttribute   *attribute,
-                            const char      **value)
-{
-  if (PANGO_ATTR_VALUE_TYPE (attribute) != PANGO_ATTR_VALUE_STRING)
-    return FALSE;
-
-  *value = attribute->str_value;
-  return TRUE;
-}
+/* {{{ Private API */
 
 gboolean
-pango_attribute_get_language (PangoAttribute  *attribute,
-                              PangoLanguage  **value)
+pango_attribute_affects_itemization (PangoAttribute *attr,
+                                     gpointer        data)
 {
-  if (PANGO_ATTR_VALUE_TYPE (attribute) != PANGO_ATTR_VALUE_LANGUAGE)
-    return FALSE;
-
-  *value = attribute->lang_value;
-  return TRUE;
+  switch ((int)attr->type)
+    {
+    /* These affect font selection */
+    case PANGO_ATTR_LANGUAGE:
+    case PANGO_ATTR_FAMILY:
+    case PANGO_ATTR_STYLE:
+    case PANGO_ATTR_WEIGHT:
+    case PANGO_ATTR_VARIANT:
+    case PANGO_ATTR_STRETCH:
+    case PANGO_ATTR_SIZE:
+    case PANGO_ATTR_FONT_DESC:
+    case PANGO_ATTR_SCALE:
+    case PANGO_ATTR_FALLBACK:
+    case PANGO_ATTR_ABSOLUTE_SIZE:
+    case PANGO_ATTR_GRAVITY:
+    case PANGO_ATTR_GRAVITY_HINT:
+    case PANGO_ATTR_FONT_SCALE:
+    /* These need to be constant across runs */
+    case PANGO_ATTR_LETTER_SPACING:
+    case PANGO_ATTR_RISE:
+    case PANGO_ATTR_BASELINE_SHIFT:
+    case PANGO_ATTR_LINE_HEIGHT:
+    case PANGO_ATTR_ABSOLUTE_LINE_HEIGHT:
+    case PANGO_ATTR_TEXT_TRANSFORM:
+      return TRUE;
+    default:
+      return FALSE;
+    }
 }
 
 gboolean
-pango_attribute_get_int (PangoAttribute *attribute,
-                         int            *value)
+pango_attribute_affects_break_or_shape (PangoAttribute *attr,
+                                        gpointer        data)
 {
-  if (PANGO_ATTR_VALUE_TYPE (attribute) != PANGO_ATTR_VALUE_INT)
-    return FALSE;
-
-  *value = attribute->int_value;
-  return TRUE;
+  switch ((int)attr->type)
+    {
+    /* Affects breaks */
+    case PANGO_ATTR_ALLOW_BREAKS:
+    case PANGO_ATTR_WORD:
+    case PANGO_ATTR_SENTENCE:
+    case PANGO_ATTR_PARAGRAPH:
+    /* Affects shaping */
+    case PANGO_ATTR_INSERT_HYPHENS:
+    case PANGO_ATTR_FONT_FEATURES:
+    case PANGO_ATTR_SHOW:
+      return TRUE;
+    default:
+      return FALSE;
+    }
 }
 
-gboolean
-pango_attribute_get_boolean (PangoAttribute *attribute,
-                             int            *value)
-{
-  if (PANGO_ATTR_VALUE_TYPE (attribute) != PANGO_ATTR_VALUE_BOOLEAN)
-    return FALSE;
-
-  *value = attribute->boolean_value;
-  return TRUE;
-}
-
-gboolean
-pango_attribute_get_float (PangoAttribute *attribute,
-                           double         *value)
-{
-  if (PANGO_ATTR_VALUE_TYPE (attribute) != PANGO_ATTR_VALUE_FLOAT)
-    return FALSE;
-
-  *value = attribute->double_value;
-  return TRUE;
-}
-
-gboolean
-pango_attribute_get_color (PangoAttribute *attribute,
-                           PangoColor     *value)
-{
-  if (PANGO_ATTR_VALUE_TYPE (attribute) != PANGO_ATTR_VALUE_COLOR)
-    return FALSE;
-
-  *value = attribute->color_value;
-  return TRUE;
-}
-
-gboolean
-pango_attribute_get_font_desc (PangoAttribute        *attribute,
-                               PangoFontDescription **value)
-{
-  if (PANGO_ATTR_VALUE_TYPE (attribute) != PANGO_ATTR_VALUE_FONT_DESC)
-    return FALSE;
-
-  *value = attribute->font_value;
-  return TRUE;
-}
-
-gboolean
-pango_attribute_get_custom (PangoAttribute *attribute,
-                            gpointer       *value)
-{
-  if (PANGO_ATTR_VALUE_TYPE (attribute) != PANGO_ATTR_VALUE_POINTER)
-    return FALSE;
-
-  *value = attribute->pointer_value;
-  return TRUE;
-}
-
-/* }}} */
-/* {{{ Attribute List */
-
-G_DEFINE_BOXED_TYPE (PangoAttrList, pango_attr_list,
-                     pango_attr_list_copy,
-                     pango_attr_list_unref);
-
-void
-_pango_attr_list_init (PangoAttrList *list)
-{
-  list->ref_count = 1;
-  list->attributes = NULL;
-}
-
-/**
- * pango_attr_list_new:
- *
- * Create a new empty attribute list with a reference
- * count of one.
- *
- * Return value: (transfer full): the newly allocated
- *   `PangoAttrList`, which should be freed with
- *   [method@Pango.AttrList.unref]
- */
-PangoAttrList *
-pango_attr_list_new (void)
-{
-  PangoAttrList *list = g_slice_new (PangoAttrList);
-
-  _pango_attr_list_init (list);
-
-  return list;
-}
-
-/**
- * pango_attr_list_ref:
- * @list: (nullable): 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)
-{
-  if (list == NULL)
-    return NULL;
-
-  g_atomic_int_inc ((int *) &list->ref_count);
-
-  return list;
-}
-
-void
-_pango_attr_list_destroy (PangoAttrList *list)
-{
-//  guint i, p;
-
-  if (!list->attributes)
-    return;
-
-#if 0
-  for (i = 0, p = list->attributes->len; i < p; i++)
-    {
-      PangoAttribute *attr = g_ptr_array_index (list->attributes, i);
-      //attr->klass->destroy (attr);
-    }
-#endif
-
-  g_ptr_array_free (list->attributes, TRUE);
-}
-
-/**
- * pango_attr_list_unref:
- * @list: (nullable): 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)
-{
-  if (list == NULL)
-    return;
-
-  g_return_if_fail (list->ref_count > 0);
-
-  if (g_atomic_int_dec_and_test ((int *) &list->ref_count))
-    {
-      _pango_attr_list_destroy (list);
-      g_slice_free (PangoAttrList, list);
-    }
-}
-
-/**
- * pango_attr_list_copy:
- * @list: (nullable): a `PangoAttrList`
- *
- * Copy @list and return an identical new list.
- *
- * Return value: (nullable): the newly allocated
- *   `PangoAttrList`, with a reference count of one,
- *   which should be freed with [method@Pango.AttrList.unref].
- *   Returns %NULL if @list was %NULL.
- */
-PangoAttrList *
-pango_attr_list_copy (PangoAttrList *list)
-{
-  PangoAttrList *new;
-
-  if (list == NULL)
-    return NULL;
-
-  new = pango_attr_list_new ();
-  if (!list->attributes || list->attributes->len == 0)
-    return new;
-
-  new->attributes = g_ptr_array_copy (list->attributes, (GCopyFunc)pango_attribute_copy, NULL);
-
-  return new;
-}
-
-static void
-pango_attr_list_insert_internal (PangoAttrList  *list,
-                                 PangoAttribute *attr,
-                                 gboolean        before)
-{
-  const guint start_index = attr->start_index;
-  PangoAttribute *last_attr;
-
-  if (G_UNLIKELY (!list->attributes))
-    list->attributes = g_ptr_array_new ();
-
-  if (list->attributes->len == 0)
-    {
-      g_ptr_array_add (list->attributes, attr);
-      return;
-    }
-
-  g_assert (list->attributes->len > 0);
-
-  last_attr = g_ptr_array_index (list->attributes, list->attributes->len - 1);
-
-  if (last_attr->start_index < start_index ||
-      (!before && last_attr->start_index == start_index))
-    {
-      g_ptr_array_add (list->attributes, attr);
-    }
-  else
-    {
-      guint i, p;
-
-      for (i = 0, p = list->attributes->len; i < p; i++)
-        {
-          PangoAttribute *cur = g_ptr_array_index (list->attributes, i);
-
-          if (cur->start_index > start_index ||
-              (before && cur->start_index == start_index))
-            {
-              g_ptr_array_insert (list->attributes, i, attr);
-              break;
-            }
-        }
-    }
-}
-
-/**
- * pango_attr_list_insert:
- * @list: a `PangoAttrList`
- * @attr: (transfer full): the attribute to insert
- *
- * 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: (transfer full): the attribute to insert
- *
- * 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: (transfer full): the attribute to insert
- *
- * 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 [method@Pango.AttrList.insert]
- * for creating an attribute list in order (potentially
- * much slower for large lists). However,
- * [method@Pango.AttrList.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)
-{
-  guint i, p;
-  guint start_index = attr->start_index;
-  guint end_index = attr->end_index;
-  gboolean inserted;
-
-  g_return_if_fail (list != NULL);
-
-  if (start_index == end_index) /* empty, nothing to do */
-    {
-      pango_attribute_destroy (attr);
-      return;
-    }
-
-  if (!list->attributes || list->attributes->len == 0)
-    {
-      pango_attr_list_insert (list, attr);
-      return;
-    }
-
-  inserted = FALSE;
-  for (i = 0, p = list->attributes->len; i < p; i++)
-    {
-      PangoAttribute *tmp_attr = g_ptr_array_index (list->attributes, i);
-
-      if (tmp_attr->start_index > start_index)
-        {
-          g_ptr_array_insert (list->attributes, i, attr);
-          inserted = TRUE;
-          break;
-        }
-
-      if (tmp_attr->type != attr->type)
-        continue;
-
-      if (tmp_attr->end_index < start_index)
-        continue; /* This attr does not overlap with the new one */
-
-      g_assert (tmp_attr->start_index <= start_index);
-      g_assert (tmp_attr->end_index >= start_index);
-
-      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;
-          inserted = TRUE;
-          break;
-        }
-      else
-        {
-          /* Split, truncate, or remove the old attribute
-           */
-          if (tmp_attr->end_index > end_index)
-            {
-              PangoAttribute *end_attr = pango_attribute_copy (tmp_attr);
-
-              end_attr->start_index = end_index;
-              pango_attr_list_insert (list, end_attr);
-            }
-
-          if (tmp_attr->start_index == start_index)
-            {
-              pango_attribute_destroy (tmp_attr);
-              g_ptr_array_remove_index (list->attributes, i);
-              break;
-            }
-          else
-            {
-              tmp_attr->end_index = start_index;
-            }
-        }
-    }
-
-  if (!inserted)
-    /* we didn't insert attr yet */
-    pango_attr_list_insert (list, attr);
-
-  /* We now have the range inserted into the list one way or the
-   * other. Fix up the remainder
-   */
-  /* Attention: No i = 0 here. */
-  for (i = i + 1, p = list->attributes->len; i < p; i++)
-    {
-      PangoAttribute *tmp_attr = g_ptr_array_index (list->attributes, i);
-
-      if (tmp_attr->start_index > end_index)
-        break;
-
-      if (tmp_attr->type != attr->type)
-        continue;
-
-      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);
-          g_ptr_array_remove_index (list->attributes, i);
-          i--;
-          p--;
-          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.
-           */
-          int k, m;
-
-          tmp_attr->start_index = attr->end_index;
-
-          for (k = i + 1, m = list->attributes->len; k < m; k++)
-            {
-              PangoAttribute *tmp_attr2 = g_ptr_array_index (list->attributes, k);
-
-              if (tmp_attr2->start_index >= tmp_attr->start_index)
-                break;
-            }
-        }
-    }
-}
-
-/**
- * pango_attr_list_update:
- * @list: a `PangoAttrList`
- * @pos: the position of the change
- * @remove: the number of removed bytes
- * @add: the number of added bytes
- *
- * Update indices of attributes in @list for a change in the
- * text they refer to.
- *
- * The change that this function applies is removing @remove
- * bytes at position @pos and inserting @add bytes instead.
- *
- * Attributes that fall entirely in the (@pos, @pos + @remove)
- * range are removed.
- *
- * Attributes that start or end inside the (@pos, @pos + @remove)
- * range are shortened to reflect the removal.
- *
- * Attributes start and end positions are updated if they are
- * behind @pos + @remove.
- *
- * Since: 1.44
- */
-void
-pango_attr_list_update (PangoAttrList *list,
-                        int             pos,
-                        int             remove,
-                        int             add)
-{
-  guint i, p;
-
-  g_return_if_fail (pos >= 0);
-  g_return_if_fail (remove >= 0);
-  g_return_if_fail (add >= 0);
-
-  if (list->attributes)
-    for (i = 0, p = list->attributes->len; i < p; i++)
-      {
-        PangoAttribute *attr = g_ptr_array_index (list->attributes, i);
-
-        if (attr->start_index >= pos &&
-          attr->end_index < pos + remove)
-          {
-            pango_attribute_destroy (attr);
-            g_ptr_array_remove_index (list->attributes, i);
-            i--; /* Look at this index again */
-            p--;
-            continue;
-          }
-
-        if (attr->start_index != PANGO_ATTR_INDEX_FROM_TEXT_BEGINNING)
-          {
-            if (attr->start_index >= pos &&
-                attr->start_index < pos + remove)
-              {
-                attr->start_index = pos + add;
-              }
-            else if (attr->start_index >= pos + remove)
-              {
-                attr->start_index += add - remove;
-              }
-          }
-
-        if (attr->end_index != PANGO_ATTR_INDEX_TO_TEXT_END)
-          {
-            if (attr->end_index >= pos &&
-                attr->end_index < pos + remove)
-              {
-                attr->end_index = pos;
-              }
-            else if (attr->end_index >= pos + remove)
-              {
-                if (add > remove &&
-                    G_MAXUINT - attr->end_index < add - remove)
-                  attr->end_index = G_MAXUINT;
-                else
-                  attr->end_index += add - remove;
-              }
-          }
-      }
-}
-
-/**
- * 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 [method@Pango.AttrList.change] with a copy
- * of each attribute in @other in sequence (offset in position
- * by @pos, and limited in length to @len).
- *
- * This operation proves useful for, for instance, inserting
- * a pre-edit string in the middle of an edit buffer.
- *
- * For backwards compatibility, the function behaves differently
- * when @len is 0. In this case, the attributes from @other are
- * not imited to @len, and are just overlayed on top of @list.
- *
- * This mode is useful for merging two lists of attributes together.
- */
-void
-pango_attr_list_splice (PangoAttrList *list,
-                        PangoAttrList *other,
-                        gint           pos,
-                        gint           len)
-{
-  guint i, p;
-  guint upos, ulen;
-  guint end;
-
-  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))
-
-  end = CLAMP_ADD (upos, ulen);
-
-  if (list->attributes)
-    for (i = 0, p = list->attributes->len; i < p; i++)
-      {
-        PangoAttribute *attr = g_ptr_array_index (list->attributes, i);;
-
-        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);
-         }
-      }
-
-  if (!other->attributes || other->attributes->len == 0)
-    return;
-
-  for (i = 0, p = other->attributes->len; i < p; i++)
-    {
-      PangoAttribute *attr = pango_attribute_copy (g_ptr_array_index (other->attributes, i));
-      if (ulen > 0)
-        {
-          attr->start_index = MIN (CLAMP_ADD (attr->start_index, upos), end);
-          attr->end_index = MIN (CLAMP_ADD (attr->end_index, upos), end);
-        }
-      else
-        {
-          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);
-    }
-#undef CLAMP_ADD
-}
-
-/**
- * pango_attr_list_get_attributes:
- * @list: a `PangoAttrList`
- *
- * Gets a list of all attributes in @list.
- *
- * Return value: (element-type Pango.Attribute) (transfer full):
- *   a list of all attributes in @list. To free this value,
- *   call [method@Pango.Attribute.destroy] on each value and
- *   g_slist_free() on the list.
- *
- * Since: 1.44
- */
-GSList *
-pango_attr_list_get_attributes (PangoAttrList *list)
-{
-  GSList *result = NULL;
-  guint i, p;
-
-  g_return_val_if_fail (list != NULL, NULL);
-
-  if (!list->attributes || list->attributes->len == 0)
-    return NULL;
-
-  for (i = 0, p = list->attributes->len; i < p; i++)
-    {
-      PangoAttribute *attr = g_ptr_array_index (list->attributes, i);
-
-      result = g_slist_prepend (result, pango_attribute_copy (attr));
-    }
-
-  return g_slist_reverse (result);
-}
-
-/**
- * pango_attr_list_equal:
- * @list: a `PangoAttrList`
- * @other_list: the other `PangoAttrList`
- *
- * Checks whether @list and @other_list contain the same
- * attributes and whether those attributes apply to the
- * same ranges.
- *
- * Beware that this will return wrong values if any list
- * contains duplicates.
- *
- * Return value: %TRUE if the lists are equal, %FALSE if
- *   they aren't
- *
- * Since: 1.46
- */
-gboolean
-pango_attr_list_equal (PangoAttrList *list,
-                       PangoAttrList *other_list)
-{
-  GPtrArray *attrs, *other_attrs;
-  guint64 skip_bitmask = 0;
-  guint i;
-
-  if (list == other_list)
-    return TRUE;
-
-  if (list == NULL || other_list == NULL)
-    return FALSE;
-
-  if (list->attributes == NULL || other_list->attributes == NULL)
-    return list->attributes == other_list->attributes;
-
-  attrs = list->attributes;
-  other_attrs = other_list->attributes;
-
-  if (attrs->len != other_attrs->len)
-    return FALSE;
-
-  for (i = 0; i < attrs->len; i++)
-    {
-      PangoAttribute *attr = g_ptr_array_index (attrs, i);
-      gboolean attr_equal = FALSE;
-      guint other_attr_index;
-
-      for (other_attr_index = 0; other_attr_index < other_attrs->len; other_attr_index++)
-        {
-          PangoAttribute *other_attr = g_ptr_array_index (other_attrs, other_attr_index);
-          guint64 other_attr_bitmask = other_attr_index < 64 ? 1 << other_attr_index : 0;
-
-          if ((skip_bitmask & other_attr_bitmask) != 0)
-            continue;
-
-          if (attr->start_index == other_attr->start_index &&
-              attr->end_index == other_attr->end_index &&
-              pango_attribute_equal (attr, other_attr))
-            {
-              skip_bitmask |= other_attr_bitmask;
-              attr_equal = TRUE;
-              break;
-            }
-
-        }
-
-      if (!attr_equal)
-        return FALSE;
-    }
-
-  return TRUE;
-}
-
-gboolean
-_pango_attr_list_has_attributes (const PangoAttrList *list)
-{
-  return list && list->attributes != NULL && list->attributes->len > 0;
-}
-
-/**
- * pango_attr_list_filter:
- * @list: a `PangoAttrList`
- * @func: (scope call) (closure data): callback function;
- *   returns %TRUE if an attribute should be filtered out
- * @data: (closure): 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: (transfer full) (nullable): 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;
-  guint i, p;
-
-  g_return_val_if_fail (list != NULL, NULL);
-
-  if (!list->attributes || list->attributes->len == 0)
-    return NULL;
-
-  for (i = 0, p = list->attributes->len; i < p; i++)
-    {
-      PangoAttribute *tmp_attr = g_ptr_array_index (list->attributes, i);
-
-      if ((*func) (tmp_attr, data))
-        {
-          g_ptr_array_remove_index (list->attributes, i);
-          i--; /* Need to look at this index again */
-          p--;
-
-          if (G_UNLIKELY (!new))
-            {
-              new = pango_attr_list_new ();
-              new->attributes = g_ptr_array_new ();
-            }
-
-          g_ptr_array_add (new->attributes, tmp_attr);
-        }
-    }
-
-  return new;
-}
-
-/* {{{ PangoAttrList serialization */
-
-/* We serialize attribute lists to strings. The format
- * is a comma-separated list of the attributes in the order
- * in which they are in the list, with each attribute having
- * this format:
- *
- * START END NICK VALUE
- *
- * Values that can contain a comma, such as font descriptions
- * are quoted with "".
- */
-static GType
-get_attr_value_type (PangoAttrType type)
-{
-  switch ((int)type)
-    {
-    case PANGO_ATTR_STYLE: return PANGO_TYPE_STYLE;
-    case PANGO_ATTR_WEIGHT: return PANGO_TYPE_WEIGHT;
-    case PANGO_ATTR_VARIANT: return PANGO_TYPE_VARIANT;
-    case PANGO_ATTR_STRETCH: return PANGO_TYPE_STRETCH;
-    case PANGO_ATTR_GRAVITY: return PANGO_TYPE_GRAVITY;
-    case PANGO_ATTR_GRAVITY_HINT: return PANGO_TYPE_GRAVITY_HINT;
-    case PANGO_ATTR_UNDERLINE: return PANGO_TYPE_UNDERLINE;
-    case PANGO_ATTR_OVERLINE: return PANGO_TYPE_OVERLINE;
-    case PANGO_ATTR_BASELINE_SHIFT: return PANGO_TYPE_BASELINE_SHIFT;
-    case PANGO_ATTR_FONT_SCALE: return PANGO_TYPE_FONT_SCALE;
-    case PANGO_ATTR_TEXT_TRANSFORM: return PANGO_TYPE_TEXT_TRANSFORM;
-    default: return G_TYPE_INVALID;
-    }
-}
-
-static void
-append_enum_value (GString *str,
-                   GType    type,
-                   int      value)
-{
-  GEnumClass *enum_class;
-  GEnumValue *enum_value;
-
-  enum_class = g_type_class_ref (type);
-  enum_value = g_enum_get_value (enum_class, value);
-  g_type_class_unref (enum_class);
-
-  if (enum_value)
-    g_string_append_printf (str, " %s", enum_value->value_nick);
-  else
-    g_string_append_printf (str, " %d", value);
-}
-
-static void
-attr_print (GString        *str,
-            PangoAttribute *attr)
-{
-  const char *name;
-
-  name = pango_attr_type_get_name (attr->type);
-  if (!name)
-    return;
-
-  g_string_append_printf (str, "%u %u %s", attr->start_index, attr->end_index, name);
-
-  switch (PANGO_ATTR_VALUE_TYPE (attr))
-    {
-    case PANGO_ATTR_VALUE_INT:
-      if (attr->type == PANGO_ATTR_WEIGHT ||
-          attr->type == PANGO_ATTR_STYLE ||
-          attr->type == PANGO_ATTR_STRETCH ||
-          attr->type == PANGO_ATTR_VARIANT ||
-          attr->type == PANGO_ATTR_GRAVITY ||
-          attr->type == PANGO_ATTR_GRAVITY_HINT ||
-          attr->type == PANGO_ATTR_UNDERLINE ||
-          attr->type == PANGO_ATTR_OVERLINE ||
-          attr->type == PANGO_ATTR_BASELINE_SHIFT ||
-          attr->type == PANGO_ATTR_FONT_SCALE ||
-          attr->type == PANGO_ATTR_TEXT_TRANSFORM)
-        append_enum_value (str, get_attr_value_type (attr->type), attr->int_value);
-      else
-        g_string_append_printf (str, " %d", attr->int_value);
-      break;
-
-    case PANGO_ATTR_VALUE_BOOLEAN:
-      g_string_append (str, attr->int_value ? " true" : " false");
-      break;
-
-    case PANGO_ATTR_VALUE_STRING:
-      g_string_append_printf (str, " \"%s\"", attr->str_value);
-      break;
-
-    case PANGO_ATTR_VALUE_LANGUAGE:
-      g_string_append_printf (str, " %s", pango_language_to_string (attr->lang_value));
-      break;
-
-    case PANGO_ATTR_VALUE_FLOAT:
-      {
-        char buf[20];
-        g_ascii_formatd (buf, 20, "%f", attr->double_value);
-        g_string_append_printf (str, " %s", buf);
-      }
-      break;
-
-    case PANGO_ATTR_VALUE_FONT_DESC:
-      {
-        char *s = pango_font_description_to_string (attr->font_value);
-        g_string_append_printf (str, " \"%s\"", s);
-        g_free (s);
-      }
-      break;
-
-    case PANGO_ATTR_VALUE_COLOR:
-      {
-        char *s = pango_color_to_string (&attr->color_value);
-        g_string_append_printf (str, " %s", s);
-        g_free (s);
-      }
-      break;
-
-    case PANGO_ATTR_VALUE_POINTER:
-      {
-        char *s = pango_attr_value_serialize (attr);
-        g_string_append_printf (str, " %s", s);
-        g_free (s);
-      }
-      break;
-
-    default:
-      g_assert_not_reached ();
-    }
-}
-
-/**
- * pango_attr_list_to_string:
- * @list: a `PangoAttrList`
- *
- * Serializes a `PangoAttrList` to a string.
- *
- * No guarantees are made about the format of the string,
- * it may change between Pango versions.
- *
- * The intended use of this function is testing and
- * debugging. The format is not meant as a permanent
- * storage format.
- *
- * Returns: (transfer full): a newly allocated string
- * Since: 1.50
- */
-char *
-pango_attr_list_to_string (PangoAttrList *list)
-{
-  GString *s;
-
-  s = g_string_new ("");
-
-  if (list->attributes)
-    for (int i = 0; i < list->attributes->len; i++)
-      {
-        PangoAttribute *attr = g_ptr_array_index (list->attributes, i);
-
-        if (i > 0)
-          g_string_append (s, "\n");
-        attr_print (s, attr);
-      }
-
-  return g_string_free (s, FALSE);
-}
-
-static PangoAttrType
-get_attr_type_by_nick (const char *nick,
-                       int         len)
-{
-  GEnumClass *enum_class;
-
-  enum_class = g_type_class_ref (pango_attr_type_get_type ());
-  for (GEnumValue *ev = enum_class->values; ev->value_name; ev++)
-    {
-      if (ev->value_nick && strncmp (ev->value_nick, nick, len) == 0)
-        {
-          g_type_class_unref (enum_class);
-          return (PangoAttrType) ev->value;
-        }
-    }
-
-  g_type_class_unref (enum_class);
-  return PANGO_ATTR_INVALID;
-}
-
-static int
-get_attr_value (PangoAttrType  type,
-                const char    *str,
-                int            len)
-{
-  GEnumClass *enum_class;
-  char *endp;
-  int value;
-
-  enum_class = g_type_class_ref (get_attr_value_type (type));
-  for (GEnumValue *ev = enum_class->values; ev->value_name; ev++)
-    {
-      if (ev->value_nick && strncmp (ev->value_nick, str, len) == 0)
-        {
-          g_type_class_unref (enum_class);
-          return ev->value;
-        }
-    }
-  g_type_class_unref (enum_class);
-
-  value = g_ascii_strtoll (str, &endp, 10);
-  if (endp - str == len)
-    return value;
-
-  return -1;
-}
-
-static gboolean
-is_valid_end_char (char c)
-{
-  return c == ',' || c == '\n' || c == '\0';
-}
-
-/**
- * pango_attr_list_from_string:
- * @text: a string
- *
- * Deserializes a `PangoAttrList` from a string.
- *
- * This is the counterpart to [method@Pango.AttrList.to_string].
- * See that functions for details about the format.
- *
- * Returns: (transfer full) (nullable): a new `PangoAttrList`
- * Since: 1.50
- */
-PangoAttrList *
-pango_attr_list_from_string (const char *text)
-{
-  PangoAttrList *list;
-  const char *p;
-
-  g_return_val_if_fail (text != NULL, NULL);
-
-  list = pango_attr_list_new ();
-
-  if (*text == '\0')
-    return list;
-
-  list->attributes = g_ptr_array_new ();
-
-  p = text + strspn (text, " \t\n");
-  while (*p)
-    {
-      char *endp;
-      gint64 start_index;
-      gint64 end_index;
-      char *str;
-      PangoAttrType attr_type;
-      PangoAttribute *attr;
-      PangoLanguage *lang;
-      gint64 integer;
-      PangoFontDescription *desc;
-      PangoColor color;
-      double num;
-
-      start_index = g_ascii_strtoll (p, &endp, 10);
-      if (*endp != ' ')
-        goto fail;
-
-      p = endp + strspn (endp, " ");
-      if (!*p)
-        goto fail;
-
-      end_index = g_ascii_strtoll (p, &endp, 10);
-      if (*endp != ' ')
-        goto fail;
-
-      p = endp + strspn (endp, " ");
-
-      endp = (char *)p + strcspn (p, " ");
-      attr_type = get_attr_type_by_nick (p, endp - p);
-
-      p = endp + strspn (endp, " ");
-      if (*p == '\0')
-        goto fail;
-
-#define INT_ATTR(name,type) \
-          integer = g_ascii_strtoll (p, &endp, 10); \
-          if (!is_valid_end_char (*endp)) goto fail; \
-          attr = pango_attr_##name##_new ((type)integer);
-
-#define BOOLEAN_ATTR(name,type) \
-          if (strncmp (p, "true", strlen ("true")) == 0) \
-            { \
-              integer = 1; \
-              endp = (char *)(p + strlen ("true")); \
-            } \
-          else if (strncmp (p, "false", strlen ("false")) == 0) \
-            { \
-              integer = 0; \
-              endp = (char *)(p + strlen ("false")); \
-            } \
-          else \
-            integer = g_ascii_strtoll (p, &endp, 10); \
-          if (!is_valid_end_char (*endp)) goto fail; \
-          attr = pango_attr_##name##_new ((type)integer);
-
-#define ENUM_ATTR(name, type, min, max) \
-          endp = (char *)p + strcspn (p, ",\n"); \
-          integer = get_attr_value (attr_type, p, endp - p); \
-          attr = pango_attr_##name##_new ((type) CLAMP (integer, min, max));
-
-#define FLOAT_ATTR(name) \
-          num = g_ascii_strtod (p, &endp); \
-          if (!is_valid_end_char (*endp)) goto fail; \
-          attr = pango_attr_##name##_new ((float)num);
-
-#define COLOR_ATTR(name) \
-          endp = (char *)p + strcspn (p, ",\n"); \
-          if (!is_valid_end_char (*endp)) goto fail; \
-          str = g_strndup (p, endp - p); \
-          if (!pango_color_parse (&color, str)) \
-            { \
-              g_free (str); \
-              goto fail; \
-            } \
-          attr = pango_attr_##name##_new (color.red, color.green, color.blue); \
-          g_free (str);
-
-      switch (attr_type)
-        {
-        case PANGO_ATTR_INVALID:
-          pango_attr_list_unref (list);
-          return NULL;
-
-        case PANGO_ATTR_LANGUAGE:
-          endp = (char *)p + strcspn (p, ",\n");
-          if (!is_valid_end_char (*endp)) goto fail;
-          str = g_strndup (p, endp - p);
-          lang = pango_language_from_string (str);
-          attr = pango_attr_language_new (lang);
-          g_free (str);
-          break;
-
-        case PANGO_ATTR_FAMILY:
-          p++;
-          endp = strchr (p, '"');
-          if (!endp) goto fail;
-          str = g_strndup (p, endp - p);
-          attr = pango_attr_family_new (str);
-          g_free (str);
-          endp++;
-          if (!is_valid_end_char (*endp)) goto fail;
-          break;
-
-        case PANGO_ATTR_STYLE:
-          ENUM_ATTR(style, PangoStyle, PANGO_STYLE_NORMAL, PANGO_STYLE_ITALIC);
-          break;
-
-        case PANGO_ATTR_WEIGHT:
-          ENUM_ATTR(weight, PangoWeight, PANGO_WEIGHT_THIN, PANGO_WEIGHT_ULTRAHEAVY);
-          break;
-
-        case PANGO_ATTR_VARIANT:
-          ENUM_ATTR(variant, PangoVariant, PANGO_VARIANT_NORMAL, PANGO_VARIANT_TITLE_CAPS);
-          break;
-
-        case PANGO_ATTR_STRETCH:
-          ENUM_ATTR(stretch, PangoStretch, PANGO_STRETCH_ULTRA_CONDENSED, PANGO_STRETCH_ULTRA_EXPANDED);
-          break;
-
-        case PANGO_ATTR_SIZE:
-          INT_ATTR(size, int);
-          break;
-
-        case PANGO_ATTR_FONT_DESC:
-          p++;
-          endp = strchr (p, '"');
-          if (!endp) goto fail;
-          str = g_strndup (p, endp - p);
-          desc = pango_font_description_from_string (str);
-          attr = pango_attr_font_desc_new (desc);
-          pango_font_description_free (desc);
-          g_free (str);
-          endp++;
-          if (!is_valid_end_char (*endp)) goto fail;
-          break;
-
-        case PANGO_ATTR_FOREGROUND:
-          COLOR_ATTR(foreground);
-          break;
-
-        case PANGO_ATTR_BACKGROUND:
-          COLOR_ATTR(background);
-          break;
-
-        case PANGO_ATTR_UNDERLINE:
-          ENUM_ATTR(underline, PangoUnderline, PANGO_UNDERLINE_NONE, PANGO_UNDERLINE_ERROR_LINE);
-          break;
-
-        case PANGO_ATTR_STRIKETHROUGH:
-          BOOLEAN_ATTR(strikethrough, gboolean);
-          break;
-
-        case PANGO_ATTR_RISE:
-          INT_ATTR(rise, int);
-          break;
-
-        case PANGO_ATTR_SCALE:
-          FLOAT_ATTR(scale);
-          break;
-
-        case PANGO_ATTR_FALLBACK:
-          BOOLEAN_ATTR(fallback, gboolean);
-          break;
-
-        case PANGO_ATTR_LETTER_SPACING:
-          INT_ATTR(letter_spacing, int);
-          break;
-
-        case PANGO_ATTR_UNDERLINE_COLOR:
-          COLOR_ATTR(underline_color);
-          break;
-
-        case PANGO_ATTR_STRIKETHROUGH_COLOR:
-          COLOR_ATTR(strikethrough_color);
-          break;
-
-        case PANGO_ATTR_ABSOLUTE_SIZE:
-          integer = g_ascii_strtoll (p, &endp, 10);
-          if (!is_valid_end_char (*endp)) goto fail;
-          attr = pango_attr_size_new_absolute (integer);
-          break;
-
-        case PANGO_ATTR_GRAVITY:
-          ENUM_ATTR(gravity, PangoGravity, PANGO_GRAVITY_SOUTH, PANGO_GRAVITY_WEST);
-          break;
-
-        case PANGO_ATTR_FONT_FEATURES:
-          p++;
-          endp = strchr (p, '"');
-          if (!endp) goto fail;
-          str = g_strndup (p, endp - p);
-          attr = pango_attr_font_features_new (str);
-          g_free (str);
-          endp++;
-          if (!is_valid_end_char (*endp)) goto fail;
-          break;
-
-        case PANGO_ATTR_GRAVITY_HINT:
-          ENUM_ATTR(gravity_hint, PangoGravityHint, PANGO_GRAVITY_HINT_NATURAL, PANGO_GRAVITY_HINT_LINE);
-          break;
-
-        case PANGO_ATTR_FOREGROUND_ALPHA:
-          INT_ATTR(foreground_alpha, int);
-          break;
-
-        case PANGO_ATTR_BACKGROUND_ALPHA:
-          INT_ATTR(background_alpha, int);
-          break;
-
-        case PANGO_ATTR_ALLOW_BREAKS:
-          BOOLEAN_ATTR(allow_breaks, gboolean);
-          break;
-
-        case PANGO_ATTR_SHOW:
-          INT_ATTR(show, PangoShowFlags);
-          break;
-
-        case PANGO_ATTR_INSERT_HYPHENS:
-          BOOLEAN_ATTR(insert_hyphens, gboolean);
-          break;
-
-        case PANGO_ATTR_OVERLINE:
-          ENUM_ATTR(overline, PangoOverline, PANGO_OVERLINE_NONE, PANGO_OVERLINE_SINGLE);
-          break;
-
-        case PANGO_ATTR_OVERLINE_COLOR:
-          COLOR_ATTR(overline_color);
-          break;
-
-        case PANGO_ATTR_LINE_HEIGHT:
-          FLOAT_ATTR(line_height);
-          break;
-
-        case PANGO_ATTR_LINE_SPACING:
-          INT_ATTR(line_spacing, int);
-          break;
-
-        case PANGO_ATTR_ABSOLUTE_LINE_HEIGHT:
-          integer = g_ascii_strtoll (p, &endp, 10);
-          if (!is_valid_end_char (*endp)) goto fail;
-          attr = pango_attr_line_height_new_absolute (integer);
-          break;
-
-        case PANGO_ATTR_TEXT_TRANSFORM:
-          ENUM_ATTR(text_transform, PangoTextTransform, PANGO_TEXT_TRANSFORM_NONE, 
PANGO_TEXT_TRANSFORM_CAPITALIZE);
-          break;
-
-        case PANGO_ATTR_WORD:
-          integer = g_ascii_strtoll (p, &endp, 10);
-          if (!is_valid_end_char (*endp)) goto fail;
-          attr = pango_attr_word_new ();
-          break;
-
-        case PANGO_ATTR_SENTENCE:
-          integer = g_ascii_strtoll (p, &endp, 10);
-          if (!is_valid_end_char (*endp)) goto fail;
-          attr = pango_attr_sentence_new ();
-          break;
-
-        case PANGO_ATTR_PARAGRAPH:
-          integer = g_ascii_strtoll (p, &endp, 10);
-          if (!is_valid_end_char (*endp)) goto fail;
-          attr = pango_attr_paragraph_new ();
-          break;
-
-        case PANGO_ATTR_BASELINE_SHIFT:
-          ENUM_ATTR(baseline_shift, PangoBaselineShift, 0, G_MAXINT);
-          break;
-
-        case PANGO_ATTR_FONT_SCALE:
-          ENUM_ATTR(font_scale, PangoFontScale, PANGO_FONT_SCALE_NONE, PANGO_FONT_SCALE_SMALL_CAPS);
-          break;
-
-        default:
-          g_assert_not_reached ();
-        }
-
-      attr->start_index = (guint)start_index;
-      attr->end_index = (guint)end_index;
-      g_ptr_array_add (list->attributes, attr);
-
-      p = endp;
-      if (*p)
-        {
-          if (*p == ',')
-            p++;
-          p += strspn (p, " \n");
-        }
-    }
-
-  goto success;
-
-fail:
-  pango_attr_list_unref (list);
-  list = NULL;
-
-success:
-  return list;
-}
-
-/* }}} */
-/* {{{ Attribute Iterator */
-
-G_DEFINE_BOXED_TYPE (PangoAttrIterator,
-                     pango_attr_iterator,
-                     pango_attr_iterator_copy,
-                     pango_attr_iterator_destroy)
-
-void
-_pango_attr_list_get_iterator (PangoAttrList     *list,
-                               PangoAttrIterator *iterator)
-{
-  iterator->attribute_stack = NULL;
-  iterator->attrs = list->attributes;
-  iterator->n_attrs = iterator->attrs ? iterator->attrs->len : 0;
-
-  iterator->attr_index = 0;
-  iterator->start_index = 0;
-  iterator->end_index = 0;
-
-  if (!pango_attr_iterator_next (iterator))
-    iterator->end_index = G_MAXUINT;
-}
-
-/**
- * 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: (transfer full): the newly allocated
- *   `PangoAttrIterator`, which should be freed with
- *   [method@Pango.AttrIterator.destroy]
- */
-PangoAttrIterator *
-pango_attr_list_get_iterator (PangoAttrList  *list)
-{
-  PangoAttrIterator *iterator;
-
-  g_return_val_if_fail (list != NULL, NULL);
-
-  iterator = g_slice_new (PangoAttrIterator);
-  _pango_attr_list_get_iterator (list, iterator);
-
-  return iterator;
-}
-
-/**
- * pango_attr_iterator_range:
- * @iterator: a PangoAttrIterator
- * @start: (out): location to store the start of the range
- * @end: (out): 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)
-{
-  int i;
-
-  g_return_val_if_fail (iterator != NULL, FALSE);
-
-  if (iterator->attr_index >= iterator->n_attrs &&
-      (!iterator->attribute_stack || iterator->attribute_stack->len == 0))
-    return FALSE;
-
-  iterator->start_index = iterator->end_index;
-  iterator->end_index = G_MAXUINT;
-
-  if (iterator->attribute_stack)
-    {
-      for (i = iterator->attribute_stack->len - 1; i>= 0; i--)
-        {
-          const PangoAttribute *attr = g_ptr_array_index (iterator->attribute_stack, i);
-
-          if (attr->end_index == iterator->start_index)
-            g_ptr_array_remove_index (iterator->attribute_stack, i); /* Can't use index_fast :( */
-          else
-            iterator->end_index = MIN (iterator->end_index, attr->end_index);
-        }
-    }
-
-  while (1)
-    {
-      PangoAttribute *attr;
-
-      if (iterator->attr_index >= iterator->n_attrs)
-        break;
-
-      attr = g_ptr_array_index (iterator->attrs, iterator->attr_index);
-
-      if (attr->start_index != iterator->start_index)
-        break;
-
-      if (attr->end_index > iterator->start_index)
-        {
-          if (G_UNLIKELY (!iterator->attribute_stack))
-            iterator->attribute_stack = g_ptr_array_new ();
-
-          g_ptr_array_add (iterator->attribute_stack, attr);
-
-          iterator->end_index = MIN (iterator->end_index, attr->end_index);
-        }
-
-      iterator->attr_index++; /* NEXT! */
-    }
-
-  if (iterator->attr_index < iterator->n_attrs)
-      {
-      PangoAttribute *attr = g_ptr_array_index (iterator->attrs, iterator->attr_index);
-
-      iterator->end_index = MIN (iterator->end_index, attr->start_index);
-    }
-
-  return TRUE;
-}
-
-/**
- * pango_attr_iterator_copy:
- * @iterator: a `PangoAttrIterator`
- *
- * Copy a `PangoAttrIterator`.
- *
- * Return value: (transfer full): the newly allocated
- *   `PangoAttrIterator`, which should be freed with
- *   [method@Pango.AttrIterator.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;
-
-  if (iterator->attribute_stack)
-    copy->attribute_stack = g_ptr_array_copy (iterator->attribute_stack, NULL, NULL);
-  else
-    copy->attribute_stack = NULL;
-
-  return copy;
-}
-
-void
-_pango_attr_iterator_destroy (PangoAttrIterator *iterator)
-{
-  if (iterator->attribute_stack)
-    g_ptr_array_free (iterator->attribute_stack, TRUE);
-}
-
-/**
- * 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);
-
-  _pango_attr_iterator_destroy (iterator);
-  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: (nullable) (transfer none): 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)
-{
-  int i;
-
-  g_return_val_if_fail (iterator != NULL, NULL);
-
-  if (!iterator->attribute_stack)
-    return NULL;
-
-  for (i = iterator->attribute_stack->len - 1; i>= 0; i--)
-    {
-      PangoAttribute *attr = g_ptr_array_index (iterator->attribute_stack, i);
-
-      if (attr->type == type)
-        return attr;
-    }
-
-  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
- *   [method@Pango.FontDescription.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:
- *   `pango_font_description_set_family (desc, pango_font_description_get_family (desc))`.
- * @language: (out) (optional): location to store language tag
- *   for item, or %NULL if none is found.
- * @extra_attrs: (out) (optional) (element-type Pango.Attribute) (transfer full):
- *   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
- *   [method@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)
-{
-  PangoFontMask mask = 0;
-  gboolean have_language = FALSE;
-  gdouble scale = 0;
-  gboolean have_scale = FALSE;
-  int i;
-
-  g_return_if_fail (iterator != NULL);
-  g_return_if_fail (desc != NULL);
-
-  if (language)
-    *language = NULL;
-
-  if (extra_attrs)
-    *extra_attrs = NULL;
-
-  if (!iterator->attribute_stack)
-    return;
-
-  for (i = iterator->attribute_stack->len - 1; i >= 0; i--)
-    {
-      const PangoAttribute *attr = g_ptr_array_index (iterator->attribute_stack, i);
-
-      switch ((int) attr->type)
-        {
-        case PANGO_ATTR_FONT_DESC:
-          {
-            PangoFontMask new_mask = pango_font_description_get_set_fields (attr->font_value) & ~mask;
-            mask |= new_mask;
-            pango_font_description_unset_fields (desc, new_mask);
-            pango_font_description_merge_static (desc, attr->font_value, FALSE);
-
-            break;
-          }
-        case PANGO_ATTR_FAMILY:
-          if (!(mask & PANGO_FONT_MASK_FAMILY))
-            {
-              mask |= PANGO_FONT_MASK_FAMILY;
-              pango_font_description_set_family (desc, attr->str_value);
-            }
-          break;
-        case PANGO_ATTR_STYLE:
-          if (!(mask & PANGO_FONT_MASK_STYLE))
-            {
-              mask |= PANGO_FONT_MASK_STYLE;
-              pango_font_description_set_style (desc, attr->int_value);
-            }
-          break;
-        case PANGO_ATTR_VARIANT:
-          if (!(mask & PANGO_FONT_MASK_VARIANT))
-            {
-              mask |= PANGO_FONT_MASK_VARIANT;
-              pango_font_description_set_variant (desc, attr->int_value);
-            }
-          break;
-        case PANGO_ATTR_WEIGHT:
-          if (!(mask & PANGO_FONT_MASK_WEIGHT))
-            {
-              mask |= PANGO_FONT_MASK_WEIGHT;
-              pango_font_description_set_weight (desc, attr->int_value);
-            }
-          break;
-        case PANGO_ATTR_STRETCH:
-          if (!(mask & PANGO_FONT_MASK_STRETCH))
-            {
-              mask |= PANGO_FONT_MASK_STRETCH;
-              pango_font_description_set_stretch (desc, attr->int_value);
-            }
-          break;
-        case PANGO_ATTR_SIZE:
-          if (!(mask & PANGO_FONT_MASK_SIZE))
-            {
-              mask |= PANGO_FONT_MASK_SIZE;
-              pango_font_description_set_size (desc, attr->int_value);
-            }
-          break;
-        case PANGO_ATTR_ABSOLUTE_SIZE:
-          if (!(mask & PANGO_FONT_MASK_SIZE))
-            {
-              mask |= PANGO_FONT_MASK_SIZE;
-              pango_font_description_set_absolute_size (desc, attr->int_value);
-            }
-          break;
-        case PANGO_ATTR_SCALE:
-          if (!have_scale)
-            {
-              have_scale = TRUE;
-              scale = attr->double_value;
-            }
-          break;
-        case PANGO_ATTR_LANGUAGE:
-          if (language)
-            {
-              if (!have_language)
-                {
-                  have_language = TRUE;
-                  *language = attr->lang_value;
-                }
-            }
-          break;
-        default:
-          if (extra_attrs)
-            {
-              gboolean found = FALSE;
-
-              /* Hack: special-case FONT_FEATURES, BASELINE_SHIFT and FONT_SCALE.
-               * We don't want these to accumulate, not override each other,
-               * so we never merge them.
-               * This needs to be handled more systematically.
-               */
-              if (attr->type != PANGO_ATTR_FONT_FEATURES &&
-                  attr->type != PANGO_ATTR_BASELINE_SHIFT &&
-                  attr->type != PANGO_ATTR_FONT_SCALE)
-                {
-                  GSList *tmp_list = *extra_attrs;
-                  while (tmp_list)
-                    {
-                      PangoAttribute *old_attr = tmp_list->data;
-                      if (attr->type == old_attr->type)
-                        {
-                          found = TRUE;
-                          break;
-                        }
-
-                      tmp_list = tmp_list->next;
-                    }
-                }
-
-              if (!found)
-                *extra_attrs = g_slist_prepend (*extra_attrs, pango_attribute_copy (attr));
-            }
-        }
-    }
-
-  if (have_scale)
-    {
-      /* We need to use a local variable to ensure that the compiler won't
-       * implicitly cast it to integer while the result is kept in registers,
-       * leading to a wrong approximation in i386 (with 387 FPU)
-       */
-      volatile double size = scale * pango_font_description_get_size (desc);
-
-      if (pango_font_description_get_size_is_absolute (desc))
-        pango_font_description_set_absolute_size (desc, size);
-      else
-        pango_font_description_set_size (desc, size);
-    }
-}
-
-/**
- * pango_attr_iterator_get_attrs:
- * @iterator: a `PangoAttrIterator`
- *
- * Gets a list of all attributes at the current position of the
- * iterator.
- *
- * Return value: (element-type Pango.Attribute) (transfer full):
- *   a list of all attributes for the current range. To free
- *   this value, call [method@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;
-  int i;
-
-  if (!iterator->attribute_stack ||
-      iterator->attribute_stack->len == 0)
-    return NULL;
-
-  for (i = iterator->attribute_stack->len - 1; i >= 0; i--)
-    {
-      PangoAttribute *attr = g_ptr_array_index (iterator->attribute_stack, i);
-      GSList *tmp_list2;
-      gboolean found = FALSE;
-
-      if (attr->type != PANGO_ATTR_FONT_DESC &&
-          attr->type != PANGO_ATTR_BASELINE_SHIFT &&
-          attr->type != PANGO_ATTR_FONT_SCALE)
-        for (tmp_list2 = attrs; tmp_list2; tmp_list2 = tmp_list2->next)
-          {
-            PangoAttribute *old_attr = tmp_list2->data;
-            if (attr->type == old_attr->type)
-              {
-                found = TRUE;
-                break;
-              }
-           }
-
-      if (!found)
-        attrs = g_slist_prepend (attrs, pango_attribute_copy (attr));
-    }
-
-  return attrs;
-}
-
-gboolean
-pango_attr_iterator_advance (PangoAttrIterator *iterator,
-                             int                index)
-{
-  int start_range, end_range;
-
-  pango_attr_iterator_range (iterator, &start_range, &end_range);
-
-  while (index >= end_range)
-    {
-      if (!pango_attr_iterator_next (iterator))
-        return FALSE;
-      pango_attr_iterator_range (iterator, &start_range, &end_range);
-    }
-
-  if (start_range > index)
-    g_warning ("pango_attr_iterator_advance(): iterator had already "
-               "moved beyond the index");
-
-  return TRUE;
-}
 /* }}} */
 
 /* vim:set foldmethod=marker expandtab: */
diff --git a/pango/pango-attributes.h b/pango/pango-attributes.h
index b008b98f..9e4b595c 100644
--- a/pango/pango-attributes.h
+++ b/pango/pango-attributes.h
@@ -19,83 +19,63 @@
  * Boston, MA 02111-1307, USA.
  */
 
-#ifndef __PANGO_ATTRIBUTES_H__
-#define __PANGO_ATTRIBUTES_H__
+#pragma once
 
 #include <pango/pango-font.h>
 #include <pango/pango-color.h>
-#include <glib-object.h>
+#include <pango/pango-attr.h>
 
 G_BEGIN_DECLS
 
 
-typedef struct _PangoAttribute        PangoAttribute;
-typedef struct _PangoAttrClass        PangoAttrClass;
-
-typedef enum
-{
-  PANGO_ATTR_VALUE_STRING,
-  PANGO_ATTR_VALUE_INT,
-  PANGO_ATTR_VALUE_BOOLEAN,
-  PANGO_ATTR_VALUE_FLOAT,
-  PANGO_ATTR_VALUE_COLOR,
-  PANGO_ATTR_VALUE_LANGUAGE,
-  PANGO_ATTR_VALUE_FONT_DESC,
-  PANGO_ATTR_VALUE_POINTER
-} PangoAttrValueType;
-
 #define PANGO_ATTR_TYPE(value) (PANGO_ATTR_VALUE_##value | (__COUNTER__ << 8))
-#define PANGO_ATTR_TYPE_VALUE_TYPE(type) ((PangoAttrValueType)((type) & 0xff))
-#define PANGO_ATTR_VALUE_TYPE(attr) PANGO_ATTR_TYPE_VALUE_TYPE ((attr)->type)
-
 /**
  * PangoAttrType:
  * @PANGO_ATTR_INVALID: does not happen
- * @PANGO_ATTR_LANGUAGE: language ([struct@Pango.AttrLanguage])
- * @PANGO_ATTR_FAMILY: font family name list ([struct@Pango.AttrString])
- * @PANGO_ATTR_STYLE: font slant style ([struct@Pango.AttrInt])
- * @PANGO_ATTR_WEIGHT: font weight ([struct@Pango.AttrInt])
- * @PANGO_ATTR_VARIANT: font variant (normal or small caps) ([struct@Pango.AttrInt])
- * @PANGO_ATTR_STRETCH: font stretch ([struct@Pango.AttrInt])
- * @PANGO_ATTR_SIZE: font size in points scaled by %PANGO_SCALE ([struct@Pango.AttrInt])
- * @PANGO_ATTR_FONT_DESC: font description ([struct@Pango.AttrFontDesc])
- * @PANGO_ATTR_FOREGROUND: foreground color ([struct@Pango.AttrColor])
- * @PANGO_ATTR_BACKGROUND: background color ([struct@Pango.AttrColor])
- * @PANGO_ATTR_UNDERLINE: whether the text has an underline ([struct@Pango.AttrInt])
- * @PANGO_ATTR_STRIKETHROUGH: whether the text is struck-through ([struct@Pango.AttrInt])
- * @PANGO_ATTR_RISE: baseline displacement ([struct@Pango.AttrInt])
- * @PANGO_ATTR_SCALE: font size scale factor ([struct@Pango.AttrFloat])
- * @PANGO_ATTR_FALLBACK: whether fallback is enabled ([struct@Pango.AttrInt])
- * @PANGO_ATTR_LETTER_SPACING: letter spacing ([struct@PangoAttrInt])
- * @PANGO_ATTR_UNDERLINE_COLOR: underline color ([struct@Pango.AttrColor])
- * @PANGO_ATTR_STRIKETHROUGH_COLOR: strikethrough color ([struct@Pango.AttrColor])
- * @PANGO_ATTR_ABSOLUTE_SIZE: font size in pixels scaled by %PANGO_SCALE ([struct@Pango.AttrInt])
- * @PANGO_ATTR_GRAVITY: base text gravity ([struct@Pango.AttrInt])
- * @PANGO_ATTR_GRAVITY_HINT: gravity hint ([struct@Pango.AttrInt])
- * @PANGO_ATTR_FONT_FEATURES: OpenType font features ([struct@Pango.AttrFontFeatures]). Since 1.38
- * @PANGO_ATTR_FOREGROUND_ALPHA: foreground alpha ([struct@Pango.AttrInt]). Since 1.38
- * @PANGO_ATTR_BACKGROUND_ALPHA: background alpha ([struct@Pango.AttrInt]). Since 1.38
- * @PANGO_ATTR_ALLOW_BREAKS: whether breaks are allowed ([struct@Pango.AttrInt]). Since 1.44
- * @PANGO_ATTR_SHOW: how to render invisible characters ([struct@Pango.AttrInt]). Since 1.44
- * @PANGO_ATTR_INSERT_HYPHENS: whether to insert hyphens at intra-word line breaks ([struct@Pango.AttrInt]). 
Since 1.44
- * @PANGO_ATTR_OVERLINE: whether the text has an overline ([struct@Pango.AttrInt]). Since 1.46
- * @PANGO_ATTR_OVERLINE_COLOR: overline color ([struct@Pango.AttrColor]). Since 1.46
- * @PANGO_ATTR_LINE_HEIGHT: line height factor ([struct@Pango.AttrFloat]). Since: 1.50
- * @PANGO_ATTR_ABSOLUTE_LINE_HEIGHT: line height ([struct@Pango.AttrInt]). Since: 1.50
- * @PANGO_ATTR_WORD: override segmentation to classify the range of the attribute as a single word 
([struct@Pango.AttrInt]). Since 1.50
- * @PANGO_ATTR_SENTENCE: override segmentation to classify the range of the attribute as a single sentence 
([struct@Pango.AttrInt]). Since 1.50
- * @PANGO_ATTR_PARAGRAPH: override segmentation to classify the range of the attribute as a single paragraph 
([struct@Pango.AttrInt]).
- * @PANGO_ATTR_BASELINE_SHIFT: baseline displacement ([struct@Pango.AttrInt]). Since 1.50
- * @PANGO_ATTR_FONT_SCALE: font-relative size change ([struct@Pango.AttrInt]). Since 1.50
- * @PANGO_ATTR_LINE_SPACING: extra space to add to the leading from the font metrics (if
- *   not overridden by line height attribute) ([struct@Pango.AttrInt])
- *
- * The `PangoAttrType` distinguishes between different types of attributes.
+ * @PANGO_ATTR_LANGUAGE: language
+ * @PANGO_ATTR_FAMILY: font family name
+ * @PANGO_ATTR_STYLE: font style
+ * @PANGO_ATTR_WEIGHT: font weight
+ * @PANGO_ATTR_VARIANT: font variant
+ * @PANGO_ATTR_STRETCH: font stretch
+ * @PANGO_ATTR_SIZE: font size in points scaled by `PANGO_SCALE`
+ * @PANGO_ATTR_FONT_DESC: font description
+ * @PANGO_ATTR_FOREGROUND: foreground color
+ * @PANGO_ATTR_BACKGROUND: background color
+ * @PANGO_ATTR_UNDERLINE: whether the text has an underline
+ * @PANGO_ATTR_STRIKETHROUGH: whether the text is struck-through
+ * @PANGO_ATTR_RISE: baseline displacement
+ * @PANGO_ATTR_SCALE: font size scale factor
+ * @PANGO_ATTR_FALLBACK: whether font fallback is enabled
+ * @PANGO_ATTR_LETTER_SPACING: letter spacing in Pango units
+ * @PANGO_ATTR_UNDERLINE_COLOR: underline color
+ * @PANGO_ATTR_STRIKETHROUGH_COLOR: strikethrough color
+ * @PANGO_ATTR_ABSOLUTE_SIZE: font size in pixels scaled by `PANGO_SCALE`
+ * @PANGO_ATTR_GRAVITY: base text gravity
+ * @PANGO_ATTR_GRAVITY_HINT: gravity hint
+ * @PANGO_ATTR_FONT_FEATURES: OpenType font features
+ * @PANGO_ATTR_FOREGROUND_ALPHA: foreground alpha
+ * @PANGO_ATTR_BACKGROUND_ALPHA: background alpha
+ * @PANGO_ATTR_ALLOW_BREAKS: whether line breaks are allowed
+ * @PANGO_ATTR_SHOW: how to render invisible characters
+ * @PANGO_ATTR_INSERT_HYPHENS: whether to insert hyphens at intra-word line breaks
+ * @PANGO_ATTR_OVERLINE: whether the text has an overline
+ * @PANGO_ATTR_OVERLINE_COLOR: overline color
+ * @PANGO_ATTR_LINE_HEIGHT: line height factor
+ * @PANGO_ATTR_ABSOLUTE_LINE_HEIGHT: line height in Pango units
+ * @PANGO_ATTR_WORD: mark the range of the attribute as a single word
+ * @PANGO_ATTR_SENTENCE: mark the range of the attribute as a single sentence
+ * @PANGO_ATTR_PARAGRAPH: mark the range of the attribute as a single paragraph
+ * @PANGO_ATTR_BASELINE_SHIFT: baseline displacement
+ * @PANGO_ATTR_FONT_SCALE: font-relative size change
+ * @PANGO_ATTR_LINE_SPACING: extra space to add to the leading from the
+ *   font metrics (if not overridden by line height attribute)
+ *
+ * The `PangoAttrType` enumeration contains predefined types for attributes.
  *
  * Along with the predefined values, it is possible to allocate additional
  * values for custom attributes using [func@AttrType.register]. The predefined
- * values are given below. The type of structure used to store the attribute is
- * listed in parentheses after the description.
+ * values are given below.
  */
 typedef enum
 {
@@ -142,6 +122,34 @@ typedef enum
 
 #undef PANGO_ATTR_TYPE
 
+
+PANGO_AVAILABLE_IN_ALL
+PangoAttribute *        pango_attr_language_new                 (PangoLanguage              *language);
+PANGO_AVAILABLE_IN_ALL
+PangoAttribute *        pango_attr_family_new                   (const char                 *family);
+PANGO_AVAILABLE_IN_ALL
+PangoAttribute *        pango_attr_foreground_new               (guint16                     red,
+                                                                 guint16                     green,
+                                                                 guint16                     blue);
+PANGO_AVAILABLE_IN_ALL
+PangoAttribute *        pango_attr_background_new               (guint16                     red,
+                                                                 guint16                     green,
+                                                                 guint16                     blue);
+PANGO_AVAILABLE_IN_ALL
+PangoAttribute *        pango_attr_size_new                     (int                         size);
+PANGO_AVAILABLE_IN_1_8
+PangoAttribute *        pango_attr_size_new_absolute            (int                         size);
+PANGO_AVAILABLE_IN_ALL
+PangoAttribute *        pango_attr_style_new                    (PangoStyle                  style);
+PANGO_AVAILABLE_IN_ALL
+PangoAttribute *        pango_attr_weight_new                   (PangoWeight                 weight);
+PANGO_AVAILABLE_IN_ALL
+PangoAttribute *        pango_attr_variant_new                  (PangoVariant                variant);
+PANGO_AVAILABLE_IN_ALL
+PangoAttribute *        pango_attr_stretch_new                  (PangoStretch                stretch);
+PANGO_AVAILABLE_IN_ALL
+PangoAttribute *        pango_attr_font_desc_new                (const PangoFontDescription *desc);
+
 /**
  * PangoUnderline:
  * @PANGO_UNDERLINE_NONE: no underline should be drawn
@@ -185,61 +193,20 @@ typedef enum {
   PANGO_UNDERLINE_ERROR_LINE
 } PangoUnderline;
 
-
-/**
- * PangoOverline:
- * @PANGO_OVERLINE_NONE: no overline should be drawn
- * @PANGO_OVERLINE_SINGLE: Draw a single line above the ink
- *   extents of the text being underlined.
- *
- * The `PangoOverline` enumeration is used to specify whether text
- * should be overlined, and if so, the type of line.
- *
- * Since: 1.46
- */
-typedef enum {
-  PANGO_OVERLINE_NONE,
-  PANGO_OVERLINE_SINGLE
-} PangoOverline;
-
-/**
- * PangoShowFlags:
- * @PANGO_SHOW_NONE: No special treatment for invisible characters
- * @PANGO_SHOW_SPACES: Render spaces, tabs and newlines visibly
- * @PANGO_SHOW_LINE_BREAKS: Render line breaks visibly
- * @PANGO_SHOW_IGNORABLES: Render default-ignorable Unicode
- *   characters visibly
- *
- * These flags affect how Pango treats characters that are normally
- * not visible in the output.
- *
- * Since: 1.44
- */
-typedef enum {
-  PANGO_SHOW_NONE        = 0,
-  PANGO_SHOW_SPACES      = 1 << 0,
-  PANGO_SHOW_LINE_BREAKS = 1 << 1,
-  PANGO_SHOW_IGNORABLES  = 1 << 2
-} PangoShowFlags;
-
-/**
- * PangoTextTransform:
- * @PANGO_TEXT_TRANSFORM_NONE: Leave text unchanged
- * @PANGO_TEXT_TRANSFORM_LOWERCASE: Display letters and numbers as lowercase
- * @PANGO_TEXT_TRANSFORM_UPPERCASE: Display letters and numbers as uppercase
- * @PANGO_TEXT_TRANSFORM_CAPITALIZE: Display the first character of a word
- *   in titlecase
- *
- * An enumeration that affects how Pango treats characters during shaping.
- *
- * Since: 1.50
- */
-typedef enum {
-  PANGO_TEXT_TRANSFORM_NONE,
-  PANGO_TEXT_TRANSFORM_LOWERCASE,
-  PANGO_TEXT_TRANSFORM_UPPERCASE,
-  PANGO_TEXT_TRANSFORM_CAPITALIZE,
-} PangoTextTransform;
+PANGO_AVAILABLE_IN_ALL
+PangoAttribute *        pango_attr_underline_new                (PangoUnderline              underline);
+PANGO_AVAILABLE_IN_1_8
+PangoAttribute *        pango_attr_underline_color_new          (guint16                     red,
+                                                                 guint16                     green,
+                                                                 guint16                     blue);
+PANGO_AVAILABLE_IN_ALL
+PangoAttribute *        pango_attr_strikethrough_new            (gboolean                    strikethrough);
+PANGO_AVAILABLE_IN_1_8
+PangoAttribute *        pango_attr_strikethrough_color_new      (guint16                     red,
+                                                                 guint16                     green,
+                                                                 guint16                     blue);
+PANGO_AVAILABLE_IN_ALL
+PangoAttribute *        pango_attr_rise_new                     (int                         rise);
 
 /**
  * PangoBaselineShift:
@@ -259,6 +226,9 @@ typedef enum {
   PANGO_BASELINE_SHIFT_SUBSCRIPT,
 } PangoBaselineShift;
 
+PANGO_AVAILABLE_IN_1_50
+PangoAttribute *        pango_attr_baseline_shift_new           (int                         shift);
+
 /**
  * PangoFontScale:
  * @PANGO_FONT_SCALE_NONE: Leave the font size unchanged
@@ -278,147 +248,6 @@ typedef enum {
   PANGO_FONT_SCALE_SMALL_CAPS,
 } PangoFontScale;
 
-/**
- * PANGO_ATTR_INDEX_FROM_TEXT_BEGINNING:
- *
- * Value for @start_index in `PangoAttribute` that indicates
- * the beginning of the text.
- *
- * Since: 1.24
- */
-#define PANGO_ATTR_INDEX_FROM_TEXT_BEGINNING ((guint)0)
-
-/**
- * PANGO_ATTR_INDEX_TO_TEXT_END: (value 4294967295)
- *
- * Value for @end_index in `PangoAttribute` that indicates
- * the end of the text.
- *
- * Since: 1.24
- */
-#define PANGO_ATTR_INDEX_TO_TEXT_END ((guint)(G_MAXUINT + 0))
-
-/**
- * PangoAttribute:
- * @klass: the class structure holding information about the type of the attribute
- * @start_index: the start index of the range (in bytes).
- * @end_index: end index of the range (in bytes). The character at this index
- *   is not included in the range.
- *
- * The `PangoAttribute` structure represents the common portions of all
- * attributes.
- *
- * Particular types of attributes include this structure as their initial
- * portion. The common portion of the attribute holds the range to which
- * the value in the type-specific part of the attribute applies and should
- * be initialized using [method Pango Attribute init]. By default, an attribute
- * will have an all-inclusive range of [0,%G_MAXUINT].
- */
-struct _PangoAttribute
-{
-  PangoAttrType type;
-  guint start_index;
-  guint end_index;
-  union {
-    char *str_value;
-    int  int_value;
-    gboolean boolean_value;
-    double double_value;
-    PangoColor color_value;
-    PangoLanguage *lang_value;
-    PangoFontDescription *font_value;
-    gpointer pointer_value;
-  };
-};
-
-
-/**
- * PangoAttrFilterFunc:
- * @attribute: a Pango attribute
- * @user_data: user data passed to the function
- *
- * Type of a function filtering a list of attributes.
- *
- * Return value: %TRUE if the attribute should be selected for
- *   filtering, %FALSE otherwise.
- */
-typedef gboolean (*PangoAttrFilterFunc) (PangoAttribute *attribute,
-                                         gpointer        user_data);
-
-/**
- * PangoAttrDataCopyFunc:
- * @user_data: user data to copy
- *
- * Type of a function that can duplicate user data for an attribute.
- *
- * Return value: new copy of @user_data.
- **/
-typedef gpointer (*PangoAttrDataCopyFunc) (gconstpointer user_data);
-
-typedef char * (*PangoAttrDataSerializeFunc) (gconstpointer user_data);
-
-PANGO_AVAILABLE_IN_ALL
-GType                   pango_attribute_get_type                (void) G_GNUC_CONST;
-
-PANGO_AVAILABLE_IN_ALL
-PangoAttrType           pango_attr_type_register                (PangoAttrDataCopyFunc       copy,
-                                                                 GDestroyNotify              destroy,
-                                                                 GEqualFunc                  equal,
-                                                                 const char                 *name,
-                                                                 PangoAttrDataSerializeFunc  serialize);
-PANGO_AVAILABLE_IN_1_22
-const char *            pango_attr_type_get_name                (PangoAttrType               type) 
G_GNUC_CONST;
-PANGO_AVAILABLE_IN_ALL
-PangoAttribute *        pango_attribute_copy                    (const PangoAttribute       *attr);
-PANGO_AVAILABLE_IN_ALL
-void                    pango_attribute_destroy                 (PangoAttribute             *attr);
-PANGO_AVAILABLE_IN_ALL
-gboolean                pango_attribute_equal                   (const PangoAttribute       *attr1,
-                                                                 const PangoAttribute       *attr2) 
G_GNUC_PURE;
-
-PANGO_AVAILABLE_IN_ALL
-PangoAttribute *        pango_attr_language_new                 (PangoLanguage              *language);
-PANGO_AVAILABLE_IN_ALL
-PangoAttribute *        pango_attr_family_new                   (const char                 *family);
-PANGO_AVAILABLE_IN_ALL
-PangoAttribute *        pango_attr_foreground_new               (guint16                     red,
-                                                                 guint16                     green,
-                                                                 guint16                     blue);
-PANGO_AVAILABLE_IN_ALL
-PangoAttribute *        pango_attr_background_new               (guint16                     red,
-                                                                 guint16                     green,
-                                                                 guint16                     blue);
-PANGO_AVAILABLE_IN_ALL
-PangoAttribute *        pango_attr_size_new                     (int                         size);
-PANGO_AVAILABLE_IN_1_8
-PangoAttribute *        pango_attr_size_new_absolute            (int                         size);
-PANGO_AVAILABLE_IN_ALL
-PangoAttribute *        pango_attr_style_new                    (PangoStyle                  style);
-PANGO_AVAILABLE_IN_ALL
-PangoAttribute *        pango_attr_weight_new                   (PangoWeight                 weight);
-PANGO_AVAILABLE_IN_ALL
-PangoAttribute *        pango_attr_variant_new                  (PangoVariant                variant);
-PANGO_AVAILABLE_IN_ALL
-PangoAttribute *        pango_attr_stretch_new                  (PangoStretch                stretch);
-PANGO_AVAILABLE_IN_ALL
-PangoAttribute *        pango_attr_font_desc_new                (const PangoFontDescription *desc);
-
-PANGO_AVAILABLE_IN_ALL
-PangoAttribute *        pango_attr_underline_new                (PangoUnderline              underline);
-PANGO_AVAILABLE_IN_1_8
-PangoAttribute *        pango_attr_underline_color_new          (guint16                     red,
-                                                                 guint16                     green,
-                                                                 guint16                     blue);
-PANGO_AVAILABLE_IN_ALL
-PangoAttribute *        pango_attr_strikethrough_new            (gboolean                    strikethrough);
-PANGO_AVAILABLE_IN_1_8
-PangoAttribute *        pango_attr_strikethrough_color_new      (guint16                     red,
-                                                                 guint16                     green,
-                                                                 guint16                     blue);
-PANGO_AVAILABLE_IN_ALL
-PangoAttribute *        pango_attr_rise_new                     (int                         rise);
-PANGO_AVAILABLE_IN_1_50
-PangoAttribute *        pango_attr_baseline_shift_new           (int                         shift);
 PANGO_AVAILABLE_IN_1_50
 PangoAttribute *        pango_attr_font_scale_new               (PangoFontScale              scale);
 PANGO_AVAILABLE_IN_ALL
@@ -439,7 +268,6 @@ PANGO_AVAILABLE_IN_1_38
 PangoAttribute *        pango_attr_background_alpha_new         (guint16                      alpha);
 PANGO_AVAILABLE_IN_1_44
 PangoAttribute *        pango_attr_allow_breaks_new             (gboolean                     allow_breaks);
-
 PANGO_AVAILABLE_IN_1_50
 PangoAttribute *        pango_attr_word_new                     (void);
 PANGO_AVAILABLE_IN_1_50
@@ -449,12 +277,50 @@ PangoAttribute *        pango_attr_paragraph_new                (void);
 
 PANGO_AVAILABLE_IN_1_44
 PangoAttribute *        pango_attr_insert_hyphens_new           (gboolean                     
insert_hyphens);
+
+/**
+ * PangoOverline:
+ * @PANGO_OVERLINE_NONE: no overline should be drawn
+ * @PANGO_OVERLINE_SINGLE: Draw a single line above the ink
+ *   extents of the text being underlined.
+ *
+ * The `PangoOverline` enumeration is used to specify whether text
+ * should be overlined, and if so, the type of line.
+ *
+ * Since: 1.46
+ */
+typedef enum {
+  PANGO_OVERLINE_NONE,
+  PANGO_OVERLINE_SINGLE
+} PangoOverline;
+
 PANGO_AVAILABLE_IN_1_46
 PangoAttribute *        pango_attr_overline_new                 (PangoOverline                overline);
 PANGO_AVAILABLE_IN_1_46
 PangoAttribute *        pango_attr_overline_color_new           (guint16                      red,
                                                                  guint16                      green,
                                                                  guint16                      blue);
+
+/**
+ * PangoShowFlags:
+ * @PANGO_SHOW_NONE: No special treatment for invisible characters
+ * @PANGO_SHOW_SPACES: Render spaces, tabs and newlines visibly
+ * @PANGO_SHOW_LINE_BREAKS: Render line breaks visibly
+ * @PANGO_SHOW_IGNORABLES: Render default-ignorable Unicode
+ *   characters visibly
+ *
+ * These flags affect how Pango treats characters that are normally
+ * not visible in the output.
+ *
+ * Since: 1.44
+ */
+typedef enum {
+  PANGO_SHOW_NONE        = 0,
+  PANGO_SHOW_SPACES      = 1 << 0,
+  PANGO_SHOW_LINE_BREAKS = 1 << 1,
+  PANGO_SHOW_IGNORABLES  = 1 << 2
+} PangoShowFlags;
+
 PANGO_AVAILABLE_IN_1_44
 PangoAttribute *        pango_attr_show_new                     (PangoShowFlags               flags);
 PANGO_AVAILABLE_IN_1_50
@@ -463,154 +329,26 @@ PANGO_AVAILABLE_IN_1_50
 PangoAttribute *        pango_attr_line_height_new_absolute     (int                          height);
 PANGO_AVAILABLE_IN_ALL
 PangoAttribute *        pango_attr_line_spacing_new             (int                          spacing);
-PANGO_AVAILABLE_IN_1_50
-PangoAttribute *        pango_attr_text_transform_new           (PangoTextTransform transform);
-PANGO_AVAILABLE_IN_ALL
-PangoAttribute *        pango_attr_custom_new                   (PangoAttrType                type,
-                                                                 gpointer                     user_data);
-
-PANGO_AVAILABLE_IN_ALL
-gboolean                pango_attribute_get_string              (PangoAttribute              *attribute,
-                                                                 const char                 **value);
-PANGO_AVAILABLE_IN_ALL
-gboolean                pango_attribute_get_language            (PangoAttribute              *attribute,
-                                                                 PangoLanguage              **value);
-PANGO_AVAILABLE_IN_ALL
-gboolean                pango_attribute_get_int                 (PangoAttribute              *attribute,
-                                                                 int                         *value);
-PANGO_AVAILABLE_IN_ALL
-gboolean                pango_attribute_get_boolean             (PangoAttribute              *attribute,
-                                                                 gboolean                    *value);
-PANGO_AVAILABLE_IN_ALL
-gboolean                pango_attribute_get_float               (PangoAttribute              *attribute,
-                                                                 double                      *value);
-PANGO_AVAILABLE_IN_ALL
-gboolean                pango_attribute_get_color               (PangoAttribute              *attribute,
-                                                                 PangoColor                  *value);
-PANGO_AVAILABLE_IN_ALL
-gboolean                pango_attribute_get_font_desc           (PangoAttribute              *attribute,
-                                                                 PangoFontDescription       **value);
-
-PANGO_AVAILABLE_IN_ALL
-gboolean                pango_attribute_get_custom              (PangoAttribute              *attribute,
-                                                                 gpointer                    *value);
-
-
-
-/* Attribute lists */
 
-typedef struct _PangoAttrList     PangoAttrList;
-typedef struct _PangoAttrIterator PangoAttrIterator;
-
-#define PANGO_TYPE_ATTR_LIST pango_attr_list_get_type ()
-
-/**
- * PangoAttrIterator:
- *
- * A `PangoAttrIterator` is used to iterate through a `PangoAttrList`.
- *
- * A new iterator is created with [method@Pango.AttrList.get_iterator].
- * Once the iterator is created, it can be advanced through the style
- * changes in the text using [method Pango AttrIterator next]. At each
- * style change, the range of the current style segment and the attributes
- * currently in effect can be queried.
- */
-
-/**
- * PangoAttrList:
- *
- * A `PangoAttrList` represents a list of attributes that apply to a section
- * of text.
- *
- * The attributes in a `PangoAttrList` are, in general, allowed to overlap in
- * an arbitrary fashion. However, if the attributes are manipulated only through
- * [method@Pango.AttrList.change], the overlap between properties will meet
- * stricter criteria.
+/*
+ * PangoTextTransform:
+ * @PANGO_TEXT_TRANSFORM_NONE: Leave text unchanged
+ * @PANGO_TEXT_TRANSFORM_LOWERCASE: Display letters and numbers as lowercase
+ * @PANGO_TEXT_TRANSFORM_UPPERCASE: Display letters and numbers as uppercase
+ * @PANGO_TEXT_TRANSFORM_CAPITALIZE: Display the first character of a word
+ *   in titlecase
  *
- * Since the `PangoAttrList` structure is stored as a linear list, it is not
- * suitable for storing attributes for large amounts of text. In general, you
- * should not use a single `PangoAttrList` for more than one paragraph of text.
- */
-
-PANGO_AVAILABLE_IN_ALL
-GType                   pango_attr_list_get_type        (void) G_GNUC_CONST;
-
-PANGO_AVAILABLE_IN_ALL
-PangoAttrList *         pango_attr_list_new             (void);
-PANGO_AVAILABLE_IN_1_10
-PangoAttrList *         pango_attr_list_ref             (PangoAttrList         *list);
-PANGO_AVAILABLE_IN_ALL
-void                    pango_attr_list_unref           (PangoAttrList         *list);
-PANGO_AVAILABLE_IN_ALL
-PangoAttrList *         pango_attr_list_copy            (PangoAttrList         *list);
-PANGO_AVAILABLE_IN_ALL
-void                    pango_attr_list_insert          (PangoAttrList         *list,
-                                                         PangoAttribute        *attr);
-PANGO_AVAILABLE_IN_ALL
-void                    pango_attr_list_insert_before   (PangoAttrList         *list,
-                                                         PangoAttribute        *attr);
-PANGO_AVAILABLE_IN_ALL
-void                    pango_attr_list_change          (PangoAttrList         *list,
-                                                         PangoAttribute        *attr);
-PANGO_AVAILABLE_IN_ALL
-void                    pango_attr_list_splice          (PangoAttrList         *list,
-                                                         PangoAttrList         *other,
-                                                         int                    pos,
-                                                         int                    len);
-PANGO_AVAILABLE_IN_1_44
-void                    pango_attr_list_update          (PangoAttrList         *list,
-                                                         int                    pos,
-                                                         int                    remove,
-                                                         int                    add);
-
-PANGO_AVAILABLE_IN_1_2
-PangoAttrList *         pango_attr_list_filter          (PangoAttrList         *list,
-                                                         PangoAttrFilterFunc    func,
-                                                         gpointer               data);
-
-PANGO_AVAILABLE_IN_1_44
-GSList *                pango_attr_list_get_attributes  (PangoAttrList         *list);
-
-PANGO_AVAILABLE_IN_1_46
-gboolean                pango_attr_list_equal           (PangoAttrList         *list,
-                                                         PangoAttrList         *other_list);
+ * An enumeration that affects how Pango treats characters during shaping.
+  */
+typedef enum {
+  PANGO_TEXT_TRANSFORM_NONE,
+  PANGO_TEXT_TRANSFORM_LOWERCASE,
+  PANGO_TEXT_TRANSFORM_UPPERCASE,
+  PANGO_TEXT_TRANSFORM_CAPITALIZE,
+} PangoTextTransform;
 
 PANGO_AVAILABLE_IN_1_50
-char *                  pango_attr_list_to_string       (PangoAttrList         *list);
-PANGO_AVAILABLE_IN_1_50
-PangoAttrList *         pango_attr_list_from_string     (const char            *text);
-
-PANGO_AVAILABLE_IN_1_44
-GType                   pango_attr_iterator_get_type    (void) G_GNUC_CONST;
-
-PANGO_AVAILABLE_IN_ALL
-PangoAttrIterator *     pango_attr_list_get_iterator    (PangoAttrList         *list);
-
-PANGO_AVAILABLE_IN_ALL
-void                    pango_attr_iterator_range       (PangoAttrIterator     *iterator,
-                                                         int                   *start,
-                                                         int                   *end);
-PANGO_AVAILABLE_IN_ALL
-gboolean                pango_attr_iterator_next        (PangoAttrIterator     *iterator);
-PANGO_AVAILABLE_IN_ALL
-PangoAttrIterator *     pango_attr_iterator_copy        (PangoAttrIterator     *iterator);
-PANGO_AVAILABLE_IN_ALL
-void                    pango_attr_iterator_destroy     (PangoAttrIterator     *iterator);
-PANGO_AVAILABLE_IN_ALL
-PangoAttribute *        pango_attr_iterator_get         (PangoAttrIterator     *iterator,
-                                                         PangoAttrType          type);
-PANGO_AVAILABLE_IN_ALL
-void                    pango_attr_iterator_get_font    (PangoAttrIterator     *iterator,
-                                                         PangoFontDescription  *desc,
-                                                         PangoLanguage        **language,
-                                                         GSList               **extra_attrs);
-PANGO_AVAILABLE_IN_1_2
-GSList *                pango_attr_iterator_get_attrs   (PangoAttrIterator     *iterator);
+PangoAttribute *        pango_attr_text_transform_new           (PangoTextTransform transform);
 
-G_DEFINE_AUTOPTR_CLEANUP_FUNC(PangoAttribute, pango_attribute_destroy)
-G_DEFINE_AUTOPTR_CLEANUP_FUNC(PangoAttrList, pango_attr_list_unref)
-G_DEFINE_AUTOPTR_CLEANUP_FUNC(PangoAttrIterator, pango_attr_iterator_destroy)
 
 G_END_DECLS
-
-#endif /* __PANGO_ATTRIBUTES_H__ */
diff --git a/pango/pango-glyph-item.c b/pango/pango-glyph-item.c
index 7eb1737d..d128f7f8 100644
--- a/pango/pango-glyph-item.c
+++ b/pango/pango-glyph-item.c
@@ -24,7 +24,8 @@
 
 #include "pango-glyph-item.h"
 #include "pango-impl-utils.h"
-#include "pango-attributes-private.h"
+#include "pango-attr-list-private.h"
+#include "pango-attr-iterator-private.h"
 
 #define LTR(glyph_item) (((glyph_item)->item->analysis.level % 2) == 0)
 
@@ -617,7 +618,7 @@ pango_glyph_item_apply_attrs (PangoGlyphItem   *glyph_item,
 
   /* Advance the attr iterator to the start of the item
    */
-  _pango_attr_list_get_iterator (list, &iter);
+  pango_attr_list_init_iterator (list, &iter);
   do
     {
       pango_attr_iterator_range (&iter, &range_start, &range_end);
@@ -713,7 +714,7 @@ pango_glyph_item_apply_attrs (PangoGlyphItem   *glyph_item,
   if (LTR (glyph_item))
     result = g_slist_reverse (result);
 
-  _pango_attr_iterator_destroy (&iter);
+  pango_attr_iterator_clear (&iter);
 
   return result;
 }
diff --git a/pango/pango-item.h b/pango/pango-item.h
index d04de33d..92b43029 100644
--- a/pango/pango-item.h
+++ b/pango/pango-item.h
@@ -23,7 +23,8 @@
 #define __PANGO_ITEM_H__
 
 #include <pango/pango-types.h>
-#include <pango/pango-attributes.h>
+#include <pango/pango-attr-list.h>
+#include <pango/pango-attr-list.h>
 
 G_BEGIN_DECLS
 
diff --git a/pango/pango-line-breaker.c b/pango/pango-line-breaker.c
index 4230369e..1429fa7f 100644
--- a/pango/pango-line-breaker.c
+++ b/pango/pango-line-breaker.c
@@ -6,6 +6,8 @@
 #include "pango-tabs.h"
 #include "pango-impl-utils.h"
 #include "pango-attributes-private.h"
+#include "pango-attr-list-private.h"
+#include "pango-attr-iterator-private.h"
 #include "pango-item-private.h"
 #include "pango-utils-internal.h"
 
@@ -169,7 +171,7 @@ apply_attributes_to_items (GList         *items,
   if (!attrs)
     return;
 
-  _pango_attr_list_get_iterator (attrs, &iter);
+  pango_attr_list_init_iterator (attrs, &iter);
 
   for (l = items; l; l = l->next)
     {
@@ -177,7 +179,7 @@ apply_attributes_to_items (GList         *items,
       pango_item_apply_attrs (item, &iter);
     }
 
-  _pango_attr_iterator_destroy (&iter);
+  pango_attr_iterator_clear (&iter);
 }
 
 static PangoLogAttr *
@@ -455,12 +457,12 @@ ensure_tab_width (PangoLineBreaker *self)
         {
           PangoAttrIterator iter;
 
-          _pango_attr_list_get_iterator (attrs, &iter);
+          pango_attr_list_init_iterator (attrs, &iter);
           pango_attr_iterator_get_font (&iter, font_desc, &language, NULL);
-          _pango_attr_iterator_destroy (&iter);
+          pango_attr_iterator_clear (&iter);
         }
 
-      _pango_attr_list_init (&tmp_attrs);
+      pango_attr_list_init (&tmp_attrs);
       attr = pango_attr_font_desc_new (font_desc);
       pango_font_description_free (font_desc);
       pango_attr_list_insert_before (&tmp_attrs, attr);
@@ -480,7 +482,7 @@ ensure_tab_width (PangoLineBreaker *self)
           attrs = NULL;
         }
 
-      _pango_attr_list_destroy (&tmp_attrs);
+      pango_attr_list_destroy (&tmp_attrs);
 
       item = items->data;
       pango_shape ("        ", 8, "        ", 8, &item->analysis, glyphs, shape_flags);
diff --git a/pango/pango-line.c b/pango/pango-line.c
index 60544f8d..a3e9c8ac 100644
--- a/pango/pango-line.c
+++ b/pango/pango-line.c
@@ -5,6 +5,7 @@
 #include "pango-tabs.h"
 #include "pango-impl-utils.h"
 #include "pango-attributes-private.h"
+#include "pango-attr-iterator-private.h"
 #include "pango-item-private.h"
 #include "pango-run-private.h"
 
@@ -436,7 +437,7 @@ pango_line_get_empty_extents (PangoLine        *line,
       PangoAttrIterator iter;
       int start, end;
 
-      _pango_attr_list_get_iterator (line->data->attrs, &iter);
+      pango_attr_list_init_iterator (line->data->attrs, &iter);
 
       do
         {
@@ -467,7 +468,7 @@ pango_line_get_empty_extents (PangoLine        *line,
         }
       while (pango_attr_iterator_next (&iter));
 
-      _pango_attr_iterator_destroy (&iter);
+      pango_attr_iterator_clear (&iter);
     }
 
   memset (logical_rect, 0, sizeof (PangoRectangle));
diff --git a/pango/pango-markup.h b/pango/pango-markup.h
index 003ee51a..b30edb8d 100644
--- a/pango/pango-markup.h
+++ b/pango/pango-markup.h
@@ -22,7 +22,7 @@
 #ifndef __PANGO_MARKUP_H__
 #define __PANGO_MARKUP_H__
 
-#include <pango/pango-attributes.h>
+#include <pango/pango-attr-list.h>
 
 G_BEGIN_DECLS
 
diff --git a/pango/pango.h b/pango/pango.h
index e3816fd3..6623478b 100644
--- a/pango/pango.h
+++ b/pango/pango.h
@@ -22,6 +22,9 @@
 #ifndef __PANGO_H__
 #define __PANGO_H__
 
+#include <pango/pango-attr.h>
+#include <pango/pango-attr-list.h>
+#include <pango/pango-attr-iterator.h>
 #include <pango/pango-attributes.h>
 #include <pango/pango-break.h>
 #include <pango/pango-color.h>
diff --git a/pango/serializer.c b/pango/serializer.c
index d9c80226..2e4e501d 100644
--- a/pango/serializer.c
+++ b/pango/serializer.c
@@ -28,7 +28,8 @@
 #include <pango/pango-line-private.h>
 #include <pango/pango-utils-internal.h>
 #include <pango/pango-hbface.h>
-#include <pango/pango-attributes-private.h>
+#include <pango/pango-attributes.h>
+#include <pango/pango-attr-private.h>
 
 #include <hb-ot.h>
 #include "pango/json/gtkjsonparserprivate.h"


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]