summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSøren Sandmann Pedersen <ssp@redhat.com>2012-10-05 19:46:31 -0400
committerSøren Sandmann Pedersen <ssp@redhat.com>2012-10-05 19:46:31 -0400
commit0e0173d59087073a34feefc518447c68422c2ac6 (patch)
tree0adfeb030323f9ff2475eb315307d594838a8fac
parent644c2143eb023b6e26e22207a135621e969f27f0 (diff)
-rw-r--r--src/cairo-pixman-surface.c217
1 files changed, 216 insertions, 1 deletions
diff --git a/src/cairo-pixman-surface.c b/src/cairo-pixman-surface.c
index 63148462..57d220da 100644
--- a/src/cairo-pixman-surface.c
+++ b/src/cairo-pixman-surface.c
@@ -342,6 +342,7 @@ cairo_pixman_surface_get_font_options (void *abstract_surface,
typedef enum
{
+ NOP,
NEW_BLANK,
NEW_BROKEN,
NEW_WHITE,
@@ -416,6 +417,9 @@ typedef union
pixman_op_t op;
int src;
int mask;
+
+ /* Generated by optimizer */
+ pixman_region32_t * clip;
} composite;
} command_t;
@@ -625,10 +629,203 @@ command_buffer_composite (command_buffer_t **buffer,
command->composite.src = src;
command->composite.mask = mask;
command->composite.op = op;
+
+ command->composite.clip = NULL;
}
static const pixman_color_t white = { 0xffff, 0xffff, 0xffff, 0xffff };
+static void
+command_buffer_optimize (command_buffer_t *buffer)
+{
+ typedef struct
+ {
+ enum {
+ UNKNOWN,
+ BLANK,
+ REGION,
+ WHITE,
+ IMAGE,
+ TRAPS,
+ GLYPHS,
+ CLIPPED_MASK,
+ } type;
+
+ int same_as;
+
+ union
+ {
+ pixman_region32_t *region;
+
+ struct
+ {
+ int mask;
+ pixman_region32_t *clip;
+ } clipped_mask;
+ } u;
+
+ } image_info_t;
+
+ image_info_t *info;
+ cairo_bool_t changed;
+ int i;
+
+ if (!(info = calloc (sizeof (image_info_t), buffer->id)))
+ return;
+
+ for (i = 0; i < buffer->id; ++i)
+ {
+ image_info_t *image = &(info[i]);
+
+ image->type = UNKNOWN;
+ image->same_as = -1;
+ }
+
+ for (i = 0; i < buffer->n_commands; ++i)
+ {
+ command_t *command = &(buffer->commands[i]);
+
+ switch (command->type)
+ {
+ case NEW_BLANK:
+ info[command->new_blank.id].type = BLANK;
+ break;
+
+ case NEW_WHITE:
+ info[command->new_white.id].type = WHITE;
+ break;
+
+ case NEW_IMAGE:
+ info[command->new_image.id].type = IMAGE;
+ break;
+
+ case NEW_REGION:
+ info[command->new_region.id].type = REGION;
+
+ info[command->new_region.id].u.region =
+ command->new_region.region;
+ break;
+
+ case NEW_TRAPS:
+ info[command->new_traps.id].type = TRAPS;
+ break;
+
+ case NEW_GLYPHS:
+ info[command->new_glyphs.id].type = GLYPHS;
+ break;
+
+ case NOP:
+ case NEW_BROKEN:
+ case COMPOSITE:
+ default:
+ break;
+ }
+ }
+
+ do
+ {
+ changed = FALSE;
+ for (i = 0; i < buffer->n_commands; ++i)
+ {
+ command_t *command = &(buffer->commands[i]);
+ int src, mask, dest;
+
+ switch (command->type)
+ {
+ case NOP:
+ break;
+
+ case COMPOSITE:
+ src = command->composite.src;
+ mask = command->composite.mask;
+ dest = command->composite.dest;
+
+ if (info[src].same_as != -1)
+ {
+ src = command->composite.src = info[src].same_as;
+ changed = TRUE;
+ }
+ if (info[mask].same_as != -1)
+ {
+ mask = command->composite.mask = info[mask].same_as;
+ changed = TRUE;
+ }
+ if (info[dest].same_as != -1)
+ {
+ dest = command->composite.dest = info[dest].same_as;
+ changed = TRUE;
+ }
+ if (command->composite.op == PIXMAN_OP_SRC)
+ {
+ if (info[src].type == REGION &&
+ info[mask].type == WHITE &&
+ info[dest].type == BLANK &&
+ !command->composite.clip)
+ {
+ info[dest].same_as = src;
+ command->type = NOP;
+
+ changed = TRUE;
+ }
+ else if (info[src].type == REGION &&
+ info[dest].type == BLANK &&
+ !command->composite.clip)
+ {
+ int j;
+ int white = -1;
+
+ for (j = 0; j < i; ++j)
+ {
+ image_info_t *in = &(info[j]);
+
+ if (in->type == WHITE)
+ {
+ white = j;
+ break;
+ }
+ }
+
+ if (white != -1)
+ {
+ printf ("tick\n");
+ command->composite.clip = info[src].u.region;
+ src = command->composite.src = white;
+ }
+
+ changed = TRUE;
+ }
+ else if (info[src].type == WHITE &&
+ info[dest].type == BLANK &&
+ command->composite.clip)
+ {
+ info[dest].type = CLIPPED_MASK;
+ info[dest].u.clipped_mask.mask = mask;
+ info[dest].u.clipped_mask.clip =
+ command->composite.clip;
+
+ changed = TRUE;
+ }
+ }
+ else if (command->composite.op == PIXMAN_OP_OVER ||
+ command->composite.op == PIXMAN_OP_ADD)
+ {
+ if (info[mask].type == CLIPPED_MASK &&
+ !command->composite.clip)
+ {
+ command->composite.mask = info[mask].u.clipped_mask.mask;
+ command->composite.clip = info[mask].u.clipped_mask.clip;
+
+ changed = TRUE;
+ }
+ }
+ }
+ }
+ } while (changed);
+
+out:
+ free (info);
+}
+
static cairo_int_status_t
command_buffer_process (command_buffer_t *buffer, int width, int height)
{
@@ -642,6 +839,8 @@ command_buffer_process (command_buffer_t *buffer, int width, int height)
if (buffer->oom)
goto out;
+ command_buffer_optimize (buffer);
+
n_images = buffer->id;
if (!(images = calloc (sizeof (pixman_image_t *), n_images)))
goto out;
@@ -657,6 +856,10 @@ command_buffer_process (command_buffer_t *buffer, int width, int height)
switch (command->type)
{
+ case NOP:
+ printf ("nop\n");
+ break;
+
case NEW_BLANK:
printf ("%d => blank\n", command->new_blank.id);
@@ -752,13 +955,25 @@ command_buffer_process (command_buffer_t *buffer, int width, int height)
break;
case COMPOSITE:
- printf ("composite %d (src: %d mask: %d dest: %d)\n", command->composite.op, command->composite.src, command->composite.mask, command->composite.dest);
+ printf ("composite %d (src: %d mask: %d dest: %d) clip: %d\n", command->composite.op, command->composite.src, command->composite.mask, command->composite.dest, command->composite.clip? pixman_region32_n_rects (command->composite.clip) : -1);
+ if (command->composite.clip)
+ {
+ pixman_image_set_clip_region32 (
+ images[command->composite.dest], command->composite.clip);
+ }
+
pixman_image_composite32 (
command->composite.op,
images[command->composite.src],
images[command->composite.mask],
images[command->composite.dest],
0, 0, 0, 0, 0, 0, width, height);
+
+ if (command->composite.clip)
+ {
+ pixman_image_set_clip_region32 (
+ images[command->composite.dest], NULL);
+ }
break;
}
}