summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSøren Sandmann Pedersen <ssp@redhat.com>2012-10-05 00:39:37 -0400
committerSøren Sandmann Pedersen <ssp@redhat.com>2012-10-05 00:39:37 -0400
commit1a505f4fdbc040da940e9c55c2cdefc5e1178a8d (patch)
tree8fba8ebf11f300e3fe4d444ca6ef40f351a718f0
parent4f5a86a90eba179a74d5ba92887814e5d4dcb504 (diff)
fimage
-rw-r--r--fimage.c476
-rw-r--r--fimage.h22
2 files changed, 498 insertions, 0 deletions
diff --git a/fimage.c b/fimage.c
new file mode 100644
index 0000000..42247d3
--- /dev/null
+++ b/fimage.c
@@ -0,0 +1,476 @@
+#include <stdlib.h>
+#include <pixman.h>
+#include "fimage.h"
+
+struct fimage_t
+{
+ pixman_bool_t broken;
+ int n_allocated_fragments;
+ int n_fragments;
+ fragment_t * fragments[1];
+};
+
+static const fimage_t broken_fimage =
+{
+ TRUE, /* broken */
+ 0,
+ NULL
+};
+
+static fimage_t *
+fimage_new (fragment_t *fragment)
+{
+ fimage_t *fimage;
+
+ if (fragment_is_broken (fragment))
+ return (fimage_t *)&broken_fimage;
+
+ fimage = malloc (sizeof *fimage);
+ if (!fimage)
+ {
+ fragment_free (fragment);
+ return (fimage_t *)&broken_fimage;
+ }
+
+ fimage->broken = FALSE;
+ fimage->n_allocated_fragments = 1;
+ fimage->n_fragments = 1;
+ fimage->fragments[0] = fragment;
+
+ return fimage;
+}
+
+static fimage_t *
+fimage_ensure_space (fimage_t *fimage, int n_more)
+{
+ size_t required_fragments = fimage->n_fragments + n_more;
+
+ if (required_fragments > fimage->n_allocated_fragments)
+ {
+ size_t pot = 1;
+ size_t space;
+ fimage_t *new_image;
+
+ while (pot < required_fragments)
+ pot *= 2;
+
+ space = sizeof (fimage_t) + (pot - 1) * sizeof (fragment_t *);
+
+ new_image = realloc (fimage, space);
+
+ if (!new_image)
+ {
+ fimage_free (fimage);
+ return (fimage_t *)&broken_fimage;
+ }
+
+ new_image->n_allocated_fragments = pot;
+
+ fimage = new_image;
+ }
+
+ return fimage;
+}
+
+static fimage_t *
+fimage_append_fragment (fimage_t *fimage, fragment_t *fragment)
+{
+ fimage = ensure_space (fimage, 1);
+ if (fimage->broken)
+ return fimage;
+
+ fimage->fragments[fimage->n_fragments++] = fragment;
+ return fimage;
+}
+
+fimage_t *
+fimage_new_blank (int width, int height)
+{
+ return fimage_new (fragment_new_blank (width, height));
+}
+
+fimage_t *
+fimage_new_white (int width, int height)
+{
+ return fimage_new (fragment_new_white (width, height));
+}
+
+fimage_t *
+fimage_new_traps (int width, int height,
+ int n_traps, pixman_trapezoid_t *traps)
+{
+ return fimage_new (fragment_new_traps (width, height, n_traps, traps));
+}
+
+fimage_t *
+fimage_new_glyphs (int width, int height,
+ pixman_glyph_cache_t *cache,
+ int n_glyphs,
+ pixman_glyph_t *glyphs)
+{
+ return fimage_new (
+ fragment_new_glyphs (width, height, cache, n_glyphs, glyphs));
+}
+
+/* Takes ownership of the image */
+fimage_t *
+fimage_new_image (int width, int height, pixman_image_t *image)
+{
+ return fimage_new (fragment_new_image (width, height, image));
+}
+
+
+/* Makes a copy of the region; does not take ownership */
+fimage_t *
+fimage_new_region (int width, int height,
+ pixman_region32_t *region)
+{
+ fragment1 = fragment_new_blank (width, height);
+
+ fragment2 = fragment_new_region (region);
+
+ fragment1 = fragment_subtract (fragment1, fragment_2);
+
+ image = fimage_new (fragment1);
+ image = fimage_append_fragment (image, fragment2);
+
+ return image;
+}
+
+
+
+
+
+/*
+
+ Memory management:
+
+ For traps we don't want to copy them, so the image should take ownership.
+ Maybe the cairo->pixman conversion should just take place inside the image?
+ Maybe it doesn't matter that much.
+ Maybe polygon images will make the question irrelevant.
+ However, we definitely don't want to copy the traps structure to
+ all the fragments.
+
+ For pimages, have the image take a ref would be more convenient.
+
+ For initializing with a region, it would be convenient, but not essential,
+ if we can avoid copying the region parameter.
+
+ Structures internal to the images and fragments are of course managed and
+ owned by the structures in question.
+
+ - images take ownership
+ - fragments take ownership
+ - fragments wrap objects in refcountable structure
+ - fragments don't ref pixman images
+ - fragments ref the given objects
+ - pixman images are reffed by the fragments, and unreffed
+ when the image is destroyed.
+
+ - ref countable state object?
+
+*/
+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)
+{
+ if (fragment->broken)
+ return;
+
+
+ /* 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 @source
+ * and one that doesn't. Both may be NULL. @dest is freed or reused.
+ */
+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)
+{
+ if ((op == PIXMAN_OP_ADD && dest->state == BLANK) ||
+ (op == PIXMAN_OP_IN && is_opaque (dest)))
+ {
+ op = PIXMAN_OP_SRC;
+ }
+
+ switch (op)
+ {
+ case PIXMAN_OP_SRC:
+ copy_state (result, src);
+ break;
+
+ case PIXMAN_OP_IN:
+ if (dest->state == BLANK || src->state == BLANK)
+ result->state == BLANK;
+ break;
+
+ case PIXMAN_OP_OUT_REVERSE:
+ if (is_opaque (src))
+ result->state == BLANK;
+ else if (src->state == BLANK)
+ copy_state (result, dest->state);
+ break;
+
+ default:
+ /* FIXME: add command to composite the images */
+ 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)
+{
+ if (image->broken)
+ return;
+
+ /* 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;
+}
diff --git a/fimage.h b/fimage.h
index cc357d2..9efc4ba 100644
--- a/fimage.h
+++ b/fimage.h
@@ -26,6 +26,8 @@ fragment_t *fragment_new_region (pixman_region32_t *region);
* (dest OP source).
*
* The intersection is subtracted from dest. The source is not changed
+ *
+ * Should probably be called "fragment_new_composite (op, dest, source)" FIXME
*/
fragment_t * fragment_composite (fragment_t *dest,
pixman_op_t op,
@@ -39,3 +41,23 @@ pixman_bool_t fragment_apply (fragment_t *fragment,
pixman_image_t *image);
void fragment_free (fragment_t *fragment);
+
+
+
+/* Images */
+typedef struct fimage_t fimage_t;
+
+fimage_t *fimage_new_blank (int width, int height);
+fimage_t *fimage_new_white (int width, int height);
+/* Takes ownership of @glyphs, but not glyph_cache */
+fimage_t *fimage_new_glyphs (int width, int height,
+ pixman_glyph_cache_t *glyph_cache,
+ int n_glyphs,
+ pixman_glyphs_t *glyphs);
+/* Takes ownership of the trapezoids */
+fimage_t *fimage_new_traps (int width, int height, int n_traps, pixman_trapezoids_t *traps);
+/* Takes ownership of the image */
+fimage_t *fimage_new_image (pixman_image_t *image);
+/* Makes a copy of the region; does not take ownership */
+fimage_t *fimage_new_region (int width, int height,
+ pixman_region32_t *region);