]> git.ipfire.org Git - thirdparty/plymouth.git/commitdiff
[libply] Add new region class
authorRay Strode <rstrode@redhat.com>
Thu, 20 Aug 2009 03:55:43 +0000 (23:55 -0400)
committerRay Strode <rstrode@redhat.com>
Mon, 28 Sep 2009 15:23:35 +0000 (11:23 -0400)
Sometimes it's necessary to deal with a disjoint
set of rectangles together.

One big example is when keeping track of which parts of
the screen have changed.

Another example would be for non-rectangular clip masks.

This commit adds a new region class to simplify the handling
of these types of cases.

src/libply/Makefile.am
src/libply/ply-region.c [new file with mode: 0644]
src/libply/ply-region.h [new file with mode: 0644]

index da145755adc9c58d2362d469119afc8cf7490518..f87bf25de5c9e9bf1d5df63e436cb40779a51bbe 100644 (file)
@@ -24,6 +24,7 @@ libply_HEADERS = \
                    ply-key-file.h                                            \
                    ply-progress.h                                            \
                    ply-rectangle.h                                           \
+                   ply-region.h                                              \
                    ply-terminal-session.h                                    \
                    ply-trigger.h                                             \
                    ply-utils.h
@@ -46,6 +47,7 @@ libply_la_SOURCES = ply-event-loop.c                                          \
                    ply-key-file.c                                            \
                    ply-progress.c                                            \
                    ply-rectangle.c                                           \
+                   ply-region.c                                              \
                    ply-terminal-session.c                                    \
                    ply-trigger.c                                             \
                    ply-utils.c
