From dec6c0868ef2c36690dc831f6f892a7d835a361a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Fri, 17 Apr 2020 11:38:46 +0200 Subject: attrs: Save iterator stack in a GPtrArray One less linked list. --- pango/pango-attributes-private.h | 2 +- pango/pango-attributes.c | 128 +++++++++++++++++++++------------------ 2 files changed, 71 insertions(+), 59 deletions(-) diff --git a/pango/pango-attributes-private.h b/pango/pango-attributes-private.h index b913cc2f..230feb3d 100644 --- a/pango/pango-attributes-private.h +++ b/pango/pango-attributes-private.h @@ -23,7 +23,7 @@ struct _PangoAttrIterator { GSList *next_attribute; - GList *attribute_stack; + GPtrArray *attribute_stack; guint start_index; guint end_index; }; diff --git a/pango/pango-attributes.c b/pango/pango-attributes.c index 97c7aeaf..44b553fc 100644 --- a/pango/pango-attributes.c +++ b/pango/pango-attributes.c @@ -2073,43 +2073,46 @@ pango_attr_iterator_range (PangoAttrIterator *iterator, gboolean pango_attr_iterator_next (PangoAttrIterator *iterator) { - GList *tmp_list; + guint i; g_return_val_if_fail (iterator != NULL, FALSE); - if (!iterator->next_attribute && !iterator->attribute_stack) + if (!iterator->next_attribute && + (!iterator->attribute_stack || iterator->attribute_stack->len == 0)) return FALSE; iterator->start_index = iterator->end_index; iterator->end_index = G_MAXUINT; - tmp_list = iterator->attribute_stack; - while (tmp_list) + if (iterator->attribute_stack) { - GList *next = tmp_list->next; - PangoAttribute *attr = tmp_list->data; - - if (attr->end_index == iterator->start_index) - { - iterator->attribute_stack = g_list_remove_link (iterator->attribute_stack, tmp_list); - g_list_free_1 (tmp_list); - } - else - { - iterator->end_index = MIN (iterator->end_index, attr->end_index); - } + for (i = 0; i < iterator->attribute_stack->len; i++) + { + const PangoAttribute *attr = g_ptr_array_index (iterator->attribute_stack, i); - tmp_list = next; + if (attr->end_index == iterator->start_index) + { + g_ptr_array_remove_index (iterator->attribute_stack, i); /* Can't use index_fast :( */; + i--; + } + else + { + iterator->end_index = MIN (iterator->end_index, attr->end_index); + } + } } while (iterator->next_attribute && - ((PangoAttribute *)iterator->next_attribute->data)->start_index == iterator->start_index) + ((PangoAttribute *)iterator->next_attribute->data)->start_index == iterator->start_index) { if (((PangoAttribute *)iterator->next_attribute->data)->end_index > iterator->start_index) - { - iterator->attribute_stack = g_list_prepend (iterator->attribute_stack, iterator->next_attribute->data); - iterator->end_index = MIN (iterator->end_index, ((PangoAttribute *)iterator->next_attribute->data)->end_index); - } + { + if (G_UNLIKELY (!iterator->attribute_stack)) + iterator->attribute_stack = g_ptr_array_new (); + + g_ptr_array_add (iterator->attribute_stack, iterator->next_attribute->data); + iterator->end_index = MIN (iterator->end_index, ((PangoAttribute *)iterator->next_attribute->data)->end_index); + } iterator->next_attribute = iterator->next_attribute->next; } @@ -2140,7 +2143,10 @@ pango_attr_iterator_copy (PangoAttrIterator *iterator) *copy = *iterator; - copy->attribute_stack = g_list_copy (iterator->attribute_stack); + if (iterator->attribute_stack) + copy->attribute_stack = g_ptr_array_copy (iterator->attribute_stack, NULL, NULL); + else + copy->attribute_stack = NULL; return copy; } @@ -2148,7 +2154,8 @@ pango_attr_iterator_copy (PangoAttrIterator *iterator) void _pango_attr_iterator_destroy (PangoAttrIterator *iterator) { - g_list_free (iterator->attribute_stack); + if (iterator->attribute_stack) + g_ptr_array_free (iterator->attribute_stack, TRUE); } /** @@ -2184,19 +2191,19 @@ PangoAttribute * pango_attr_iterator_get (PangoAttrIterator *iterator, PangoAttrType type) { - GList *tmp_list; + guint i; g_return_val_if_fail (iterator != NULL, NULL); - tmp_list = iterator->attribute_stack; - while (tmp_list) + if (!iterator->attribute_stack) + return NULL; + + for (i = 0; i < iterator->attribute_stack->len; i++) { - PangoAttribute *attr = tmp_list->data; + PangoAttribute *attr = g_ptr_array_index (iterator->attribute_stack, i); if (attr->klass->type == type) - return attr; - - tmp_list = tmp_list->next; + return attr; } return NULL; @@ -2228,13 +2235,11 @@ pango_attr_iterator_get_font (PangoAttrIterator *iterator, PangoLanguage **language, GSList **extra_attrs) { - GList *tmp_list1; - GSList *tmp_list2; - PangoFontMask mask = 0; gboolean have_language = FALSE; gdouble scale = 0; gboolean have_scale = FALSE; + int i; g_return_if_fail (iterator != NULL); g_return_if_fail (desc != NULL); @@ -2245,11 +2250,12 @@ pango_attr_iterator_get_font (PangoAttrIterator *iterator, if (extra_attrs) *extra_attrs = NULL; - tmp_list1 = iterator->attribute_stack; - while (tmp_list1) + if (!iterator->attribute_stack) + return; + + for (i = iterator->attribute_stack->len - 1; i >= 0; i--) { - PangoAttribute *attr = tmp_list1->data; - tmp_list1 = tmp_list1->next; + const PangoAttribute *attr = g_ptr_array_index (iterator->attribute_stack, i); switch ((int) attr->klass->type) { @@ -2333,22 +2339,24 @@ pango_attr_iterator_get_font (PangoAttrIterator *iterator, { gboolean found = FALSE; - tmp_list2 = *extra_attrs; /* Hack: special-case FONT_FEATURES. We don't want them to * override each other, so we never merge them. This should * be fixed when we implement attr-merging. */ if (attr->klass->type != PANGO_ATTR_FONT_FEATURES) - while (tmp_list2) - { - PangoAttribute *old_attr = tmp_list2->data; - if (attr->klass->type == old_attr->klass->type) - { - found = TRUE; - break; - } - - tmp_list2 = tmp_list2->next; - } + { + GSList *tmp_list = *extra_attrs; + while (tmp_list) + { + PangoAttribute *old_attr = tmp_list->data; + if (attr->klass->type == old_attr->klass->type) + { + found = TRUE; + break; + } + + tmp_list = tmp_list->next; + } + } if (!found) *extra_attrs = g_slist_prepend (*extra_attrs, pango_attribute_copy (attr)); @@ -2453,22 +2461,26 @@ GSList * pango_attr_iterator_get_attrs (PangoAttrIterator *iterator) { GSList *attrs = NULL; - GList *tmp_list; + int i; + + if (!iterator->attribute_stack || + iterator->attribute_stack->len == 0) + return NULL; - for (tmp_list = iterator->attribute_stack; tmp_list; tmp_list = tmp_list->next) + for (i = iterator->attribute_stack->len - 1; i >= 0; i--) { - PangoAttribute *attr = tmp_list->data; + PangoAttribute *attr = g_ptr_array_index (iterator->attribute_stack, i); GSList *tmp_list2; gboolean found = FALSE; for (tmp_list2 = attrs; tmp_list2; tmp_list2 = tmp_list2->next) { PangoAttribute *old_attr = tmp_list2->data; - if (attr->klass->type == old_attr->klass->type) - { - found = TRUE; - break; - } + if (attr->klass->type == old_attr->klass->type) + { + found = TRUE; + break; + } } if (!found) -- cgit v1.2.1 From 648bdfad516bd1413800f81c32d63450db4c27e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Fri, 17 Apr 2020 14:15:53 +0200 Subject: attrlist: Remove attributes_tail It's only very rarely used, and will become even less important later. --- pango/pango-attributes-private.h | 1 - pango/pango-attributes.c | 35 +++++++++++------------------------ 2 files changed, 11 insertions(+), 25 deletions(-) diff --git a/pango/pango-attributes-private.h b/pango/pango-attributes-private.h index 230feb3d..bf5bdade 100644 --- a/pango/pango-attributes-private.h +++ b/pango/pango-attributes-private.h @@ -32,7 +32,6 @@ struct _PangoAttrList { guint ref_count; GSList *attributes; - GSList *attributes_tail; }; void _pango_attr_list_init (PangoAttrList *list); diff --git a/pango/pango-attributes.c b/pango/pango-attributes.c index 44b553fc..c858638a 100644 --- a/pango/pango-attributes.c +++ b/pango/pango-attributes.c @@ -1311,7 +1311,6 @@ _pango_attr_list_init (PangoAttrList *list) { list->ref_count = 1; list->attributes = NULL; - list->attributes_tail = NULL; } /** @@ -1427,7 +1426,6 @@ pango_attr_list_copy (PangoAttrList *list) } /* we're going to reverse the nodes, so head becomes tail */ - new->attributes_tail = new_attrs; new->attributes = g_slist_reverse (new_attrs); return new; @@ -1439,19 +1437,21 @@ pango_attr_list_insert_internal (PangoAttrList *list, gboolean before) { GSList *tmp_list, *prev, *link; - guint start_index = attr->start_index; + const guint start_index = attr->start_index; + PangoAttribute *last_attr; if (!list->attributes) { list->attributes = g_slist_prepend (NULL, attr); - list->attributes_tail = list->attributes; + return; } - else if (((PangoAttribute *)list->attributes_tail->data)->start_index < start_index || - (!before && ((PangoAttribute *)list->attributes_tail->data)->start_index == start_index)) + + last_attr = g_slist_last (list->attributes)->data; + + if (last_attr->start_index < start_index || + (!before && last_attr->start_index == start_index)) { - list->attributes_tail = g_slist_append (list->attributes_tail, attr); - list->attributes_tail = list->attributes_tail->next; - g_assert (list->attributes_tail); + list->attributes = g_slist_append (list->attributes, attr); } else { @@ -1574,9 +1574,6 @@ pango_attr_list_change (PangoAttrList *list, else list->attributes = link; - if (!tmp_list) - list->attributes_tail = link; - prev = link; tmp_list = prev->next; break; @@ -1668,9 +1665,6 @@ pango_attr_list_change (PangoAttrList *list, pango_attribute_destroy (tmp_attr); prev->next = tmp_list->next; - if (!prev->next) - list->attributes_tail = prev; - g_slist_free_1 (tmp_list); tmp_list = prev->next; @@ -1713,9 +1707,6 @@ pango_attr_list_change (PangoAttrList *list, prev2->next = tmp_list; tmp_list->next = tmp_list2; - if (!tmp_list->next) - list->attributes_tail = tmp_list; - tmp_list = old_next; continue; @@ -2410,9 +2401,6 @@ pango_attr_list_filter (PangoAttrList *list, if ((*func) (tmp_attr, data)) { - if (!tmp_list->next) - list->attributes_tail = prev; - if (prev) prev->next = tmp_list->next; else @@ -2423,12 +2411,11 @@ pango_attr_list_filter (PangoAttrList *list, if (!new) { new = pango_attr_list_new (); - new->attributes = new->attributes_tail = tmp_list; + new->attributes = tmp_list; } else { - new->attributes_tail->next = tmp_list; - new->attributes_tail = tmp_list; + g_slist_last (new->attributes)->next = tmp_list; } goto next_attr; -- cgit v1.2.1 From 009065cf0c8509e9957cfc4fdd05221e3205cc98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Fri, 17 Apr 2020 17:08:32 +0200 Subject: attrs: Save attribute list in a GPtrArray --- pango/pango-attributes-private.h | 7 +- pango/pango-attributes.c | 526 +++++++++++++++++---------------------- 2 files changed, 231 insertions(+), 302 deletions(-) diff --git a/pango/pango-attributes-private.h b/pango/pango-attributes-private.h index bf5bdade..e2b9a2d5 100644 --- a/pango/pango-attributes-private.h +++ b/pango/pango-attributes-private.h @@ -22,8 +22,13 @@ struct _PangoAttrIterator { + GPtrArray *attrs; /* From the list */ + guint n_attrs; /* Copied from the list */ + GSList *next_attribute; GPtrArray *attribute_stack; + + guint attr_index; guint start_index; guint end_index; }; @@ -31,7 +36,7 @@ struct _PangoAttrIterator struct _PangoAttrList { guint ref_count; - GSList *attributes; + GPtrArray *attributes; }; void _pango_attr_list_init (PangoAttrList *list); diff --git a/pango/pango-attributes.c b/pango/pango-attributes.c index c858638a..239fc935 100644 --- a/pango/pango-attributes.c +++ b/pango/pango-attributes.c @@ -1355,18 +1355,19 @@ pango_attr_list_ref (PangoAttrList *list) void _pango_attr_list_destroy (PangoAttrList *list) { - GSList *tmp_list; + guint i, p; - tmp_list = list->attributes; - while (tmp_list) + if (!list->attributes) + return; + + for (i = 0, p = list->attributes->len; i < p; i++) { - PangoAttribute *attr = tmp_list->data; - tmp_list = tmp_list->next; + PangoAttribute *attr = g_ptr_array_index (list->attributes, i); attr->klass->destroy (attr); } - g_slist_free (list->attributes); + g_ptr_array_free (list->attributes, TRUE); } /** @@ -1407,26 +1408,15 @@ PangoAttrList * pango_attr_list_copy (PangoAttrList *list) { PangoAttrList *new; - GSList *iter; - GSList *new_attrs; if (list == NULL) return NULL; new = pango_attr_list_new (); + if (!list->attributes || list->attributes->len == 0) + return new; - iter = list->attributes; - new_attrs = NULL; - while (iter != NULL) - { - new_attrs = g_slist_prepend (new_attrs, - pango_attribute_copy (iter->data)); - - iter = g_slist_next (iter); - } - - /* we're going to reverse the nodes, so head becomes tail */ - new->attributes = g_slist_reverse (new_attrs); + new->attributes = g_ptr_array_copy (list->attributes, (GCopyFunc)pango_attribute_copy, NULL); return new; } @@ -1436,49 +1426,42 @@ pango_attr_list_insert_internal (PangoAttrList *list, PangoAttribute *attr, gboolean before) { - GSList *tmp_list, *prev, *link; const guint start_index = attr->start_index; PangoAttribute *last_attr; - if (!list->attributes) + if (G_UNLIKELY (!list->attributes)) + list->attributes = g_ptr_array_new (); + + if (list->attributes->len == 0) { - list->attributes = g_slist_prepend (NULL, attr); + g_ptr_array_add (list->attributes, attr); return; } - last_attr = g_slist_last (list->attributes)->data; + 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)) + (!before && last_attr->start_index == start_index)) { - list->attributes = g_slist_append (list->attributes, attr); + g_ptr_array_add (list->attributes, attr); } else { - prev = NULL; - tmp_list = list->attributes; - while (1) - { - PangoAttribute *tmp_attr = tmp_list->data; - - if (tmp_attr->start_index > start_index || - (before && tmp_attr->start_index == start_index)) - { - link = g_slist_alloc (); - link->next = tmp_list; - link->data = attr; + guint i, p; - if (prev) - prev->next = link; - else - list->attributes = link; - - break; - } + for (i = 0, p = list->attributes->len; i < p; i++) + { + PangoAttribute *cur = g_ptr_array_index (list->attributes, i); - prev = tmp_list; - tmp_list = tmp_list->next; - } + if (cur->start_index > start_index || + (before && cur->start_index == start_index)) + { + g_ptr_array_insert (list->attributes, i, attr); + break; + } + } } } @@ -1533,7 +1516,7 @@ pango_attr_list_insert_before (PangoAttrList *list, * and be merged with any adjoining attributes that are identical. * * This function is slower than pango_attr_list_insert() for - * creating a attribute list in order (potentially much slower + * creating an attribute list in order (potentially much slower * for large lists). However, pango_attr_list_insert() is not * suitable for continually changing a set of attributes * since it never removes or combines existing attributes. @@ -1542,7 +1525,7 @@ void pango_attr_list_change (PangoAttrList *list, PangoAttribute *attr) { - GSList *tmp_list, *prev, *link; + guint i, p; guint start_index = attr->start_index; guint end_index = attr->end_index; @@ -1554,168 +1537,119 @@ pango_attr_list_change (PangoAttrList *list, return; } - tmp_list = list->attributes; - prev = NULL; - while (1) + if (!list->attributes || list->attributes->len == 0) { - PangoAttribute *tmp_attr; - - if (!tmp_list || - ((PangoAttribute *)tmp_list->data)->start_index > start_index) - { - /* We need to insert a new attribute - */ - link = g_slist_alloc (); - link->next = tmp_list; - link->data = attr; + pango_attr_list_insert (list, attr); + return; + } - if (prev) - prev->next = link; - else - list->attributes = link; + for (i = 0, p = list->attributes->len; i < p; i++) + { + PangoAttribute *tmp_attr = g_ptr_array_index (list->attributes, i); - prev = link; - tmp_list = prev->next; - break; - } + if (tmp_attr->start_index > start_index) + { + g_ptr_array_insert (list->attributes, i, attr); + break; + } - tmp_attr = tmp_list->data; + if (tmp_attr->klass->type != attr->klass->type) + continue; - if (tmp_attr->klass->type == attr->klass->type && - tmp_attr->end_index >= start_index) - { - /* We overlap with an existing attribute */ - if (pango_attribute_equal (tmp_attr, attr)) - { - /* We can merge the new attribute with this attribute - */ - if (tmp_attr->end_index >= end_index) - { - /* We are totally overlapping the previous attribute. - * No action is needed. - */ - pango_attribute_destroy (attr); - return; - } - tmp_attr->end_index = end_index; - pango_attribute_destroy (attr); + if (tmp_attr->end_index < start_index) + continue; /* This attr does not overlap with the new one */ - attr = tmp_attr; + g_assert (tmp_attr->end_index >= start_index); + g_assert (start_index < tmp_attr->end_index); - prev = tmp_list; - tmp_list = tmp_list->next; + 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. + */ + g_ptr_array_remove_index (list->attributes, i); + pango_attribute_destroy (attr); + return; + } - break; - } - else - { - /* Split, truncate, or remove the old attribute - */ - if (tmp_attr->end_index > attr->end_index) - { - PangoAttribute *end_attr = pango_attribute_copy (tmp_attr); + tmp_attr->end_index = end_index; + pango_attribute_destroy (attr); - end_attr->start_index = attr->end_index; - pango_attr_list_insert (list, end_attr); - } + attr = tmp_attr; + break; + } + else + { + /* Split, truncate, or remove the old attribute + */ + if (tmp_attr->end_index > attr->end_index) + { + PangoAttribute *end_attr = pango_attribute_copy (tmp_attr); - if (tmp_attr->start_index == attr->start_index) - { - pango_attribute_destroy (tmp_attr); - tmp_list->data = attr; + end_attr->start_index = attr->end_index; + pango_attr_list_insert (list, end_attr); + } - prev = tmp_list; - tmp_list = tmp_list->next; - break; - } - else - { - tmp_attr->end_index = attr->start_index; - } - } - } - prev = tmp_list; - tmp_list = tmp_list->next; + if (tmp_attr->start_index == attr->start_index) + { + pango_attribute_destroy (tmp_attr); + g_ptr_array_remove_index (list->attributes, i); + break; + } + else + { + tmp_attr->end_index = attr->start_index; + } + } } - /* At this point, prev points to the list node with attr in it, - * tmp_list points to prev->next. - */ - - g_assert (prev->data == attr); - g_assert (prev->next == tmp_list); /* We now have the range inserted into the list one way or the - * other. Fix up the remainder - */ - while (tmp_list) + * other. Fix up the remainder */ + /* Attention: No i = 0 here. */ + for (i = i + 1, p = list->attributes->len; i < p; i++) { - PangoAttribute *tmp_attr = tmp_list->data; + PangoAttribute *tmp_attr = g_ptr_array_index (list->attributes, i); if (tmp_attr->start_index > end_index) - break; - else if (tmp_attr->klass->type == attr->klass->type) - { - if (tmp_attr->end_index <= attr->end_index || - pango_attribute_equal (tmp_attr, attr)) - { - /* We can merge the new attribute with this attribute. - */ - attr->end_index = MAX (end_index, tmp_attr->end_index); - - pango_attribute_destroy (tmp_attr); - prev->next = tmp_list->next; - - g_slist_free_1 (tmp_list); - tmp_list = prev->next; - - continue; - } - else - { - /* Trim the start of this attribute that it begins at the end - * of the new attribute. This may involve moving - * it in the list to maintain the required non-decreasing - * order of start indices - */ - GSList *tmp_list2; - GSList *prev2; - - tmp_attr->start_index = attr->end_index; - - tmp_list2 = tmp_list->next; - prev2 = tmp_list; - - while (tmp_list2) - { - PangoAttribute *tmp_attr2 = tmp_list2->data; - - if (tmp_attr2->start_index >= tmp_attr->start_index) - break; - - prev2 = tmp_list2; - tmp_list2 = tmp_list2->next; - } + break; - /* Now remove and insert before tmp_list2. We'll - * hit this attribute again later, but that's harmless. - */ - if (prev2 != tmp_list) - { - GSList *old_next = tmp_list->next; + if (tmp_attr->klass->type != attr->klass->type) + continue; - prev->next = old_next; - prev2->next = tmp_list; - tmp_list->next = tmp_list2; + 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_list = old_next; + tmp_attr->start_index = attr->end_index; - continue; - } - } - } + for (k = i + 1, m = list->attributes->len; k < m; k++) + { + PangoAttribute *tmp_attr2 = g_ptr_array_index (list->attributes, k); - prev = tmp_list; - tmp_list = tmp_list->next; + if (tmp_attr2->start_index >= tmp_attr->start_index) + break; + } + } } } @@ -1751,52 +1685,41 @@ pango_attr_list_update (PangoAttrList *list, int remove, int add) { - GSList *l, *prev, *next; + guint i, p; - prev = NULL; - l = list->attributes; - while (l) + for (i = 0, p = list->attributes->len; i < p; i++) { - PangoAttribute *attr = l->data; - next = l->next; + PangoAttribute *attr = g_ptr_array_index (list->attributes, i); if (attr->start_index >= pos && attr->end_index < pos + remove) { pango_attribute_destroy (attr); - if (prev == NULL) - list->attributes = next; - else - prev->next = next; + g_ptr_array_remove_index (list->attributes, i); + i--; /* Look at this index again */ + p--; + continue; + } - g_slist_free_1 (l); + if (attr->start_index >= pos && + attr->start_index < pos + remove) + { + attr->start_index = pos + add; } - else + else if (attr->start_index >= pos + remove) { - prev = l; - - 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 >= pos && - attr->end_index < pos + remove) - { - attr->end_index = pos; - } - else if (attr->end_index >= pos + remove) - { - attr->end_index += add - remove; - } + attr->start_index += add - remove; } - l = next; + if (attr->end_index >= pos && + attr->end_index < pos + remove) + { + attr->end_index = pos; + } + else if (attr->end_index >= pos + remove) + { + attr->end_index += add - remove; + } } } @@ -1826,7 +1749,7 @@ pango_attr_list_splice (PangoAttrList *list, gint pos, gint len) { - GSList *tmp_list; + guint i, p; guint upos, ulen; g_return_if_fail (list != NULL); @@ -1842,10 +1765,9 @@ pango_attr_list_splice (PangoAttrList *list, */ #define CLAMP_ADD(a,b) (((a) + (b) < (a)) ? G_MAXUINT : (a) + (b)) - tmp_list = list->attributes; - while (tmp_list) + for (i = 0, p = list->attributes->len; i < p; i++) { - PangoAttribute *attr = tmp_list->data; + PangoAttribute *attr = g_ptr_array_index (list->attributes, i);; if (attr->start_index <= upos) { @@ -1861,15 +1783,15 @@ pango_attr_list_splice (PangoAttrList *list, */ attr->start_index = CLAMP_ADD (attr->start_index, ulen); attr->end_index = CLAMP_ADD (attr->end_index, ulen); - } - - tmp_list = tmp_list->next; + } } - tmp_list = other->attributes; - while (tmp_list) + if (!other->attributes || other->attributes->len == 0) + return; + + for (i = 0, p = other->attributes->len; i < p; i++) { - PangoAttribute *attr = pango_attribute_copy (tmp_list->data); + PangoAttribute *attr = pango_attribute_copy (g_ptr_array_index (other->attributes, i)); attr->start_index = CLAMP_ADD (attr->start_index, upos); attr->end_index = CLAMP_ADD (attr->end_index, upos); @@ -1877,8 +1799,6 @@ pango_attr_list_splice (PangoAttrList *list, * pango_attr_list_change() will take care of deleting it. */ pango_attr_list_change (list, attr); - - tmp_list = tmp_list->next; } #undef CLAMP_ADD } @@ -1899,9 +1819,22 @@ pango_attr_list_splice (PangoAttrList *list, GSList * pango_attr_list_get_attributes (PangoAttrList *list) { + GSList *result = NULL; + guint i, p; + g_return_val_if_fail (list != NULL, NULL); - return g_slist_copy_deep (list->attributes, (GCopyFunc)pango_attribute_copy, 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); } /** @@ -1921,9 +1854,7 @@ gboolean pango_attr_list_equal (PangoAttrList *list, PangoAttrList *other_list) { - GSList *attrs, *other_attrs; - GSList *iter = NULL; - guint attrs_length = 0; + GPtrArray *attrs, *other_attrs; guint64 skip_bitmask = 0; if (list == other_list) @@ -1935,28 +1866,21 @@ pango_attr_list_equal (PangoAttrList *list, attrs = list->attributes; other_attrs = other_list->attributes; - for (iter = attrs; iter != NULL; iter = iter->next) + if (attrs->len != other_attrs->len) + return FALSE; + + for (guint i = 0; i < attrs->len; i++) { - PangoAttribute *attr = iter->data; - GSList *other_iter = NULL; + PangoAttribute *attr = g_ptr_array_index (attrs, i); gboolean attr_equal = FALSE; - guint other_attr_index = 0; - - attrs_length++; - for (other_iter = other_attrs; - other_iter != NULL; - other_iter = other_iter->next) + for (guint other_attr_index = 0; other_attr_index < other_attrs->len; other_attr_index++) { - PangoAttribute *other_attr = other_iter->data; - guint64 other_attr_bitmask = - other_attr_index < 64 ? 1 << other_attr_index : 0; + 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) - { - other_attr_index++; - continue; - } + continue; if (attr->start_index == other_attr->start_index && attr->end_index == other_attr->end_index && @@ -1967,23 +1891,19 @@ pango_attr_list_equal (PangoAttrList *list, break; } - other_attr_index++; } if (!attr_equal) return FALSE; } - if (attrs_length != g_slist_length (other_attrs)) - return FALSE; - return TRUE; } gboolean _pango_attr_list_has_attributes (const PangoAttrList *list) { - return list && (list->attributes != NULL); + return list && list->attributes != NULL && list->attributes->len > 0; } G_DEFINE_BOXED_TYPE (PangoAttrIterator, @@ -1995,9 +1915,11 @@ void _pango_attr_list_get_iterator (PangoAttrList *list, PangoAttrIterator *iterator) { - iterator->next_attribute = list->attributes; 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; @@ -2068,7 +1990,7 @@ pango_attr_iterator_next (PangoAttrIterator *iterator) g_return_val_if_fail (iterator != NULL, FALSE); - if (!iterator->next_attribute && + if (iterator->attr_index >= iterator->n_attrs && (!iterator->attribute_stack || iterator->attribute_stack->len == 0)) return FALSE; @@ -2093,22 +2015,37 @@ pango_attr_iterator_next (PangoAttrIterator *iterator) } } - while (iterator->next_attribute && - ((PangoAttribute *)iterator->next_attribute->data)->start_index == iterator->start_index) + while (1) { - if (((PangoAttribute *)iterator->next_attribute->data)->end_index > iterator->start_index) + 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, iterator->next_attribute->data); - iterator->end_index = MIN (iterator->end_index, ((PangoAttribute *)iterator->next_attribute->data)->end_index); + g_ptr_array_add (iterator->attribute_stack, attr); + + iterator->end_index = MIN (iterator->end_index, attr->end_index); } - iterator->next_attribute = iterator->next_attribute->next; + + iterator->attr_index++; /* NEXT! */ } - if (iterator->next_attribute) - iterator->end_index = MIN (iterator->end_index, ((PangoAttribute *)iterator->next_attribute->data)->start_index); + 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; } @@ -2387,44 +2324,31 @@ pango_attr_list_filter (PangoAttrList *list, { PangoAttrList *new = NULL; - GSList *tmp_list; - GSList *prev; + guint i, p; g_return_val_if_fail (list != NULL, NULL); - tmp_list = list->attributes; - prev = NULL; - while (tmp_list) + if (!list->attributes || list->attributes->len == 0) + return NULL; + + for (i = 0, p = list->attributes->len; i < p; i++) { - GSList *next = tmp_list->next; - PangoAttribute *tmp_attr = tmp_list->data; + PangoAttribute *tmp_attr = g_ptr_array_index (list->attributes, i); if ((*func) (tmp_attr, data)) - { - if (prev) - prev->next = tmp_list->next; - else - list->attributes = tmp_list->next; - - tmp_list->next = NULL; - - if (!new) - { - new = pango_attr_list_new (); - new->attributes = tmp_list; - } - else - { - g_slist_last (new->attributes)->next = tmp_list; - } - - goto next_attr; - } + { + g_ptr_array_remove_index (list->attributes, i); + i--; /* Need to look at this index again */ + p--; - prev = tmp_list; + if (G_UNLIKELY (!new)) + { + new = pango_attr_list_new (); + new->attributes = g_ptr_array_new (); + } - next_attr: - tmp_list = next; + g_ptr_array_add (new->attributes, tmp_attr); + } } return new; -- cgit v1.2.1 From 410ea34c65ec5e96034a92397869abc788af3476 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Mon, 8 Jun 2020 19:04:09 +0200 Subject: attrs: Remove unused iterator member --- pango/pango-attributes-private.h | 1 - 1 file changed, 1 deletion(-) diff --git a/pango/pango-attributes-private.h b/pango/pango-attributes-private.h index e2b9a2d5..f7384fd0 100644 --- a/pango/pango-attributes-private.h +++ b/pango/pango-attributes-private.h @@ -25,7 +25,6 @@ struct _PangoAttrIterator GPtrArray *attrs; /* From the list */ guint n_attrs; /* Copied from the list */ - GSList *next_attribute; GPtrArray *attribute_stack; guint attr_index; -- cgit v1.2.1 From 3b122eb3cc8b2585e8094a5f97c5a2c75fff2723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Wed, 10 Jun 2020 05:21:06 +0200 Subject: pangocairo-render: Make a local const Avoiding this warning: ../pango/pangocairo-render.c:506:19: warning: assigning to 'char *' from 'const char *' discards qualifiers [-Wincompatible-pointer-types-discards-qualifiers] for (row = 0, p = name; row < rows; row++) ^ ~~~~ --- pango/pangocairo-render.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pango/pangocairo-render.c b/pango/pangocairo-render.c index e268ebd5..614a3a44 100644 --- a/pango/pangocairo-render.c +++ b/pango/pangocairo-render.c @@ -374,7 +374,7 @@ _pango_cairo_renderer_draw_unknown_glyph (PangoCairoRenderer *crenderer, PangoCairoFontHexBoxInfo *hbi; gunichar ch; gboolean invalid_input; - char *p; + const char *p; const char *name; cairo_save (crenderer->cr); -- cgit v1.2.1 From 560b9b575792e1aa4faca4a0c159baa96b4a04e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Wed, 10 Jun 2020 05:31:36 +0200 Subject: pango-ot-info: Fix an uninitialized value We never assign a value to l_index. Also, we pass on language_index to hb_ot_layout_script_select_language, even though the last parameter of that function is not nullable, while our language_index parameter is. Fix this to pass &l_index to hb_ot_layout_script_select_language, which is what I believe should happen. --- pango/pango-ot-info.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pango/pango-ot-info.c b/pango/pango-ot-info.c index f995c1d4..2b1b61f4 100644 --- a/pango/pango-ot-info.c +++ b/pango/pango-ot-info.c @@ -184,7 +184,7 @@ pango_ot_info_find_language (PangoOTInfo *info, guint *required_feature_index) { gboolean ret; - unsigned l_index; + guint l_index; hb_tag_t tt = get_hb_table_type (table_type); ret = hb_ot_layout_script_select_language (info->hb_face, @@ -192,8 +192,9 @@ pango_ot_info_find_language (PangoOTInfo *info, script_index, 1, &language_tag, - language_index); - if (language_index) *language_index = l_index; + &l_index); + if (language_index) + *language_index = l_index; hb_ot_layout_language_get_required_feature_index (info->hb_face, tt, script_index, -- cgit v1.2.1 From 9983edf5294d2ae29dde8e49c7d4b94bff970ea1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Wed, 10 Jun 2020 05:50:51 +0200 Subject: pango-context: avoid assignment to uninitialized value We're assigning EMBEDDING_CHANGED to state->changed in update_embedding_end(). At that point state->changed is uninitialized, but that doesn't matter since we later override the value anyway. Just pull the initialization to earlier in that function, which assigns EMBEDDING_CHANGED anyway, so doesn't change anything. --- pango/pango-context.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pango/pango-context.c b/pango/pango-context.c index a64eb79f..7772878f 100644 --- a/pango/pango-context.c +++ b/pango/pango-context.c @@ -1006,6 +1006,8 @@ itemize_state_init (ItemizeState *state, state->item = NULL; state->run_start = text + start_index; + state->changed = EMBEDDING_CHANGED | SCRIPT_CHANGED | LANG_CHANGED | + FONT_CHANGED | WIDTH_CHANGED | EMOJI_CHANGED; /* First, apply the bidirectional algorithm to break * the text into directional runs. @@ -1079,7 +1081,6 @@ itemize_state_init (ItemizeState *state, state->cache = NULL; state->base_font = NULL; - state->changed = EMBEDDING_CHANGED | SCRIPT_CHANGED | LANG_CHANGED | FONT_CHANGED | WIDTH_CHANGED | EMOJI_CHANGED; } static gboolean -- cgit v1.2.1 From 3c5c50d547e4ca81696b16dffe34741611f094eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Wed, 10 Jun 2020 05:52:42 +0200 Subject: pangofc-fontmap: Avoid a dead assignment I believe this was meant to assign to variable and not res. --- pango/pangofc-fontmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pango/pangofc-fontmap.c b/pango/pangofc-fontmap.c index b0c8365d..8aa27c1e 100644 --- a/pango/pangofc-fontmap.c +++ b/pango/pangofc-fontmap.c @@ -1468,7 +1468,7 @@ ensure_families (PangoFcFontMap *fcfontmap) { variable = FALSE; #ifdef FC_VARIABLE - res = FcPatternGetBool (fontset->fonts[i], FC_VARIABLE, 0, &variable); + variable = FcPatternGetBool (fontset->fonts[i], FC_VARIABLE, 0, &variable); #endif if (variable) temp_family->variable = TRUE; -- cgit v1.2.1 From dc5e67b2d74386f6482f6b978f972c4bfd8401cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Wed, 10 Jun 2020 05:54:01 +0200 Subject: pango-layout: Help static analysis a bit Make sure we have a valid iter here, which is of course always the case in reality. --- pango/pango-layout.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pango/pango-layout.c b/pango/pango-layout.c index 6d4d94cb..97e24d1b 100644 --- a/pango/pango-layout.c +++ b/pango/pango-layout.c @@ -2090,6 +2090,8 @@ pango_layout_xy_to_index (PangoLayout *layout, PangoRectangle line_logical; int first_y, last_y; + g_assert (!ITER_IS_INVALID (&iter)); + pango_layout_iter_get_line_extents (&iter, NULL, &line_logical); pango_layout_iter_get_line_yrange (&iter, &first_y, &last_y); -- cgit v1.2.1 From 29674a51c0cd9a41e323fe7e3473ca327b79c3f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Wed, 10 Jun 2020 05:54:27 +0200 Subject: pango-tabs: Avoid passing NULL to memcpy pango_tab_array_new might not actually allocate anything for ->tabs. --- pango/pango-tabs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pango/pango-tabs.c b/pango/pango-tabs.c index 1ffa8356..56a34468 100644 --- a/pango/pango-tabs.c +++ b/pango/pango-tabs.c @@ -192,7 +192,8 @@ pango_tab_array_copy (PangoTabArray *src) copy = pango_tab_array_new (src->size, src->positions_in_pixels); - memcpy (copy->tabs, src->tabs, sizeof(PangoTab)*src->size); + if (copy->tabs) + memcpy (copy->tabs, src->tabs, sizeof(PangoTab) * src->size); return copy; } -- cgit v1.2.1 From 6fa5ddf4d0fabad39c7488461f4f24559088a342 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Wed, 10 Jun 2020 06:11:48 +0200 Subject: tests: Add some tests for pango_attr_list_equal --- tests/testattributes.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/tests/testattributes.c b/tests/testattributes.c index 6b5e849b..4eea97da 100644 --- a/tests/testattributes.c +++ b/tests/testattributes.c @@ -618,6 +618,76 @@ test_list_update (void) pango_attr_list_unref (list); } +static void +test_list_equal (void) +{ + PangoAttrList *list1, *list2; + PangoAttribute *attr; + + list1 = pango_attr_list_new (); + list2 = pango_attr_list_new (); + + attr = pango_attr_size_new (10 * PANGO_SCALE); + attr->start_index = 0; + attr->end_index = 7; + pango_attr_list_insert (list1, pango_attribute_copy (attr)); + pango_attr_list_insert (list2, pango_attribute_copy (attr)); + pango_attribute_destroy (attr); + + g_assert_true (pango_attr_list_equal (list1, list2)); + + attr = pango_attr_stretch_new (PANGO_STRETCH_CONDENSED); + attr->start_index = 0; + attr->end_index = 1; + pango_attr_list_insert (list1, pango_attribute_copy (attr)); + g_assert_true (!pango_attr_list_equal (list1, list2)); + + pango_attr_list_insert (list2, pango_attribute_copy (attr)); + g_assert_true (pango_attr_list_equal (list1, list2)); + pango_attribute_destroy (attr); + + attr = pango_attr_size_new (30 * PANGO_SCALE); + /* Same range as the first attribute */ + attr->start_index = 0; + attr->end_index = 7; + pango_attr_list_insert (list2, pango_attribute_copy (attr)); + g_assert_true (!pango_attr_list_equal (list1, list2)); + pango_attr_list_insert (list1, pango_attribute_copy (attr)); + g_assert_true (pango_attr_list_equal (list1, list2)); + pango_attribute_destroy (attr); + + pango_attr_list_unref (list1); + pango_attr_list_unref (list2); + + + /* Same range but different order */ + { + PangoAttrList *list1, *list2; + PangoAttribute *attr1, *attr2; + + list1 = pango_attr_list_new (); + list2 = pango_attr_list_new (); + + attr1 = pango_attr_size_new (10 * PANGO_SCALE); + attr2 = pango_attr_stretch_new (PANGO_STRETCH_CONDENSED); + + pango_attr_list_insert (list1, pango_attribute_copy (attr1)); + pango_attr_list_insert (list1, pango_attribute_copy (attr2)); + + pango_attr_list_insert (list2, pango_attribute_copy (attr2)); + pango_attr_list_insert (list2, pango_attribute_copy (attr1)); + + pango_attribute_destroy (attr1); + pango_attribute_destroy (attr2); + + g_assert_true (pango_attr_list_equal (list1, list2)); + g_assert_true (pango_attr_list_equal (list2, list1)); + + pango_attr_list_unref (list1); + pango_attr_list_unref (list2); + } +} + int main (int argc, char *argv[]) { @@ -630,6 +700,7 @@ main (int argc, char *argv[]) g_test_add_func ("/attributes/list/splice", test_list_splice); g_test_add_func ("/attributes/list/filter", test_list_filter); g_test_add_func ("/attributes/list/update", test_list_update); + g_test_add_func ("/attributes/list/equal", test_list_equal); g_test_add_func ("/attributes/iter/basic", test_iter); g_test_add_func ("/attributes/iter/get", test_iter_get); g_test_add_func ("/attributes/iter/get_font", test_iter_get_font); -- cgit v1.2.1 From 1bb4e61c3285f95e01f13d70354716c11c27ce39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Wed, 10 Jun 2020 06:39:38 +0200 Subject: layout: Ignore setting the attributes to the same list --- pango/pango-layout.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pango/pango-layout.c b/pango/pango-layout.c index 97e24d1b..3c138327 100644 --- a/pango/pango-layout.c +++ b/pango/pango-layout.c @@ -694,6 +694,10 @@ pango_layout_set_attributes (PangoLayout *layout, !_pango_attr_list_has_attributes (attrs)) return; + if (layout->attrs && + pango_attr_list_equal (layout->attrs, attrs)) + return; + old_attrs = layout->attrs; /* We always clear lines such that this function can be called -- cgit v1.2.1