[gimp] Bug 735810- performance shrinkage of Paths tool



commit 1e47343b04fe915c830e84a3cc079a99be3ccb97
Author: Simon Budig <simon budig de>
Date:   Thu Jan 28 23:53:42 2016 +0100

    Bug 735810- performance shrinkage of Paths tool
    
    Apply revised version of Mitchs patch that
    changes the anchor list to a GQueue.

 app/vectors/gimpbezierstroke.c   |  272 ++++++++++++++++++++------------------
 app/vectors/gimpstroke.c         |   61 ++++-----
 app/vectors/gimpstroke.h         |    2 +-
 app/vectors/gimpvectors-compat.c |    8 +-
 app/vectors/gimpvectors-warp.c   |    2 +-
 5 files changed, 174 insertions(+), 171 deletions(-)
---
diff --git a/app/vectors/gimpbezierstroke.c b/app/vectors/gimpbezierstroke.c
index 2556d19..fc78162 100644
--- a/app/vectors/gimpbezierstroke.c
+++ b/app/vectors/gimpbezierstroke.c
@@ -235,17 +235,19 @@ gimp_bezier_stroke_anchor_delete (GimpStroke *stroke,
   gint   i;
 
   /* Anchors always are surrounded by two handles that have to
-   * be deleted too */
+   * be deleted too
+   */
 
-  list2 = g_list_find (stroke->anchors, anchor);
-  list = g_list_previous(list2);
+  list2 = g_queue_find (stroke->anchors, anchor);
+  list = g_list_previous (list2);
 
-  for (i=0; i < 3; i++)
+  for (i = 0; i < 3; i++)
     {
       g_return_if_fail (list != NULL);
+
       list2 = g_list_next (list);
-      gimp_anchor_free (GIMP_ANCHOR (list->data));
-      stroke->anchors = g_list_delete_link (stroke->anchors, list);
+      gimp_anchor_free (list->data);
+      g_queue_delete_link (stroke->anchors, list);
       list = list2;
     }
 }
