diff options
author | Søren Sandmann Pedersen <ssp@redhat.com> | 2012-10-02 13:19:48 -0400 |
---|---|---|
committer | Søren Sandmann Pedersen <ssp@redhat.com> | 2012-10-02 13:19:48 -0400 |
commit | 179bf69ffaf55854be017e742ac8aff12e11ee97 (patch) | |
tree | 057be0f59414d4dad198309b2a5d26e832b8725e |
Initial checkin
-rw-r--r-- | fragments.c | 280 |
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; +} |