Bug 735810 - performance shrinkage of Paths tool

Use a GQueue instead of a GList in GimpCanvasGroup, so adding items
takes constant time instead of O(n). Also, removing items was
traversing the list twice. This should generally speed up tools with
lots of canvas items.

Also, add a private pointer to the instance struct instead of using a
GET_PRIVATE() macro.
This commit is contained in:
Michael Natterer
2016-01-24 00:54:48 +01:00
parent c8ee9f951d
commit 4920033c42
2 changed files with 49 additions and 59 deletions

View File

@ -40,20 +40,13 @@ enum
};
typedef struct _GimpCanvasGroupPrivate GimpCanvasGroupPrivate;
struct _GimpCanvasGroupPrivate
{
GList *items;
GQueue *items;
gboolean group_stroking;
gboolean group_filling;
};
#define GET_PRIVATE(group) \
G_TYPE_INSTANCE_GET_PRIVATE (group, \
GIMP_TYPE_CANVAS_GROUP, \
GimpCanvasGroupPrivate)
/* local function prototypes */
@ -115,17 +108,22 @@ gimp_canvas_group_class_init (GimpCanvasGroupClass *klass)
static void
gimp_canvas_group_init (GimpCanvasGroup *group)
{
group->priv = G_TYPE_INSTANCE_GET_PRIVATE (group,
GIMP_TYPE_CANVAS_GROUP,
GimpCanvasGroupPrivate);
group->priv->items = g_queue_new ();
}
static void
gimp_canvas_group_dispose (GObject *object)
{
GimpCanvasGroupPrivate *private = GET_PRIVATE (object);
GimpCanvasGroup *group = GIMP_CANVAS_GROUP (object);
if (private->items)
if (group->priv->items)
{
g_list_free_full (private->items, (GDestroyNotify) g_object_unref);
private->items = NULL;
g_queue_free_full (group->priv->items, (GDestroyNotify) g_object_unref);
group->priv->items = NULL;
}
G_OBJECT_CLASS (parent_class)->dispose (object);
@ -137,15 +135,15 @@ gimp_canvas_group_set_property (GObject *object,
const GValue *value,
GParamSpec *pspec)
{
GimpCanvasGroupPrivate *private = GET_PRIVATE (object);
GimpCanvasGroup *group = GIMP_CANVAS_GROUP (object);
switch (property_id)
{
case PROP_GROUP_STROKING:
private->group_stroking = g_value_get_boolean (value);
group->priv->group_stroking = g_value_get_boolean (value);
break;
case PROP_GROUP_FILLING:
private->group_filling = g_value_get_boolean (value);
group->priv->group_filling = g_value_get_boolean (value);
break;
default:
@ -160,15 +158,15 @@ gimp_canvas_group_get_property (GObject *object,
GValue *value,
GParamSpec *pspec)
{
GimpCanvasGroupPrivate *private = GET_PRIVATE (object);
GimpCanvasGroup *group = GIMP_CANVAS_GROUP (object);
switch (property_id)
{
case PROP_GROUP_STROKING:
g_value_set_boolean (value, private->group_stroking);
g_value_set_boolean (value, group->priv->group_stroking);
break;
case PROP_GROUP_FILLING:
g_value_set_boolean (value, private->group_filling);
g_value_set_boolean (value, group->priv->group_filling);
break;
default:
@ -181,31 +179,31 @@ static void
gimp_canvas_group_draw (GimpCanvasItem *item,
cairo_t *cr)
{
GimpCanvasGroupPrivate *private = GET_PRIVATE (item);
GimpCanvasGroup *group = GIMP_CANVAS_GROUP (item);
GList *list;
for (list = private->items; list; list = g_list_next (list))
for (list = group->priv->items->head; list; list = g_list_next (list))
{
GimpCanvasItem *sub_item = list->data;
gimp_canvas_item_draw (sub_item, cr);
}
if (private->group_stroking)
if (group->priv->group_stroking)
_gimp_canvas_item_stroke (item, cr);
if (private->group_filling)
if (group->priv->group_filling)
_gimp_canvas_item_fill (item, cr);
}
static cairo_region_t *
gimp_canvas_group_get_extents (GimpCanvasItem *item)
{
GimpCanvasGroupPrivate *private = GET_PRIVATE (item);
GimpCanvasGroup *group = GIMP_CANVAS_GROUP (item);
cairo_region_t *region = NULL;
GList *list;
for (list = private->items; list; list = g_list_next (list))
for (list = group->priv->items->head; list; list = g_list_next (list))
{
GimpCanvasItem *sub_item = list->data;
cairo_region_t *sub_region = gimp_canvas_item_get_extents (sub_item);
@ -229,10 +227,10 @@ gimp_canvas_group_hit (GimpCanvasItem *item,
gdouble x,
gdouble y)
{
GimpCanvasGroupPrivate *private = GET_PRIVATE (item);
GimpCanvasGroup *group = GIMP_CANVAS_GROUP (item);
GList *list;
for (list = private->items; list; list = g_list_next (list))
for (list = group->priv->items->head; list; list = g_list_next (list))
{
if (gimp_canvas_item_hit (list->data, x, y))
return TRUE;
@ -267,21 +265,17 @@ void
gimp_canvas_group_add_item (GimpCanvasGroup *group,
GimpCanvasItem *item)
{
GimpCanvasGroupPrivate *private;
g_return_if_fail (GIMP_IS_CANVAS_GROUP (group));
g_return_if_fail (GIMP_IS_CANVAS_ITEM (item));
g_return_if_fail (GIMP_CANVAS_ITEM (group) != item);
private = GET_PRIVATE (group);
if (private->group_stroking)
if (group->priv->group_stroking)
gimp_canvas_item_suspend_stroking (item);
if (private->group_filling)
if (group->priv->group_filling)
gimp_canvas_item_suspend_filling (item);
private->items = g_list_append (private->items, g_object_ref (item));
g_queue_push_tail (group->priv->items, g_object_ref (item));
if (_gimp_canvas_item_needs_update (GIMP_CANVAS_ITEM (group)))
{
@ -303,21 +297,21 @@ void
gimp_canvas_group_remove_item (GimpCanvasGroup *group,
GimpCanvasItem *item)
{
GimpCanvasGroupPrivate *private;
GList *list;
g_return_if_fail (GIMP_IS_CANVAS_GROUP (group));
g_return_if_fail (GIMP_IS_CANVAS_ITEM (item));
private = GET_PRIVATE (group);
list = g_queue_find (group->priv->items, item);
g_return_if_fail (g_list_find (private->items, item));
g_return_if_fail (list != NULL);
private->items = g_list_remove (private->items, item);
g_queue_delete_link (group->priv->items, list);
if (private->group_stroking)
if (group->priv->group_stroking)
gimp_canvas_item_resume_stroking (item);
if (private->group_filling)
if (group->priv->group_filling)
gimp_canvas_item_resume_filling (item);
if (_gimp_canvas_item_needs_update (GIMP_CANVAS_ITEM (group)))
@ -342,13 +336,9 @@ void
gimp_canvas_group_set_group_stroking (GimpCanvasGroup *group,
gboolean group_stroking)
{
GimpCanvasGroupPrivate *private;
g_return_if_fail (GIMP_IS_CANVAS_GROUP (group));
private = GET_PRIVATE (group);
if (private->group_stroking != group_stroking)
if (group->priv->group_stroking != group_stroking)
{
GList *list;
@ -358,9 +348,9 @@ gimp_canvas_group_set_group_stroking (GimpCanvasGroup *group,
"group-stroking", group_stroking ? TRUE : FALSE,
NULL);
for (list = private->items; list; list = g_list_next (list))
for (list = group->priv->items->head; list; list = g_list_next (list))
{
if (private->group_stroking)
if (group->priv->group_stroking)
gimp_canvas_item_suspend_stroking (list->data);
else
gimp_canvas_item_resume_stroking (list->data);
@ -374,13 +364,9 @@ void
gimp_canvas_group_set_group_filling (GimpCanvasGroup *group,
gboolean group_filling)
{
GimpCanvasGroupPrivate *private;
g_return_if_fail (GIMP_IS_CANVAS_GROUP (group));
private = GET_PRIVATE (group);
if (private->group_filling != group_filling)
if (group->priv->group_filling != group_filling)
{
GList *list;
@ -390,9 +376,9 @@ gimp_canvas_group_set_group_filling (GimpCanvasGroup *group,
"group-filling", group_filling ? TRUE : FALSE,
NULL);
for (list = private->items; list; list = g_list_next (list))
for (list = group->priv->items->head; list; list = g_list_next (list))
{
if (private->group_filling)
if (group->priv->group_filling)
gimp_canvas_item_suspend_filling (list->data);
else
gimp_canvas_item_resume_filling (list->data);

View File

@ -33,11 +33,15 @@
#define GIMP_CANVAS_GROUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_CANVAS_GROUP, GimpCanvasGroupClass))
typedef struct _GimpCanvasGroupPrivate GimpCanvasGroupPrivate;
typedef struct _GimpCanvasGroupClass GimpCanvasGroupClass;
struct _GimpCanvasGroup
{
GimpCanvasItem parent_instance;
GimpCanvasGroupPrivate *priv;
};
struct _GimpCanvasGroupClass