mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-01-18 14:40:30 +01:00
PS: Add finer-grained image fallback support
The analysis surface now keeps track of two regions: supported
operations, and unsupported operations. If the target surface returns
CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY, the analysis surface will check
if any previous operation intersects with this operation. If there is
nothing previously drawn under the operation, the status is changed to
supported.
The meta surface has two new functions:
_cairo_meta_surface_replay_region()
_cairo_meta_surface_replay_and_create_regions()
During the analysis stage, the paginated surface replays the meta
surface using _cairo_meta_surface_replay_and_create_regions(). The
return status from each analyzed operation is saved in the meta
surface. The _cairo_meta_surface_replay_region() function allows only
operations from either the supported or unsupported region to be
replayed. This allows the paginated surface to replay only the
supported operations before emitting a fallback image for each
rectangle in the unsupported region.
This commit is contained in:
parent
bf4bdbb607
commit
bf92255edd
9 changed files with 591 additions and 139 deletions
|
|
@ -48,6 +48,9 @@ _cairo_analysis_surface_get_supported (cairo_surface_t *surface);
|
|||
cairo_private cairo_region_t *
|
||||
_cairo_analysis_surface_get_unsupported (cairo_surface_t *unsupported);
|
||||
|
||||
cairo_private cairo_bool_t
|
||||
_cairo_analysis_surface_has_supported (cairo_surface_t *unsupported);
|
||||
|
||||
cairo_private cairo_bool_t
|
||||
_cairo_analysis_surface_has_unsupported (cairo_surface_t *unsupported);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright © 2006 Keith Packard
|
||||
* Copyright © 2007 Adrian Johnson
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it either under the terms of the GNU Lesser General Public
|
||||
|
|
@ -30,12 +31,14 @@
|
|||
*
|
||||
* Contributor(s):
|
||||
* Keith Packard <keithp@keithp.com>
|
||||
* Adrian Johnson <ajohnson@redneon.com>
|
||||
*/
|
||||
|
||||
#include "cairoint.h"
|
||||
|
||||
#include "cairo-analysis-surface-private.h"
|
||||
#include "cairo-paginated-private.h"
|
||||
#include "cairo-region-private.h"
|
||||
|
||||
typedef struct {
|
||||
cairo_surface_t base;
|
||||
|
|
@ -44,9 +47,121 @@ typedef struct {
|
|||
|
||||
cairo_surface_t *target;
|
||||
|
||||
cairo_bool_t fallback;
|
||||
cairo_bool_t has_supported;
|
||||
cairo_bool_t has_unsupported;
|
||||
|
||||
cairo_region_t supported_region;
|
||||
cairo_region_t fallback_region;
|
||||
cairo_rectangle_int_t current_clip;
|
||||
|
||||
} cairo_analysis_surface_t;
|
||||
|
||||
static cairo_int_status_t
|
||||
_cairo_analysis_surface_add_operation (cairo_analysis_surface_t *surface,
|
||||
cairo_rectangle_int_t *rect,
|
||||
cairo_int_status_t backend_status)
|
||||
{
|
||||
cairo_int_status_t status;
|
||||
|
||||
if (rect->width == 0 || rect->height == 0)
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
/* If the operation is completely enclosed within the fallback
|
||||
* region there is no benefit in emitting a native operation as
|
||||
* the fallback image will be painted on top.
|
||||
*/
|
||||
if (_cairo_region_contains_rectangle (&surface->fallback_region, rect) == PIXMAN_REGION_IN)
|
||||
return CAIRO_INT_STATUS_IMAGE_FALLBACK;
|
||||
|
||||
if (backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY) {
|
||||
/* A status of CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY indicates
|
||||
* that the backend only supports this operation if the
|
||||
* transparency removed. If the extents of this operation does
|
||||
* not intersect any other native operation, the operation is
|
||||
* natively supported and the backend will blend the
|
||||
* transparency into the white background.
|
||||
*/
|
||||
if (_cairo_region_contains_rectangle (&surface->supported_region, rect) == PIXMAN_REGION_OUT)
|
||||
backend_status = CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (backend_status == CAIRO_STATUS_SUCCESS) {
|
||||
/* Add the operation to the supported region. Operations in
|
||||
* this region will be emitted as native operations.
|
||||
*/
|
||||
surface->has_supported = TRUE;
|
||||
status = _cairo_region_union_rect (&surface->supported_region,
|
||||
&surface->supported_region,
|
||||
rect);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Add the operation to the unsupported region. This region will
|
||||
* be painted as an image after all native operations have been
|
||||
* emitted.
|
||||
*/
|
||||
surface->has_unsupported = TRUE;
|
||||
status = _cairo_region_union_rect (&surface->fallback_region,
|
||||
&surface->fallback_region,
|
||||
rect);
|
||||
|
||||
/* The status CAIRO_INT_STATUS_IMAGE_FALLBACK is used to indicate
|
||||
* unsupported operations to the meta surface as using
|
||||
* CAIRO_INT_STATUS_UNSUPPORTED would cause cairo-surface to
|
||||
* invoke the cairo-surface-fallback path then return
|
||||
* CAIRO_STATUS_SUCCESS.
|
||||
*/
|
||||
if (status == CAIRO_STATUS_SUCCESS)
|
||||
return CAIRO_INT_STATUS_IMAGE_FALLBACK;
|
||||
else
|
||||
return status;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_analysis_surface_finish (void *abstract_surface)
|
||||
{
|
||||
cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
|
||||
|
||||
_cairo_region_fini (&surface->supported_region);
|
||||
_cairo_region_fini (&surface->fallback_region);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static cairo_int_status_t
|
||||
_cairo_analysis_surface_intersect_clip_path (void *abstract_surface,
|
||||
cairo_path_fixed_t *path,
|
||||
cairo_fill_rule_t fill_rule,
|
||||
double tolerance,
|
||||
cairo_antialias_t antialias)
|
||||
{
|
||||
cairo_analysis_surface_t *surface = abstract_surface;
|
||||
double x1, y1, x2, y2;
|
||||
cairo_rectangle_int_t extent;
|
||||
cairo_status_t status;
|
||||
|
||||
if (path == NULL) {
|
||||
surface->current_clip.x = 0;
|
||||
surface->current_clip.y = 0;
|
||||
surface->current_clip.width = surface->width;
|
||||
surface->current_clip.height = surface->height;
|
||||
status = CAIRO_STATUS_SUCCESS;
|
||||
} else {
|
||||
status = _cairo_path_fixed_bounds (path, &x1, &y1, &x2, &y2);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
extent.x = floor (x1);
|
||||
extent.y = floor (y1);
|
||||
extent.width = ceil (x2) - extent.x;
|
||||
extent.height = ceil (y2) - extent.y;
|
||||
|
||||
_cairo_rectangle_intersect (&surface->current_clip, &extent);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static cairo_int_status_t
|
||||
_cairo_analysis_surface_get_extents (void *abstract_surface,
|
||||
cairo_rectangle_int_t *rectangle)
|
||||
|
|
@ -62,17 +177,32 @@ _cairo_analysis_surface_paint (void *abstract_surface,
|
|||
cairo_pattern_t *source)
|
||||
{
|
||||
cairo_analysis_surface_t *surface = abstract_surface;
|
||||
cairo_status_t status;
|
||||
cairo_status_t status, backend_status;
|
||||
cairo_rectangle_int_t extents;
|
||||
|
||||
if (!surface->target->backend->paint)
|
||||
status = CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
else
|
||||
status = (*surface->target->backend->paint) (surface->target, op,
|
||||
source);
|
||||
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
|
||||
surface->fallback = TRUE;
|
||||
status = CAIRO_STATUS_SUCCESS;
|
||||
backend_status = (*surface->target->backend->paint) (surface->target, op,
|
||||
source);
|
||||
|
||||
status = _cairo_surface_get_extents (&surface->base, &extents);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
if (_cairo_operator_bounded_by_source (op)) {
|
||||
cairo_rectangle_int_t source_extents;
|
||||
status = _cairo_pattern_get_extents (source, &source_extents);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
_cairo_rectangle_intersect (&extents, &source_extents);
|
||||
}
|
||||
|
||||
_cairo_rectangle_intersect (&extents, &surface->current_clip);
|
||||
|
||||
status = _cairo_analysis_surface_add_operation (surface, &extents, backend_status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
@ -83,17 +213,38 @@ _cairo_analysis_surface_mask (void *abstract_surface,
|
|||
cairo_pattern_t *mask)
|
||||
{
|
||||
cairo_analysis_surface_t *surface = abstract_surface;
|
||||
cairo_status_t status;
|
||||
cairo_status_t status, backend_status;
|
||||
cairo_rectangle_int_t extents;
|
||||
|
||||
if (!surface->target->backend->mask)
|
||||
status = CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
else
|
||||
status = (*surface->target->backend->mask) (surface->target, op,
|
||||
source, mask);
|
||||
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
|
||||
surface->fallback = TRUE;
|
||||
status = CAIRO_STATUS_SUCCESS;
|
||||
backend_status = (*surface->target->backend->mask) (surface->target, op,
|
||||
source, mask);
|
||||
|
||||
status = _cairo_surface_get_extents (&surface->base, &extents);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
if (_cairo_operator_bounded_by_source (op)) {
|
||||
cairo_rectangle_int_t source_extents;
|
||||
status = _cairo_pattern_get_extents (source, &source_extents);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
_cairo_rectangle_intersect (&extents, &source_extents);
|
||||
|
||||
status = _cairo_pattern_get_extents (mask, &source_extents);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
_cairo_rectangle_intersect (&extents, &source_extents);
|
||||
}
|
||||
|
||||
_cairo_rectangle_intersect (&extents, &surface->current_clip);
|
||||
|
||||
status = _cairo_analysis_surface_add_operation (surface, &extents, backend_status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
@ -109,19 +260,61 @@ _cairo_analysis_surface_stroke (void *abstract_surface,
|
|||
cairo_antialias_t antialias)
|
||||
{
|
||||
cairo_analysis_surface_t *surface = abstract_surface;
|
||||
cairo_status_t status;
|
||||
cairo_status_t status, backend_status;
|
||||
cairo_traps_t traps;
|
||||
cairo_box_t box;
|
||||
cairo_rectangle_int_t extents;
|
||||
|
||||
if (!surface->target->backend->stroke)
|
||||
status = CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
else
|
||||
status = (*surface->target->backend->stroke) (surface->target, op,
|
||||
source, path, style,
|
||||
ctm, ctm_inverse,
|
||||
tolerance, antialias);
|
||||
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
|
||||
surface->fallback = TRUE;
|
||||
status = CAIRO_STATUS_SUCCESS;
|
||||
backend_status = (*surface->target->backend->stroke) (surface->target, op,
|
||||
source, path, style,
|
||||
ctm, ctm_inverse,
|
||||
tolerance, antialias);
|
||||
|
||||
status = _cairo_surface_get_extents (&surface->base, &extents);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
if (_cairo_operator_bounded_by_source (op)) {
|
||||
cairo_rectangle_int_t source_extents;
|
||||
status = _cairo_pattern_get_extents (source, &source_extents);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
_cairo_rectangle_intersect (&extents, &source_extents);
|
||||
}
|
||||
|
||||
_cairo_rectangle_intersect (&extents, &surface->current_clip);
|
||||
|
||||
box.p1.x = _cairo_fixed_from_int (extents.x);
|
||||
box.p1.y = _cairo_fixed_from_int (extents.y);
|
||||
box.p2.x = _cairo_fixed_from_int (extents.x + extents.width);
|
||||
box.p2.y = _cairo_fixed_from_int (extents.y + extents.height);
|
||||
|
||||
_cairo_traps_init (&traps);
|
||||
|
||||
_cairo_traps_limit (&traps, &box);
|
||||
|
||||
status = _cairo_path_fixed_stroke_to_traps (path,
|
||||
style,
|
||||
ctm, ctm_inverse,
|
||||
tolerance,
|
||||
&traps);
|
||||
if (status)
|
||||
goto FINISH;
|
||||
|
||||
_cairo_traps_extents (&traps, &box);
|
||||
extents.x = _cairo_fixed_integer_floor (box.p1.x);
|
||||
extents.y = _cairo_fixed_integer_floor (box.p1.y);
|
||||
extents.width = _cairo_fixed_integer_ceil (box.p2.x) - extents.x;
|
||||
extents.height = _cairo_fixed_integer_ceil (box.p2.y) - extents.y;
|
||||
status = _cairo_analysis_surface_add_operation (surface, &extents, backend_status);
|
||||
|
||||
FINISH:
|
||||
_cairo_traps_fini (&traps);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
@ -135,18 +328,59 @@ _cairo_analysis_surface_fill (void *abstract_surface,
|
|||
cairo_antialias_t antialias)
|
||||
{
|
||||
cairo_analysis_surface_t *surface = abstract_surface;
|
||||
cairo_status_t status;
|
||||
cairo_status_t status, backend_status;
|
||||
cairo_traps_t traps;
|
||||
cairo_box_t box;
|
||||
cairo_rectangle_int_t extents;
|
||||
|
||||
if (!surface->target->backend->fill)
|
||||
status = CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
else
|
||||
status = (*surface->target->backend->fill) (surface->target, op,
|
||||
backend_status = (*surface->target->backend->fill) (surface->target, op,
|
||||
source, path, fill_rule,
|
||||
tolerance, antialias);
|
||||
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
|
||||
surface->fallback = TRUE;
|
||||
status = CAIRO_STATUS_SUCCESS;
|
||||
|
||||
status = _cairo_surface_get_extents (&surface->base, &extents);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
if (_cairo_operator_bounded_by_source (op)) {
|
||||
cairo_rectangle_int_t source_extents;
|
||||
status = _cairo_pattern_get_extents (source, &source_extents);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
_cairo_rectangle_intersect (&extents, &source_extents);
|
||||
}
|
||||
|
||||
_cairo_rectangle_intersect (&extents, &surface->current_clip);
|
||||
|
||||
box.p1.x = _cairo_fixed_from_int (extents.x);
|
||||
box.p1.y = _cairo_fixed_from_int (extents.y);
|
||||
box.p2.x = _cairo_fixed_from_int (extents.x + extents.width);
|
||||
box.p2.y = _cairo_fixed_from_int (extents.y + extents.height);
|
||||
|
||||
_cairo_traps_init (&traps);
|
||||
|
||||
_cairo_traps_limit (&traps, &box);
|
||||
|
||||
status = _cairo_path_fixed_fill_to_traps (path,
|
||||
fill_rule,
|
||||
tolerance,
|
||||
&traps);
|
||||
if (status)
|
||||
goto FINISH;
|
||||
|
||||
_cairo_traps_extents (&traps, &box);
|
||||
extents.x = _cairo_fixed_integer_floor (box.p1.x);
|
||||
extents.y = _cairo_fixed_integer_floor (box.p1.y);
|
||||
extents.width = _cairo_fixed_integer_ceil (box.p2.x) - extents.x;
|
||||
extents.height = _cairo_fixed_integer_ceil (box.p2.y) - extents.y;
|
||||
status = _cairo_analysis_surface_add_operation (surface, &extents, backend_status);
|
||||
|
||||
FINISH:
|
||||
_cairo_traps_fini (&traps);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
@ -159,26 +393,34 @@ _cairo_analysis_surface_show_glyphs (void *abstract_surface,
|
|||
cairo_scaled_font_t *scaled_font)
|
||||
{
|
||||
cairo_analysis_surface_t *surface = abstract_surface;
|
||||
cairo_status_t status;
|
||||
cairo_status_t status, backend_status;
|
||||
cairo_rectangle_int_t extent;
|
||||
|
||||
if (!surface->target->backend->show_glyphs)
|
||||
status = CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
else
|
||||
status = (*surface->target->backend->show_glyphs) (surface->target, op,
|
||||
backend_status = (*surface->target->backend->show_glyphs) (surface->target, op,
|
||||
source,
|
||||
glyphs, num_glyphs,
|
||||
scaled_font);
|
||||
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
|
||||
surface->fallback = TRUE;
|
||||
status = CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
status = _cairo_scaled_font_glyph_device_extents (scaled_font,
|
||||
glyphs,
|
||||
num_glyphs,
|
||||
&extent);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
_cairo_rectangle_intersect (&extent, &surface->current_clip);
|
||||
status = _cairo_analysis_surface_add_operation (surface, &extent, backend_status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static const cairo_surface_backend_t cairo_analysis_surface_backend = {
|
||||
CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS,
|
||||
NULL, /* create_similar */
|
||||
NULL, /* finish_surface */
|
||||
_cairo_analysis_surface_finish,
|
||||
NULL, /* acquire_source_image */
|
||||
NULL, /* release_source_image */
|
||||
NULL, /* acquire_dest_image */
|
||||
|
|
@ -190,7 +432,7 @@ static const cairo_surface_backend_t cairo_analysis_surface_backend = {
|
|||
NULL, /* copy_page */
|
||||
NULL, /* show_page */
|
||||
NULL, /* set_clip_region */
|
||||
NULL, /* clip_path */
|
||||
_cairo_analysis_surface_intersect_clip_path,
|
||||
_cairo_analysis_surface_get_extents,
|
||||
NULL, /* old_show_glyphs */
|
||||
NULL, /* get_font_options */
|
||||
|
|
@ -206,7 +448,7 @@ static const cairo_surface_backend_t cairo_analysis_surface_backend = {
|
|||
NULL, /* snapshot */
|
||||
};
|
||||
|
||||
cairo_private cairo_surface_t *
|
||||
cairo_surface_t *
|
||||
_cairo_analysis_surface_create (cairo_surface_t *target,
|
||||
int width,
|
||||
int height)
|
||||
|
|
@ -226,7 +468,15 @@ _cairo_analysis_surface_create (cairo_surface_t *target,
|
|||
surface->height = height;
|
||||
|
||||
surface->target = target;
|
||||
surface->fallback = FALSE;
|
||||
surface->has_supported = FALSE;
|
||||
surface->has_unsupported = FALSE;
|
||||
_cairo_region_init (&surface->supported_region);
|
||||
_cairo_region_init (&surface->fallback_region);
|
||||
|
||||
surface->current_clip.x = 0;
|
||||
surface->current_clip.y = 0;
|
||||
surface->current_clip.width = width;
|
||||
surface->current_clip.height = height;
|
||||
|
||||
return &surface->base;
|
||||
FAIL:
|
||||
|
|
@ -234,24 +484,34 @@ FAIL:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
cairo_private cairo_region_t *
|
||||
cairo_region_t *
|
||||
_cairo_analysis_surface_get_supported (cairo_surface_t *abstract_surface)
|
||||
{
|
||||
/* XXX */
|
||||
return NULL;
|
||||
cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
|
||||
|
||||
return &surface->supported_region;
|
||||
}
|
||||
|
||||
cairo_private cairo_region_t *
|
||||
cairo_region_t *
|
||||
_cairo_analysis_surface_get_unsupported (cairo_surface_t *abstract_surface)
|
||||
{
|
||||
/* XXX */
|
||||
return NULL;
|
||||
cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
|
||||
|
||||
return &surface->fallback_region;
|
||||
}
|
||||
|
||||
cairo_private cairo_bool_t
|
||||
cairo_bool_t
|
||||
_cairo_analysis_surface_has_supported (cairo_surface_t *abstract_surface)
|
||||
{
|
||||
cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
|
||||
|
||||
return surface->has_supported;
|
||||
}
|
||||
|
||||
cairo_bool_t
|
||||
_cairo_analysis_surface_has_unsupported (cairo_surface_t *abstract_surface)
|
||||
{
|
||||
cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
|
||||
|
||||
return surface->fallback;
|
||||
return surface->has_unsupported;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
*
|
||||
* Contributor(s):
|
||||
* Kristian Høgsberg <krh@redhat.com>
|
||||
* Adrian Johnson <ajohnson@redneon.com>
|
||||
*/
|
||||
|
||||
#ifndef CAIRO_META_SURFACE_H
|
||||
|
|
@ -57,21 +58,32 @@ typedef enum {
|
|||
|
||||
} cairo_command_type_t;
|
||||
|
||||
typedef struct _cairo_command_paint {
|
||||
typedef enum {
|
||||
CAIRO_META_REGION_ALL,
|
||||
CAIRO_META_REGION_NATIVE,
|
||||
CAIRO_META_REGION_IMAGE_FALLBACK,
|
||||
} cairo_meta_region_type_t;
|
||||
|
||||
typedef struct _cairo_command_header {
|
||||
cairo_command_type_t type;
|
||||
cairo_meta_region_type_t region;
|
||||
} cairo_command_header_t;
|
||||
|
||||
typedef struct _cairo_command_paint {
|
||||
cairo_command_header_t header;
|
||||
cairo_operator_t op;
|
||||
cairo_pattern_union_t source;
|
||||
} cairo_command_paint_t;
|
||||
|
||||
typedef struct _cairo_command_mask {
|
||||
cairo_command_type_t type;
|
||||
cairo_command_header_t header;
|
||||
cairo_operator_t op;
|
||||
cairo_pattern_union_t source;
|
||||
cairo_pattern_union_t mask;
|
||||
} cairo_command_mask_t;
|
||||
|
||||
typedef struct _cairo_command_stroke {
|
||||
cairo_command_type_t type;
|
||||
cairo_command_header_t header;
|
||||
cairo_operator_t op;
|
||||
cairo_pattern_union_t source;
|
||||
cairo_path_fixed_t path;
|
||||
|
|
@ -83,7 +95,7 @@ typedef struct _cairo_command_stroke {
|
|||
} cairo_command_stroke_t;
|
||||
|
||||
typedef struct _cairo_command_fill {
|
||||
cairo_command_type_t type;
|
||||
cairo_command_header_t header;
|
||||
cairo_operator_t op;
|
||||
cairo_pattern_union_t source;
|
||||
cairo_path_fixed_t path;
|
||||
|
|
@ -93,7 +105,7 @@ typedef struct _cairo_command_fill {
|
|||
} cairo_command_fill_t;
|
||||
|
||||
typedef struct _cairo_command_show_glyphs {
|
||||
cairo_command_type_t type;
|
||||
cairo_command_header_t header;
|
||||
cairo_operator_t op;
|
||||
cairo_pattern_union_t source;
|
||||
cairo_glyph_t *glyphs;
|
||||
|
|
@ -102,7 +114,7 @@ typedef struct _cairo_command_show_glyphs {
|
|||
} cairo_command_show_glyphs_t;
|
||||
|
||||
typedef struct _cairo_command_intersect_clip_path {
|
||||
cairo_command_type_t type;
|
||||
cairo_command_header_t header;
|
||||
cairo_path_fixed_t *path_pointer;
|
||||
cairo_path_fixed_t path;
|
||||
cairo_fill_rule_t fill_rule;
|
||||
|
|
@ -111,7 +123,7 @@ typedef struct _cairo_command_intersect_clip_path {
|
|||
} cairo_command_intersect_clip_path_t;
|
||||
|
||||
typedef union _cairo_command {
|
||||
cairo_command_type_t type;
|
||||
cairo_command_header_t header;
|
||||
|
||||
/* The 5 basic drawing operations. */
|
||||
cairo_command_paint_t paint;
|
||||
|
|
@ -151,6 +163,14 @@ cairo_private cairo_status_t
|
|||
_cairo_meta_surface_replay (cairo_surface_t *surface,
|
||||
cairo_surface_t *target);
|
||||
|
||||
cairo_private cairo_status_t
|
||||
_cairo_meta_surface_replay_and_create_regions (cairo_surface_t *surface,
|
||||
cairo_surface_t *target);
|
||||
cairo_private cairo_status_t
|
||||
_cairo_meta_surface_replay_region (cairo_surface_t *surface,
|
||||
cairo_surface_t *target,
|
||||
cairo_meta_region_type_t region);
|
||||
|
||||
cairo_private cairo_bool_t
|
||||
_cairo_surface_is_meta (const cairo_surface_t *surface);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
/* cairo - a vector graphics library with display and print output
|
||||
*
|
||||
* Copyright © 2005 Red Hat, Inc
|
||||
* Copyright © 2007 Adrian Johnson
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it either under the terms of the GNU Lesser General Public
|
||||
|
|
@ -32,6 +33,7 @@
|
|||
* Contributor(s):
|
||||
* Kristian Høgsberg <krh@redhat.com>
|
||||
* Carl Worth <cworth@cworth.org>
|
||||
* Adrian Johnson <ajohnson@redneon.com>
|
||||
*/
|
||||
|
||||
/* A meta surface is a surface that records all drawing operations at
|
||||
|
|
@ -123,7 +125,7 @@ _cairo_meta_surface_finish (void *abstract_surface)
|
|||
elements = _cairo_array_index (&meta->commands, 0);
|
||||
for (i = 0; i < num_elements; i++) {
|
||||
command = elements[i];
|
||||
switch (command->type) {
|
||||
switch (command->header.type) {
|
||||
|
||||
/* 5 basic drawing operations */
|
||||
|
||||
|
|
@ -253,7 +255,8 @@ _cairo_meta_surface_paint (void *abstract_surface,
|
|||
if (command == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
||||
command->type = CAIRO_COMMAND_PAINT;
|
||||
command->header.type = CAIRO_COMMAND_PAINT;
|
||||
command->header.region = CAIRO_META_REGION_ALL;
|
||||
command->op = op;
|
||||
|
||||
status = _init_pattern_with_snapshot (&command->source.base, source);
|
||||
|
|
@ -287,7 +290,8 @@ _cairo_meta_surface_mask (void *abstract_surface,
|
|||
if (command == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
||||
command->type = CAIRO_COMMAND_MASK;
|
||||
command->header.type = CAIRO_COMMAND_MASK;
|
||||
command->header.region = CAIRO_META_REGION_ALL;
|
||||
command->op = op;
|
||||
|
||||
status = _init_pattern_with_snapshot (&command->source.base, source);
|
||||
|
|
@ -332,7 +336,8 @@ _cairo_meta_surface_stroke (void *abstract_surface,
|
|||
if (command == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
||||
command->type = CAIRO_COMMAND_STROKE;
|
||||
command->header.type = CAIRO_COMMAND_STROKE;
|
||||
command->header.region = CAIRO_META_REGION_ALL;
|
||||
command->op = op;
|
||||
|
||||
status = _init_pattern_with_snapshot (&command->source.base, source);
|
||||
|
|
@ -386,7 +391,8 @@ _cairo_meta_surface_fill (void *abstract_surface,
|
|||
if (command == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
||||
command->type = CAIRO_COMMAND_FILL;
|
||||
command->header.type = CAIRO_COMMAND_FILL;
|
||||
command->header.region = CAIRO_META_REGION_ALL;
|
||||
command->op = op;
|
||||
|
||||
status = _init_pattern_with_snapshot (&command->source.base, source);
|
||||
|
|
@ -432,7 +438,8 @@ _cairo_meta_surface_show_glyphs (void *abstract_surface,
|
|||
if (command == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
||||
command->type = CAIRO_COMMAND_SHOW_GLYPHS;
|
||||
command->header.type = CAIRO_COMMAND_SHOW_GLYPHS;
|
||||
command->header.region = CAIRO_META_REGION_ALL;
|
||||
command->op = op;
|
||||
|
||||
status = _init_pattern_with_snapshot (&command->source.base, source);
|
||||
|
|
@ -521,7 +528,8 @@ _cairo_meta_surface_intersect_clip_path (void *dst,
|
|||
if (command == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
||||
command->type = CAIRO_COMMAND_INTERSECT_CLIP_PATH;
|
||||
command->header.type = CAIRO_COMMAND_INTERSECT_CLIP_PATH;
|
||||
command->header.region = CAIRO_META_REGION_ALL;
|
||||
|
||||
if (path) {
|
||||
status = _cairo_path_fixed_init_copy (&command->path, path);
|
||||
|
|
@ -622,7 +630,7 @@ static const cairo_surface_backend_t cairo_meta_surface_backend = {
|
|||
static cairo_path_fixed_t *
|
||||
_cairo_command_get_path (cairo_command_t *command)
|
||||
{
|
||||
switch (command->type) {
|
||||
switch (command->header.type) {
|
||||
case CAIRO_COMMAND_PAINT:
|
||||
case CAIRO_COMMAND_MASK:
|
||||
case CAIRO_COMMAND_SHOW_GLYPHS:
|
||||
|
|
@ -639,9 +647,11 @@ _cairo_command_get_path (cairo_command_t *command)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_meta_surface_replay (cairo_surface_t *surface,
|
||||
cairo_surface_t *target)
|
||||
static cairo_status_t
|
||||
_cairo_meta_surface_replay_internal (cairo_surface_t *surface,
|
||||
cairo_surface_t *target,
|
||||
cairo_bool_t create_regions,
|
||||
cairo_meta_region_type_t region)
|
||||
{
|
||||
cairo_meta_surface_t *meta;
|
||||
cairo_command_t *command, **elements;
|
||||
|
|
@ -665,9 +675,14 @@ _cairo_meta_surface_replay (cairo_surface_t *surface,
|
|||
for (i = meta->replay_start_idx; i < num_elements; i++) {
|
||||
command = elements[i];
|
||||
|
||||
if (!create_regions && region != CAIRO_META_REGION_ALL) {
|
||||
if (command->header.region != region)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* For all commands except intersect_clip_path, we have to
|
||||
* ensure the current clip gets set on the surface. */
|
||||
if (command->type != CAIRO_COMMAND_INTERSECT_CLIP_PATH) {
|
||||
if (command->header.type != CAIRO_COMMAND_INTERSECT_CLIP_PATH) {
|
||||
status = _cairo_surface_set_clip (target, &clip);
|
||||
if (status)
|
||||
break;
|
||||
|
|
@ -682,7 +697,7 @@ _cairo_meta_surface_replay (cairo_surface_t *surface,
|
|||
dev_path = &path_copy;
|
||||
}
|
||||
|
||||
switch (command->type) {
|
||||
switch (command->header.type) {
|
||||
case CAIRO_COMMAND_PAINT:
|
||||
status = _cairo_surface_paint (target,
|
||||
command->paint.op,
|
||||
|
|
@ -770,6 +785,7 @@ _cairo_meta_surface_replay (cairo_surface_t *surface,
|
|||
command->intersect_clip_path.tolerance,
|
||||
command->intersect_clip_path.antialias,
|
||||
target);
|
||||
assert (status == 0);
|
||||
break;
|
||||
default:
|
||||
ASSERT_NOT_REACHED;
|
||||
|
|
@ -778,6 +794,14 @@ _cairo_meta_surface_replay (cairo_surface_t *surface,
|
|||
if (dev_path == &path_copy)
|
||||
_cairo_path_fixed_fini (&path_copy);
|
||||
|
||||
if (create_regions) {
|
||||
if (status == CAIRO_STATUS_SUCCESS) {
|
||||
command->header.region = CAIRO_META_REGION_NATIVE;
|
||||
} else if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) {
|
||||
command->header.region = CAIRO_META_REGION_IMAGE_FALLBACK;
|
||||
status = CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
if (status)
|
||||
break;
|
||||
}
|
||||
|
|
@ -786,3 +810,31 @@ _cairo_meta_surface_replay (cairo_surface_t *surface,
|
|||
|
||||
return status;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_meta_surface_replay (cairo_surface_t *surface,
|
||||
cairo_surface_t *target)
|
||||
{
|
||||
return _cairo_meta_surface_replay_internal (surface, target, FALSE, CAIRO_META_REGION_ALL);
|
||||
}
|
||||
|
||||
/* Replay meta to surface. When the return status of each operation is
|
||||
* one of CAIRO_STATUS_SUCCESS, CAIRO_INT_STATUS_UNSUPPORTED, or
|
||||
* CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY the status of each operation
|
||||
* will be stored in the meta surface. Any other status will abort the
|
||||
* replay and return the status.
|
||||
*/
|
||||
cairo_status_t
|
||||
_cairo_meta_surface_replay_and_create_regions (cairo_surface_t *surface,
|
||||
cairo_surface_t *target)
|
||||
{
|
||||
return _cairo_meta_surface_replay_internal (surface, target, TRUE, CAIRO_META_REGION_ALL);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_meta_surface_replay_region (cairo_surface_t *surface,
|
||||
cairo_surface_t *target,
|
||||
cairo_meta_region_type_t region)
|
||||
{
|
||||
return _cairo_meta_surface_replay_internal (surface, target, FALSE, region);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
/* cairo - a vector graphics library with display and print output
|
||||
*
|
||||
* Copyright © 2005 Red Hat, Inc
|
||||
* Copyright © 2007 Adrian Johnson
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it either under the terms of the GNU Lesser General Public
|
||||
|
|
@ -32,6 +33,7 @@
|
|||
* Contributor(s):
|
||||
* Carl Worth <cworth@cworth.org>
|
||||
* Keith Packard <keithp@keithp.com>
|
||||
* Adrian Johnson <ajohnson@redneon.com>
|
||||
*/
|
||||
|
||||
/* The paginated surface layer exists to provide as much code sharing
|
||||
|
|
@ -209,13 +211,55 @@ _cairo_paginated_surface_release_source_image (void *abstract_surface,
|
|||
cairo_surface_destroy (&image->base);
|
||||
}
|
||||
|
||||
static cairo_int_status_t
|
||||
_paint_fallback_image (cairo_paginated_surface_t *surface,
|
||||
cairo_box_int_t *box)
|
||||
{
|
||||
double x_scale = surface->base.x_fallback_resolution / 72.0;
|
||||
double y_scale = surface->base.y_fallback_resolution / 72.0;
|
||||
cairo_matrix_t matrix;
|
||||
int x, y, width, height;
|
||||
cairo_status_t status;
|
||||
cairo_surface_t *image;
|
||||
cairo_pattern_t *pattern;
|
||||
|
||||
x = box->p1.x;
|
||||
y = box->p1.y;
|
||||
width = box->p2.x - x;
|
||||
height = box->p2.y - y;
|
||||
image = _cairo_paginated_surface_create_image_surface (surface,
|
||||
width * x_scale,
|
||||
height * y_scale);
|
||||
_cairo_surface_set_device_scale (image, x_scale, y_scale);
|
||||
/* set_device_offset just sets the x0/y0 components of the matrix;
|
||||
* so we have to do the scaling manually. */
|
||||
cairo_surface_set_device_offset (image, -x*x_scale, -y*y_scale);
|
||||
|
||||
status = _cairo_meta_surface_replay (surface->meta, image);
|
||||
if (status)
|
||||
goto CLEANUP_IMAGE;
|
||||
|
||||
pattern = cairo_pattern_create_for_surface (image);
|
||||
cairo_matrix_init (&matrix, x_scale, 0, 0, y_scale, -x*x_scale, -y*y_scale);
|
||||
cairo_pattern_set_matrix (pattern, &matrix);
|
||||
|
||||
status = _cairo_surface_paint (surface->target,
|
||||
CAIRO_OPERATOR_SOURCE,
|
||||
pattern);
|
||||
|
||||
cairo_pattern_destroy (pattern);
|
||||
CLEANUP_IMAGE:
|
||||
cairo_surface_destroy (image);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static cairo_int_status_t
|
||||
_paint_page (cairo_paginated_surface_t *surface)
|
||||
{
|
||||
cairo_surface_t *analysis;
|
||||
cairo_surface_t *image;
|
||||
cairo_pattern_t *pattern;
|
||||
cairo_status_t status;
|
||||
cairo_bool_t has_supported, has_page_fallback, has_finegrained_fallback;
|
||||
|
||||
analysis = _cairo_analysis_surface_create (surface->target,
|
||||
surface->width, surface->height);
|
||||
|
|
@ -223,7 +267,7 @@ _paint_page (cairo_paginated_surface_t *surface)
|
|||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
||||
surface->backend->set_paginated_mode (surface->target, CAIRO_PAGINATED_MODE_ANALYZE);
|
||||
status = _cairo_meta_surface_replay (surface->meta, analysis);
|
||||
status = _cairo_meta_surface_replay_and_create_regions (surface->meta, analysis);
|
||||
surface->backend->set_paginated_mode (surface->target, CAIRO_PAGINATED_MODE_RENDER);
|
||||
|
||||
if (status || analysis->status) {
|
||||
|
|
@ -233,35 +277,70 @@ _paint_page (cairo_paginated_surface_t *surface)
|
|||
return status;
|
||||
}
|
||||
|
||||
if (_cairo_analysis_surface_has_unsupported (analysis))
|
||||
{
|
||||
double x_scale = surface->base.x_fallback_resolution / 72.0;
|
||||
double y_scale = surface->base.y_fallback_resolution / 72.0;
|
||||
cairo_matrix_t matrix;
|
||||
|
||||
image = _cairo_paginated_surface_create_image_surface (surface,
|
||||
surface->width * x_scale,
|
||||
surface->height * y_scale);
|
||||
_cairo_surface_set_device_scale (image, x_scale, y_scale);
|
||||
|
||||
status = _cairo_meta_surface_replay (surface->meta, image);
|
||||
if (status)
|
||||
goto CLEANUP_IMAGE;
|
||||
|
||||
pattern = cairo_pattern_create_for_surface (image);
|
||||
cairo_matrix_init_scale (&matrix, x_scale, y_scale);
|
||||
cairo_pattern_set_matrix (pattern, &matrix);
|
||||
|
||||
status = _cairo_surface_paint (surface->target, CAIRO_OPERATOR_SOURCE, pattern);
|
||||
|
||||
cairo_pattern_destroy (pattern);
|
||||
|
||||
CLEANUP_IMAGE:
|
||||
cairo_surface_destroy (image);
|
||||
/* Finer grained fallbacks are currently only supported for PostScript surfaces */
|
||||
if (surface->target->type == CAIRO_SURFACE_TYPE_PS) {
|
||||
has_supported = _cairo_analysis_surface_has_supported (analysis);
|
||||
has_page_fallback = FALSE;
|
||||
has_finegrained_fallback = _cairo_analysis_surface_has_unsupported (analysis);
|
||||
} else {
|
||||
if (_cairo_analysis_surface_has_unsupported (analysis)) {
|
||||
has_supported = FALSE;
|
||||
has_page_fallback = TRUE;
|
||||
} else {
|
||||
has_supported = TRUE;
|
||||
has_page_fallback = FALSE;
|
||||
}
|
||||
has_finegrained_fallback = FALSE;
|
||||
}
|
||||
else
|
||||
|
||||
if (has_supported) {
|
||||
status = _cairo_meta_surface_replay_region (surface->meta,
|
||||
surface->target,
|
||||
CAIRO_META_REGION_NATIVE);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
|
||||
if (has_page_fallback)
|
||||
{
|
||||
status = _cairo_meta_surface_replay (surface->meta, surface->target);
|
||||
cairo_box_int_t box;
|
||||
|
||||
box.p1.x = 0;
|
||||
box.p1.y = 0;
|
||||
box.p2.x = surface->width;
|
||||
box.p2.y = surface->height;
|
||||
status = _paint_fallback_image (surface, &box);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
|
||||
if (has_finegrained_fallback)
|
||||
{
|
||||
cairo_region_t *region;
|
||||
cairo_box_int_t *boxes;
|
||||
int num_boxes, i;
|
||||
|
||||
/* Reset clip region before drawing the fall back images */
|
||||
status = _cairo_surface_intersect_clip_path (surface->target,
|
||||
NULL,
|
||||
CAIRO_FILL_RULE_WINDING,
|
||||
CAIRO_GSTATE_TOLERANCE_DEFAULT,
|
||||
CAIRO_ANTIALIAS_DEFAULT);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
region = _cairo_analysis_surface_get_unsupported (analysis);
|
||||
status = _cairo_region_get_boxes (region, &num_boxes, &boxes);
|
||||
if (status)
|
||||
return status;
|
||||
for (i = 0; i < num_boxes; i++) {
|
||||
status = _paint_fallback_image (surface, &boxes[i]);
|
||||
if (status) {
|
||||
_cairo_region_boxes_fini (region, boxes);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
_cairo_region_boxes_fini (region, boxes);
|
||||
}
|
||||
|
||||
cairo_surface_destroy (analysis);
|
||||
|
|
|
|||
|
|
@ -1359,34 +1359,53 @@ pattern_supported (const cairo_pattern_t *pattern)
|
|||
}
|
||||
|
||||
static cairo_int_status_t
|
||||
_cairo_ps_surface_operation_supported (cairo_ps_surface_t *surface,
|
||||
cairo_operator_t op,
|
||||
const cairo_pattern_t *pattern)
|
||||
_cairo_ps_surface_analyze_operation (cairo_ps_surface_t *surface,
|
||||
cairo_operator_t op,
|
||||
const cairo_pattern_t *pattern)
|
||||
{
|
||||
if (surface->force_fallbacks)
|
||||
return FALSE;
|
||||
if (surface->force_fallbacks && surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
|
||||
if (! pattern_supported (pattern))
|
||||
return FALSE;
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
|
||||
if (op == CAIRO_OPERATOR_SOURCE)
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
if (op != CAIRO_OPERATOR_OVER)
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
|
||||
/* CAIRO_OPERATOR_OVER is only supported for opaque patterns. If
|
||||
* the pattern contains transparency, we return
|
||||
* CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY to the analysis
|
||||
* surface. If the analysis surface determines that there is
|
||||
* anything drawn under this operation, a fallback image will be
|
||||
* used. Otherwise the operation will be replayed during the
|
||||
* render stage and we blend the transarency into the white
|
||||
* background to convert the pattern to opaque.
|
||||
*/
|
||||
|
||||
if (_cairo_operator_always_opaque (op))
|
||||
return TRUE;
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
if (_cairo_operator_always_translucent (op))
|
||||
return FALSE;
|
||||
return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
|
||||
|
||||
return _cairo_pattern_is_opaque (pattern);
|
||||
}
|
||||
|
||||
static cairo_int_status_t
|
||||
_cairo_ps_surface_analyze_operation (cairo_ps_surface_t *surface,
|
||||
cairo_operator_t op,
|
||||
const cairo_pattern_t *pattern)
|
||||
{
|
||||
if (_cairo_ps_surface_operation_supported (surface, op, pattern))
|
||||
if (_cairo_pattern_is_opaque (pattern))
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
else
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
|
||||
}
|
||||
|
||||
static cairo_bool_t
|
||||
_cairo_ps_surface_operation_supported (cairo_ps_surface_t *surface,
|
||||
cairo_operator_t op,
|
||||
const cairo_pattern_t *pattern)
|
||||
{
|
||||
if (_cairo_ps_surface_analyze_operation (surface, op, pattern) != CAIRO_INT_STATUS_UNSUPPORTED)
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* The "standard" implementation limit for PostScript string sizes is
|
||||
|
|
@ -1514,8 +1533,8 @@ _string_array_stream_create (cairo_output_stream_t *output)
|
|||
|
||||
static cairo_status_t
|
||||
_cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
|
||||
cairo_image_surface_t *image,
|
||||
const char *name)
|
||||
cairo_image_surface_t *image,
|
||||
const char *name)
|
||||
{
|
||||
cairo_status_t status, status2;
|
||||
unsigned char *rgb, *compressed;
|
||||
|
|
@ -1659,24 +1678,33 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
|
|||
}
|
||||
|
||||
static void
|
||||
_cairo_ps_surface_emit_solid_pattern (cairo_ps_surface_t *surface,
|
||||
cairo_solid_pattern_t *pattern)
|
||||
_cairo_ps_surface_emit_solid_pattern (cairo_ps_surface_t *surface,
|
||||
cairo_solid_pattern_t *pattern)
|
||||
{
|
||||
if (color_is_gray (&pattern->color))
|
||||
cairo_color_t color = pattern->color;
|
||||
|
||||
if (!CAIRO_COLOR_IS_OPAQUE(&color)) {
|
||||
/* Blend into white */
|
||||
color.red = color.red*color.alpha + 1 - color.alpha;
|
||||
color.green = color.green*color.alpha + 1 - color.alpha;
|
||||
color.blue = color.blue*color.alpha + 1 - color.alpha;
|
||||
}
|
||||
|
||||
if (color_is_gray (&color))
|
||||
_cairo_output_stream_printf (surface->stream,
|
||||
"%f G\n",
|
||||
pattern->color.red);
|
||||
color.red);
|
||||
else
|
||||
_cairo_output_stream_printf (surface->stream,
|
||||
"%f %f %f R\n",
|
||||
pattern->color.red,
|
||||
pattern->color.green,
|
||||
pattern->color.blue);
|
||||
color.red,
|
||||
color.green,
|
||||
color.blue);
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
|
||||
cairo_surface_pattern_t *pattern)
|
||||
_cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
|
||||
cairo_surface_pattern_t *pattern)
|
||||
{
|
||||
cairo_status_t status;
|
||||
double bbox_width, bbox_height;
|
||||
|
|
@ -1919,15 +1947,7 @@ _cairo_ps_surface_paint (void *abstract_surface,
|
|||
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
|
||||
return _cairo_ps_surface_analyze_operation (surface, op, source);
|
||||
|
||||
/* XXX: It would be nice to be able to assert this condition
|
||||
* here. But, we actually allow one 'cheat' that is used when
|
||||
* painting the final image-based fallbacks. The final fallbacks
|
||||
* do have alpha which we support by blending with white. This is
|
||||
* possible only because there is nothing between the fallback
|
||||
* images and the paper, nor is anything painted above. */
|
||||
/*
|
||||
assert (_cairo_ps_surface_operation_supported (op, source));
|
||||
*/
|
||||
assert (_cairo_ps_surface_operation_supported (surface, op, source));
|
||||
|
||||
_cairo_output_stream_printf (stream,
|
||||
"%% _cairo_ps_surface_paint\n");
|
||||
|
|
@ -2017,7 +2037,6 @@ _cairo_ps_surface_stroke (void *abstract_surface,
|
|||
|
||||
assert (_cairo_ps_surface_operation_supported (surface, op, source));
|
||||
|
||||
|
||||
_cairo_output_stream_printf (stream,
|
||||
"%% _cairo_ps_surface_stroke\n");
|
||||
|
||||
|
|
|
|||
|
|
@ -102,4 +102,8 @@ cairo_private void
|
|||
_cairo_region_translate (cairo_region_t *region,
|
||||
int x, int y);
|
||||
|
||||
cairo_private pixman_region_overlap_t
|
||||
_cairo_region_contains_rectangle (cairo_region_t *region, cairo_rectangle_int_t *box);
|
||||
|
||||
|
||||
#endif /* CAIRO_REGION_PRIVATE_H */
|
||||
|
|
|
|||
|
|
@ -207,3 +207,16 @@ _cairo_region_translate (cairo_region_t *region,
|
|||
{
|
||||
pixman_region_translate (®ion->rgn, x, y);
|
||||
}
|
||||
|
||||
pixman_region_overlap_t
|
||||
_cairo_region_contains_rectangle (cairo_region_t *region, cairo_rectangle_int_t *rect)
|
||||
{
|
||||
pixman_box16_t pbox;
|
||||
|
||||
pbox.x1 = rect->x;
|
||||
pbox.y1 = rect->y;
|
||||
pbox.x2 = rect->x + rect->width;
|
||||
pbox.y2 = rect->y + rect->height;
|
||||
|
||||
return pixman_region_contains_rectangle (®ion->rgn, &pbox);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -325,7 +325,9 @@ typedef enum cairo_int_status {
|
|||
CAIRO_INT_STATUS_DEGENERATE = 1000,
|
||||
CAIRO_INT_STATUS_UNSUPPORTED,
|
||||
CAIRO_INT_STATUS_NOTHING_TO_DO,
|
||||
CAIRO_INT_STATUS_CACHE_EMPTY
|
||||
CAIRO_INT_STATUS_CACHE_EMPTY,
|
||||
CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY,
|
||||
CAIRO_INT_STATUS_IMAGE_FALLBACK
|
||||
} cairo_int_status_t;
|
||||
|
||||
typedef enum cairo_internal_surface_type {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue