From 935764d91c6fee4aa30ea59464f4670e5f70f7c8 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 9 Oct 2005 20:40:12 +0000 Subject: [PATCH] Switch fallback from list of rects to region. Check operator and patterns for non-ps drawing ability. Operators can sometimes be always opaque, independent of the pattern, sometimes always translucent, independent of the pattern and sometimes depend on whether is translucent. reviewed by: cworth --- ChangeLog | 20 +++++ src/cairo-ps-surface.c | 183 ++++++++++++++++++++++++++++++++--------- 2 files changed, 165 insertions(+), 38 deletions(-) diff --git a/ChangeLog b/ChangeLog index e19f576a4..e5a2a040a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,23 @@ +2005-10-09 Keith Packard + + reviewed by: cworth + + * src/cairo-ps-surface.c: (_ps_output_add_fallback_area), + (_ps_output_finish), (format_is_translucent), + (surface_is_translucent), (gradient_is_translucent), + (pattern_is_translucent), (operator_always_opaque), + (operator_always_translucent), (color_operation_needs_fallback), + (pattern_operation_needs_fallback), (_ps_output_fill_rectangles), + (_ps_output_composite_trapezoids), (_ps_output_show_glyphs), + (_ps_output_fill_path), (_ps_output_render_fallbacks), + (_ps_output_surface_create): + Switch fallback from list of rects to region. + Check operator and patterns for non-ps drawing ability. + Operators can sometimes be always opaque, independent of + the pattern, sometimes always translucent, independent of + the pattern and sometimes depend on whether is + translucent. + 2005-10-09 Keith Packard * src/cairo-image-surface.c: (_cairo_surface_is_image): diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c index 29c3c1238..6aa9ca78f 100644 --- a/src/cairo-ps-surface.c +++ b/src/cairo-ps-surface.c @@ -34,6 +34,7 @@ * Contributor(s): * Carl D. Worth * Kristian Høgsberg + * Keith Packard */ #include "cairoint.h" @@ -572,17 +573,10 @@ _cairo_ps_surface_write_font_subsets (cairo_ps_surface_t *surface) return CAIRO_STATUS_SUCCESS; } -typedef struct _cairo_ps_fallback_area cairo_ps_fallback_area_t; -struct _cairo_ps_fallback_area { - int x, y; - unsigned int width, height; - cairo_ps_fallback_area_t *next; -}; - typedef struct _ps_output_surface { cairo_surface_t base; cairo_ps_surface_t *parent; - cairo_ps_fallback_area_t *fallback_areas; + pixman_region16_t *fallback_region; } ps_output_surface_t; static cairo_int_status_t @@ -591,23 +585,11 @@ _ps_output_add_fallback_area (ps_output_surface_t *surface, unsigned int width, unsigned int height) { - cairo_ps_fallback_area_t *area; + if (!surface->fallback_region) + surface->fallback_region = pixman_region_create (); - /* FIXME: Do a better job here. Ideally, we would use a 32 bit - * region type, but probably just computing bounding boxes would - * also work fine. */ - - area = malloc (sizeof (cairo_ps_fallback_area_t)); - if (area == NULL) - return CAIRO_STATUS_NO_MEMORY; - - area->x = x; - area->y = y; - area->width = width; - area->height = height; - area->next = surface->fallback_areas; - - surface->fallback_areas = area; + pixman_region_union_rect (surface->fallback_region, surface->fallback_region, + x, y, width, height); return CAIRO_STATUS_SUCCESS; } @@ -616,12 +598,9 @@ static cairo_status_t _ps_output_finish (void *abstract_surface) { ps_output_surface_t *surface = abstract_surface; - cairo_ps_fallback_area_t *area, *next; - for (area = surface->fallback_areas; area != NULL; area = next) { - next = area->next; - free (area); - } + if (surface->fallback_region) + pixman_region_destroy (surface->fallback_region); return CAIRO_STATUS_SUCCESS; } @@ -642,24 +621,152 @@ color_is_translucent (const cairo_color_t *color) } static cairo_bool_t -pattern_is_translucent (cairo_pattern_t *abstract_pattern) +format_is_translucent (cairo_format_t format) { - cairo_pattern_union_t *pattern; + switch (format) { + case CAIRO_FORMAT_ARGB32: + return TRUE; + case CAIRO_FORMAT_RGB24: + return FALSE; + case CAIRO_FORMAT_A8: + return TRUE; + case CAIRO_FORMAT_A1: + return TRUE; + } + return TRUE; +} + +static cairo_bool_t +surface_is_translucent (const cairo_surface_t *surface) +{ + if (_cairo_surface_is_image (surface)) { + const cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface; + + return format_is_translucent (image_surface->format); + } + return TRUE; +} + +static cairo_bool_t +gradient_is_translucent (const cairo_gradient_pattern_t *gradient) +{ + return TRUE; /* XXX no gradient support */ +#if 0 + int i; + + for (i = 0; i < gradient->n_stops; i++) + if (color_is_translucent (&gradient->stops[i].color)) + return TRUE; + return FALSE; +#endif +} + +static cairo_bool_t +pattern_is_translucent (const cairo_pattern_t *abstract_pattern) +{ + const cairo_pattern_union_t *pattern; pattern = (cairo_pattern_union_t *) abstract_pattern; switch (pattern->base.type) { case CAIRO_PATTERN_SOLID: return color_is_translucent (&pattern->solid.color); case CAIRO_PATTERN_SURFACE: + return surface_is_translucent (pattern->surface.surface); case CAIRO_PATTERN_LINEAR: case CAIRO_PATTERN_RADIAL: - return FALSE; + return gradient_is_translucent (&pattern->gradient.base); } ASSERT_NOT_REACHED; return FALSE; } +static cairo_bool_t +operator_always_opaque (cairo_operator_t operator) +{ + switch (operator) { + case CAIRO_OPERATOR_CLEAR: + + case CAIRO_OPERATOR_SOURCE: + return TRUE; + + case CAIRO_OPERATOR_OVER: + case CAIRO_OPERATOR_IN: + case CAIRO_OPERATOR_OUT: + case CAIRO_OPERATOR_ATOP: + return FALSE; + + case CAIRO_OPERATOR_DEST: + return TRUE; + + case CAIRO_OPERATOR_DEST_OVER: + case CAIRO_OPERATOR_DEST_IN: + case CAIRO_OPERATOR_DEST_OUT: + case CAIRO_OPERATOR_DEST_ATOP: + return FALSE; + + case CAIRO_OPERATOR_XOR: + case CAIRO_OPERATOR_ADD: + case CAIRO_OPERATOR_SATURATE: + return FALSE; + } + return FALSE; +} + +static cairo_bool_t +operator_always_translucent (cairo_operator_t operator) +{ + switch (operator) { + case CAIRO_OPERATOR_CLEAR: + + case CAIRO_OPERATOR_SOURCE: + return FALSE; + + case CAIRO_OPERATOR_OVER: + case CAIRO_OPERATOR_IN: + case CAIRO_OPERATOR_OUT: + case CAIRO_OPERATOR_ATOP: + return FALSE; + + case CAIRO_OPERATOR_DEST: + return FALSE; + + case CAIRO_OPERATOR_DEST_OVER: + case CAIRO_OPERATOR_DEST_IN: + case CAIRO_OPERATOR_DEST_OUT: + case CAIRO_OPERATOR_DEST_ATOP: + return FALSE; + + case CAIRO_OPERATOR_XOR: + case CAIRO_OPERATOR_ADD: + case CAIRO_OPERATOR_SATURATE: + return TRUE; + } + return TRUE; +} + +static cairo_bool_t +color_operation_needs_fallback (cairo_operator_t operator, + const cairo_color_t *color) +{ + if (operator_always_opaque (operator)) + return FALSE; + if (operator_always_translucent (operator)) + return TRUE; + return color_is_translucent (color); +} + +static cairo_bool_t +pattern_operation_needs_fallback (cairo_operator_t operator, + const cairo_pattern_t *pattern) +{ + if (operator_always_opaque (operator)) + return FALSE; + if (operator_always_translucent (operator)) + return TRUE; + return pattern_is_translucent (pattern); +} + /* PS Output - this section handles output of the parts of the meta * surface we can render natively in PS. */ @@ -946,7 +1053,7 @@ _ps_output_fill_rectangles (void *abstract_surface, if (!num_rects) return CAIRO_STATUS_SUCCESS; - if (color_is_translucent (color)) { + if (color_operation_needs_fallback (operator, color)) { int min_x = rects[0].x; int min_y = rects[0].y; int max_x = rects[0].x + rects[0].width; @@ -1008,7 +1115,7 @@ _ps_output_composite_trapezoids (cairo_operator_t operator, cairo_output_stream_t *stream = surface->parent->stream; int i; - if (pattern_is_translucent (pattern)) + if (pattern_operation_needs_fallback (operator, pattern)) return _ps_output_add_fallback_area (surface, x_dst, y_dst, width, height); _cairo_output_stream_printf (stream, @@ -1189,7 +1296,7 @@ _ps_output_show_glyphs (cairo_scaled_font_t *scaled_font, if (! _cairo_scaled_font_is_ft (scaled_font)) return CAIRO_INT_STATUS_UNSUPPORTED; - if (pattern_is_translucent (pattern)) + if (pattern_operation_needs_fallback (operator, pattern)) return _ps_output_add_fallback_area (surface, dest_x, dest_y, width, height); _cairo_output_stream_printf (stream, @@ -1242,7 +1349,7 @@ _ps_output_fill_path (cairo_operator_t operator, ps_output_path_info_t info; const char *ps_operator; - if (pattern_is_translucent (pattern)) + if (pattern_operation_needs_fallback (operator, pattern)) return _ps_output_add_fallback_area (surface, 0, 0, surface->parent->width, @@ -1311,7 +1418,7 @@ _ps_output_render_fallbacks (cairo_surface_t *surface, int width, height; ps_output = (ps_output_surface_t *) surface; - if (ps_output->fallback_areas == NULL) + if (ps_output->fallback_region == NULL) return CAIRO_STATUS_SUCCESS; width = ps_output->parent->width * ps_output->parent->x_dpi / 72; @@ -1361,7 +1468,7 @@ _ps_output_surface_create (cairo_ps_surface_t *parent) _cairo_surface_init (&ps_output->base, &ps_output_backend); ps_output->parent = parent; - ps_output->fallback_areas = NULL; + ps_output->fallback_region = NULL; return &ps_output->base; }