summaryrefslogtreecommitdiff
path: root/pango2/pango-attr.c
diff options
context:
space:
mode:
Diffstat (limited to 'pango2/pango-attr.c')
-rw-r--r--pango2/pango-attr.c761
1 files changed, 761 insertions, 0 deletions
diff --git a/pango2/pango-attr.c b/pango2/pango-attr.c
new file mode 100644
index 00000000..5f7876d3
--- /dev/null
+++ b/pango2/pango-attr.c
@@ -0,0 +1,761 @@
+/* Pango2
+ * 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-attributes-private.h"
+#include "pango-impl-utils.h"
+
+/**
+ * Pango2Attribute:
+ *
+ * A `Pango2Attribute` structure associates a named attribute with
+ * a certain range of a text.
+ *
+ * Attributes can have basic types, such as int, float, boolean
+ * `Pango2Color`, `Pango2FontDescription or `Pango2Language`. It is
+ * also possible to define new, custom attributes.
+ *
+ * By default, an attribute will have an all-inclusive range of
+ * `[0,G_MAXUINT]`.
+ */
+
+/* {{{ Generic attribute code */
+
+G_LOCK_DEFINE_STATIC (attr_type);
+static GArray *attr_type;
+
+#define MIN_CUSTOM 1000
+
+typedef struct _Pango2AttrClass Pango2AttrClass;
+
+struct _Pango2AttrClass {
+ guint type;
+ const char *name;
+ Pango2AttrDataCopyFunc copy;
+ GDestroyNotify destroy;
+ GEqualFunc equal;
+ Pango2AttrDataSerializeFunc serialize;
+};
+
+static const char *
+get_attr_type_nick (Pango2AttrType type)
+{
+ GEnumClass *enum_class;
+ GEnumValue *enum_value;
+
+ enum_class = g_type_class_ref (pango2_attr_type_get_type ());
+ enum_value = g_enum_get_value (enum_class, type);
+ g_type_class_unref (enum_class);
+
+ return enum_value->value_nick;
+}
+
+static gboolean
+is_valid_attr_type (guint type)
+{
+ switch (type)
+ {
+ case PANGO2_ATTR_INVALID:
+ return FALSE;
+ case PANGO2_ATTR_LANGUAGE:
+ case PANGO2_ATTR_FAMILY:
+ case PANGO2_ATTR_STYLE:
+ case PANGO2_ATTR_WEIGHT:
+ case PANGO2_ATTR_VARIANT:
+ case PANGO2_ATTR_STRETCH:
+ case PANGO2_ATTR_SIZE:
+ case PANGO2_ATTR_FONT_DESC:
+ case PANGO2_ATTR_FOREGROUND:
+ case PANGO2_ATTR_BACKGROUND:
+ case PANGO2_ATTR_UNDERLINE:
+ case PANGO2_ATTR_STRIKETHROUGH:
+ case PANGO2_ATTR_RISE:
+ case PANGO2_ATTR_SCALE:
+ case PANGO2_ATTR_FALLBACK:
+ case PANGO2_ATTR_LETTER_SPACING:
+ case PANGO2_ATTR_UNDERLINE_COLOR:
+ case PANGO2_ATTR_STRIKETHROUGH_COLOR:
+ case PANGO2_ATTR_ABSOLUTE_SIZE:
+ case PANGO2_ATTR_GRAVITY:
+ case PANGO2_ATTR_GRAVITY_HINT:
+ case PANGO2_ATTR_FONT_FEATURES:
+ case PANGO2_ATTR_ALLOW_BREAKS:
+ case PANGO2_ATTR_SHOW:
+ case PANGO2_ATTR_INSERT_HYPHENS:
+ case PANGO2_ATTR_OVERLINE:
+ case PANGO2_ATTR_OVERLINE_COLOR:
+ case PANGO2_ATTR_LINE_HEIGHT:
+ case PANGO2_ATTR_ABSOLUTE_LINE_HEIGHT:
+ case PANGO2_ATTR_TEXT_TRANSFORM:
+ case PANGO2_ATTR_WORD:
+ case PANGO2_ATTR_SENTENCE:
+ case PANGO2_ATTR_BASELINE_SHIFT:
+ case PANGO2_ATTR_FONT_SCALE:
+ case PANGO2_ATTR_SHAPE:
+ return TRUE;
+ default:
+ if (!attr_type)
+ return FALSE;
+ else
+ {
+ gboolean result = FALSE;
+
+ G_LOCK (attr_type);
+
+ for (int i = 0; i < attr_type->len; i++)
+ {
+ Pango2AttrClass *class = &g_array_index (attr_type, Pango2AttrClass, i);
+ if (class->type == type)
+ {
+ result = TRUE;
+ break;
+ }
+ }
+
+ G_UNLOCK (attr_type);
+
+ return result;
+ }
+ }
+}
+
+/**
+ * pango2_attr_type_register:
+ * @name: (nullable): an identifier for the type
+ * @value_type: the `Pango2AttrValueType` for the attribute
+ * @affects: `Pango2AttrAffects` flags for the attribute
+ * @merge: `Pango2AttrMerge` flags for the attribute
+ * @copy: (scope forever) (nullable): function to copy the data of an attribute
+ * of this type
+ * @destroy: (scope forever) (nullable): function to free the data of an attribute
+ * of this type
+ * @equal: (scope forever) (nullable): function to compare the data of two attributes
+ * of this type
+ * @serialize: (scope forever) (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@Pango2.AttrType.get_name].
+ *
+ * The callbacks are only needed if @type is `PANGO2_ATTR_VALUE_POINTER`,
+ * Pango2 knows how to handle other value types and will only use the
+ * callbacks for generic pointer values.
+ *
+ * If @name and @serialize are provided, they will be used
+ * to serialize attributes of this type.
+ *
+ * To create attributes with the new type, use [ctor@Pango2.Attribute.new].
+ *
+ * Return value: the attribute type ID
+ */
+guint
+pango2_attr_type_register (const char *name,
+ Pango2AttrValueType value_type,
+ Pango2AttrAffects affects,
+ Pango2AttrMerge merge,
+ Pango2AttrDataCopyFunc copy,
+ GDestroyNotify destroy,
+ GEqualFunc equal,
+ Pango2AttrDataSerializeFunc serialize)
+{
+ static guint current_id = MIN_CUSTOM; /* MT-safe */
+ Pango2AttrClass class;
+
+ G_LOCK (attr_type);
+
+ class.type = value_type | (affects << 8) | (merge << 12) | (current_id << 16);
+ 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 (Pango2AttrClass));
+
+ g_array_append_val (attr_type, class);
+
+ G_UNLOCK (attr_type);
+
+ return class.type;
+}
+
+/**
+ * pango2_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@Pango2.AttrType.register].
+ *
+ * The returned value is an interned string (see
+ * [func@GLib.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 Pango2
+ * attribute type or invalid.
+ */
+const char *
+pango2_attr_type_get_name (guint type)
+{
+ const char *result = NULL;
+
+ if ((type >> 16) < MIN_CUSTOM)
+ return get_attr_type_nick (type);
+
+ G_LOCK (attr_type);
+
+ for (int i = 0; i < attr_type->len; i++)
+ {
+ Pango2AttrClass *class = &g_array_index (attr_type, Pango2AttrClass, i);
+ if (class->type == type)
+ {
+ result = class->name;
+ break;
+ }
+ }
+
+ G_UNLOCK (attr_type);
+
+ return result;
+}
+
+/**
+ * pango2_attribute_copy:
+ * @attr: a `Pango2Attribute`
+ *
+ * Make a copy of an attribute.
+ *
+ * Return value: (transfer full): the newly allocated
+ * `Pango2Attribute`, which should be freed with
+ * [method@Pango2.Attribute.destroy].
+ */
+Pango2Attribute *
+pango2_attribute_copy (const Pango2Attribute *attr)
+{
+ Pango2Attribute *result;
+
+ g_return_val_if_fail (attr != NULL, NULL);
+
+ result = g_slice_dup (Pango2Attribute, attr);
+
+ switch (PANGO2_ATTR_VALUE_TYPE (attr))
+ {
+ case PANGO2_ATTR_VALUE_STRING:
+ result->str_value = g_strdup (attr->str_value);
+ break;
+
+ case PANGO2_ATTR_VALUE_FONT_DESC:
+ result->font_value = pango2_font_description_copy (attr->font_value);
+ break;
+
+ case PANGO2_ATTR_VALUE_POINTER:
+ if (attr->type == PANGO2_ATTR_SHAPE)
+ {
+ ShapeData *shape_data;
+
+ shape_data = g_memdup2 (attr->pointer_value, sizeof (ShapeData));
+ if (shape_data->copy)
+ shape_data->data = shape_data->copy (shape_data->data);
+
+ result->pointer_value = shape_data;
+ }
+ else
+ {
+ Pango2AttrDataCopyFunc copy = NULL;
+
+ G_LOCK (attr_type);
+
+ g_assert (attr_type != NULL);
+
+ for (int i = 0; i < attr_type->len; i++)
+ {
+ Pango2AttrClass *class = &g_array_index (attr_type, Pango2AttrClass, i);
+ if (class->type == attr->type)
+ {
+ copy = class->copy;
+ break;
+ }
+ }
+
+ G_UNLOCK (attr_type);
+
+ if (copy)
+ result->pointer_value = copy (attr->pointer_value);
+ }
+ break;
+
+ case PANGO2_ATTR_VALUE_INT:
+ case PANGO2_ATTR_VALUE_BOOLEAN:
+ case PANGO2_ATTR_VALUE_FLOAT:
+ case PANGO2_ATTR_VALUE_COLOR:
+ case PANGO2_ATTR_VALUE_LANGUAGE:
+ default: ;
+ }
+
+ return result;
+}
+
+/**
+ * pango2_attribute_destroy:
+ * @attr: a `Pango2Attribute`.
+ *
+ * Destroy a `Pango2Attribute` and free all associated memory.
+ */
+void
+pango2_attribute_destroy (Pango2Attribute *attr)
+{
+ g_return_if_fail (attr != NULL);
+
+ switch (PANGO2_ATTR_VALUE_TYPE (attr))
+ {
+ case PANGO2_ATTR_VALUE_STRING:
+ g_free (attr->str_value);
+ break;
+
+ case PANGO2_ATTR_VALUE_FONT_DESC:
+ pango2_font_description_free (attr->font_value);
+ break;
+
+ case PANGO2_ATTR_VALUE_POINTER:
+ if (attr->type == PANGO2_ATTR_SHAPE)
+ {
+ ShapeData *shape_data = attr->pointer_value;
+
+ if (shape_data->destroy)
+ shape_data->destroy (shape_data->data);
+
+ g_free (shape_data);
+ }
+ else
+ {
+ GDestroyNotify destroy = NULL;
+
+ G_LOCK (attr_type);
+
+ g_assert (attr_type != NULL);
+
+ for (int i = 0; i < attr_type->len; i++)
+ {
+ Pango2AttrClass *class = &g_array_index (attr_type, Pango2AttrClass, i);
+ if (class->type == attr->type)
+ {
+ destroy = class->destroy;
+ break;
+ }
+ }
+
+ G_UNLOCK (attr_type);
+
+ if (destroy)
+ destroy (attr->pointer_value);
+ }
+ break;
+
+ case PANGO2_ATTR_VALUE_INT:
+ case PANGO2_ATTR_VALUE_BOOLEAN:
+ case PANGO2_ATTR_VALUE_FLOAT:
+ case PANGO2_ATTR_VALUE_COLOR:
+ case PANGO2_ATTR_VALUE_LANGUAGE:
+ default: ;
+ }
+
+ g_slice_free (Pango2Attribute, attr);
+}
+
+G_DEFINE_BOXED_TYPE (Pango2Attribute, pango2_attribute,
+ pango2_attribute_copy,
+ pango2_attribute_destroy);
+
+/**
+ * pango2_attribute_equal:
+ * @attr1: a `Pango2Attribute`
+ * @attr2: another `Pango2Attribute`
+ *
+ * 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
+pango2_attribute_equal (const Pango2Attribute *attr1,
+ const Pango2Attribute *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 (PANGO2_ATTR_VALUE_TYPE (attr1))
+ {
+ case PANGO2_ATTR_VALUE_STRING:
+ return strcmp (attr1->str_value, attr2->str_value) == 0;
+
+ case PANGO2_ATTR_VALUE_INT:
+ return attr1->int_value == attr2->int_value;
+
+ case PANGO2_ATTR_VALUE_BOOLEAN:
+ return attr1->boolean_value == attr2->boolean_value;
+
+ case PANGO2_ATTR_VALUE_FLOAT:
+ return attr1->double_value == attr2->double_value;
+
+ case PANGO2_ATTR_VALUE_COLOR:
+ return memcmp (&attr1->color_value, &attr2->color_value, sizeof (Pango2Color)) == 0;
+
+ case PANGO2_ATTR_VALUE_LANGUAGE:
+ return attr1->lang_value == attr2->lang_value;
+
+ case PANGO2_ATTR_VALUE_FONT_DESC:
+ return pango2_font_description_equal (attr1->font_value, attr2->font_value);
+
+ case PANGO2_ATTR_VALUE_POINTER:
+ {
+ GEqualFunc equal = NULL;
+
+ G_LOCK (attr_type);
+
+ g_assert (attr_type != NULL);
+
+ for (int i = 0; i < attr_type->len; i++)
+ {
+ Pango2AttrClass *class = &g_array_index (attr_type, Pango2AttrClass, i);
+ if (class->type == attr1->type)
+ {
+ equal = class->equal;
+ break;
+ }
+ }
+
+ G_UNLOCK (attr_type);
+
+ if (equal)
+ return equal (attr1->pointer_value, attr2->pointer_value);
+
+ return attr1->pointer_value == attr2->pointer_value;
+ }
+
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+/**
+ * pango2_attribute_new:
+ * @type: the attribute type
+ * @value: pointer to the value to be copied, must be of the right type
+ *
+ * Creates a new attribute for the given type.
+ *
+ * The type must be one of the `Pango2AttrType` values, or
+ * have been registered with [func@Pango2.AttrType.register].
+ *
+ * Pango2 will initialize @start_index and @end_index to an
+ * all-inclusive range of `[0,G_MAXUINT]`. The value is copied.
+ *
+ * Return value: (transfer full): the newly allocated
+ * `Pango2Attribute`, which should be freed with
+ * [method@Pango2.Attribute.destroy]
+ */
+Pango2Attribute *
+pango2_attribute_new (guint type,
+ gconstpointer value)
+{
+ Pango2Attribute attr;
+
+ g_return_val_if_fail (is_valid_attr_type (type), NULL);
+
+ attr.type = type;
+ attr.start_index = PANGO2_ATTR_INDEX_FROM_TEXT_BEGINNING;
+ attr.end_index = PANGO2_ATTR_INDEX_TO_TEXT_END;
+
+ switch (PANGO2_ATTR_TYPE_VALUE_TYPE (type))
+ {
+ case PANGO2_ATTR_VALUE_STRING:
+ attr.str_value = (char *)value;
+ break;
+ case PANGO2_ATTR_VALUE_INT:
+ attr.int_value = *(int *)value;
+ break;
+ case PANGO2_ATTR_VALUE_BOOLEAN:
+ attr.boolean_value = *(gboolean *)value;
+ break;
+ case PANGO2_ATTR_VALUE_FLOAT:
+ attr.double_value = *(double *)value;
+ break;
+ case PANGO2_ATTR_VALUE_COLOR:
+ attr.color_value = *(Pango2Color *)value;
+ break;
+ case PANGO2_ATTR_VALUE_LANGUAGE:
+ attr.lang_value = (Pango2Language *)value;
+ break;
+ case PANGO2_ATTR_VALUE_FONT_DESC:
+ attr.font_value = (Pango2FontDescription *)value;
+ break;
+ case PANGO2_ATTR_VALUE_POINTER:
+ attr.pointer_value = (gpointer)value;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ /* Copy the value */
+ return pango2_attribute_copy (&attr);
+}
+
+/**
+ * pango2_attribute_type:
+ * @attribute: a `Pango2Attribute`
+ *
+ * Returns the type of @attribute, either a
+ * value from the [enum@Pango2.AttrType] enumeration
+ * or a registered custom type.
+ *
+ * Return value: the type of `Pango2Attribute`
+ */
+guint
+pango2_attribute_type (const Pango2Attribute *attribute)
+{
+ return attribute->type;
+}
+
+/* }}} */
+ /* {{{ Private API */
+
+char *
+pango2_attr_value_serialize (Pango2Attribute *attr)
+{
+ Pango2AttrDataSerializeFunc serialize = NULL;
+
+ G_LOCK (attr_type);
+
+ g_assert (attr_type != NULL);
+
+ for (int i = 0; i < attr_type->len; i++)
+ {
+ Pango2AttrClass *class = &g_array_index (attr_type, Pango2AttrClass, i);
+ if (class->type == attr->type)
+ {
+ serialize = class->serialize;
+ break;
+ }
+ }
+
+ G_UNLOCK (attr_type);
+
+ if (serialize)
+ return serialize (attr->pointer_value);
+
+ return g_strdup_printf ("%p", attr->pointer_value);
+}
+
+/* }}} */
+/* {{{ Binding Helpers */
+
+/**
+ * pango2_attribute_set_range:
+ * @attribute: a `Pango2Attribute`
+ * @start_index: start index
+ * @end_index: end index
+ *
+ * Sets the range of the attribute.
+ */
+void
+pango2_attribute_set_range (Pango2Attribute *attribute,
+ guint start_index,
+ guint end_index)
+{
+ attribute->start_index = start_index;
+ attribute->end_index = end_index;
+}
+
+/**
+ * pango2_attribute_get_range:
+ * @attribute: a `Pango2Attribute`
+ * @start_index: (out caller-allocates): return location for start index
+ * @end_index: (out caller-allocates): return location for end index
+ *
+ * Gets the range of the attribute.
+ */
+void
+pango2_attribute_get_range (Pango2Attribute *attribute,
+ guint *start_index,
+ guint *end_index)
+{
+ *start_index = attribute->start_index;
+ *end_index = attribute->end_index;
+}
+
+/**
+ * pango2_attribute_get_string:
+ * @attribute: a `Pango2Attribute`
+ *
+ * Gets the value of an attribute whose value type is string.
+ *
+ * Returns: (nullable): the string value
+ */
+const char *
+pango2_attribute_get_string (Pango2Attribute *attribute)
+{
+ if (PANGO2_ATTR_VALUE_TYPE (attribute) != PANGO2_ATTR_VALUE_STRING)
+ return NULL;
+
+ return attribute->str_value;
+}
+
+/**
+ * pango2_attribute_get_language:
+ * @attribute: a `Pango2Attribute`
+ *
+ * Gets the value of an attribute whose value type is `Pango2Language`.
+ *
+ * Returns: (nullable): the language value
+ */
+Pango2Language *
+pango2_attribute_get_language (Pango2Attribute *attribute)
+{
+ if (PANGO2_ATTR_VALUE_TYPE (attribute) != PANGO2_ATTR_VALUE_LANGUAGE)
+ return NULL;
+
+ return attribute->lang_value;
+}
+
+/**
+ * pango2_attribute_get_int:
+ * @attribute: a `Pango2Attribute`
+ *
+ * Gets the value of an attribute whose value type is `int`.
+ *
+ * Returns: the integer value, or 0
+ */
+int
+pango2_attribute_get_int (Pango2Attribute *attribute)
+{
+ if (PANGO2_ATTR_VALUE_TYPE (attribute) != PANGO2_ATTR_VALUE_INT)
+ return 0;
+
+ return attribute->int_value;
+}
+
+/**
+ * pango2_attribute_get_boolean:
+ * @attribute: a `Pango2Attribute`
+ *
+ * Gets the value of an attribute whose value type is `gboolean`.
+ *
+ * Returns: the boolean value, or `FALSE`
+ */
+gboolean
+pango2_attribute_get_boolean (Pango2Attribute *attribute)
+{
+ if (PANGO2_ATTR_VALUE_TYPE (attribute) != PANGO2_ATTR_VALUE_BOOLEAN)
+ return FALSE;
+
+ return attribute->boolean_value;
+}
+
+/**
+ * pango2_attribute_get_float:
+ * @attribute: a `Pango2Attribute`
+ *
+ * Gets the value of an attribute whose value type is `double`.
+ *
+ * Returns: the float value, or 0
+ */
+double
+pango2_attribute_get_float (Pango2Attribute *attribute)
+{
+ if (PANGO2_ATTR_VALUE_TYPE (attribute) != PANGO2_ATTR_VALUE_FLOAT)
+ return 0.;
+
+ return attribute->double_value;
+}
+
+/**
+ * pango2_attribute_get_color:
+ * @attribute: a `Pango2Attribute`
+ *
+ * Gets the value of an attribute whose value type is `Pango2Color`.
+ *
+ * Returns: (nullable): pointer to the color value
+ */
+Pango2Color *
+pango2_attribute_get_color (Pango2Attribute *attribute)
+{
+ if (PANGO2_ATTR_VALUE_TYPE (attribute) != PANGO2_ATTR_VALUE_COLOR)
+ return NULL;
+
+ return &attribute->color_value;
+}
+
+/**
+ * pango2_attribute_get_font_desc:
+ * @attribute: a `Pango2Attribute`
+ *
+ * Gets the value of an attribute whose value type is `Pango2FontDescription`.
+ *
+ * Returns: (nullable): the font description
+ */
+Pango2FontDescription *
+pango2_attribute_get_font_desc (Pango2Attribute *attribute)
+{
+ if (PANGO2_ATTR_VALUE_TYPE (attribute) != PANGO2_ATTR_VALUE_FONT_DESC)
+ return NULL;
+
+ return attribute->font_value;
+}
+
+/**
+ * pango2_attribute_get_pointer:
+ * @attribute: a `Pango2Attribute`
+ *
+ * Gets the value of an attribute whose value type is `gpointer`.
+ *
+ * Returns: (nullable): the pointer value
+ */
+gpointer
+pango2_attribute_get_pointer (Pango2Attribute *attribute)
+{
+ if (PANGO2_ATTR_VALUE_TYPE (attribute) != PANGO2_ATTR_VALUE_POINTER)
+ return NULL;
+
+ return attribute->pointer_value;
+}
+
+/* }}} */
+
+/* vim:set foldmethod=marker expandtab: */