diff --git a/src/libply/ply-region.c b/src/libply/ply-region.c
new file mode 100644 (file)
index 0000000..ec6ca5d
--- /dev/null
@@ -0,0 +1,390 @@
+/* ply-region.c
+ *
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * Based in part on some work by:
+ *  Copyright (C) 2009 Charlie Brej <cbrej@cs.man.ac.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Written by: Charlie Brej <cbrej@cs.man.ac.uk>
+ *             Ray Strode <rstrode@redhat.com>
+ */
+#include "config.h"
+#include "ply-region.h"
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "ply-list.h"
+#include "ply-rectangle.h"
+
+struct _ply_region
+{
+  ply_list_t *rectangle_list;
+};
+
+ply_region_t *
+ply_region_new (void)
+{
+  ply_region_t *region;
+
+  region = calloc (1, sizeof (ply_region_t));
+
+  region->rectangle_list = ply_list_new ();
+
+  return region;
+}
+
+void
+ply_region_clear (ply_region_t *region)
+{
+  ply_list_node_t *node;
+
+  node = ply_list_get_first_node (region->rectangle_list);
+  while (node != NULL)
+    {
+      ply_list_node_t *next_node;
+      ply_rectangle_t *rectangle;
+
+      rectangle = (ply_rectangle_t *) ply_list_node_get_data (node);
+
+      next_node = ply_list_get_next_node (region->rectangle_list, node);
+
+      free (rectangle);
+      ply_list_remove_node (region->rectangle_list, node);
+
+      node = next_node;
+    }
+}
+
+void
+ply_region_free (ply_region_t *region)
+{
+
+  ply_region_clear (region);
+  ply_list_free (region->rectangle_list);
+  free (region);
+}
+
+static ply_rectangle_t *
+copy_rectangle (ply_rectangle_t *rectangle)
+{
+  ply_rectangle_t *new_rectangle;
+
+  new_rectangle = malloc (sizeof (*rectangle));
+  *new_rectangle = *rectangle;
+
+  return new_rectangle;
+}
+
+static void
+merge_rectangle_with_sub_list (ply_region_t    *region,
+                               ply_rectangle_t *new_area,
+                               ply_list_node_t *node)
+{
+
+  if (ply_rectangle_is_empty (new_area))
+    return;
+
+  while (node != NULL)
+    {
+      ply_list_node_t *next_node;
+      ply_rectangle_t *old_area;
+      ply_rectangle_overlap_t overlap;
+
+      old_area = (ply_rectangle_t *) ply_list_node_get_data (node);
+
+      next_node = ply_list_get_next_node (region->rectangle_list, node);
+
+      overlap = ply_rectangle_find_overlap (old_area, new_area);
+
+      switch (overlap)
+        {
+          /* NNNN      The new rectangle and node rectangle don't touch,
+           * NNNN OOOO so let's move on to the next one.
+           *      OOOO
+           */
+          case PLY_RECTANGLE_OVERLAP_NONE:
+          break;
+
+          /* NNNNN   We need to split the new rectangle into
+           * NNOOOOO two rectangles:  The top row of Ns and
+           * NNOOOOO the left side of Ns.
+           *   OOOOO
+           */
+          case PLY_RECTANGLE_OVERLAP_TOP_AND_LEFT_EDGES:
+            {
+              ply_rectangle_t *rectangle;
+
+              rectangle = copy_rectangle (new_area);
+              rectangle->y = old_area->y;
+              rectangle->width = old_area->x - new_area->x;
+              rectangle->height = (new_area->y + new_area->height) - old_area->y;
+
+              merge_rectangle_with_sub_list (region, rectangle, node);
+
+              new_area->height = old_area->y - new_area->y;
+            }
+          break;
+
+          /*   NNNNN We need to split the new rectangle into
+           * OOOOONN two rectangles:  The top row of Ns and
+           * OOOOONN the right side of Ns.
+           * OOOOO
+           */
+          case PLY_RECTANGLE_OVERLAP_TOP_AND_RIGHT_EDGES:
+            {
+              ply_rectangle_t *rectangle;
+
+              rectangle = copy_rectangle (new_area);
+              rectangle->x = new_area->x + old_area->width;
+              rectangle->y = old_area->y;
+              rectangle->width = (old_area->x + new_area->width) - (old_area->x + old_area->width);
+              rectangle->height = (new_area->y + new_area->height) - old_area->y;
+
+              merge_rectangle_with_sub_list (region, rectangle, node);
+
+              new_area->height = old_area->y - new_area->y;
+            }
+          break;
+
+          /* NNNNNNN We need to trim out the part of
+           * NOOOOON old rectangle that overlaps the new
+           * NOOOOON rectangle by shrinking and moving it
+           *  OOOOO  and then we need to add the new rectangle.
+           */
+          case PLY_RECTANGLE_OVERLAP_TOP_AND_SIDE_EDGES:
+            {
+              old_area->height = (old_area->y + old_area->height)
+                                 - (new_area->y + new_area->height);
+              old_area->y = new_area->y + new_area->height;
+            }
+
+          /*   NNN  We only care about the top row of Ns,
+           *  ONNNO everything below that is already handled by
+           *  ONNNO the old rectangle.
+           *  OOOOO
+           */
+          case PLY_RECTANGLE_OVERLAP_TOP_EDGE:
+            new_area->height = old_area->y - new_area->y;
+          break;
+
+          /*   OOOOO We need to split the new rectangle into
+           * NNOOOOO two rectangles:  The left side of Ns and
+           * NNOOOOO the bottom row of Ns.
+           * NNOOOOO
+           * NNNNN
+           */
+          case PLY_RECTANGLE_OVERLAP_BOTTOM_AND_LEFT_EDGES:
+            {
+              ply_rectangle_t *rectangle;
+
+              rectangle = copy_rectangle (new_area);
+
+              rectangle->y = old_area->y;
+              rectangle->width = old_area->x - new_area->x;
+              rectangle->height = (old_area->y + old_area->height) - new_area->y;
+
+              merge_rectangle_with_sub_list (region, rectangle, node);
+
+              new_area->height = (new_area->y + new_area->height) - (old_area->y + old_area->height);
+              new_area->width = new_area->width;
+              new_area->y = old_area->y + old_area->height;
+            }
+          break;
+
+          /*   OOOOO   We need to split the new rectangle into
+           *   OOOOONN two rectangles:  The right side of Ns and
+           *   OOOOONN the bottom row of Ns.
+           *   OOOOONN
+           *     NNNNN
+           */
+          case PLY_RECTANGLE_OVERLAP_BOTTOM_AND_RIGHT_EDGES:
+            {
+              ply_rectangle_t *rectangle;
+
+              rectangle = copy_rectangle (new_area);
+
+              rectangle->x = old_area->x + old_area->width;
+              rectangle->width = (new_area->x + new_area->width) - (old_area->x + old_area->width);
+              rectangle->height = (old_area->y + old_area->height) - new_area->y;
+
+              merge_rectangle_with_sub_list (region, rectangle, node);
+
+              new_area->height = (new_area->y + new_area->height) - (old_area->y + old_area->height);
+              new_area->y = old_area->y + old_area->height;
+            }
+          break;
+
+          /*  OOOOO  We need to trim out the part of
+           * NOOOOON old rectangle that overlaps the new
+           * NOOOOON rectangle by shrinking it
+           * NNNNNNN and then we need to add the new rectangle.
+           */
+          case PLY_RECTANGLE_OVERLAP_BOTTOM_AND_SIDE_EDGES:
+            {
+              old_area->height = (new_area->y + new_area->height)
+                                 - (old_area->y + old_area->height);
+            }
+          break;
+
+          /*  OOOOO We only care about the bottom row of Ns,
+           *  ONNNO everything above that is already handled by
+           *  ONNNO the old rectangle.
+           *   NNN
+           */
+          case PLY_RECTANGLE_OVERLAP_BOTTOM_EDGE:
+            {
+              new_area->height = (new_area->y + new_area->height) - (old_area->y + old_area->height);
+              new_area->y = old_area->y + old_area->height;
+            }
+          break;
+
+          /*  NNNN   We need to trim out the part of
+           *  NNNNO  old rectangle that overlaps the new
+           *  NNNNO  rectangle by shrinking it and moving it
+           *  NNNN   and then we need to add the new rectangle.
+           */
+          case PLY_RECTANGLE_OVERLAP_TOP_LEFT_AND_BOTTOM_EDGES:
+            {
+              old_area->width = (old_area->x + old_area->width)
+                                 - (new_area->x + new_area->width);
+              old_area->x = new_area->x + new_area->width;
+            }
+          break;
+
+          /*  NNNN  We need to trim out the part of
+           * ONNNN  old rectangle that overlaps the new
+           * ONNNN  rectangle by shrinking it and then we
+           *  NNNN  need to add the new rectangle.
+           */
+          case PLY_RECTANGLE_OVERLAP_TOP_RIGHT_AND_BOTTOM_EDGES:
+            old_area->width = new_area->x - old_area->x;
+          break;
+
+          /* NNNNNNN The old rectangle is completely inside the new rectangle
+           * NOOOOON so replace the old rectangle with the new rectangle.
+           * NOOOOON
+           * NNNNNNN
+           */
+          case PLY_RECTANGLE_OVERLAP_ALL_EDGES:
+            free (old_area);
+            ply_list_remove_node (region->rectangle_list, node);
+          break;
+
+          /*  NNN  We need to split the new rectangle into
+           * ONNNO two rectangles: the top and bottom row of Ns
+           * ONNNO
+           *  NNN
+           */
+          case PLY_RECTANGLE_OVERLAP_TOP_AND_BOTTOM_EDGES:
+            {
+              ply_rectangle_t *rectangle;
+
+              rectangle = copy_rectangle (new_area);
+              rectangle->y = old_area->y + old_area->height;
+              rectangle->width = new_area->width;
+              rectangle->height = (new_area->y + new_area->height) - (old_area->y + old_area->height);
+              merge_rectangle_with_sub_list (region, rectangle, node);
+
+              new_area->height = old_area->y - new_area->y;
+            }
+          break;
+
+          /*  OOOOO We only care about the side row of Ns,
+           * NNNNOO everything rigth of that is already handled by
+           * NNNNOO the old rectangle.
+           *  OOOOO
+           */
+          case PLY_RECTANGLE_OVERLAP_LEFT_EDGE:
+            new_area->width = old_area->x - new_area->x;
+          break;
+
+          /* OOOOO  We only care about the side row of Ns,
+           * NNNNNN everything left of that is already handled by
+           * NNNNNN the old rectangle.
+           * OOOOO
+           */
+          case PLY_RECTANGLE_OVERLAP_RIGHT_EDGE:
+            {
+              new_area->width = (new_area->x + new_area->width) - (old_area->x + old_area->width);
+              new_area->x = old_area->x + old_area->width;
+            }
+          break;
+
+          /*  OOOOO  We need to split the new rectangle into
+           * NNNNNNN two rectangles: the side columns of Ns
+           * NNNNNNN
+           *  OOOOO
+           */
+          case PLY_RECTANGLE_OVERLAP_SIDE_EDGES:
+            {
+              ply_rectangle_t *rectangle;
+
+              rectangle = copy_rectangle (new_area);
+
+              rectangle->x = old_area->x + old_area->width;
+              rectangle->width = (new_area->x + new_area->width) - (old_area->x + old_area->width);
+
+              merge_rectangle_with_sub_list (region, rectangle, node);
+
+              new_area->width = old_area->x - new_area->x;
+            }
+          break;
+
+          /* OOOOOOO The new rectangle is completely inside an old rectangle
+           * ONNNNNO so return early without adding the new rectangle.
+           * ONNNNNO
+           * OOOOOOO
+           */
+          case PLY_RECTANGLE_OVERLAP_NO_EDGES:
+            free (new_area);
+            return;
+
+        }
+
+      node = next_node;
+    }
+
+  ply_list_append_data (region->rectangle_list, new_area);
+}
+
+void
+ply_region_add_rectangle (ply_region_t    *region,
+                          ply_rectangle_t *rectangle)
+{
+  ply_list_node_t *first_node;
+  ply_rectangle_t *rectangle_copy;
+
+  assert (region != NULL);
+  assert (rectangle != NULL);
+
+  first_node = ply_list_get_first_node (region->rectangle_list);
+
+  rectangle_copy = copy_rectangle (rectangle);
+  merge_rectangle_with_sub_list (region,
+                                 rectangle_copy,
+                                 first_node);
+}
+
+ply_list_t *
+ply_region_get_rectangle_list (ply_region_t *region)
+{
+  return region->rectangle_list;
+}
+
+/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */
diff --git a/src/libply/ply-region.h b/src/libply/ply-region.h
new file mode 100644 (file)
index 0000000..ee6e992
--- /dev/null
@@ -0,0 +1,47 @@
+/* ply-region.h
+ *
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Written By: Ray Strode <rstrode@redhat.com>
+ */
+#ifndef PLY_REGION_H
+#define PLY_REGION_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "ply-list.h"
+#include "ply-rectangle.h"
+#include "ply-utils.h"
+
+typedef struct _ply_region ply_region_t;
+
+#ifndef PLY_HIDE_FUNCTION_DECLARATIONS
+ply_region_t *ply_region_new (void);
+void ply_region_free (ply_region_t *region);
+void ply_region_add_rectangle (ply_region_t    *region,
+                               ply_rectangle_t *rectangle);
+void ply_region_clear (ply_region_t *region);
+ply_list_t *ply_region_get_rectangle_list (ply_region_t *region);
+
+bool ply_region_is_empty (ply_region_t *region);
+
+#endif
+
+#endif /* PLY_REGION_H */
+/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */