summaryrefslogtreecommitdiff
path: root/pango/pango-attributes.c
diff options
context:
space:
mode:
Diffstat (limited to 'pango/pango-attributes.c')
-rw-r--r--pango/pango-attributes.c2264
1 files changed, 10 insertions, 2254 deletions
diff --git a/pango/pango-attributes.c b/pango/pango-attributes.c
index 73fd5799..8e8e1746 100644
--- a/pango/pango-attributes.c
+++ b/pango/pango-attributes.c
@@ -23,346 +23,10 @@
#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,39 +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;
-}
/* }}} */
-/* {{{ Public API */
+/* {{{ Attribute types */
/**
* pango_attr_family_new:
@@ -1214,1884 +848,6 @@ 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;
-}
-
-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;
-}
-
-/* }}} */
-/* {{{ 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_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;
-}
-
-/* }}} */
-/* {{{ 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: */