summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSøren Sandmann Pedersen <ssp@redhat.com>2012-10-02 13:19:48 -0400
committerSøren Sandmann Pedersen <ssp@redhat.com>2012-10-02 13:19:48 -0400
commit179bf69ffaf55854be017e742ac8aff12e11ee97 (patch)
tree057be0f59414d4dad198309b2a5d26e832b8725e
Initial checkin
-rw-r--r--fragments.c280
1 files changed, 280 insertions, 0 deletions
diff --git a/fragments.c b/fragments.c
new file mode 100644
index 0000000..670e97f
--- /dev/null
+++ b/fragments.c
@@ -0,0 +1,280 @@
+#include <stdlib.h>
+#include <pixman.h>
+
+typedef struct fragment_t fragment_t;
+typedef struct image_t image_t;
+typedef struct command_buffer_t command_buffer_t;
+
+#define TRUE 1
+#define FALSE 0
+
+typedef enum
+{
+ BLANK,
+ WHITE,
+ SOLID,
+ TRAPS,
+ PIXMAN,
+ COMMANDS
+} state_t;
+
+struct fragment_t
+{
+ pixman_bool_t broken;
+ pixman_region32_t region;
+ fragment_t * next;
+
+ /* State - should this be a separate structure? */
+ state_t state;
+ pixman_bool_t alpha_only;
+ union
+ {
+ pixman_color_t solid;
+ struct
+ {
+ int n_traps;
+ pixman_trapezoid_t *traps;
+ } traps;
+ pixman_image_t *image;
+ command_buffer_t *buffer;
+ } u;
+};
+
+struct image_t
+{
+ pixman_bool_t broken;
+ int width, height;
+ fragment_t * fragments;
+};
+
+static const image_t broken =
+{
+ TRUE /* broken */
+};
+
+static const fragment_t broken_fragment =
+{
+ TRUE
+};
+
+static fragment_t *
+fragment_new (int width, int height)
+{
+ fragment_t *result = malloc (sizeof *result);
+
+ if (!result)
+ return (fragment_t *)&broken_fragment;
+
+ pixman_region32_init_rect (&result->region, 0, 0, width, height);
+
+ return result;
+}
+
+static void
+fragment_free (fragment_t *fragment)
+{
+ /* FIXME */
+}
+
+static void
+fragment_set_blank (fragment_t *fragment)
+{
+ if (fragment->broken)
+ return;
+
+ fragment->state = BLANK;
+}
+
+static void
+fragment_set_pixman (fragment_t *fragment, pixman_image_t *image)
+{
+ if (fragment->broken)
+ return;
+
+ fragment->state = PIXMAN;
+ fragment->u.image = image;
+}
+
+/* Split @fragment into two parts: one that intersects with other,
+ * and one that doesn't.
+ */
+static void
+fragment_intersect (fragment_t *dest, fragment_t *source,
+ fragment_t **intersection,
+ fragment_t **remains)
+{
+ *intersection = NULL;
+
+ if (dest->broken)
+ {
+ *remains = NULL;
+ return;
+ }
+
+ *remains = dest;
+
+ if (source->broken)
+ {
+ *intersection = NULL;
+ return;
+ }
+
+ *intersection = fragment_new (0, 0);
+
+ if ((*intersection)->broken)
+ {
+ *intersection = NULL;
+ return;
+ }
+
+ if (!pixman_region32_intersect (&((*intersection)->region),
+ &(dest->region),
+ &(source->region)))
+ {
+ fragment_free (*intersection);
+ *intersection = NULL;
+ return;
+ }
+
+ if (!pixman_region32_subtract (&(dest->region), &(dest->region),
+ &(*intersection)->region))
+ {
+ fragment_free (dest);
+ fragment_free (*intersection);
+ *remains = NULL;
+ *intersection = NULL;
+ return;
+ }
+
+ if (!pixman_region32_not_empty (&(*intersection)->region))
+ {
+ fragment_free (*intersection);
+ *intersection = NULL;
+ }
+
+ if (!pixman_region32_not_empty (&dest->region))
+ {
+ fragment_free (dest);
+ *remains = NULL;
+ }
+}
+
+static void
+fragment_composite (fragment_t *result, pixman_op_t op,
+ fragment_t *dest, fragment_t *src)
+{
+ switch (op)
+ {
+ case PIXMAN_OP_IN:
+ if (dest->state == BLANK || src->state == BLANK)
+ result->state == BLANK;
+ else if (is_opaque (dest))
+ copy_state (result, src);
+ break;
+ }
+}
+
+static image_t *
+allocate_image (int width, int height)
+{
+ image_t *image = malloc (sizeof *image);
+
+ if (!image)
+ return (image_t *)&broken;
+
+ image->width = width;
+ image->height = height;
+ image->fragments = fragment_new (width, height);
+
+ return image;
+}
+
+static image_t *
+image_new_blank (int width, int height)
+{
+ image_t *image;
+
+ image = allocate_image (width, height);
+ if (image->broken)
+ return image;
+
+ fragment_set_blank (image->fragments);
+ return image;
+}
+
+void
+image_free (image_t *image)
+{
+ /* FIXME */
+}
+
+static image_t *
+image_new_pixman (int width, int height, pixman_image_t *pimage)
+{
+ image_t *image;
+
+ image = allocate_image (width, height);
+ if (image->broken)
+ return image;
+
+ fragment_set_pixman (image->fragments, pimage);
+ return image;
+}
+
+static void
+image_composite (image_t *dest, pixman_op_t op, image_t *src, image_t *mask)
+{
+ fragment_t *sfrag;
+
+ if (dest->broken || src->broken || (mask && mask->broken))
+ return;
+
+ if (mask)
+ {
+ image_t *tmp = allocate_image (dest->width, dest->height);
+
+ image_composite (tmp, PIXMAN_OP_SRC, mask, NULL);
+ image_composite (tmp, PIXMAN_OP_IN, src, NULL);
+ image_composite (dest, op, tmp, NULL);
+
+ image_free (tmp);
+
+ return;
+ }
+
+ sfrag = src->fragments;
+ while (sfrag)
+ {
+ fragment_t *new_fragments = NULL;
+ fragment_t *dfrag;
+
+ dfrag = dest->fragments;
+ while (dfrag != NULL)
+ {
+ fragment_t *intersection, *remains;
+ fragment_t *next = dfrag->next;
+
+ fragment_intersect (dfrag, sfrag, &intersection, &remains);
+
+ if (intersection)
+ {
+ fragment_composite (intersect, op, dfrag, sfrag);
+
+ intersection->next = new_fragments;
+ new_fragments = intersection;
+ }
+
+ if (remains)
+ {
+ remains->next = new_fragments;
+ new_fragments = remains;
+ }
+
+ dfrag = next;
+ }
+
+ sfrag = sfrag->next;
+ }
+
+ dest->fragments = new_fragments;
+}