@@ -258,7 +260,7 @@ gimp_bezier_stroke_open (GimpStroke *stroke,
   GList      *list2;
   GimpStroke *new_stroke = NULL;
 
-  list = g_list_find (stroke->anchors, end_anchor);
+  list = g_queue_find (stroke->anchors, end_anchor);
 
   g_return_val_if_fail (list != NULL && list->next != NULL, NULL);
 
@@ -269,16 +271,28 @@ gimp_bezier_stroke_open (GimpStroke *stroke,
 
   if (list2 != NULL)
     {
+      GList *tail = stroke->anchors->tail;
+
+      stroke->anchors->tail = list;
+      stroke->anchors->length -= g_list_length (list2);
+
       list2->prev = NULL;
 
       if (stroke->closed)
         {
-          stroke->anchors = g_list_concat (list2, stroke->anchors);
+          GList *l;
+
+          for (l = tail; l; l = g_list_previous (l))
+            g_queue_push_head (stroke->anchors, l->data);
+
+          g_list_free (list2);
         }
       else
         {
           new_stroke = gimp_bezier_stroke_new ();
-          new_stroke->anchors = list2;
+          new_stroke->anchors->head = list2;
+          new_stroke->anchors->tail = g_list_last (list2);
+          new_stroke->anchors->length = g_list_length (list2);
         }
     }
 
@@ -293,7 +307,7 @@ gimp_bezier_stroke_anchor_is_insertable (GimpStroke *stroke,
                                          GimpAnchor *predec,
                                          gdouble     position)
 {
-  return (g_list_find (stroke->anchors, predec) != NULL);
+  return (g_queue_find (stroke->anchors, predec) != NULL);
 }
 
 
@@ -309,7 +323,7 @@ gimp_bezier_stroke_anchor_insert (GimpStroke *stroke,
   GimpCoords  beziercoords[4];
   gint        i;
 
-  segment_start = g_list_find (stroke->anchors, predec);
+  segment_start = g_queue_find (stroke->anchors, predec);
 
   if (! segment_start)
     return NULL;
@@ -320,8 +334,8 @@ gimp_bezier_stroke_anchor_insert (GimpStroke *stroke,
     {
       beziercoords[i] = GIMP_ANCHOR (list->data)->position;
       list = g_list_next (list);
-      if (!list)
-        list = stroke->anchors;
+      if (! list)
+        list = stroke->anchors->head;
     }
 
   subdivided[0] = beziercoords[0];
@@ -375,7 +389,6 @@ gimp_bezier_stroke_anchor_insert (GimpStroke *stroke,
 
           if (i == 3)
             segment_start = list;
-
         }
       else
         {
@@ -383,12 +396,13 @@ gimp_bezier_stroke_anchor_insert (GimpStroke *stroke,
         }
 
       list = g_list_next (list);
-      if (!list)
-        list = stroke->anchors;
-
+      if (! list)
+        list = stroke->anchors->head;
     }
 
-  stroke->anchors = g_list_first (stroke->anchors);
+  stroke->anchors->head = g_list_first (list);
+  stroke->anchors->tail = g_list_last (list);
+  stroke->anchors->length += 3;
 
   return GIMP_ANCHOR (segment_start->data);
 }
@@ -399,7 +413,7 @@ gimp_bezier_stroke_point_is_movable (GimpStroke *stroke,
                                      GimpAnchor *predec,
                                      gdouble     position)
 {
-  return (g_list_find (stroke->anchors, predec) != NULL);
+  return (g_queue_find (stroke->anchors, predec) != NULL);
 }
 
 
@@ -416,14 +430,15 @@ gimp_bezier_stroke_point_move_relative (GimpStroke            *stroke,
   gint        i;
   gdouble     feel_good;
 
-  segment_start = g_list_find (stroke->anchors, predec);
+  segment_start = g_queue_find (stroke->anchors, predec);
 
   g_return_if_fail (segment_start != NULL);
 
   /* dragging close to endpoints just moves the handle related to
    * the endpoint. Just make sure that feel_good is in the range from
    * 0 to 1. The 1.0 / 6.0 and 5.0 / 6.0 are duplicated in
-   * tools/gimpvectortool.c.  */
+   * tools/gimpvectortool.c.
+   */
   if (position <= 1.0 / 6.0)
     feel_good = 0;
   else if (position <= 0.5)
@@ -443,16 +458,16 @@ gimp_bezier_stroke_point_move_relative (GimpStroke            *stroke,
 
   list = segment_start;
   list = g_list_next (list);
-  if (!list)
-    list = stroke->anchors;
+  if (! list)
+    list = stroke->anchors->head;
 
   for (i = 0; i <= 1; i++)
     {
       gimp_stroke_anchor_move_relative (stroke, GIMP_ANCHOR (list->data),
                                         &(offsetcoords[i]), feature);
       list = g_list_next (list);
-      if (!list)
-        list = stroke->anchors;
+      if (! list)
+        list = stroke->anchors->head;
     }
 }
 
@@ -471,7 +486,7 @@ gimp_bezier_stroke_point_move_absolute (GimpStroke            *stroke,
   GList      *list;
   gint        i;
 
-  segment_start = g_list_find (stroke->anchors, predec);
+  segment_start = g_queue_find (stroke->anchors, predec);
 
   g_return_if_fail (segment_start != NULL);
 
@@ -481,8 +496,8 @@ gimp_bezier_stroke_point_move_absolute (GimpStroke            *stroke,
     {
       beziercoords[i] = GIMP_ANCHOR (list->data)->position;
       list = g_list_next (list);
-      if (!list)
-        list = stroke->anchors;
+      if (! list)
+        list = stroke->anchors->head;
     }
 
   gimp_coords_mix ((1-position)*(1-position)*(1-position), &(beziercoords[0]),
@@ -506,8 +521,8 @@ gimp_bezier_stroke_close (GimpStroke *stroke)
   GList      *end;
   GimpAnchor *anchor;
 
-  start = g_list_first (stroke->anchors);
-  end = g_list_last (stroke->anchors);
+  start = stroke->anchors->head;
+  end   = stroke->anchors->tail;
 
   g_return_if_fail (start->next != NULL && end->prev != NULL);
 
@@ -522,23 +537,17 @@ gimp_bezier_stroke_close (GimpStroke *stroke)
         {
           /* redundant segment */
 
-          anchor = GIMP_ANCHOR (stroke->anchors->data);
-          stroke->anchors = g_list_delete_link (stroke->anchors,
-                                                stroke->anchors);
-          gimp_anchor_free (anchor);
+          gimp_anchor_free (stroke->anchors->tail->data);
+          g_queue_delete_link (stroke->anchors, stroke->anchors->tail);
 
-          anchor = GIMP_ANCHOR (stroke->anchors->data);
-          stroke->anchors = g_list_delete_link (stroke->anchors,
-                                                stroke->anchors);
-          gimp_anchor_free (anchor);
+          gimp_anchor_free (stroke->anchors->tail->data);
+          g_queue_delete_link (stroke->anchors, stroke->anchors->tail);
 
-          anchor = GIMP_ANCHOR (stroke->anchors->data);
-          stroke->anchors = g_list_delete_link (stroke->anchors,
-                                                stroke->anchors);
+          anchor = stroke->anchors->tail->data;
+          g_queue_delete_link (stroke->anchors, stroke->anchors->tail);
 
-          end = g_list_last (stroke->anchors);
-          gimp_anchor_free (GIMP_ANCHOR (end->data));
-          end->data = anchor;
+          gimp_anchor_free (stroke->anchors->head->data);
+          stroke->anchors->head->data = anchor;
         }
     }
 
@@ -563,14 +572,14 @@ gimp_bezier_stroke_nearest_point_get (const GimpStroke     *stroke,
   GimpAnchor *anchor;
   gint        count;
 
-  if (!stroke->anchors)
+  if (g_queue_is_empty (stroke->anchors))
     return -1.0;
 
   count = 0;
   min_dist = -1;
   pos = 0;
 
-  for (anchorlist = stroke->anchors;
+  for (anchorlist = stroke->anchors->head;
        GIMP_ANCHOR (anchorlist->data)->type != GIMP_ANCHOR_ANCHOR;
        anchorlist = g_list_next (anchorlist));
 
@@ -611,9 +620,9 @@ gimp_bezier_stroke_nearest_point_get (const GimpStroke     *stroke,
         }
     }
 
-  if (stroke->closed && stroke->anchors)
+  if (stroke->closed && stroke->anchors->head)
     {
-      anchorlist = stroke->anchors;
+      anchorlist = stroke->anchors->head;
 
       while (count < 3)
         {
@@ -800,13 +809,13 @@ gimp_bezier_stroke_nearest_tangent_get (const GimpStroke  *stroke,
   GimpAnchor *anchor;
   gint        count;
 
-  if (!stroke->anchors)
+  if (g_queue_is_empty (stroke->anchors))
     return -1.0;
 
   count = 0;
   min_dist = -1;
 
-  for (anchorlist = stroke->anchors;
+  for (anchorlist = stroke->anchors->head;
        GIMP_ANCHOR (anchorlist->data)->type != GIMP_ANCHOR_ANCHOR;
        anchorlist = g_list_next (anchorlist));
 
@@ -847,9 +856,9 @@ gimp_bezier_stroke_nearest_tangent_get (const GimpStroke  *stroke,
         }
     }
 
-  if (stroke->closed && stroke->anchors)
+  if (stroke->closed && ! g_queue_is_empty (stroke->anchors))
     {
-      anchorlist = stroke->anchors;
+      anchorlist = stroke->anchors->head;
 
       while (count < 3)
         {
@@ -987,14 +996,14 @@ gimp_bezier_stroke_is_extendable (GimpStroke *stroke,
   if (stroke->closed)
     return FALSE;
 
-  if (stroke->anchors == NULL)
+  if (g_queue_is_empty (stroke->anchors))
     return TRUE;
 
   /* assure that there is a neighbor specified */
   g_return_val_if_fail (neighbor != NULL, FALSE);
 
   loose_end = 0;
-  listneighbor = g_list_last (stroke->anchors);
+  listneighbor = stroke->anchors->tail;
 
   /* Check if the neighbor is at an end of the control points */
   if (listneighbor->data == neighbor)
@@ -1003,7 +1012,8 @@ gimp_bezier_stroke_is_extendable (GimpStroke *stroke,
     }
   else
     {
-      listneighbor = g_list_first (stroke->anchors);
+      listneighbor = g_list_first (stroke->anchors->head);
+
       if (listneighbor->data == neighbor)
         {
           loose_end = -1;
@@ -1016,7 +1026,7 @@ gimp_bezier_stroke_is_extendable (GimpStroke *stroke,
            * Yes, this is tedious.
            */
 
-          listneighbor = g_list_find (stroke->anchors, neighbor);
+          listneighbor = g_queue_find (stroke->anchors, neighbor);
 
           if (listneighbor && neighbor->type == GIMP_ANCHOR_CONTROL)
             {
@@ -1069,14 +1079,14 @@ gimp_bezier_stroke_extend (GimpStroke           *stroke,
   GList      *listneighbor;
   gint        loose_end, control_count;
 
-  if (stroke->anchors == NULL)
+  if (g_queue_is_empty (stroke->anchors))
     {
       /* assure that there is no neighbor specified */
       g_return_val_if_fail (neighbor == NULL, NULL);
 
       anchor = gimp_anchor_new (GIMP_ANCHOR_CONTROL, coords);
 
-      stroke->anchors = g_list_append (stroke->anchors, anchor);
+      g_queue_push_tail (stroke->anchors, anchor);
 
       switch (extend_mode)
         {
@@ -1107,7 +1117,7 @@ gimp_bezier_stroke_extend (GimpStroke           *stroke,
       g_return_val_if_fail (neighbor != NULL, NULL);
 
       loose_end = 0;
-      listneighbor = g_list_last (stroke->anchors);
+      listneighbor = stroke->anchors->tail;
 
       /* Check if the neighbor is at an end of the control points */
       if (listneighbor->data == neighbor)
@@ -1116,7 +1126,8 @@ gimp_bezier_stroke_extend (GimpStroke           *stroke,
         }
       else
         {
-          listneighbor = g_list_first (stroke->anchors);
+          listneighbor = stroke->anchors->head;
+
           if (listneighbor->data == neighbor)
             {
               loose_end = -1;
@@ -1129,7 +1140,7 @@ gimp_bezier_stroke_extend (GimpStroke           *stroke,
                * Yes, this is tedious.
                */
 
-              listneighbor = g_list_find (stroke->anchors, neighbor);
+              listneighbor = g_queue_find (stroke->anchors, neighbor);
 
               if (listneighbor && neighbor->type == GIMP_ANCHOR_CONTROL)
                 {
@@ -1156,7 +1167,7 @@ gimp_bezier_stroke_extend (GimpStroke           *stroke,
                  */
                 {
                   if (listneighbor->next &&
-                           listneighbor->next->next == NULL)
+                      listneighbor->next->next == NULL)
                     {
                       loose_end = 1;
                       listneighbor = listneighbor->next;
@@ -1224,10 +1235,10 @@ gimp_bezier_stroke_extend (GimpStroke           *stroke,
               anchor = gimp_anchor_new (type, coords);
 
               if (loose_end == 1)
-                stroke->anchors = g_list_append (stroke->anchors, anchor);
+                g_queue_push_tail (stroke->anchors, anchor);
 
               if (loose_end == -1)
-                stroke->anchors = g_list_prepend (stroke->anchors, anchor);
+                g_queue_push_head (stroke->anchors, anchor);
               break;
 
             case EXTEND_EDITABLE:
@@ -1262,6 +1273,7 @@ gimp_bezier_stroke_extend (GimpStroke           *stroke,
 
           return anchor;
         }
+
       return NULL;
     }
 }
@@ -1275,9 +1287,9 @@ gimp_bezier_stroke_connect_stroke (GimpStroke *stroke,
   GList *list1;
   GList *list2;
 
-  list1 = g_list_find (stroke->anchors, anchor);
+  list1 = g_queue_find (stroke->anchors, anchor);
   list1 = gimp_bezier_stroke_get_anchor_listitem (list1);
-  list2 = g_list_find (extension->anchors, neighbor);
+  list2 = g_queue_find (extension->anchors, neighbor);
   list2 = gimp_bezier_stroke_get_anchor_listitem (list2);
 
   g_return_val_if_fail (list1 != NULL && list2 != NULL, FALSE);
@@ -1294,20 +1306,22 @@ gimp_bezier_stroke_connect_stroke (GimpStroke *stroke,
 
   if (list1->prev && list1->prev->prev == NULL)
     {
-      stroke->anchors = g_list_reverse (stroke->anchors);
+      g_queue_reverse (stroke->anchors);
     }
 
   g_return_val_if_fail (list1->next && list1->next->next == NULL, FALSE);
 
   if (list2->next && list2->next->next == NULL)
     {
-      extension->anchors = g_list_reverse (extension->anchors);
+      g_queue_reverse (extension->anchors);
     }
 
   g_return_val_if_fail (list2->prev && list2->prev->prev == NULL, FALSE);
 
-  stroke->anchors = g_list_concat (stroke->anchors, extension->anchors);
-  extension->anchors = NULL;
+  for (list1 = extension->anchors->head; list1; list1 = g_list_next (list1))
+    g_queue_push_tail (stroke->anchors, list1->data);
+
+  g_queue_clear (extension->anchors);
 
   return TRUE;
 }
@@ -1331,7 +1345,7 @@ gimp_bezier_stroke_anchor_move_relative (GimpStroke            *stroke,
   gimp_coords_add (&(anchor->position), &delta, &coord1);
   anchor->position = coord1;
 
-  anchor_list = g_list_find (stroke->anchors, anchor);
+  anchor_list = g_queue_find (stroke->anchors, anchor);
   g_return_if_fail (anchor_list != NULL);
 
   if (anchor->type == GIMP_ANCHOR_ANCHOR)
@@ -1406,7 +1420,7 @@ gimp_bezier_stroke_anchor_convert (GimpStroke            *stroke,
 {
   GList *anchor_list;
 
-  anchor_list = g_list_find (stroke->anchors, anchor);
+  anchor_list = g_queue_find (stroke->anchors, anchor);
 
   g_return_if_fail (anchor_list != NULL);
 
@@ -1540,7 +1554,7 @@ gimp_bezier_stroke_interpolate (const GimpStroke  *stroke,
   gint        count;
   gboolean    need_endpoint = FALSE;
 
-  if (!stroke->anchors)
+  if (g_queue_is_empty (stroke->anchors))
     {
       if (ret_closed)
         *ret_closed = FALSE;
@@ -1551,7 +1565,7 @@ gimp_bezier_stroke_interpolate (const GimpStroke  *stroke,
 
   count = 0;
 
-  for (anchorlist = stroke->anchors;
+  for (anchorlist = stroke->anchors->head;
        anchorlist && GIMP_ANCHOR (anchorlist->data)->type != GIMP_ANCHOR_ANCHOR;
        anchorlist = g_list_next (anchorlist));
 
@@ -1576,9 +1590,9 @@ gimp_bezier_stroke_interpolate (const GimpStroke  *stroke,
         }
     }
 
-  if (stroke->closed && stroke->anchors)
+  if (stroke->closed && ! g_queue_is_empty (stroke->anchors))
     {
-      anchorlist = stroke->anchors;
+      anchorlist = stroke->anchors->head;
 
       while (count < 3)
         {
@@ -1617,19 +1631,17 @@ gimp_bezier_stroke_interpolate (const GimpStroke  *stroke,
 GimpStroke *
 gimp_bezier_stroke_new_moveto (const GimpCoords *start)
 {
-  GimpStroke *stroke;
-
-  stroke = gimp_bezier_stroke_new ();
-
-  stroke->anchors = g_list_prepend (stroke->anchors,
-                                    gimp_anchor_new (GIMP_ANCHOR_CONTROL,
-                                                     start));
-  stroke->anchors = g_list_prepend (stroke->anchors,
-                                    gimp_anchor_new (GIMP_ANCHOR_ANCHOR,
-                                                     start));
-  stroke->anchors = g_list_prepend (stroke->anchors,
-                                    gimp_anchor_new (GIMP_ANCHOR_CONTROL,
-                                                     start));
+  GimpStroke *stroke = gimp_bezier_stroke_new ();
+
+  g_queue_push_tail (stroke->anchors,
+                     gimp_anchor_new (GIMP_ANCHOR_CONTROL,
+                                      start));
+  g_queue_push_tail (stroke->anchors,
+                     gimp_anchor_new (GIMP_ANCHOR_ANCHOR,
+                                      start));
+  g_queue_push_tail (stroke->anchors,
+                     gimp_anchor_new (GIMP_ANCHOR_CONTROL,
+                                      start));
   return stroke;
 }
 
@@ -1639,17 +1651,17 @@ gimp_bezier_stroke_lineto (GimpStroke       *stroke,
 {
   g_return_if_fail (GIMP_IS_BEZIER_STROKE (stroke));
   g_return_if_fail (stroke->closed == FALSE);
-  g_return_if_fail (stroke->anchors != NULL);
-
-  stroke->anchors = g_list_prepend (stroke->anchors,
-                                    gimp_anchor_new (GIMP_ANCHOR_CONTROL,
-                                                     end));
-  stroke->anchors = g_list_prepend (stroke->anchors,
-                                    gimp_anchor_new (GIMP_ANCHOR_ANCHOR,
-                                                     end));
-  stroke->anchors = g_list_prepend (stroke->anchors,
-                                    gimp_anchor_new (GIMP_ANCHOR_CONTROL,
-                                                     end));
+  g_return_if_fail (g_queue_is_empty (stroke->anchors) == FALSE);
+
+  g_queue_push_tail (stroke->anchors,
+                     gimp_anchor_new (GIMP_ANCHOR_CONTROL,
+                                      end));
+  g_queue_push_tail (stroke->anchors,
+                     gimp_anchor_new (GIMP_ANCHOR_ANCHOR,
+                                      end));
+  g_queue_push_tail (stroke->anchors,
+                     gimp_anchor_new (GIMP_ANCHOR_CONTROL,
+                                      end));
 }
 
 void
@@ -1661,26 +1673,25 @@ gimp_bezier_stroke_conicto (GimpStroke       *stroke,
 
   g_return_if_fail (GIMP_IS_BEZIER_STROKE (stroke));
   g_return_if_fail (stroke->closed == FALSE);
-  g_return_if_fail (stroke->anchors != NULL);
-  g_return_if_fail (stroke->anchors->next != NULL);
+  g_return_if_fail (g_queue_get_length (stroke->anchors) > 1);
 
-  start = GIMP_ANCHOR (stroke->anchors->next->data)->position;
+  start = GIMP_ANCHOR (stroke->anchors->tail->prev->data)->position;
 
   gimp_coords_mix (2.0 / 3.0, control, 1.0 / 3.0, &start, &coords);
 
-  GIMP_ANCHOR (stroke->anchors->data)->position = coords;
+  GIMP_ANCHOR (stroke->anchors->tail->data)->position = coords;
 
   gimp_coords_mix (2.0 / 3.0, control, 1.0 / 3.0, end, &coords);
 
-  stroke->anchors = g_list_prepend (stroke->anchors,
-                                    gimp_anchor_new (GIMP_ANCHOR_CONTROL,
-                                                     &coords));
-  stroke->anchors = g_list_prepend (stroke->anchors,
-                                    gimp_anchor_new (GIMP_ANCHOR_ANCHOR,
-                                                     end));
-  stroke->anchors = g_list_prepend (stroke->anchors,
-                                    gimp_anchor_new (GIMP_ANCHOR_CONTROL,
-                                                     end));
+  g_queue_push_tail (stroke->anchors,
+                     gimp_anchor_new (GIMP_ANCHOR_CONTROL,
+                                      &coords));
+  g_queue_push_tail (stroke->anchors,
+                     gimp_anchor_new (GIMP_ANCHOR_CONTROL,
+                                      end));
+  g_queue_push_tail (stroke->anchors,
+                     gimp_anchor_new (GIMP_ANCHOR_ANCHOR,
+                                      end));
 }
 
 void
@@ -1691,19 +1702,19 @@ gimp_bezier_stroke_cubicto (GimpStroke       *stroke,
 {
   g_return_if_fail (GIMP_IS_BEZIER_STROKE (stroke));
   g_return_if_fail (stroke->closed == FALSE);
-  g_return_if_fail (stroke->anchors != NULL);
-
-  GIMP_ANCHOR (stroke->anchors->data)->position = *control1;
-
-  stroke->anchors = g_list_prepend (stroke->anchors,
-                                    gimp_anchor_new (GIMP_ANCHOR_CONTROL,
-                                                     control2));
-  stroke->anchors = g_list_prepend (stroke->anchors,
-                                    gimp_anchor_new (GIMP_ANCHOR_ANCHOR,
-                                                     end));
-  stroke->anchors = g_list_prepend (stroke->anchors,
-                                    gimp_anchor_new (GIMP_ANCHOR_CONTROL,
-                                                     end));
+  g_return_if_fail (g_queue_is_empty (stroke->anchors) == FALSE);
+
+  GIMP_ANCHOR (stroke->anchors->tail->data)->position = *control1;
+
+  g_queue_push_tail (stroke->anchors,
+                     gimp_anchor_new (GIMP_ANCHOR_CONTROL,
+                                      control2));
+  g_queue_push_tail (stroke->anchors,
+                     gimp_anchor_new (GIMP_ANCHOR_CONTROL,
+                                      end));
+  g_queue_push_tail (stroke->anchors,
+                     gimp_anchor_new (GIMP_ANCHOR_ANCHOR,
+                                      end));
 }
 
 static gdouble
@@ -1866,8 +1877,7 @@ gimp_bezier_stroke_arcto (GimpStroke       *bez_stroke,
 
   g_return_if_fail (GIMP_IS_BEZIER_STROKE (bez_stroke));
   g_return_if_fail (bez_stroke->closed == FALSE);
-  g_return_if_fail (bez_stroke->anchors != NULL);
-  g_return_if_fail (bez_stroke->anchors->next != NULL);
+  g_return_if_fail (g_queue_get_length (bez_stroke->anchors) > 1);
 
   if (radius_x == 0 || radius_y == 0)
     {
@@ -1875,7 +1885,7 @@ gimp_bezier_stroke_arcto (GimpStroke       *bez_stroke,
       return;
     }
 
-  start = GIMP_ANCHOR (bez_stroke->anchors->next->data)->position;
+  start = GIMP_ANCHOR (bez_stroke->anchors->tail->prev->data)->position;
 
   gimp_matrix3_identity (&anglerot);
   gimp_matrix3_rotate (&anglerot, -angle_rad);
@@ -2043,7 +2053,7 @@ gimp_bezier_stroke_new_ellipse (const GimpCoords *center,
   gimp_coords_mix (1.0, center, 1.0, &dx, &p1);
   stroke = gimp_bezier_stroke_new_moveto (&p1);
 
-  handle = g_list_last (GIMP_STROKE (stroke)->anchors)->data;
+  handle = g_queue_peek_tail (stroke->anchors);
   gimp_coords_mix (1.0,    &p1, -circlemagic, &dy, &handle->position);
 
   gimp_coords_mix (1.0,    &p1,  circlemagic, &dy, &p1);
@@ -2061,7 +2071,7 @@ gimp_bezier_stroke_new_ellipse (const GimpCoords *center,
   gimp_coords_mix (1.0,    &p3, -circlemagic, &dx, &p2);
   gimp_bezier_stroke_cubicto (stroke, &p1, &p2, &p3);
 
-  handle = g_list_first (GIMP_STROKE (stroke)->anchors)->data;
+  handle = g_queue_peek_tail (stroke->anchors);
   gimp_coords_mix (1.0,    &p3,  circlemagic, &dx, &handle->position);
 
   gimp_stroke_close (stroke);
diff --git a/app/vectors/gimpstroke.c b/app/vectors/gimpstroke.c
index b71dd79..8351852 100644
--- a/app/vectors/gimpstroke.c
+++ b/app/vectors/gimpstroke.c
@@ -264,9 +264,7 @@ gimp_stroke_class_init (GimpStrokeClass *klass)
 static void
 gimp_stroke_init (GimpStroke *stroke)
 {
-  stroke->ID      = 0;
-  stroke->anchors = NULL;
-  stroke->closed  = FALSE;
+  stroke->anchors = g_queue_new ();
 }
 
 static void
@@ -287,7 +285,7 @@ gimp_stroke_set_property (GObject      *object,
       break;
 
     case PROP_CONTROL_POINTS:
-      g_return_if_fail (stroke->anchors == NULL);
+      g_return_if_fail (g_queue_is_empty (stroke->anchors));
       g_return_if_fail (value != NULL);
 
       val_array = g_value_get_boxed (value);
@@ -302,8 +300,7 @@ gimp_stroke_set_property (GObject      *object,
           GValue *item = gimp_value_array_index (val_array, i);
 
           g_return_if_fail (G_VALUE_HOLDS (item, GIMP_TYPE_ANCHOR));
-          stroke->anchors = g_list_append (stroke->anchors,
-                                           g_value_dup_boxed (item));
+          g_queue_push_tail (stroke->anchors, g_value_dup_boxed (item));
         }
 
       break;
@@ -339,11 +336,8 @@ gimp_stroke_finalize (GObject *object)
 {
   GimpStroke *stroke = GIMP_STROKE (object);
 
-  if (stroke->anchors)
-    {
-      g_list_free_full (stroke->anchors, (GDestroyNotify) gimp_anchor_free);
-      stroke->anchors = NULL;
-    }
+  g_queue_free_full (stroke->anchors, (GDestroyNotify) gimp_anchor_free);
+  stroke->anchors = NULL;
 
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
@@ -355,7 +349,7 @@ gimp_stroke_get_memsize (GimpObject *object,
   GimpStroke *stroke  = GIMP_STROKE (object);
   gint64      memsize = 0;
 
-  memsize += gimp_g_list_get_memsize (stroke->anchors, sizeof (GimpAnchor));
+  memsize += gimp_g_queue_get_memsize (stroke->anchors, sizeof (GimpAnchor));
 
   return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object,
                                                                   gui_size);
@@ -528,13 +522,13 @@ gimp_stroke_real_anchor_get_next (const GimpStroke *stroke,
 
   if (prev)
     {
-      list = g_list_find (stroke->anchors, prev);
+      list = g_queue_find (stroke->anchors, prev);
       if (list)
         list = g_list_next (list);
     }
   else
     {
-      list = stroke->anchors;
+      list = stroke->anchors->head;
     }
 
   if (list)
@@ -562,9 +556,7 @@ gimp_stroke_real_anchor_select (GimpStroke *stroke,
                                 gboolean    selected,
                                 gboolean    exclusive)
 {
-  GList *list;
-
-  list = stroke->anchors;
+  GList *list = stroke->anchors->head;
 
   if (exclusive)
     {
@@ -575,7 +567,7 @@ gimp_stroke_real_anchor_select (GimpStroke *stroke,
         }
     }
 
-  list = g_list_find (stroke->anchors, anchor);
+  list = g_queue_find (stroke->anchors, anchor);
 
   if (list)
     GIMP_ANCHOR (list->data)->selected = selected;
@@ -590,7 +582,7 @@ gimp_stroke_anchor_move_relative (GimpStroke            *stroke,
 {
   g_return_if_fail (GIMP_IS_STROKE (stroke));
   g_return_if_fail (anchor != NULL);
-  g_return_if_fail (g_list_find (stroke->anchors, anchor));
+  g_return_if_fail (g_queue_find (stroke->anchors, anchor));
 
   GIMP_STROKE_GET_CLASS (stroke)->anchor_move_relative (stroke, anchor,
                                                         delta, feature);
@@ -615,7 +607,7 @@ gimp_stroke_anchor_move_absolute (GimpStroke            *stroke,
 {
   g_return_if_fail (GIMP_IS_STROKE (stroke));
   g_return_if_fail (anchor != NULL);
-  g_return_if_fail (g_list_find (stroke->anchors, anchor));
+  g_return_if_fail (g_queue_find (stroke->anchors, anchor));
 
   GIMP_STROKE_GET_CLASS (stroke)->anchor_move_absolute (stroke, anchor,
                                                         coord, feature);
@@ -707,7 +699,7 @@ void
 gimp_stroke_close (GimpStroke *stroke)
 {
   g_return_if_fail (GIMP_IS_STROKE (stroke));
-  g_return_if_fail (stroke->anchors != NULL);
+  g_return_if_fail (g_queue_is_empty (stroke->anchors) == FALSE);
 
   GIMP_STROKE_GET_CLASS (stroke)->close (stroke);
 }
@@ -896,7 +888,7 @@ gimp_stroke_is_empty (const GimpStroke *stroke)
 static gboolean
 gimp_stroke_real_is_empty (const GimpStroke *stroke)
 {
-  return stroke->anchors == NULL;
+  return g_queue_is_empty (stroke->anchors);
 }
 
 
@@ -918,7 +910,7 @@ gimp_stroke_real_get_length (const GimpStroke *stroke,
   gdouble     length;
   GimpCoords  difference;
 
-  if (!stroke->anchors)
+  if (g_queue_is_empty (stroke->anchors))
     return -1;
 
   points = gimp_stroke_interpolate (stroke, precision, NULL);
@@ -999,9 +991,9 @@ gimp_stroke_real_duplicate (const GimpStroke *stroke)
                              "name", gimp_object_get_name (stroke),
                              NULL);
 
-  new_stroke->anchors = g_list_copy (stroke->anchors);
+  new_stroke->anchors = g_queue_copy (stroke->anchors);
 
-  for (list = new_stroke->anchors; list; list = g_list_next (list))
+  for (list = new_stroke->anchors->head; list; list = g_list_next (list))
     {
       list->data = gimp_anchor_copy (GIMP_ANCHOR (list->data));
     }
@@ -1047,7 +1039,7 @@ gimp_stroke_real_translate (GimpStroke *stroke,
 {
   GList *list;
 
-  for (list = stroke->anchors; list; list = g_list_next (list))
+  for (list = stroke->anchors->head; list; list = g_list_next (list))
     {
       GimpAnchor *anchor = list->data;
 
@@ -1074,7 +1066,7 @@ gimp_stroke_real_scale (GimpStroke *stroke,
 {
   GList *list;
 
-  for (list = stroke->anchors; list; list = g_list_next (list))
+  for (list = stroke->anchors->head; list; list = g_list_next (list))
     {
       GimpAnchor *anchor = list->data;
 
@@ -1174,7 +1166,7 @@ gimp_stroke_real_transform (GimpStroke        *stroke,
 {
   GList *list;
 
-  for (list = stroke->anchors; list; list = g_list_next (list))
+  for (list = stroke->anchors->head; list; list = g_list_next (list))
     {
       GimpAnchor *anchor = list->data;
 
@@ -1201,7 +1193,7 @@ gimp_stroke_real_get_draw_anchors (const GimpStroke  *stroke)
   GList *list;
   GList *ret_list = NULL;
 
-  for (list = stroke->anchors; list; list = g_list_next (list))
+  for (list = stroke->anchors->head; list; list = g_list_next (list))
     {
       if (GIMP_ANCHOR (list->data)->type == GIMP_ANCHOR_ANCHOR)
         ret_list = g_list_prepend (ret_list, list->data);
@@ -1225,7 +1217,7 @@ gimp_stroke_real_get_draw_controls (const GimpStroke  *stroke)
   GList *list;
   GList *ret_list = NULL;
 
-  for (list = stroke->anchors; list; list = g_list_next (list))
+  for (list = stroke->anchors->head; list; list = g_list_next (list))
     {
       GimpAnchor *anchor = list->data;
 
@@ -1238,7 +1230,8 @@ gimp_stroke_real_get_draw_controls (const GimpStroke  *stroke)
             {
               /* Ok, this is a hack.
                * The idea is to give control points at the end of a
-               * stroke a higher priority for the interactive tool. */
+               * stroke a higher priority for the interactive tool.
+               */
               if (prev)
                 ret_list = g_list_prepend (ret_list, anchor);
               else
@@ -1274,7 +1267,7 @@ gimp_stroke_real_get_draw_lines (const GimpStroke  *stroke)
   GArray *ret_lines = NULL;
   gint    count = 0;
 
-  for (list = stroke->anchors; list; list = g_list_next (list))
+  for (list = stroke->anchors->head; list; list = g_list_next (list))
     {
       GimpAnchor *anchor = list->data;
 
@@ -1327,11 +1320,11 @@ gimp_stroke_real_control_points_get (const GimpStroke *stroke,
   GArray *ret_array;
   GList *list;
 
-  num_anchors = g_list_length (stroke->anchors);
+  num_anchors = g_queue_get_length (stroke->anchors);
   ret_array = g_array_sized_new (FALSE, FALSE,
                                  sizeof (GimpAnchor), num_anchors);
 
-  for (list = g_list_first (stroke->anchors); list; list = g_list_next (list))
+  for (list = stroke->anchors->head; list; list = g_list_next (list))
     {
       g_array_append_vals (ret_array, list->data, 1);
     }
diff --git a/app/vectors/gimpstroke.h b/app/vectors/gimpstroke.h
index 34a1c4c..1823382 100644
--- a/app/vectors/gimpstroke.h
+++ b/app/vectors/gimpstroke.h
@@ -39,7 +39,7 @@ struct _GimpStroke
   GimpObject  parent_instance;
   gint        ID;
 
-  GList      *anchors;
+  GQueue     *anchors;
 
   gboolean    closed;
 };
diff --git a/app/vectors/gimpvectors-compat.c b/app/vectors/gimpvectors-compat.c
index 1826088..e4ef13e 100644
--- a/app/vectors/gimpvectors-compat.c
+++ b/app/vectors/gimpvectors-compat.c
@@ -204,7 +204,7 @@ gimp_vectors_compat_get_points (GimpVectors *vectors,
             }
         }
 
-      n_anchors = g_list_length (stroke->anchors);
+      n_anchors = g_queue_get_length (stroke->anchors);
 
       if (! stroke->closed)
         n_anchors--;
@@ -237,7 +237,7 @@ gimp_vectors_compat_get_points (GimpVectors *vectors,
           postponed = NULL;
         }
 
-      for (anchors = stroke->anchors;
+      for (anchors = stroke->anchors->head;
            anchors;
            anchors = g_list_next (anchors))
         {
@@ -250,7 +250,7 @@ gimp_vectors_compat_get_points (GimpVectors *vectors,
           switch (anchor->type)
             {
             case GIMP_ANCHOR_ANCHOR:
-              if (anchors->prev == stroke->anchors && ! first_stroke)
+              if (anchors->prev == stroke->anchors->head && ! first_stroke)
                 points[i].type = GIMP_VECTORS_COMPAT_NEW_STROKE;
               else
                 points[i].type = GIMP_VECTORS_COMPAT_ANCHOR;
@@ -269,7 +269,7 @@ gimp_vectors_compat_get_points (GimpVectors *vectors,
           /*  write the skipped control point  */
           if (! anchors->next && stroke->closed)
             {
-              anchor = GIMP_ANCHOR (stroke->anchors->data);
+              anchor = g_queue_peek_head (stroke->anchors);
 
               points[i].type = GIMP_VECTORS_COMPAT_CONTROL;
               points[i].x    = anchor->position.x;
diff --git a/app/vectors/gimpvectors-warp.c b/app/vectors/gimpvectors-warp.c
index 17d8401..938b64c 100644
--- a/app/vectors/gimpvectors-warp.c
+++ b/app/vectors/gimpvectors-warp.c
@@ -141,7 +141,7 @@ gimp_vectors_warp_stroke (const GimpVectors *vectors,
 {
   GList *list;
 
-  for (list = stroke->anchors; list; list = g_list_next (list))
+  for (list = stroke->anchors->head; list; list = g_list_next (list))
     {
       GimpAnchor *anchor = list->data;
 


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