Remove clip handling from generic surface layer.

Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)

In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.

Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:

ppc:
Speedups
========
image-rgba         evolution-20090607-0    1026085.22 0.18% -> 672972.07 0.77%:  1.52x speedup
▌
image-rgba         evolution-20090618-0    680579.98 0.12% -> 573237.66  0.16%:  1.19x speedup
▎
image-rgba      swfdec-fill-rate-4xaa-0    460296.92 0.36% -> 407464.63  0.42%:  1.13x speedup
▏
image-rgba      swfdec-fill-rate-2xaa-0    128431.95 0.47% -> 115051.86  0.42%:  1.12x speedup
▏
Slowdowns
=========
image-rgba     firefox-periodic-table-0    56837.61 0.78% -> 66055.17    3.20%:  1.09x slowdown
▏
This commit is contained in:
Chris Wilson 2009-07-23 15:32:13 +01:00
parent f5a1cdf283
commit bed2701e1c
193 changed files with 7844 additions and 6006 deletions

6
NEWS
View file

@ -9,6 +9,12 @@ API additions:
Finally exporting the internal meta-surface so that applications
have a method to record and replay a sequence of drawing commands.
cairo_in_clip()
Determines whether a given point is inside the current clip.
??? Should this be called cairo_in_paint() instead? in-clip is the test
that is performed, but in-paint would be similar to in-fill and in-stroke.
New utilities:
cairo-test-trace

View file

@ -33,7 +33,6 @@
static const cairo_user_data_key_t glitz_closure_key;
typedef struct _glitz_glx_target_closure {
glitz_target_closure_base_t base;
Display *dpy;
int scr;
Window win;
@ -206,9 +205,6 @@ _cairo_boilerplate_glitz_glx_create_surface (const char *name,
if (cairo_surface_status (surface))
goto FAIL_CLOSE_DISPLAY;
gxtc->base.width = width;
gxtc->base.height = height;
gxtc->base.content = content;
status = cairo_surface_set_user_data (surface,
&glitz_closure_key, gxtc, NULL);
if (status == CAIRO_STATUS_SUCCESS)

View file

@ -129,7 +129,6 @@ _cairo_boilerplate_pdf_finish_surface (cairo_surface_t *surface)
if (status)
return status;
cairo_surface_finish (surface);
status = cairo_surface_status (surface);
if (status)
return status;

View file

@ -178,6 +178,7 @@ _cairo_boilerplate_ps_finish_surface (cairo_surface_t *surface)
if (ptc->target) {
cairo_t *cr;
cr = cairo_create (ptc->target);
cairo_set_source_surface (cr, surface, 0, 0);
cairo_paint (cr);
@ -188,7 +189,6 @@ _cairo_boilerplate_ps_finish_surface (cairo_surface_t *surface)
if (status)
return status;
cairo_surface_finish (surface);
status = cairo_surface_status (surface);
if (status)
return status;
@ -197,11 +197,7 @@ _cairo_boilerplate_ps_finish_surface (cairo_surface_t *surface)
}
cairo_surface_finish (surface);
status = cairo_surface_status (surface);
if (status)
return status;
return CAIRO_STATUS_SUCCESS;
return cairo_surface_status (surface);
}
static cairo_status_t

View file

@ -30,7 +30,7 @@
* The Initial Developer of the Original Code is Chris Wilson.
*/
#include "cairo-boilerplate.h"
#include "cairo-boilerplate-private.h"
#include <cairo-qt.h>
@ -108,4 +108,6 @@ static const cairo_boilerplate_target_t targets[] = {
_cairo_boilerplate_qt_cleanup
},
};
extern "C" {
CAIRO_BOILERPLATE (qt, targets)
}

View file

@ -166,7 +166,6 @@ _cairo_boilerplate_svg_finish_surface (cairo_surface_t *surface)
if (status)
return status;
cairo_surface_finish (surface);
status = cairo_surface_status (surface);
if (status)
return status;

View file

@ -33,6 +33,7 @@
#include <test-paginated-surface.h>
#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,9,3)
#include <test-null-surface.h>
#include <test-wrapping-surface.h>
#endif
#include <cairo-types-private.h>
@ -49,7 +50,8 @@ _cairo_boilerplate_test_fallback_create_surface (const char *name,
void **closure)
{
*closure = NULL;
return _cairo_test_fallback_surface_create (content, width, height);
return _cairo_test_fallback_surface_create (content,
ceil (width), ceil (height));
}
static cairo_surface_t *
@ -64,7 +66,8 @@ _cairo_boilerplate_test_fallback16_create_surface (const char *name,
void **closure)
{
*closure = NULL;
return _cairo_test_fallback16_surface_create (content, width, height);
return _cairo_test_fallback16_surface_create (content,
ceil (width), ceil (height));
}
static cairo_surface_t *
@ -89,11 +92,7 @@ _cairo_boilerplate_test_null_create_surface (const char *name,
static const cairo_user_data_key_t test_paginated_closure_key;
typedef struct {
unsigned char *data;
cairo_content_t content;
int width;
int height;
int stride;
cairo_surface_t *target;
} test_paginated_closure_t;
static cairo_surface_t *
@ -115,18 +114,10 @@ _cairo_boilerplate_test_paginated_create_surface (const char *name,
*closure = tpc = xmalloc (sizeof (test_paginated_closure_t));
format = cairo_boilerplate_format_from_content (content);
tpc->target = cairo_image_surface_create (format,
ceil (width), ceil (height));
tpc->content = content;
tpc->width = width;
tpc->height = height;
tpc->stride = cairo_format_stride_for_width (format, width);
tpc->data = xcalloc (tpc->stride, height);
surface = _cairo_test_paginated_surface_create_for_data (tpc->data,
tpc->content,
tpc->width,
tpc->height,
tpc->stride);
surface = _cairo_test_paginated_surface_create (tpc->target);
if (cairo_surface_status (surface))
goto CLEANUP;
@ -139,8 +130,9 @@ _cairo_boilerplate_test_paginated_create_surface (const char *name,
cairo_surface_destroy (surface);
surface = cairo_boilerplate_surface_create_in_error (status);
cairo_surface_destroy (tpc->target);
CLEANUP:
free (tpc->data);
free (tpc);
return surface;
}
@ -160,8 +152,6 @@ static cairo_status_t
_cairo_boilerplate_test_paginated_surface_write_to_png (cairo_surface_t *surface,
const char *filename)
{
cairo_surface_t *image;
cairo_format_t format;
test_paginated_closure_t *tpc;
cairo_status_t status;
@ -172,19 +162,7 @@ _cairo_boilerplate_test_paginated_surface_write_to_png (cairo_surface_t *surface
return status;
tpc = cairo_surface_get_user_data (surface, &test_paginated_closure_key);
format = cairo_boilerplate_format_from_content (tpc->content);
image = cairo_image_surface_create_for_data (tpc->data,
format,
tpc->width,
tpc->height,
tpc->stride);
status = cairo_surface_write_to_png (image, filename);
cairo_surface_destroy (image);
return status;
return cairo_surface_write_to_png (tpc->target, filename);
}
static cairo_surface_t *
@ -193,7 +171,6 @@ _cairo_boilerplate_test_paginated_get_image_surface (cairo_surface_t *surface,
int width,
int height)
{
cairo_format_t format;
test_paginated_closure_t *tpc;
cairo_status_t status;
@ -208,30 +185,7 @@ _cairo_boilerplate_test_paginated_get_image_surface (cairo_surface_t *surface,
return cairo_boilerplate_surface_create_in_error (status);
tpc = cairo_surface_get_user_data (surface, &test_paginated_closure_key);
format = cairo_boilerplate_format_from_content (tpc->content);
if (0) {
return cairo_image_surface_create_for_data (tpc->data + tpc->stride * (tpc->height - height) + 4 * (tpc->width - width), /* hide the device offset */
format,
width,
height,
tpc->stride);
} else {
cairo_surface_t *image, *surface;
image = cairo_image_surface_create_for_data (tpc->data,
format,
tpc->width,
tpc->height,
tpc->stride);
cairo_surface_set_device_offset (image,
tpc->width - width,
tpc->height - height);
surface = _cairo_boilerplate_get_image_surface (image, 0, width, height);
cairo_surface_destroy (image);
return surface;
}
return _cairo_boilerplate_get_image_surface (tpc->target, 0, width, height);
}
static void
@ -239,10 +193,40 @@ _cairo_boilerplate_test_paginated_cleanup (void *closure)
{
test_paginated_closure_t *tpc = closure;
free (tpc->data);
cairo_surface_destroy (tpc->target);
free (tpc);
}
static cairo_surface_t *
_cairo_boilerplate_test_wrapping_create_surface (const char *name,
cairo_content_t content,
double width,
double height,
double max_width,
double max_height,
cairo_boilerplate_mode_t mode,
int id,
void **closure)
{
#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,9,3)
cairo_surface_t *target;
cairo_surface_t *surface;
cairo_format_t format;
*closure = NULL;
format = cairo_boilerplate_format_from_content (content);
target = cairo_image_surface_create (format, ceil (width), ceil (height));
surface = _cairo_test_wrapping_surface_create (target);
cairo_surface_destroy (target);
return surface;
#else
*closure = NULL;
return NULL;
#endif
}
static const cairo_boilerplate_target_t targets[] = {
{
"test-fallback", "image", NULL, NULL,
@ -304,6 +288,15 @@ static const cairo_boilerplate_target_t targets[] = {
NULL,
FALSE, TRUE
},
{
"test-wrapping", "image", NULL, NULL,
CAIRO_INTERNAL_SURFACE_TYPE_TEST_WRAPPING,
CAIRO_CONTENT_COLOR_ALPHA, 0,
_cairo_boilerplate_test_wrapping_create_surface,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
cairo_surface_write_to_png,
},
{
"null", "image", NULL, NULL,
CAIRO_INTERNAL_SURFACE_TYPE_NULL,

View file

@ -32,6 +32,10 @@
#include <cairo-types-private.h>
#include <cairo-scaled-font-private.h>
#if CAIRO_HAS_SCRIPT_SURFACE
#include <cairo-script.h>
#endif
/* get the "real" version info instead of dummy cairo-version.h */
#undef CAIRO_VERSION_H
#include "../cairo-version.h"
@ -136,48 +140,74 @@ _cairo_boilerplate_meta_create_surface (const char *name,
int id,
void **closure)
{
cairo_rectangle_t extents;
*closure = NULL;
return cairo_meta_surface_create (content, width, height);
extents.x = 0;
extents.y = 0;
extents.width = width;
extents.height = height;
return cairo_meta_surface_create (content, &extents);
}
const cairo_user_data_key_t cairo_boilerplate_output_basename_key;
#if CAIRO_HAS_SCRIPT_SURFACE
static cairo_status_t
stdio_write (void *closure, const unsigned char *data, unsigned int len)
{
if (fwrite (data, len, 1, closure) != 1)
return CAIRO_STATUS_WRITE_ERROR;
return CAIRO_STATUS_SUCCESS;
}
#endif
cairo_surface_t *
_cairo_boilerplate_get_image_surface (cairo_surface_t *src,
int page,
int width,
int height)
{
cairo_surface_t *surface;
FILE *file = NULL;
cairo_surface_t *surface, *image;
cairo_t *cr;
cairo_status_t status;
if (cairo_surface_status (src))
return cairo_surface_reference (src);
#if 0
if (cairo_surface_get_type (src) == CAIRO_SURFACE_TYPE_IMAGE) {
int ww = cairo_image_surface_get_width (src);
int hh = cairo_image_surface_get_height (src);
if (width == ww && hh == height) {
return cairo_surface_reference (src);
} else {
cairo_format_t format = cairo_image_surface_get_format (src);
unsigned char *data = cairo_image_surface_get_data (src);
int stride = cairo_image_surface_get_stride (src);
data += stride * (hh - height) + 4 * (ww - width);
return cairo_image_surface_create_for_data (data,
format,
width,
height,
stride);
}
}
#endif
if (page != 0)
return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
/* extract sub-surface */
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
image = cairo_surface_reference (surface);
/* open a logging channel (only interesting for meta surfaces) */
#if CAIRO_HAS_SCRIPT_SURFACE
if (cairo_surface_get_type (src) == CAIRO_SURFACE_TYPE_META) {
const char *test_name;
test_name = cairo_surface_get_user_data (src,
&cairo_boilerplate_output_basename_key);
if (test_name != NULL) {
char *filename;
xasprintf (&filename, "%s.out.trace", test_name);
file = fopen (filename, "w");
free (filename);
if (file != NULL) {
surface = cairo_script_surface_create_for_target (image,
stdio_write,
file);
}
}
}
#endif
cr = cairo_create (surface);
cairo_surface_destroy (surface);
@ -185,10 +215,17 @@ _cairo_boilerplate_get_image_surface (cairo_surface_t *src,
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_paint (cr);
surface = cairo_surface_reference (cairo_get_target (cr));
status = cairo_status (cr);
if (status) {
cairo_surface_destroy (image);
image = cairo_surface_reference (cairo_get_target (cr));
}
cairo_destroy (cr);
return surface;
if (file != NULL)
fclose (file);
return image;
}
cairo_surface_t *
@ -705,8 +742,13 @@ cairo_boilerplate_convert_to_image (const char *filename, int page)
image = cairo_boilerplate_image_surface_create_from_ppm_stream (file);
ret = pclose (file);
/* check for fatal errors from the interpreter */
if (ret) { /* any2pmm should never die... */
cairo_surface_destroy (image);
return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_INVALID_STATUS);
}
if (cairo_surface_status (image) == CAIRO_STATUS_READ_ERROR) {
if (ret == 0 && cairo_surface_status (image) == CAIRO_STATUS_READ_ERROR) {
if (flags == 0) {
/* Try again in a standalone process. */
cairo_surface_destroy (image);
@ -715,12 +757,6 @@ cairo_boilerplate_convert_to_image (const char *filename, int page)
}
}
if (cairo_surface_status (image) == CAIRO_STATUS_SUCCESS && ret != 0) {
cairo_surface_destroy (image);
image =
cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_READ_ERROR);
};
return image;
}

View file

@ -99,6 +99,8 @@ CAIRO_BEGIN_DECLS
* PDF surfaces. */
#define CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED ((unsigned int) -1)
extern const cairo_user_data_key_t cairo_boilerplate_output_basename_key;
cairo_content_t
cairo_boilerplate_content (cairo_content_t content);

View file

@ -49,6 +49,9 @@ do_unaligned_clip (cairo_t *cr, int width, int height)
cairo_rectangle (cr, 55, 55, 35, 35);
cairo_clip (cr);
/* And paint something to force the clip to be evaluated. */
cairo_paint (cr);
cairo_perf_timer_stop ();
cairo_restore (cr);

View file

@ -79,11 +79,14 @@ cairo_private = \
cairo-path-private.h \
cairo-private.h \
cairo-reference-count-private.h \
cairo-region-private.h \
cairo-scaled-font-private.h \
cairo-skiplist-private.h \
cairo-spans-private.h \
cairo-surface-fallback-private.h \
cairo-surface-private.h \
cairo-surface-clipper-private.h \
cairo-surface-wrapper-private.h \
cairo-types-private.h \
cairo-user-font-private.h \
cairo-wideint-private.h \
@ -138,6 +141,8 @@ cairo_sources = \
cairo-stroke-style.c \
cairo-surface.c \
cairo-surface-fallback.c \
cairo-surface-clipper.c \
cairo-surface-wrapper.c \
cairo-tor-scan-converter.c \
cairo-system.c \
cairo-traps.c \
@ -198,12 +203,14 @@ cairo_test_surfaces_private = \
test-fallback16-surface.h \
test-null-surface.h \
test-paginated-surface.h \
test-wrapping-surface.h \
$(NULL)
cairo_test_surfaces_sources = \
test-fallback-surface.c \
test-fallback16-surface.c \
test-null-surface.c \
test-paginated-surface.c \
test-wrapping-surface.c \
$(NULL)
cairo_xlib_headers = cairo-xlib.h

View file

@ -38,13 +38,11 @@
#include "cairoint.h"
cairo_private cairo_surface_t *
_cairo_analysis_surface_create (cairo_surface_t *target,
int width,
int height);
_cairo_analysis_surface_create (cairo_surface_t *target);
cairo_private void
_cairo_analysis_surface_set_ctm (cairo_surface_t *surface,
cairo_matrix_t *ctm);
const cairo_matrix_t *ctm);
cairo_private void
_cairo_analysis_surface_get_ctm (cairo_surface_t *surface,

View file

@ -39,13 +39,12 @@
#include "cairo-analysis-surface-private.h"
#include "cairo-paginated-private.h"
#include "cairo-meta-surface-private.h"
#include "cairo-region-private.h"
typedef struct {
cairo_surface_t base;
int width;
int height;
cairo_surface_t *target;
cairo_surface_t *target;
cairo_bool_t first_op;
cairo_bool_t has_supported;
@ -53,7 +52,6 @@ typedef struct {
cairo_region_t supported_region;
cairo_region_t fallback_region;
cairo_rectangle_int_t current_clip;
cairo_box_t page_bbox;
cairo_bool_t has_ctm;
@ -97,61 +95,38 @@ static cairo_int_status_t
_analyze_meta_surface_pattern (cairo_analysis_surface_t *surface,
const cairo_pattern_t *pattern)
{
cairo_surface_t *analysis = &surface->base;
const cairo_surface_pattern_t *surface_pattern;
cairo_status_t status;
cairo_bool_t old_has_ctm;
cairo_matrix_t old_ctm, p2d;
cairo_rectangle_int_t old_clip;
cairo_rectangle_int_t meta_extents;
int old_width;
int old_height;
cairo_status_t status;
assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE);
surface_pattern = (const cairo_surface_pattern_t *) pattern;
assert (_cairo_surface_is_meta (surface_pattern->surface));
old_width = surface->width;
old_height = surface->height;
old_clip = surface->current_clip;
status = _cairo_surface_get_extents (surface_pattern->surface, &meta_extents);
if (_cairo_status_is_error (status))
return status;
surface->width = meta_extents.width;
surface->height = meta_extents.height;
surface->current_clip.x = 0;
surface->current_clip.y = 0;
surface->current_clip.width = surface->width;
surface->current_clip.height = surface->height;
old_ctm = surface->ctm;
old_has_ctm = surface->has_ctm;
p2d = pattern->matrix;
status = cairo_matrix_invert (&p2d);
/* _cairo_pattern_set_matrix guarantees invertibility */
assert (status == CAIRO_STATUS_SUCCESS);
cairo_matrix_multiply (&surface->ctm, &p2d, &surface->ctm);
surface->has_ctm = !_cairo_matrix_is_identity (&surface->ctm);
surface->has_ctm = ! _cairo_matrix_is_identity (&surface->ctm);
status = _cairo_meta_surface_replay_and_create_regions (surface_pattern->surface,
analysis);
if (status == CAIRO_STATUS_SUCCESS)
status = analysis->status;
&surface->base);
surface->ctm = old_ctm;
surface->has_ctm = old_has_ctm;
surface->current_clip = old_clip;
surface->width = old_width;
surface->height = old_height;
return status;
}
static cairo_int_status_t
_add_operation (cairo_analysis_surface_t *surface,
cairo_rectangle_int_t *rect,
cairo_int_status_t backend_status)
_add_operation (cairo_analysis_surface_t *surface,
cairo_rectangle_int_t *rect,
cairo_int_status_t backend_status)
{
cairo_int_status_t status;
cairo_box_t bbox;
@ -174,26 +149,33 @@ _add_operation (cairo_analysis_surface_t *surface,
_cairo_box_from_rectangle (&bbox, rect);
if (surface->has_ctm) {
int tx, ty;
_cairo_matrix_transform_bounding_box_fixed (&surface->ctm, &bbox, NULL);
if (_cairo_matrix_is_integer_translation (&surface->ctm, &tx, &ty)) {
rect->x += tx;
rect->y += ty;
} else {
_cairo_matrix_transform_bounding_box_fixed (&surface->ctm,
&bbox, NULL);
if (bbox.p1.x == bbox.p2.x || bbox.p1.y == bbox.p2.y) {
/* Even though the operation is not visible we must be
* careful to not allow unsupported operations to be
* replayed to the backend during
* CAIRO_PAGINATED_MODE_RENDER */
if (backend_status == CAIRO_STATUS_SUCCESS ||
backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY)
{
return CAIRO_STATUS_SUCCESS;
}
else
{
return CAIRO_INT_STATUS_IMAGE_FALLBACK;
if (bbox.p1.x == bbox.p2.x || bbox.p1.y == bbox.p2.y) {
/* Even though the operation is not visible we must be
* careful to not allow unsupported operations to be
* replayed to the backend during
* CAIRO_PAGINATED_MODE_RENDER */
if (backend_status == CAIRO_STATUS_SUCCESS ||
backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY)
{
return CAIRO_STATUS_SUCCESS;
}
else
{
return CAIRO_INT_STATUS_IMAGE_FALLBACK;
}
}
_cairo_box_round_to_rectangle (&bbox, rect);
}
_cairo_box_round_to_rectangle (&bbox, rect);
}
if (surface->first_op) {
@ -234,8 +216,7 @@ _add_operation (cairo_analysis_surface_t *surface,
* this region will be emitted as native operations.
*/
surface->has_supported = TRUE;
status = cairo_region_union_rectangle (&surface->supported_region, rect);
return status;
return cairo_region_union_rectangle (&surface->supported_region, rect);
}
/* Add the operation to the unsupported region. This region will
@ -270,33 +251,7 @@ _cairo_analysis_surface_finish (void *abstract_surface)
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;
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;
} else {
cairo_rectangle_int_t extents;
cairo_bool_t is_empty;
_cairo_path_fixed_approximate_clip_extents (path, &extents);
is_empty = _cairo_rectangle_intersect (&surface->current_clip,
&extents);
}
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
static cairo_bool_t
_cairo_analysis_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
@ -305,66 +260,92 @@ _cairo_analysis_surface_get_extents (void *abstract_surface,
return _cairo_surface_get_extents (surface->target, rectangle);
}
static cairo_int_status_t
_cairo_analysis_surface_paint (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_rectangle_int_t *paint_extents)
static void
_rectangle_intersect_clip (cairo_rectangle_int_t *extents, cairo_clip_t *clip)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_status_t status, backend_status;
cairo_rectangle_int_t extents;
const cairo_rectangle_int_t *clip_extents;
cairo_bool_t is_empty;
if (!surface->target->backend->paint)
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
else
backend_status = (*surface->target->backend->paint) (surface->target, op,
source, NULL);
clip_extents = NULL;
if (clip != NULL)
clip_extents = _cairo_clip_get_extents (clip);
if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
backend_status = _analyze_meta_surface_pattern (surface, source);
if (clip_extents != NULL)
is_empty = _cairo_rectangle_intersect (extents, clip_extents);
}
status = _cairo_surface_get_extents (&surface->base, &extents);
if (_cairo_status_is_error (status))
return status;
static void
_cairo_analysis_surface_operation_extents (cairo_analysis_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_clip_t *clip,
cairo_rectangle_int_t *extents)
{
cairo_bool_t is_empty;
is_empty = _cairo_surface_get_extents (&surface->base, extents);
if (_cairo_operator_bounded_by_source (op)) {
cairo_rectangle_int_t source_extents;
status = _cairo_pattern_get_extents (source, &source_extents);
if (unlikely (status))
return status;
is_empty = _cairo_rectangle_intersect (&extents, &source_extents);
_cairo_pattern_get_extents (source, &source_extents);
is_empty = _cairo_rectangle_intersect (extents, &source_extents);
}
is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip);
if (paint_extents)
*paint_extents = extents;
status = _add_operation (surface, &extents, backend_status);
return status;
_rectangle_intersect_clip (extents, clip);
}
static cairo_int_status_t
_cairo_analysis_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_rectangle_int_t *mask_extents)
_cairo_analysis_surface_paint (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_clip_t *clip)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_int_status_t status, backend_status;
cairo_status_t backend_status;
cairo_rectangle_int_t extents;
if (surface->target->backend->paint == NULL) {
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
} else {
backend_status =
surface->target->backend->paint (surface->target,
op, source, clip);
if (_cairo_status_is_error (backend_status))
return backend_status;
}
if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
backend_status = _analyze_meta_surface_pattern (surface, source);
_cairo_analysis_surface_operation_extents (surface,
op, source, clip,
&extents);
return _add_operation (surface, &extents, backend_status);
}
static cairo_int_status_t
_cairo_analysis_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_clip_t *clip)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_int_status_t backend_status;
cairo_rectangle_int_t extents;
cairo_bool_t is_empty;
if (!surface->target->backend->mask)
if (surface->target->backend->mask == NULL) {
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
else
backend_status = (*surface->target->backend->mask) (surface->target, op,
source, mask, NULL);
} else {
backend_status =
surface->target->backend->mask (surface->target,
op, source, mask, clip);
if (_cairo_status_is_error (backend_status))
return backend_status;
}
if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN) {
cairo_int_status_t backend_source_status = CAIRO_STATUS_SUCCESS;
@ -395,37 +376,19 @@ _cairo_analysis_surface_mask (void *abstract_surface,
backend_mask_status);
}
status = _cairo_surface_get_extents (&surface->base, &extents);
if (_cairo_status_is_error (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 (unlikely (status))
return status;
is_empty = _cairo_rectangle_intersect (&extents, &source_extents);
}
_cairo_analysis_surface_operation_extents (surface,
op, source, clip,
&extents);
if (_cairo_operator_bounded_by_mask (op)) {
cairo_rectangle_int_t mask_extents;
status = _cairo_pattern_get_extents (mask, &mask_extents);
if (unlikely (status))
return status;
_cairo_pattern_get_extents (mask, &mask_extents);
is_empty = _cairo_rectangle_intersect (&extents, &mask_extents);
}
is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip);
if (mask_extents)
*mask_extents = extents;
status = _add_operation (surface, &extents, backend_status);
return status;
return _add_operation (surface, &extents, backend_status);
}
static cairo_int_status_t
@ -438,55 +401,61 @@ _cairo_analysis_surface_stroke (void *abstract_surface,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *stroke_extents)
cairo_clip_t *clip)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_status_t status, backend_status;
cairo_status_t backend_status;
cairo_rectangle_int_t extents;
cairo_bool_t is_empty;
if (!surface->target->backend->stroke)
if (surface->target->backend->stroke == NULL) {
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
else
backend_status = (*surface->target->backend->stroke) (surface->target, op,
source, path, style,
ctm, ctm_inverse,
tolerance, antialias, NULL);
} else {
backend_status =
surface->target->backend->stroke (surface->target, op,
source, path, style,
ctm, ctm_inverse,
tolerance, antialias,
clip);
if (_cairo_status_is_error (backend_status))
return backend_status;
}
if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
backend_status = _analyze_meta_surface_pattern (surface, source);
status = _cairo_surface_get_extents (&surface->base, &extents);
if (_cairo_status_is_error (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 (unlikely (status))
return status;
is_empty = _cairo_rectangle_intersect (&extents, &source_extents);
}
is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip);
_cairo_analysis_surface_operation_extents (surface,
op, source, clip,
&extents);
if (_cairo_operator_bounded_by_mask (op)) {
cairo_rectangle_int_t mask_extents;
_cairo_path_fixed_approximate_stroke_extents (path,
style, ctm,
&mask_extents);
/* If the backend can handle the stroke, then mark the approximate
* extents of the operation. However, if we need to fallback in order
* to draw the stroke, then ensure that the fallback is as tight as
* possible -- both to minimise output file size and to ensure good
* quality printed output for neighbouring regions.
*/
if (backend_status == CAIRO_STATUS_SUCCESS) {
_cairo_path_fixed_approximate_stroke_extents (path,
style, ctm,
&mask_extents);
} else {
cairo_status_t status;
status = _cairo_path_fixed_stroke_extents (path, style,
ctm, ctm_inverse,
tolerance,
&mask_extents);
if (unlikely (status))
return status;
}
is_empty = _cairo_rectangle_intersect (&extents, &mask_extents);
}
if (stroke_extents)
*stroke_extents = extents;
status = _add_operation (surface, &extents, backend_status);
return status;
return _add_operation (surface, &extents, backend_status);
}
static cairo_int_status_t
@ -497,53 +466,49 @@ _cairo_analysis_surface_fill (void *abstract_surface,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *fill_extents)
cairo_clip_t *clip)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_status_t status, backend_status;
cairo_status_t backend_status;
cairo_rectangle_int_t extents;
cairo_bool_t is_empty;
if (!surface->target->backend->fill)
if (surface->target->backend->fill == NULL) {
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
else
backend_status = (*surface->target->backend->fill) (surface->target, op,
source, path, fill_rule,
tolerance, antialias, NULL);
} else {
backend_status =
surface->target->backend->fill (surface->target, op,
source, path, fill_rule,
tolerance, antialias,
clip);
if (_cairo_status_is_error (backend_status))
return backend_status;
}
if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
backend_status = _analyze_meta_surface_pattern (surface, source);
status = _cairo_surface_get_extents (&surface->base, &extents);
if (_cairo_status_is_error (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 (unlikely (status))
return status;
is_empty = _cairo_rectangle_intersect (&extents, &source_extents);
}
is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip);
_cairo_analysis_surface_operation_extents (surface,
op, source, clip,
&extents);
if (_cairo_operator_bounded_by_mask (op)) {
cairo_rectangle_int_t mask_extents;
_cairo_path_fixed_approximate_fill_extents (path,
&mask_extents);
/* We want speed for the likely case where the operation can be
* performed natively, but accuracy if we have to resort to
* using images.
*/
if (backend_status == CAIRO_STATUS_SUCCESS) {
_cairo_path_fixed_approximate_fill_extents (path, &mask_extents);
} else {
_cairo_path_fixed_fill_extents (path, fill_rule, tolerance,
&mask_extents);
}
is_empty = _cairo_rectangle_intersect (&extents, &mask_extents);
}
if (fill_extents)
*fill_extents = extents;
status = _add_operation (surface, &extents, backend_status);
return status;
return _add_operation (surface, &extents, backend_status);
}
static cairo_int_status_t
@ -553,8 +518,8 @@ _cairo_analysis_surface_show_glyphs (void *abstract_surface,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs,
cairo_rectangle_int_t *show_glyphs_extents)
cairo_clip_t *clip,
int *remaining_glyphs)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_status_t status, backend_status;
@ -562,41 +527,42 @@ _cairo_analysis_surface_show_glyphs (void *abstract_surface,
cairo_bool_t is_empty;
/* Adapted from _cairo_surface_show_glyphs */
if (surface->target->backend->show_glyphs)
backend_status = (*surface->target->backend->show_glyphs) (surface->target, op,
source,
glyphs, num_glyphs,
scaled_font,
remaining_glyphs, NULL);
else if (surface->target->backend->show_text_glyphs)
backend_status = surface->target->backend->show_text_glyphs (surface->target, op,
source,
NULL, 0,
glyphs, num_glyphs,
NULL, 0,
FALSE,
scaled_font, NULL);
if (surface->target->backend->show_glyphs != NULL) {
backend_status =
surface->target->backend->show_glyphs (surface->target, op,
source,
glyphs, num_glyphs,
scaled_font,
clip,
remaining_glyphs);
if (_cairo_status_is_error (backend_status))
return backend_status;
}
else if (surface->target->backend->show_text_glyphs != NULL)
{
backend_status =
surface->target->backend->show_text_glyphs (surface->target, op,
source,
NULL, 0,
glyphs, num_glyphs,
NULL, 0,
FALSE,
scaled_font,
clip);
if (_cairo_status_is_error (backend_status))
return backend_status;
}
else
{
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
}
if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
backend_status = _analyze_meta_surface_pattern (surface, source);
status = _cairo_surface_get_extents (&surface->base, &extents);
if (_cairo_status_is_error (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 (unlikely (status))
return status;
is_empty = _cairo_rectangle_intersect (&extents, &source_extents);
}
is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip);
_cairo_analysis_surface_operation_extents (surface,
op, source, clip,
&extents);
if (_cairo_operator_bounded_by_mask (op)) {
status = _cairo_scaled_font_glyph_device_extents (scaled_font,
@ -608,12 +574,8 @@ _cairo_analysis_surface_show_glyphs (void *abstract_surface,
is_empty = _cairo_rectangle_intersect (&extents, &glyph_extents);
}
if (show_glyphs_extents)
*show_glyphs_extents = extents;
status = _add_operation (surface, &extents, backend_status);
return status;
return _add_operation (surface, &extents, backend_status);
}
static cairo_bool_t
@ -636,7 +598,7 @@ _cairo_analysis_surface_show_text_glyphs (void *abstract_surface,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_scaled_font_t *scaled_font,
cairo_rectangle_int_t *show_text_glyphs_extents)
cairo_clip_t *clip)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_status_t status, backend_status;
@ -645,20 +607,33 @@ _cairo_analysis_surface_show_text_glyphs (void *abstract_surface,
/* Adapted from _cairo_surface_show_glyphs */
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
if (surface->target->backend->show_text_glyphs)
backend_status = surface->target->backend->show_text_glyphs (surface->target, op,
source,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters, cluster_flags,
scaled_font, NULL);
if (backend_status == CAIRO_INT_STATUS_UNSUPPORTED && surface->target->backend->show_glyphs) {
if (surface->target->backend->show_text_glyphs != NULL) {
backend_status =
surface->target->backend->show_text_glyphs (surface->target, op,
source,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters,
cluster_flags,
scaled_font,
clip);
if (_cairo_status_is_error (backend_status))
return backend_status;
}
if (backend_status == CAIRO_INT_STATUS_UNSUPPORTED &&
surface->target->backend->show_glyphs != NULL)
{
int remaining_glyphs = num_glyphs;
backend_status = surface->target->backend->show_glyphs (surface->target, op,
source,
glyphs, num_glyphs,
scaled_font,
&remaining_glyphs, NULL);
backend_status =
surface->target->backend->show_glyphs (surface->target, op,
source,
glyphs, num_glyphs,
scaled_font,
clip,
&remaining_glyphs);
if (_cairo_status_is_error (backend_status))
return backend_status;
glyphs += num_glyphs - remaining_glyphs;
num_glyphs = remaining_glyphs;
if (remaining_glyphs == 0)
@ -668,21 +643,9 @@ _cairo_analysis_surface_show_text_glyphs (void *abstract_surface,
if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
backend_status = _analyze_meta_surface_pattern (surface, source);
status = _cairo_surface_get_extents (&surface->base, &extents);
if (_cairo_status_is_error (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 (unlikely (status))
return status;
is_empty = _cairo_rectangle_intersect (&extents, &source_extents);
}
is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip);
_cairo_analysis_surface_operation_extents (surface,
op, source, clip,
&extents);
if (_cairo_operator_bounded_by_mask (op)) {
status = _cairo_scaled_font_glyph_device_extents (scaled_font,
@ -694,12 +657,8 @@ _cairo_analysis_surface_show_text_glyphs (void *abstract_surface,
is_empty = _cairo_rectangle_intersect (&extents, &glyph_extents);
}
if (show_text_glyphs_extents)
*show_text_glyphs_extents = extents;
status = _add_operation (surface, &extents, backend_status);
return status;
return _add_operation (surface, &extents, backend_status);
}
static const cairo_surface_backend_t cairo_analysis_surface_backend = {
@ -718,8 +677,6 @@ static const cairo_surface_backend_t cairo_analysis_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
NULL, /* set_clip_region */
_cairo_analysis_surface_intersect_clip_path,
_cairo_analysis_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
@ -734,7 +691,6 @@ static const cairo_surface_backend_t cairo_analysis_surface_backend = {
_cairo_analysis_surface_show_glyphs,
NULL, /* snapshot */
NULL, /* is_similar */
NULL, /* reset */
NULL, /* fill_stroke */
NULL, /* create_solid_pattern_surface */
NULL, /* can_repaint_solid_pattern_surface */
@ -743,9 +699,7 @@ static const cairo_surface_backend_t cairo_analysis_surface_backend = {
};
cairo_surface_t *
_cairo_analysis_surface_create (cairo_surface_t *target,
int width,
int height)
_cairo_analysis_surface_create (cairo_surface_t *target)
{
cairo_analysis_surface_t *surface;
cairo_status_t status;
@ -763,8 +717,6 @@ _cairo_analysis_surface_create (cairo_surface_t *target,
_cairo_surface_init (&surface->base, &cairo_analysis_surface_backend,
CAIRO_CONTENT_COLOR_ALPHA);
surface->width = width;
surface->height = height;
cairo_matrix_init_identity (&surface->ctm);
surface->has_ctm = FALSE;
@ -781,24 +733,12 @@ _cairo_analysis_surface_create (cairo_surface_t *target,
surface->page_bbox.p2.x = 0;
surface->page_bbox.p2.y = 0;
if (width == -1 && height == -1) {
surface->current_clip.x = CAIRO_RECT_INT_MIN;
surface->current_clip.y = CAIRO_RECT_INT_MIN;
surface->current_clip.width = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN;
surface->current_clip.height = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN;
} else {
surface->current_clip.x = 0;
surface->current_clip.y = 0;
surface->current_clip.width = width;
surface->current_clip.height = height;
}
return &surface->base;
}
void
_cairo_analysis_surface_set_ctm (cairo_surface_t *abstract_surface,
cairo_matrix_t *ctm)
const cairo_matrix_t *ctm)
{
cairo_analysis_surface_t *surface;
@ -808,7 +748,7 @@ _cairo_analysis_surface_set_ctm (cairo_surface_t *abstract_surface,
surface = (cairo_analysis_surface_t *) abstract_surface;
surface->ctm = *ctm;
surface->has_ctm = !_cairo_matrix_is_identity (&surface->ctm);
surface->has_ctm = ! _cairo_matrix_is_identity (&surface->ctm);
}
void
@ -871,22 +811,18 @@ _return_success (void)
}
/* These typedefs are just to silence the compiler... */
typedef cairo_int_status_t
(*_set_clip_region_func) (void *surface,
cairo_region_t *region);
typedef cairo_int_status_t
(*_paint_func) (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_rectangle_int_t *extents);
cairo_clip_t *clip);
typedef cairo_int_status_t
(*_mask_func) (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_rectangle_int_t *extents);
cairo_clip_t *clip);
typedef cairo_int_status_t
(*_stroke_func) (void *surface,
@ -898,7 +834,7 @@ typedef cairo_int_status_t
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *extents);
cairo_clip_t *clip);
typedef cairo_int_status_t
(*_fill_func) (void *surface,
@ -908,7 +844,7 @@ typedef cairo_int_status_t
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *extents);
cairo_clip_t *clip);
typedef cairo_int_status_t
(*_show_glyphs_func) (void *surface,
@ -917,8 +853,8 @@ typedef cairo_int_status_t
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs,
cairo_rectangle_int_t *extents);
cairo_clip_t *clip,
int *remaining_glyphs);
static const cairo_surface_backend_t cairo_null_surface_backend = {
CAIRO_INTERNAL_SURFACE_TYPE_NULL,
@ -937,8 +873,6 @@ static const cairo_surface_backend_t cairo_null_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
(_set_clip_region_func) _return_success, /* set_clip_region */
NULL, /* intersect_clip_path */
NULL, /* get_extents */
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
@ -953,7 +887,6 @@ static const cairo_surface_backend_t cairo_null_surface_backend = {
(_show_glyphs_func) _return_success, /* show_glyphs */
NULL, /* snapshot */
NULL, /* is_similar */
NULL, /* reset */
NULL, /* fill_stroke */
NULL, /* create_solid_pattern_surface */
NULL, /* can_repaint_solid_pattern_surface */

View file

@ -56,6 +56,8 @@
struct cairo_beos_surface_t {
cairo_surface_t base;
cairo_region_t *clip_region;
BView* view;
/*
@ -70,7 +72,6 @@ struct cairo_beos_surface_t {
BBitmap* bitmap;
// If true, surface and view should be deleted when this surface is
// destroyed
bool owns_bitmap_view;
@ -101,27 +102,28 @@ _cairo_beos_surface_create_internal (BView* view,
BBitmap* bmp,
bool owns_bitmap_view = false);
static BRect
_cairo_rect_to_brect (const cairo_rectangle_int16_t* rect)
static inline BRect
_cairo_rectangle_to_brect (const cairo_rectangle_int_t* rect)
{
// A BRect is one pixel wider than you'd think
return BRect(rect->x, rect->y, rect->x + rect->width - 1,
rect->y + rect->height - 1);
return BRect (rect->x, rect->y,
rect->x + rect->width - 1,
rect->y + rect->height - 1);
}
static cairo_rectangle_int16_t
_brect_to_cairo_rect (const BRect& rect)
static inline cairo_rectangle_int_t
_brect_to_cairo_rectangle (const BRect &rect)
{
cairo_rectangle_int16_t retval;
retval.x = int(rect.left + 0.5);
retval.y = int(rect.top + 0.5);
retval.width = rect.IntegerWidth() + 1;
retval.height = rect.IntegerHeight() + 1;
cairo_rectangle_int_t retval;
retval.x = floor (rect.left);
retval.y = floor (rect.top);
retval.width = ceil (rect.right) - retval.x + 1;
retval.height = ceil (rect.bottom) - rectval.y + 1;
return retval;
}
static rgb_color
_cairo_color_to_be_color (const cairo_color_t* color)
static inline rgb_color
_cairo_color_to_be_color (const cairo_color_t *color)
{
// This factor ensures a uniform distribution of numbers
const float factor = 256 - 1e-5;
@ -199,32 +201,8 @@ _cairo_beos_view_to_bitmap (BView* view,
return ERROR;
}
inline unsigned char
unpremultiply (unsigned char color,
unsigned char alpha)
{
if (alpha == 0)
return 0;
// plus alpha/2 to round instead of truncate
return (color * 255 + alpha / 2) / alpha;
}
inline unsigned char
premultiply (unsigned char color,
unsigned char alpha)
{
// + 127 to round, instead of truncate
return (color * alpha + 127) / 255;
}
/**
* unpremultiply_rgba:
*
* Takes an input in ABGR premultiplied image data and unmultiplies it.
* The result is stored in retdata.
**/
static void
unpremultiply_rgba (unsigned char* data,
unpremultiply_bgra (unsigned char* data,
int width,
int height,
int stride,
@ -235,52 +213,108 @@ unpremultiply_rgba (unsigned char* data,
in < end;
in += stride, out += stride)
{
for (int i = 0; i < width; ++i) {
// XXX for a big-endian platform this'd have to change
int idx = 4 * i;
unsigned char alpha = in[idx + 3];
out[idx + 0] = unpremultiply(in[idx + 0], alpha); // B
out[idx + 1] = unpremultiply(in[idx + 1], alpha); // G
out[idx + 2] = unpremultiply(in[idx + 2], alpha); // R
out[idx + 3] = in[idx + 3]; // Alpha
for (int i = 0; i < width; i ++) {
uint8_t *b = &out[4*i];
uint32_t pixel;
uint8_t alpha;
memcpy (&pixel, &data[4*i], sizeof (uint32_t));
alpha = pixel & 0xff;
if (alpha == 0) {
b[0] = b[1] = b[2] = b[3] = 0;
} else {
b[0] = (((pixel >> 24) & 0xff) * 255 + alpha / 2) / alpha;
b[1] = (((pixel >> 16) & 0xff) * 255 + alpha / 2) / alpha;
b[2] = (((pixel >> 8) & 0xff) * 255 + alpha / 2) / alpha;
b[3] = alpha;
}
}
}
}
/**
* premultiply_rgba:
*
* Takes an input in ABGR non-premultiplied image data and premultiplies it.
* The returned data must be freed with free().
**/
static inline int
multiply_alpha (int alpha, int color)
{
int temp = (alpha * color) + 0x80;
return ((temp + (temp >> 8)) >> 8);
}
static unsigned char*
premultiply_rgba (unsigned char* data,
premultiply_bgra (unsigned char* data,
int width,
int height,
int stride)
{
unsigned char* retdata = reinterpret_cast<unsigned char*>(_cairo_malloc_ab(height, stride));
uint8_t * retdata = reinterpret_cast<unsigned char*>(_cairo_malloc_ab(height, stride));
if (!retdata)
return NULL;
unsigned char* end = data + stride * height;
for (unsigned char* in = data, *out = retdata;
uint8_t * end = data + stride * height;
for (uint8_t * in = data, *out = retdata;
in < end;
in += stride, out += stride)
{
for (int i = 0; i < width; ++i) {
// XXX for a big-endian platform this'd have to change
int idx = 4 * i;
unsigned char alpha = in[idx + 3];
out[idx + 0] = premultiply(in[idx + 0], alpha); // B
out[idx + 1] = premultiply(in[idx + 1], alpha); // G
out[idx + 2] = premultiply(in[idx + 2], alpha); // R
out[idx + 3] = in[idx + 3]; // Alpha
for (int i = 0; i < width; i ++) {
uint8_t *base = &in[4*i];
uint8_t alpha = base[3];
uint32_t p;
if (alpha == 0) {
p = 0;
} else {
uint8_t blue = base[0];
uint8_t green = base[1];
uint8_t red = base[2];
if (alpha != 0xff) {
blue = multiply_alpha (alpha, blue);
green = multiply_alpha (alpha, green);
red = multiply_alpha (alpha, red);
}
p = (alpha << 0) | (red << 8) | (green << 16) | (blue << 24);
}
memcpy (&out[4*i], &p, sizeof (uint32_t));
}
}
return retdata;
}
static cairo_int_status_t
_cairo_beos_surface_set_clip_region (cairo_beos_surface_t *surface,
cairo_region_t *region)
{
cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
abstract_surface);
AutoLockView locker(surface->view);
assert (locker);
if (region == surface->clip_region)
return CAIRO_INT_STATUS_SUCCESS;
cairo_region_destroy (surface->clip_region);
surface->clip_region = cairo_region_reference (region);
if (region == NULL) {
// No clipping
surface->view->ConstrainClippingRegion(NULL);
return CAIRO_INT_STATUS_SUCCESS;
}
int count = cairo_region_num_rectangles (region);
BRegion bregion;
for (int i = 0; i < count; ++i) {
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (region, i, &rect);
// Have to substract one, because for pixman, the second coordinate
// lies outside the rectangle.
bregion.Include (_cairo_rectangle_to_brect (&rect));
}
surface->view->ConstrainClippingRegion(&bregion);
return CAIRO_INT_STATUS_SUCCESS;
}
/**
* _cairo_beos_bitmap_to_surface:
*
@ -309,8 +343,8 @@ _cairo_beos_bitmap_to_surface (BBitmap* bitmap)
return imgsurf;
}
cairo_format_t cformat = format == B_RGB32 ? CAIRO_FORMAT_RGB24
: CAIRO_FORMAT_ARGB32;
cairo_format_t cformat = format == B_RGB32 ?
CAIRO_FORMAT_RGB24 : CAIRO_FORMAT_ARGB32;
BRect bounds(bitmap->Bounds());
unsigned char* bits = reinterpret_cast<unsigned char*>(bitmap->Bits());
@ -318,8 +352,8 @@ _cairo_beos_bitmap_to_surface (BBitmap* bitmap)
int height = bounds.IntegerHeight() + 1;
unsigned char* premultiplied;
if (cformat == CAIRO_FORMAT_ARGB32) {
premultiplied = premultiply_rgba(bits, width, height,
bitmap->BytesPerRow());
premultiplied = premultiply_bgra (bits, width, height,
bitmap->BytesPerRow());
} else {
premultiplied = reinterpret_cast<unsigned char*>(
_cairo_malloc_ab(bitmap->BytesPerRow(), height));
@ -327,7 +361,7 @@ _cairo_beos_bitmap_to_surface (BBitmap* bitmap)
memcpy(premultiplied, bits, bitmap->BytesPerRow() * height);
}
if (!premultiplied)
return NULL;
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
cairo_image_surface_t* surf = reinterpret_cast<cairo_image_surface_t*>
(cairo_image_surface_create_for_data(premultiplied,
@ -355,11 +389,11 @@ _cairo_image_surface_to_bitmap (cairo_image_surface_t* surface)
switch (surface->format) {
case CAIRO_FORMAT_ARGB32: {
BBitmap* data = new BBitmap(size, B_RGBA32);
unpremultiply_rgba(surface->data,
surface->width,
surface->height,
surface->stride,
reinterpret_cast<unsigned char*>(data->Bits()));
unpremultiply_bgra (surface->data,
surface->width,
surface->height,
surface->stride,
reinterpret_cast<unsigned char*>(data->Bits()));
return data;
}
case CAIRO_FORMAT_RGB24: {
@ -384,44 +418,44 @@ _cairo_op_to_be_op (cairo_operator_t cairo_op,
drawing_mode* beos_op)
{
switch (cairo_op) {
case CAIRO_OPERATOR_SOURCE:
*beos_op = B_OP_COPY;
return true;
case CAIRO_OPERATOR_OVER:
*beos_op = B_OP_ALPHA;
return true;
case CAIRO_OPERATOR_SOURCE:
*beos_op = B_OP_COPY;
return true;
case CAIRO_OPERATOR_OVER:
*beos_op = B_OP_ALPHA;
return true;
case CAIRO_OPERATOR_ADD:
// Does not actually work
case CAIRO_OPERATOR_ADD:
// Does not actually work
// XXX This is a fundamental compositing operator, it has to work!
#if 1
return false;
return false;
#else
*beos_op = B_OP_ADD;
return true;
*beos_op = B_OP_ADD;
return true;
#endif
case CAIRO_OPERATOR_CLEAR:
// Does not map to B_OP_ERASE - it replaces the dest with the low
// color, instead of transparency; could be done by setting low
// color appropriately.
case CAIRO_OPERATOR_CLEAR:
// Does not map to B_OP_ERASE - it replaces the dest with the low
// color, instead of transparency; could be done by setting low
// color appropriately.
case CAIRO_OPERATOR_IN:
case CAIRO_OPERATOR_OUT:
case CAIRO_OPERATOR_ATOP:
case CAIRO_OPERATOR_IN:
case CAIRO_OPERATOR_OUT:
case CAIRO_OPERATOR_ATOP:
case CAIRO_OPERATOR_DEST:
case CAIRO_OPERATOR_DEST_OVER:
case CAIRO_OPERATOR_DEST_IN:
case CAIRO_OPERATOR_DEST_OUT:
case CAIRO_OPERATOR_DEST_ATOP:
case CAIRO_OPERATOR_DEST:
case CAIRO_OPERATOR_DEST_OVER:
case CAIRO_OPERATOR_DEST_IN:
case CAIRO_OPERATOR_DEST_OUT:
case CAIRO_OPERATOR_DEST_ATOP:
case CAIRO_OPERATOR_XOR:
case CAIRO_OPERATOR_SATURATE:
case CAIRO_OPERATOR_XOR:
case CAIRO_OPERATOR_SATURATE:
default:
return false;
};
default:
return false;
}
}
static cairo_surface_t *
@ -430,8 +464,6 @@ _cairo_beos_surface_create_similar (void *abstract_surface,
int width,
int height)
{
fprintf(stderr, "Creating similar\n");
cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
abstract_surface);
@ -444,9 +476,7 @@ _cairo_beos_surface_create_similar (void *abstract_surface,
BBitmap* bmp;
switch (content) {
case CAIRO_CONTENT_ALPHA:
// Can't support this natively
return _cairo_image_surface_create_with_content(content, width,
height);
return NULL;
case CAIRO_CONTENT_COLOR_ALPHA:
bmp = new BBitmap(rect, B_RGBA32, true);
break;
@ -470,10 +500,9 @@ _cairo_beos_surface_create_similar (void *abstract_surface,
}
break;
default:
assert(0);
ASSERT_NOT_REACHED;
return NULL;
};
}
BView* view = new BView(rect, "Cairo bitmap view", B_FOLLOW_ALL_SIDES, 0);
bmp->AddChild(view);
return _cairo_beos_surface_create_internal(view, bmp, true);
@ -495,6 +524,8 @@ _cairo_beos_surface_finish (void *abstract_surface)
surface->bitmap = NULL;
}
cairo_region_destroy (surface->clip_region);
return CAIRO_STATUS_SUCCESS;
}
@ -503,7 +534,6 @@ _cairo_beos_surface_acquire_source_image (void *abstract_surfa
cairo_image_surface_t **image_out,
void **image_extra)
{
fprintf(stderr, "Getting source image\n");
cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
abstract_surface);
AutoLockView locker(surface->view);
@ -514,9 +544,9 @@ _cairo_beos_surface_acquire_source_image (void *abstract_surfa
surface->view->Sync();
if (surface->bitmap) {
*image_out = _cairo_beos_bitmap_to_surface(surface->bitmap);
if (!*image_out)
return CAIRO_STATUS_NO_MEMORY;
*image_out = _cairo_beos_bitmap_to_surface (surface->bitmap);
if (unlikely ((*image_out)->base.status))
return (*image_out)->base.status;
*image_extra = NULL;
return CAIRO_STATUS_SUCCESS;
@ -526,10 +556,10 @@ _cairo_beos_surface_acquire_source_image (void *abstract_surfa
if (_cairo_beos_view_to_bitmap(surface->view, &bmp) != OK)
return CAIRO_STATUS_NO_MEMORY; /// XXX incorrect if the error was NOT_VISIBLE
*image_out = _cairo_beos_bitmap_to_surface(bmp);
if (!*image_out) {
*image_out = _cairo_beos_bitmap_to_surface (bmp);
if (unlikely ((*image_out)->base.status)) {
delete bmp;
return CAIRO_STATUS_NO_MEMORY;
return (*image_out)->base.status;
}
*image_extra = bmp;
@ -543,17 +573,17 @@ _cairo_beos_surface_release_source_image (void *abstract_surfac
{
cairo_surface_destroy (&image->base);
BBitmap* bmp = static_cast<BBitmap*>(image_extra);
delete bmp;
if (image_extra != NULL) {
BBitmap* bmp = static_cast<BBitmap*>(image_extra);
delete bmp;
}
}
static cairo_status_t
_cairo_beos_surface_acquire_dest_image (void *abstract_surface,
cairo_rectangle_int16_t *interest_rect,
cairo_rectangle_int_t *interest_rect,
cairo_image_surface_t **image_out,
cairo_rectangle_int16_t *image_rect,
cairo_rectangle_int_t *image_rect,
void **image_extra)
{
cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
@ -563,14 +593,14 @@ _cairo_beos_surface_acquire_dest_image (void *abstract_surface,
if (!locker) {
*image_out = NULL;
*image_extra = NULL;
return CAIRO_STATUS_SUCCESS;
return (cairo_status_t) CAIRO_INT_STATUS_NOTHING_TO_DO;
}
if (surface->bitmap) {
surface->view->Sync();
*image_out = _cairo_beos_bitmap_to_surface(surface->bitmap);
if (!*image_out)
return CAIRO_STATUS_NO_MEMORY;
if (unlikely ((*image_out)->base.status))
return (*image_out)->base.status;
image_rect->x = 0;
image_rect->y = 0;
@ -581,7 +611,7 @@ _cairo_beos_surface_acquire_dest_image (void *abstract_surface,
return CAIRO_STATUS_SUCCESS;
}
BRect b_interest_rect(_cairo_rect_to_brect(interest_rect));
BRect b_interest_rect (_cairo_rectangle_to_brect (interest_rect));
BRect rect;
BBitmap* bitmap;
@ -595,18 +625,11 @@ _cairo_beos_surface_acquire_dest_image (void *abstract_surface,
if (status == ERROR)
return CAIRO_STATUS_NO_MEMORY;
*image_rect = _brect_to_cairo_rect(rect);
#if 0
fprintf(stderr, "Requested: (cairo rects) (%ix%i) dim (%u, %u) returning (%ix%i) dim (%u, %u)\n",
interest_rect->x, interest_rect->y, interest_rect->width, interest_rect->height,
image_rect->x, image_rect->y, image_rect->width, image_rect->height);
#endif
*image_rect = _brect_to_cairo_rectangle(rect);
*image_out = _cairo_beos_bitmap_to_surface(bitmap);
delete bitmap;
if (!*image_out)
return CAIRO_STATUS_NO_MEMORY;
if (unlikely ((*image_out)->base.status))
return (*image_out)->base.status;
*image_extra = NULL;
@ -616,13 +639,11 @@ _cairo_beos_surface_acquire_dest_image (void *abstract_surface,
static void
_cairo_beos_surface_release_dest_image (void *abstract_surface,
cairo_rectangle_int16_t *intersect_rect,
cairo_rectangle_int_t *intersect_rect,
cairo_image_surface_t *image,
cairo_rectangle_int16_t *image_rect,
cairo_rectangle_int_t *image_rect,
void *image_extra)
{
fprintf(stderr, "Fallback drawing\n");
cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
abstract_surface);
@ -634,9 +655,9 @@ _cairo_beos_surface_release_dest_image (void *abstract_surface,
surface->view->PushState();
surface->view->SetDrawingMode(B_OP_COPY);
BRect rect(_cairo_rect_to_brect(image_rect));
surface->view->DrawBitmap(bitmap_to_draw, rect);
surface->view->DrawBitmap (bitmap_to_draw,
_cairo_rectangle_to_brect (image_rect));
surface->view->PopState();
@ -649,17 +670,19 @@ _cairo_beos_surface_composite (cairo_operator_t op,
cairo_pattern_t *src,
cairo_pattern_t *mask,
void *dst,
int src_x,
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height)
unsigned int height,
cairo_region_t *clip_region)
{
cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
dst);
cairo_int_status_t status;
AutoLockView locker(surface->view);
if (!locker)
return CAIRO_INT_STATUS_SUCCESS;
@ -684,6 +707,10 @@ _cairo_beos_surface_composite (cairo_operator_t op,
if (!_cairo_matrix_is_integer_translation(&src->matrix, &itx, &ity))
return CAIRO_INT_STATUS_UNSUPPORTED;
status = _cairo_beos_surface_set_clip_region (surface, clip_region);
if (unlikely (status))
return status;
BRect srcRect(src_x + itx,
src_y + ity,
src_x + itx + width - 1,
@ -731,8 +758,6 @@ _cairo_beos_surface_composite (cairo_operator_t op,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
fprintf(stderr, "Composite\n");
// Draw it on screen.
surface->view->PushState();
@ -767,24 +792,17 @@ _cairo_beos_surface_composite (cairo_operator_t op,
}
static void
_cairo_beos_surface_fill_rectangle (cairo_beos_surface_t *surface,
cairo_rectangle_int16_t *rect)
{
BRect brect(_cairo_rect_to_brect(rect));
surface->view->FillRect(brect);
}
static cairo_int_status_t
_cairo_beos_surface_fill_rectangles (void *abstract_surface,
cairo_operator_t op,
const cairo_color_t *color,
cairo_rectangle_int16_t *rects,
int num_rects)
cairo_rectangle_int_t *rects,
int num_rects,
cairo_region_t *clip_region)
{
fprintf(stderr, "Drawing %i rectangles\n", num_rects);
cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
abstract_surface);
cairo_int_status_t status;
if (num_rects <= 0)
return CAIRO_INT_STATUS_SUCCESS;
@ -797,6 +815,10 @@ _cairo_beos_surface_fill_rectangles (void *abstract_surface,
if (!_cairo_op_to_be_op(op, &mode))
return CAIRO_INT_STATUS_UNSUPPORTED;
status = _cairo_beos_surface_set_clip_region (surface, clip_region);
if (unlikely (status))
return status;
rgb_color be_color = _cairo_color_to_be_color(color);
if (mode == B_OP_ALPHA && be_color.alpha == 0xFF)
@ -808,9 +830,9 @@ _cairo_beos_surface_fill_rectangles (void *abstract_surface,
if (mode == B_OP_COPY && be_color.alpha != 0xFF &&
(!surface->bitmap || surface->bitmap->ColorSpace() != B_RGBA32))
{
be_color.red = premultiply(be_color.red, be_color.alpha);
be_color.green = premultiply(be_color.green, be_color.alpha);
be_color.blue = premultiply(be_color.blue, be_color.alpha);
be_color.red = color->red_short >> 8;
be_color.green = color->green_short >> 8;
be_color.blue = color->blue_short >> 8;
}
surface->view->PushState();
@ -822,65 +844,26 @@ _cairo_beos_surface_fill_rectangles (void *abstract_surface,
else
surface->view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY);
for (int i = 0; i < num_rects; ++i) {
_cairo_beos_surface_fill_rectangle(surface, &rects[i]);
}
for (int i = 0; i < num_rects; ++i)
surface->view->FillRect (_cairo_rectangle_to_brect (&rects[i]));
surface->view->PopState();
return CAIRO_INT_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_beos_surface_set_clip_region (void *abstract_surface,
pixman_region16_t *region)
{
fprintf(stderr, "Setting clip region\n");
cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
abstract_surface);
AutoLockView locker(surface->view);
if (!locker)
return CAIRO_INT_STATUS_SUCCESS;
if (region == NULL) {
// No clipping
surface->view->ConstrainClippingRegion(NULL);
return CAIRO_INT_STATUS_SUCCESS;
}
int count = pixman_region_num_rects(region);
pixman_box16_t* rects = pixman_region_rects(region);
BRegion bregion;
for (int i = 0; i < count; ++i) {
// Have to substract one, because for pixman, the second coordinate
// lies outside the rectangle.
bregion.Include(BRect(rects[i].x1, rects[i].y1, rects[i].x2 - 1, rects[i].y2 - 1));
}
surface->view->ConstrainClippingRegion(&bregion);
return CAIRO_INT_STATUS_SUCCESS;
}
static cairo_int_status_t
static cairo_bool_t
_cairo_beos_surface_get_extents (void *abstract_surface,
cairo_rectangle_int16_t *rectangle)
cairo_rectangle_int_t *rectangle)
{
cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
abstract_surface);
AutoLockView locker(surface->view);
if (!locker)
return CAIRO_INT_STATUS_UNSUPPORTED;
return FALSE;
BRect size = surface->view->Bounds();
*rectangle = _brect_to_cairo_rect(size);
// Make sure to have our upperleft edge as (0,0)
rectangle->x = 0;
rectangle->y = 0;
return CAIRO_INT_STATUS_SUCCESS;
*rectangle = _brect_to_cairo_rectangle (surface->view->Bounds());
return TRUE;
}
static const struct _cairo_surface_backend cairo_beos_surface_backend = {
@ -899,8 +882,6 @@ static const struct _cairo_surface_backend cairo_beos_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
_cairo_beos_surface_set_clip_region,
NULL, /* intersect_clip_path */
_cairo_beos_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
@ -938,7 +919,9 @@ _cairo_beos_surface_create_internal (BView* view,
surface->bitmap = bmp;
surface->owns_bitmap_view = owns_bitmap_view;
return (cairo_surface_t *) surface;
surface->clip_region = NULL;
return &surface->base;
}
/**

View file

@ -43,6 +43,11 @@
extern const cairo_private cairo_rectangle_list_t _cairo_rectangles_nil;
enum {
CAIRO_CLIP_PATH_HAS_REGION = 0x1,
CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED = 0x2
};
struct _cairo_clip_path {
cairo_reference_count_t ref_count;
cairo_path_fixed_t path;
@ -50,84 +55,74 @@ struct _cairo_clip_path {
double tolerance;
cairo_antialias_t antialias;
cairo_clip_path_t *prev;
cairo_rectangle_int_t extents;
/* partial caches */
unsigned int flags;
cairo_region_t *region;
cairo_surface_t *surface;
};
struct _cairo_clip {
cairo_clip_mode_t mode;
/* can be used as a cairo_hash_entry_t for live clips */
cairo_clip_path_t *path;
cairo_bool_t all_clipped;
/*
* Mask-based clipping for cases where the backend
* clipping isn't sufficiently able.
*
* The rectangle here represents the
* portion of the destination surface that this
* clip surface maps to, it does not
* represent the extents of the clip region or
* clip paths
*/
cairo_surface_t *surface;
cairo_rectangle_int_t surface_rect;
/*
* Surface clip serial number to store
* in the surface when this clip is set
*/
unsigned int serial;
/*
* A clip region that can be placed in the surface
*/
cairo_region_t *region;
/*
* If the surface supports path clipping, we store the list of
* clipping paths that has been set here as a linked list.
*/
cairo_clip_path_t *path;
};
cairo_private void
_cairo_clip_init (cairo_clip_t *clip, cairo_surface_t *target);
_cairo_clip_init (cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_clip_init_rectangle (cairo_clip_t *clip,
const cairo_rectangle_int_t *rect);
cairo_private void
_cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other);
cairo_private cairo_status_t
_cairo_clip_init_deep_copy (cairo_clip_t *clip,
cairo_clip_t *other,
cairo_surface_t *target);
_cairo_clip_init_copy_transformed (cairo_clip_t *clip,
cairo_clip_t *other,
const cairo_matrix_t *matrix);
cairo_private void
_cairo_clip_reset (cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_clip_clip (cairo_clip_t *clip,
cairo_path_fixed_t *path,
const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_surface_t *target);
cairo_antialias_t antialias);
cairo_private cairo_status_t
_cairo_clip_intersect_to_rectangle (cairo_clip_t *clip,
cairo_rectangle_int_t *rectangle);
_cairo_clip_apply_clip (cairo_clip_t *clip,
const cairo_clip_t *other);
cairo_private cairo_status_t
_cairo_clip_intersect_to_region (cairo_clip_t *clip,
cairo_region_t *region);
cairo_private const cairo_rectangle_int_t *
_cairo_clip_get_extents (const cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_clip_combine_to_surface (cairo_clip_t *clip,
cairo_operator_t op,
cairo_surface_t *dst,
int dst_x,
int dst_y,
const cairo_rectangle_int_t *extents);
cairo_private cairo_surface_t *
_cairo_clip_get_surface (cairo_clip_t *clip, cairo_surface_t *dst);
cairo_private cairo_int_status_t
_cairo_clip_get_region (cairo_clip_t *clip,
cairo_region_t **region);
cairo_private void
_cairo_clip_translate (cairo_clip_t *clip,
cairo_fixed_t tx,
cairo_fixed_t ty);
cairo_private void
_cairo_clip_transform (cairo_clip_t *clip,
const cairo_matrix_t *transform);
cairo_private void
_cairo_clip_drop_cache (cairo_clip_t *clip);
cairo_private cairo_rectangle_list_t*
_cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate);

File diff suppressed because it is too large Load diff

View file

@ -75,6 +75,8 @@ cairo_debug_reset_static_data (void)
_cairo_pattern_reset_static_data ();
_cairo_clip_reset_static_data ();
CAIRO_MUTEX_FINALIZE ();
}

View file

@ -38,14 +38,16 @@
#include "cairoint.h"
#include "cairo-directfb.h"
#include "cairo-clip-private.h"
#include <pixman.h>
#include <directfb.h>
#include <direct/types.h>
#include <direct/debug.h>
#include <direct/memcpy.h>
#include <direct/util.h>
#include "cairo-clip-private.h"
/*
* Rectangle works fine.
* Bugs 361377, 359553, 359243 in Gnome BTS are caused
@ -68,6 +70,8 @@
*/
#define DFB_SHOW_GLYPHS 1
#define PIXMAN_invalid (pixman_format_code_t) 0
D_DEBUG_DOMAIN (CairoDFB_Acquire, "CairoDFB/Acquire", "Cairo DirectFB Acquire");
D_DEBUG_DOMAIN (CairoDFB_Clip, "CairoDFB/Clip", "Cairo DirectFB Clipping");
@ -78,17 +82,15 @@ D_DEBUG_DOMAIN (CairoDFB_Surface, "CairoDFB/Surface", "Cairo DirectFB Surface");
/*****************************************************************************/
typedef struct _cairo_directfb_surface {
cairo_surface_t base;
cairo_format_t format;
cairo_content_t content;
cairo_surface_t base;
IDirectFB *dfb;
IDirectFBSurface *dfbsurface;
IDirectFBSurface *tmpsurface;
pixman_format_code_t pixman_format;
cairo_bool_t supported_destination;
cairo_bool_t has_clip;
DFBRegion *clips;
int n_clips;
IDirectFB *dfb;
IDirectFBSurface *dfbsurface;
IDirectFBSurface *tmpsurface;
pixman_format_code_t tmpformat;
int width;
int height;
@ -119,13 +121,18 @@ static int _directfb_argb_font = 0;
/*****************************************************************************/
#define RUN_CLIPPED(surface, clip, func) {\
if ((surface)->has_clip) {\
int k;\
for (k = 0; k < (surface)->n_clips; k++) {\
#define RUN_CLIPPED(surface, clip_region, clip, func) {\
if ((clip_region) != NULL) {\
int n_clips = cairo_region_num_rectangles (clip_region), n; \
for (n = 0; n < n_clips; n++) {\
if (clip) {\
DFBRegion reg = (surface)->clips[k];\
DFBRegion *cli = (clip);\
DFBRegion reg, *cli = (clip); \
cairo_rectangle_int_t rect; \
cairo_region_get_rectangle (clip_region, n, &rect); \
reg.x1 = rect.x; \
reg.y1 = rect.y; \
reg.x2 = rect.x + rect.width - 1; \
reg.y2 = rect.y + rect.height - 1; \
if (reg.x2 < cli->x1 || reg.y2 < cli->y1 ||\
reg.x1 > cli->x2 || reg.y1 > cli->y2)\
continue;\
@ -139,8 +146,14 @@ static int _directfb_argb_font = 0;
reg.y2 = cli->y2;\
(surface)->dfbsurface->SetClip ((surface)->dfbsurface, &reg);\
} else {\
(surface)->dfbsurface->SetClip ((surface)->dfbsurface,\
&(surface)->clips[k]);\
DFBRegion reg; \
cairo_rectangle_int_t rect; \
cairo_region_get_rectangle (clip_region, n, &rect); \
reg.x1 = rect.x; \
reg.y1 = rect.y; \
reg.x2 = rect.x + rect.width - 1; \
reg.y2 = rect.y + rect.height - 1; \
(surface)->dfbsurface->SetClip ((surface)->dfbsurface, &reg); \
}\
func;\
}\
@ -150,19 +163,19 @@ static int _directfb_argb_font = 0;
}\
}
#define TRANSFORM_POINT2X(m, x, y, ret_x, ret_y) {\
double _x = (x);\
double _y = (y);\
(ret_x) = (_x * (m).xx + (m).x0);\
(ret_y) = (_y * (m).yy + (m).y0);\
}
#define TRANSFORM_POINT2X(m, x, y, ret_x, ret_y) do { \
double _x = (x); \
double _y = (y); \
(ret_x) = (_x * (m).xx + (m).x0); \
(ret_y) = (_y * (m).yy + (m).y0); \
} while (0)
#define TRANSFORM_POINT3X(m, x, y, ret_x, ret_y) {\
double _x = (x);\
double _y = (y);\
(ret_x) = (_x * (m).xx + _y * (m).xy + (m).x0);\
(ret_y) = (_x * (m).yx + _y * (m).yy + (m).y0);\
}
#define TRANSFORM_POINT3X(m, x, y, ret_x, ret_y) do { \
double _x = (x); \
double _y = (y); \
(ret_x) = (_x * (m).xx + _y * (m).xy + (m).x0); \
(ret_y) = (_x * (m).yx + _y * (m).yy + (m).y0); \
} while (0)
/* XXX: A1 has a different bits ordering in cairo.
* Probably we should drop it.
@ -200,23 +213,65 @@ _cairo_to_directfb_format (cairo_format_t format)
return -1;
}
static inline cairo_format_t
_directfb_to_cairo_format (DFBSurfacePixelFormat format)
static inline pixman_format_code_t
_directfb_to_pixman_format (DFBSurfacePixelFormat format)
{
switch (format) {
case DSPF_RGB32:
return CAIRO_FORMAT_RGB24;
case DSPF_ARGB:
return CAIRO_FORMAT_ARGB32;
case DSPF_A8:
return CAIRO_FORMAT_A8;
case DSPF_A1:
return CAIRO_FORMAT_A1;
default:
break;
case DSPF_UNKNOWN: return PIXMAN_invalid;
case DSPF_ARGB1555: return PIXMAN_a1r5g5b5;
case DSPF_RGB16: return PIXMAN_r5g6b5;
case DSPF_RGB24: return PIXMAN_r8g8b8;
case DSPF_RGB32: return PIXMAN_x8r8g8b8;
case DSPF_ARGB: return PIXMAN_a8r8g8b8;
case DSPF_A8: return PIXMAN_a8;
case DSPF_YUY2: return PIXMAN_yuy2;
case DSPF_RGB332: return PIXMAN_r3g3b2;
case DSPF_UYVY: return PIXMAN_invalid;
case DSPF_I420: return PIXMAN_invalid;
case DSPF_YV12: return PIXMAN_yv12;
case DSPF_LUT8: return PIXMAN_invalid;
case DSPF_ALUT44: return PIXMAN_invalid;
case DSPF_AiRGB: return PIXMAN_invalid;
case DSPF_A1: return PIXMAN_a1; /* bit reversed, oops */
case DSPF_NV12: return PIXMAN_invalid;
case DSPF_NV16: return PIXMAN_invalid;
case DSPF_ARGB2554: return PIXMAN_invalid;
case DSPF_ARGB4444: return PIXMAN_a4r4g4b4;
case DSPF_NV21: return PIXMAN_invalid;
case DSPF_AYUV: return PIXMAN_invalid;
case DSPF_A4: return PIXMAN_a4;
case DSPF_ARGB1666: return PIXMAN_invalid;
case DSPF_ARGB6666: return PIXMAN_invalid;
case DSPF_RGB18: return PIXMAN_invalid;
case DSPF_LUT2: return PIXMAN_invalid;
case DSPF_RGB444: return PIXMAN_x4r4g4b4;
case DSPF_RGB555: return PIXMAN_x1r5g5b5;
case DSPF_BGR555: return PIXMAN_x1b5g5r5;
}
return PIXMAN_invalid;
}
return -1;
static inline DFBSurfacePixelFormat
_directfb_from_pixman_format (pixman_format_code_t format)
{
switch ((int) format) {
case PIXMAN_a1r5g5b5: return DSPF_ARGB1555;
case PIXMAN_r5g6b5: return DSPF_RGB16;
case PIXMAN_r8g8b8: return DSPF_RGB24;
case PIXMAN_x8r8g8b8: return DSPF_RGB32;
case PIXMAN_a8r8g8b8: return DSPF_ARGB;
case PIXMAN_a8: return DSPF_A8;
case PIXMAN_yuy2: return DSPF_YUY2;
case PIXMAN_r3g3b2: return DSPF_RGB332;
case PIXMAN_yv12: return DSPF_YV12;
case PIXMAN_a1: return DSPF_A1; /* bit reversed, oops */
case PIXMAN_a4r4g4b4: return DSPF_ARGB4444;
case PIXMAN_a4: return DSPF_A4;
case PIXMAN_x4r4g4b4: return DSPF_RGB444;
case PIXMAN_x1r5g5b5: return DSPF_RGB555;
case PIXMAN_x1b5g5r5: return DSPF_BGR555;
default: return 0;
}
}
static cairo_bool_t
@ -350,17 +405,14 @@ _directfb_acquire_surface (cairo_directfb_surface_t *surface,
IDirectFBSurface *buffer = NULL;
DFBRectangle source_rect;
cairo_surface_t *image;
cairo_format_t cairo_format;
pixman_image_t *pixman_image;
pixman_format_code_t pixman_format;
cairo_status_t status;
void *data;
int pitch;
if (surface->format == (cairo_format_t) -1 ||
(lock_flags & DSLF_WRITE && surface->has_clip))
{
DFBSurfaceCapabilities caps;
if (intrest_rec) {
if (surface->pixman_format == PIXMAN_invalid) {
if (intrest_rec != NULL) {
source_rect.x = intrest_rec->x;
source_rect.y = intrest_rec->y;
source_rect.w = intrest_rec->width;
@ -372,30 +424,38 @@ _directfb_acquire_surface (cairo_directfb_surface_t *surface,
&source_rect.w, &source_rect.h);
}
if (surface->tmpsurface) {
if (surface->tmpsurface != NULL) {
int w, h;
surface->tmpsurface->GetSize (surface->tmpsurface, &w, &h);
if (w < source_rect.w || h < source_rect.h) {
surface->tmpsurface->Release (surface->tmpsurface);
surface->tmpsurface = NULL;
surface->tmpformat = PIXMAN_invalid;
}
}
cairo_format = _cairo_format_from_content (surface->content);
if (!surface->tmpsurface) {
if (surface->tmpsurface == NULL) {
DFBSurfacePixelFormat format;
D_DEBUG_AT (CairoDFB_Acquire, "Allocating buffer for surface %p.\n", surface);
format = _cairo_to_directfb_format (_cairo_format_from_content (surface->base.content));
status =
_directfb_buffer_surface_create (surface->dfb,
_cairo_to_directfb_format (cairo_format),
_directfb_buffer_surface_create (surface->dfb, format,
source_rect.w, source_rect.h,
&surface->tmpsurface);
if (status)
if (unlikely (status))
goto ERROR;
surface->tmpformat = _directfb_to_pixman_format (format);
}
buffer = surface->tmpsurface;
pixman_format = surface->tmpformat;
/* surface->dfbsurface->GetCapabilities (surface->dfbsurface, &caps);
DFBSurfaceCapabilities caps;
if (caps & DSCAPS_FLIPPING) {
DFBRegion region = { .x1 = source_rect.x, .y1 = source_rect.y,
.x2 = source_rect.x + source_rect.w - 1,
@ -406,7 +466,7 @@ _directfb_acquire_surface (cairo_directfb_surface_t *surface,
} else {
/*might be a subsurface get the offset*/
surface->dfbsurface->GetVisibleRectangle (surface->dfbsurface, &source_rect);
cairo_format = surface->format;
pixman_format = surface->pixman_format;
buffer = surface->dfbsurface;
}
@ -416,9 +476,16 @@ _directfb_acquire_surface (cairo_directfb_surface_t *surface,
goto ERROR;
}
image = cairo_image_surface_create_for_data (data, cairo_format,
source_rect.w, source_rect.h,
pitch);
pixman_image = pixman_image_create_bits (pixman_format,
source_rect.w, source_rect.h,
data, pitch);
if (pixman_image == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto ERROR;
}
image = _cairo_image_surface_create_for_pixman_image (pixman_image,
pixman_format);
status = image->status;
if (status)
goto ERROR;
@ -451,37 +518,27 @@ ERROR:
}
static cairo_surface_t *
_cairo_directfb_surface_create_similar (void *abstract_src,
cairo_content_t content,
int width,
int height)
_cairo_directfb_surface_create_internal (IDirectFB *dfb,
DFBSurfacePixelFormat format,
cairo_content_t content,
int width,
int height)
{
cairo_directfb_surface_t *source = abstract_src;
cairo_directfb_surface_t *surface;
cairo_format_t format;
cairo_status_t status;
D_DEBUG_AT (CairoDFB_Surface,
"%s( src=%p, content=0x%x, width=%d, height=%d).\n",
__FUNCTION__, source, content, width, height);
width = (width <= 0) ? 1 : width;
height = (height<= 0) ? 1 : height;
format = _cairo_format_from_content (content);
surface = calloc (1, sizeof (cairo_directfb_surface_t));
if (unlikely (surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
surface->dfb = source->dfb;
surface->dfb = dfb;
if (width < 8 || height < 8) {
IDirectFBSurface *tmp;
DFBRectangle rect = { .x=0, .y=0, .w=width, .h=height };
/* Some cards (e.g. Matrox) don't support surfaces smaller than 8x8 */
status = _directfb_buffer_surface_create (surface->dfb,
_cairo_to_directfb_format (format),
status = _directfb_buffer_surface_create (dfb, format,
MAX (width, 8), MAX (height, 8),
&tmp);
if (status) {
@ -492,11 +549,9 @@ _cairo_directfb_surface_create_similar (void *abstract_src,
tmp->GetSubSurface (tmp, &rect, &surface->dfbsurface);
tmp->Release (tmp);
} else {
status =
_directfb_buffer_surface_create (surface->dfb,
_cairo_to_directfb_format (format),
width, height,
&surface->dfbsurface);
status = _directfb_buffer_surface_create (dfb, format,
width, height,
&surface->dfbsurface);
if (status) {
free (surface);
return _cairo_surface_create_in_error (status);
@ -506,8 +561,9 @@ _cairo_directfb_surface_create_similar (void *abstract_src,
_cairo_surface_init (&surface->base,
&_cairo_directfb_surface_backend,
content);
surface->format = format;
surface->content = content;
surface->pixman_format = _directfb_to_pixman_format (format);
surface->supported_destination = pixman_format_supported_destination (surface->pixman_format);
surface->width = width;
surface->height = height;
surface->local = TRUE;
@ -516,6 +572,27 @@ _cairo_directfb_surface_create_similar (void *abstract_src,
return &surface->base;
}
static cairo_surface_t *
_cairo_directfb_surface_create_similar (void *abstract_src,
cairo_content_t content,
int width,
int height)
{
cairo_directfb_surface_t *other = abstract_src;
DFBSurfacePixelFormat format;
D_DEBUG_AT (CairoDFB_Surface,
"%s( src=%p, content=0x%x, width=%d, height=%d).\n",
__FUNCTION__, other, content, width, height);
width = (width <= 0) ? 1 : width;
height = (height<= 0) ? 1 : height;
format = _cairo_to_directfb_format (_cairo_format_from_content (content));
return _cairo_directfb_surface_create_internal (other->dfb, format,
content, width, height);
}
static cairo_status_t
_cairo_directfb_surface_finish (void *data)
{
@ -523,12 +600,6 @@ _cairo_directfb_surface_finish (void *data)
D_DEBUG_AT (CairoDFB_Surface, "%s( surface=%p ).\n", __FUNCTION__, surface);
if (surface->clips) {
free (surface->clips);
surface->clips = NULL;
surface->n_clips = 0;
}
if (surface->tmpsurface) {
surface->tmpsurface->Release (surface->tmpsurface);
surface->tmpsurface = NULL;
@ -564,11 +635,10 @@ _cairo_directfb_surface_release_source_image (void *abstract_su
cairo_image_surface_t *image,
void *image_extra)
{
cairo_directfb_surface_t *surface = abstract_surface;
IDirectFBSurface *buffer = image_extra;
D_DEBUG_AT (CairoDFB_Acquire,
"%s( surface=%p ).\n", __FUNCTION__, surface);
"%s( release=%p ).\n", __FUNCTION__, abstract_surface);
buffer->Unlock (buffer);
@ -620,10 +690,10 @@ _cairo_directfb_surface_release_dest_image (void *abstract_surf
.y2 = interest_rect->y + interest_rect->height - 1
};
surface->dfbsurface->SetBlittingFlags (surface->dfbsurface, DSBLIT_NOFX);
RUN_CLIPPED (surface, &region,
surface->dfbsurface->Blit (surface->dfbsurface,
buffer, NULL,
image_rect->x, image_rect->y));
surface->dfbsurface->SetClip (surface->dfbsurface, &region);
surface->dfbsurface->Blit (surface->dfbsurface,
buffer, NULL,
image_rect->x, image_rect->y);
}
cairo_surface_destroy (&image->base);
@ -655,56 +725,51 @@ _cairo_directfb_surface_clone_similar (void *abstract_surface,
return CAIRO_STATUS_SUCCESS;
} else if (_cairo_surface_is_image (src)) {
cairo_image_surface_t *image_src = (cairo_image_surface_t *) src;
unsigned char *dst, *src = image_src->data;
int pitch;
int i, j;
DFBSurfacePixelFormat format;
DFBResult ret;
pixman_image_t *pixman_image;
void *data;
int pitch;
format = _directfb_from_pixman_format (image_src->pixman_format);
if (format == 0)
return CAIRO_INT_STATUS_UNSUPPORTED;
clone = (cairo_directfb_surface_t *)
_cairo_directfb_surface_create_similar (surface,
_cairo_content_from_format (image_src->format),
width, height);
if (clone == NULL)
return CAIRO_INT_STATUS_UNSUPPORTED;
if (clone->base.status)
_cairo_directfb_surface_create_internal (surface->dfb, format,
image_src->base.content,
width, height);
if (unlikely (clone->base.status))
return clone->base.status;
ret = clone->dfbsurface->Lock (clone->dfbsurface,
DSLF_WRITE, (void *)&dst, &pitch);
DSLF_WRITE, (void *)&data, &pitch);
if (ret) {
DirectFBError ("IDirectFBSurface::Lock()", ret);
cairo_surface_destroy (&clone->base);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
src += image_src->stride * src_y;
if (image_src->format == CAIRO_FORMAT_A1) {
/* A1 -> A8 */
dst -= src_x;
for (i = 0; i < height; i++) {
for (j = src_x; j < src_x + width; j++)
dst[j] = (src[j>>3] & (1 << (j&7))) ? 0xff : 0x00;
dst += pitch;
src += image_src->stride;
}
} else {
int len;
if (image_src->format == CAIRO_FORMAT_A8) {
src += src_x;
len = width;
} else {
src += src_x * 4;
len = width * 4;
}
for (i = 0; i < height; i++) {
direct_memcpy (dst, src, len);
dst += pitch;
src += image_src->stride;
}
pixman_image = pixman_image_create_bits (clone->pixman_format,
width, height,
data, pitch);
if (unlikely (pixman_image == NULL)) {
DirectFBError ("IDirectFBSurface::Lock()", ret);
cairo_surface_destroy (&clone->base);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
pixman_image_composite (PIXMAN_OP_SRC,
image_src->pixman_image,
NULL,
pixman_image,
src_x, src_y,
0, 0,
0, 0,
width, height);
pixman_image_unref (pixman_image);
clone->dfbsurface->Unlock (clone->dfbsurface);
*clone_offset_x = src_x;
@ -745,8 +810,6 @@ _directfb_prepare_composite (cairo_directfb_surface_t *dst,
return CAIRO_INT_STATUS_UNSUPPORTED;
if (mask_pattern) {
cairo_solid_pattern_t *pattern;
return CAIRO_INT_STATUS_UNSUPPORTED;
if (mask_pattern->type != CAIRO_PATTERN_TYPE_SOLID) {
const cairo_pattern_t *tmp;
@ -794,7 +857,7 @@ _directfb_prepare_composite (cairo_directfb_surface_t *dst,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
if (src->content == CAIRO_CONTENT_COLOR) {
if ((src->base.content & CAIRO_CONTENT_ALPHA) == 0) {
if (sblend == DSBF_SRCALPHA)
sblend = DSBF_ONE;
else if (sblend == DSBF_INVSRCALPHA)
@ -806,7 +869,7 @@ _directfb_prepare_composite (cairo_directfb_surface_t *dst,
dblend = DSBF_ZERO;
}
if (dst->content == CAIRO_CONTENT_COLOR) {
if ((dst->base.content & CAIRO_CONTENT_ALPHA) == 0) {
if (sblend == DSBF_DESTALPHA)
sblend = DSBF_ONE;
else if (sblend == DSBF_INVDESTALPHA)
@ -913,7 +976,8 @@ _cairo_directfb_surface_composite (cairo_operator_t op,
int mask_x, int mask_y,
int dst_x, int dst_y,
unsigned int width,
unsigned int height)
unsigned int height,
cairo_region_t *clip_region)
{
cairo_directfb_surface_t *dst = abstract_dst;
cairo_directfb_surface_t *src;
@ -930,6 +994,9 @@ _cairo_directfb_surface_composite (cairo_operator_t op,
__FUNCTION__, op, src_pattern, mask_pattern, dst,
src_x, src_y, mask_x, mask_y, dst_x, dst_y, width, height);
if (! dst->supported_destination)
return CAIRO_INT_STATUS_UNSUPPORTED;
status = _directfb_prepare_composite (dst, src_pattern, mask_pattern, op,
&src_x, &src_y, &mask_x, &mask_y,
width, height, &src, &src_attr);
@ -956,7 +1023,7 @@ _cairo_directfb_surface_composite (cairo_operator_t op,
src_x += src_attr.x_offset;
src_y += src_attr.y_offset;
switch (accel) {
switch ((int) accel) {
case DFXL_BLIT:
{
DFBRectangle sr;
@ -974,11 +1041,10 @@ _cairo_directfb_surface_composite (cairo_operator_t op,
if (src_attr.extend == CAIRO_EXTEND_NONE) {
D_DEBUG_AT (CairoDFB_Render, "Running Blit().\n");
RUN_CLIPPED (dst, NULL,
RUN_CLIPPED (dst, clip_region, NULL,
dst->dfbsurface->Blit (dst->dfbsurface,
src->dfbsurface,
&sr,
dst_x, dst_y));
&sr, dst_x, dst_y));
} else if (src_attr.extend == CAIRO_EXTEND_REPEAT) {
DFBRegion clip;
@ -989,11 +1055,10 @@ _cairo_directfb_surface_composite (cairo_operator_t op,
D_DEBUG_AT (CairoDFB_Render, "Running TileBlit().\n");
RUN_CLIPPED (dst, &clip,
RUN_CLIPPED (dst, clip_region, &clip,
dst->dfbsurface->TileBlit (dst->dfbsurface,
src->dfbsurface,
&sr,
dst_x, dst_y));
&sr, dst_x, dst_y));
}
break;
}
@ -1020,9 +1085,10 @@ _cairo_directfb_surface_composite (cairo_operator_t op,
D_DEBUG_AT (CairoDFB_Render, "Running StretchBlit().\n");
RUN_CLIPPED (dst, NULL,
RUN_CLIPPED (dst, clip_region, NULL,
dst->dfbsurface->StretchBlit (dst->dfbsurface,
src->dfbsurface, &sr, &dr));
src->dfbsurface,
&sr, &dr));
break;
}
@ -1044,29 +1110,25 @@ _cairo_directfb_surface_composite (cairo_operator_t op,
src->dfbsurface->GetSize (src->dfbsurface, &w, &h);
TRANSFORM_POINT3X (src_attr.matrix,
x1, y1, v[0].x, v[0].y);
TRANSFORM_POINT3X (src_attr.matrix, x1, y1, v[0].x, v[0].y);
v[0].z = 0;
v[0].w = 1;
v[0].s = x1 / w;
v[0].t = y1 / h;
TRANSFORM_POINT3X (src_attr.matrix,
x2, y1, v[1].x, v[1].y);
TRANSFORM_POINT3X (src_attr.matrix, x2, y1, v[1].x, v[1].y);
v[1].z = 0;
v[1].w = 1;
v[1].s = x2 / w;
v[1].t = y1 / h;
TRANSFORM_POINT3X (src_attr.matrix,
x2, y2, v[2].x, v[2].y);
TRANSFORM_POINT3X (src_attr.matrix, x2, y2, v[2].x, v[2].y);
v[2].z = 0;
v[2].w = 1;
v[2].s = x2 / w;
v[2].t = y2 / h;
TRANSFORM_POINT3X (src_attr.matrix,
x1, y2, v[3].x, v[3].y);
TRANSFORM_POINT3X (src_attr.matrix, x1, y2, v[3].x, v[3].y);
v[3].z = 0;
v[3].w = 1;
v[3].s = x1 / w;
@ -1079,9 +1141,11 @@ _cairo_directfb_surface_composite (cairo_operator_t op,
D_DEBUG_AT (CairoDFB_Render, "Running TextureTriangles().\n");
RUN_CLIPPED (dst, &clip,
RUN_CLIPPED (dst, clip_region, &clip,
dst->dfbsurface->TextureTriangles (dst->dfbsurface,
src->dfbsurface, v, NULL, 4, DTTF_FAN));
src->dfbsurface,
v, NULL,
4, DTTF_FAN));
break;
}
@ -1092,7 +1156,7 @@ _cairo_directfb_surface_composite (cairo_operator_t op,
_directfb_finish_composite (dst, src_pattern, &src->base, &src_attr);
return status;
return CAIRO_STATUS_SUCCESS;
}
#endif /* DFB_COMPOSITE */
@ -1115,8 +1179,8 @@ _cairo_directfb_surface_fill_rectangles (void *abstract_surface
"%s( dst=%p, op=%d, color=%p, rects=%p, n_rects=%d ).\n",
__FUNCTION__, dst, op, color, rects, n_rects);
if (! _cairo_operator_bounded_by_source (op))
return CAIRO_INT_STATUS_UNSUPPORTED;
if (! dst->supported_destination)
return CAIRO_INT_STATUS_UNSUPPORTED;
if (! _directfb_get_operator (op, &sblend, &dblend))
return CAIRO_INT_STATUS_UNSUPPORTED;
@ -1132,7 +1196,7 @@ _cairo_directfb_surface_fill_rectangles (void *abstract_surface
else if (dblend == DSBF_INVSRCALPHA)
dblend = DSBF_ZERO;
}
if (dst->content == CAIRO_CONTENT_COLOR) {
if ((dst->base.content & CAIRO_CONTENT_ALPHA) == 0) {
if (sblend == DSBF_DESTALPHA)
sblend = DSBF_ONE;
else if (sblend == DSBF_INVDESTALPHA)
@ -1164,7 +1228,7 @@ _cairo_directfb_surface_fill_rectangles (void *abstract_surface
r[i].h = rects[i].height;
}
RUN_CLIPPED (dst, NULL,
RUN_CLIPPED (dst, NULL, NULL,
dst->dfbsurface->FillRectangles (dst->dfbsurface, r, n_rects));
return CAIRO_STATUS_SUCCESS;
@ -1182,7 +1246,8 @@ _cairo_directfb_surface_composite_trapezoids (cairo_operator_t op,
unsigned int width,
unsigned int height,
cairo_trapezoid_t *traps,
int num_traps)
int num_traps,
cairo_region_t *clip_region)
{
cairo_directfb_surface_t *dst = abstract_dst;
cairo_directfb_surface_t *src;
@ -1197,6 +1262,9 @@ _cairo_directfb_surface_composite_trapezoids (cairo_operator_t op,
__FUNCTION__, op, pattern, dst, antialias,
src_x, src_y, dst_x, dst_y, width, height, traps, num_traps);
if (! dst->supported_destination)
return CAIRO_INT_STATUS_UNSUPPORTED;
if (antialias != CAIRO_ANTIALIAS_NONE)
return CAIRO_INT_STATUS_UNSUPPORTED;
@ -1291,7 +1359,7 @@ _cairo_directfb_surface_composite_trapezoids (cairo_operator_t op,
D_DEBUG_AT (CairoDFB_Render, "Running TextureTriangles().\n");
RUN_CLIPPED (dst, NULL,
RUN_CLIPPED (dst, clip_region, NULL,
dst->dfbsurface->TextureTriangles (dst->dfbsurface,
src->dfbsurface,
vertex, NULL, n,
@ -1306,64 +1374,7 @@ _cairo_directfb_surface_composite_trapezoids (cairo_operator_t op,
}
#endif /* DFB_COMPOSITE_TRAPEZOIDS */
static cairo_int_status_t
_cairo_directfb_surface_set_clip_region (void *abstract_surface,
cairo_region_t *region)
{
cairo_directfb_surface_t *surface = abstract_surface;
D_DEBUG_AT (CairoDFB_Clip,
"%s( surface=%p, region=%p ).\n",
__FUNCTION__, surface, region);
if (region) {
int n_rects;
cairo_status_t status;
int i;
surface->has_clip = TRUE;
n_rects = cairo_region_num_rectangles (region);
if (n_rects == 0)
return CAIRO_STATUS_SUCCESS;
if (surface->n_clips != n_rects) {
if (surface->clips)
free (surface->clips);
surface->clips = _cairo_malloc_ab (n_rects, sizeof (DFBRegion));
if (!surface->clips) {
surface->n_clips = 0;
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
surface->n_clips = n_rects;
}
for (i = 0; i < n_rects; i++) {
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (region, i, &rect);
surface->clips[i].x1 = rect.x;
surface->clips[i].y1 = rect.y;
surface->clips[i].x2 = rect.x + rect.width - 1;
surface->clips[i].y2 = rect.y + rect.height - 1;
}
} else {
surface->has_clip = FALSE;
if (surface->clips) {
free (surface->clips);
surface->clips = NULL;
surface->n_clips = 0;
}
}
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
static cairo_bool_t
_cairo_directfb_abstract_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
@ -1383,7 +1394,7 @@ _cairo_directfb_abstract_surface_get_extents (void *abstract_su
rectangle->width = surface->width;
rectangle->height = surface->height;
return CAIRO_STATUS_SUCCESS;
return TRUE;
}
#if DFB_SHOW_GLYPHS
@ -1422,6 +1433,7 @@ _directfb_destroy_font_cache (cairo_directfb_font_cache_t *cache)
free (cache);
}
/* XXX hook into rtree font cache from drm */
static cairo_status_t
_directfb_acquire_font_cache (cairo_directfb_surface_t *surface,
cairo_scaled_font_t *scaled_font,
@ -1473,6 +1485,7 @@ _directfb_acquire_font_cache (cairo_directfb_surface_t *surface,
case CAIRO_FORMAT_A8:
case CAIRO_FORMAT_ARGB32:
break;
case CAIRO_FORMAT_RGB24:
default:
D_DEBUG_AT (CairoDFB_Font,
" -> Unsupported font format %d!\n", img->format);
@ -1705,8 +1718,8 @@ _cairo_directfb_surface_show_glyphs (void *abstract_dst,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip,
int *remaining_glyphs)
{
cairo_directfb_surface_t *dst = abstract_dst;
cairo_directfb_font_cache_t *cache;
@ -1718,28 +1731,29 @@ _cairo_directfb_surface_show_glyphs (void *abstract_dst,
DFBPoint points[num_glyphs];
int num;
const cairo_color_t *color;
cairo_region_t *clip_region = NULL;
D_DEBUG_AT (CairoDFB_Font,
"%s( dst=%p, op=%d, pattern=%p, glyphs=%p, num_glyphs=%d, scaled_font=%p ).\n",
__FUNCTION__, dst, op, pattern, glyphs, num_glyphs, scaled_font);
if (! dst->supported_destination)
return CAIRO_INT_STATUS_UNSUPPORTED;
if (pattern->type != CAIRO_PATTERN_TYPE_SOLID)
return CAIRO_INT_STATUS_UNSUPPORTED;
/* Fallback if we need to emulate clip regions */
if (dst->base.clip &&
(dst->base.clip->mode != CAIRO_CLIP_MODE_REGION ||
dst->base.clip->surface != NULL))
{
return CAIRO_INT_STATUS_UNSUPPORTED;
if (clip != NULL) {
status = _cairo_clip_get_region (clip, &clip_region);
assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO);
if (status)
return status;
}
/* XXX Unbounded operators are not handled correctly */
if (! _cairo_operator_bounded_by_mask (op))
return CAIRO_INT_STATUS_UNSUPPORTED;
if (! _cairo_operator_bounded_by_source (op))
return CAIRO_INT_STATUS_UNSUPPORTED;
if (! _directfb_get_operator (op, &sblend, &dblend) ||
sblend == DSBF_DESTALPHA || sblend == DSBF_INVDESTALPHA)
@ -1788,7 +1802,7 @@ _cairo_directfb_surface_show_glyphs (void *abstract_dst,
D_DEBUG_AT (CairoDFB_Font, "Running BatchBlit().\n");
RUN_CLIPPED (dst, NULL,
RUN_CLIPPED (dst, clip_region, NULL,
dst->dfbsurface->BatchBlit (dst->dfbsurface,
cache->dfbsurface, rects, points, num));
@ -1835,8 +1849,6 @@ _cairo_directfb_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
_cairo_directfb_surface_set_clip_region,/* set_clip_region */
NULL, /* intersect_clip_path */
_cairo_directfb_abstract_surface_get_extents,/* get_extents */
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
@ -1860,7 +1872,6 @@ _cairo_directfb_surface_backend = {
#endif
NULL, /* snapshot */
_cairo_directfb_surface_is_similar,
NULL /* reset */
};
@ -1933,8 +1944,8 @@ cairo_directfb_surface_create (IDirectFB *dfb, IDirectFBSurface *dfbsurface)
dfbsurface->GetSize (dfbsurface, &surface->width, &surface->height);
surface->dfb = dfb;
surface->dfbsurface = dfbsurface;
surface->format = _directfb_to_cairo_format (format);
surface->content = _directfb_format_to_content (format);
surface->pixman_format = _directfb_to_pixman_format (format);
surface->supported_destination = pixman_format_supported_destination (surface->pixman_format);
dfbsurface->GetCapabilities (dfbsurface, &caps);
if (caps & DSCAPS_PREMULTIPLIED)
@ -1942,7 +1953,7 @@ cairo_directfb_surface_create (IDirectFB *dfb, IDirectFBSurface *dfbsurface)
_cairo_surface_init (&surface->base,
&_cairo_directfb_surface_backend,
surface->content);
_directfb_format_to_content (format));
return &surface->base;
}

View file

@ -1146,7 +1146,7 @@ _render_glyph_bitmap (FT_Face face,
cairo_image_surface_t **surface)
{
FT_GlyphSlot glyphslot = face->glyph;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_status_t status;
FT_Error error;
/* According to the FreeType docs, glyphslot->format could be
@ -1162,7 +1162,9 @@ _render_glyph_bitmap (FT_Face face,
if (error == FT_Err_Out_Of_Memory)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = _get_bitmap_surface (&glyphslot->bitmap, FALSE, font_options, surface);
status = _get_bitmap_surface (&glyphslot->bitmap,
FALSE, font_options,
surface);
if (unlikely (status))
return status;
@ -1177,7 +1179,7 @@ _render_glyph_bitmap (FT_Face face,
-glyphslot->bitmap_left,
+glyphslot->bitmap_top);
return status;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
@ -1275,11 +1277,8 @@ _transform_glyph_bitmap (cairo_matrix_t * shape,
_cairo_pattern_init_for_surface (&pattern, &(*surface)->base);
cairo_pattern_set_matrix (&pattern.base, &transformed_to_original);
status = _cairo_surface_composite (CAIRO_OPERATOR_OVER,
&pattern.base, NULL, image,
0, 0, 0, 0, 0, 0,
width,
height);
status = _cairo_surface_paint (image, CAIRO_OPERATOR_OVER,
&pattern.base, NULL);
_cairo_pattern_fini (&pattern.base);
@ -1301,7 +1300,7 @@ _transform_glyph_bitmap (cairo_matrix_t * shape,
cairo_surface_set_device_offset (&(*surface)->base,
_cairo_lround (origin_x),
_cairo_lround (origin_y));
return status;
return CAIRO_STATUS_SUCCESS;
}
static const cairo_unscaled_font_backend_t cairo_ft_unscaled_font_backend = {
@ -1390,8 +1389,8 @@ _get_pattern_ft_options (FcPattern *pattern, cairo_ft_options_t *ret)
ft_options.base.antialias = CAIRO_ANTIALIAS_SUBPIXEL;
}
#ifdef FC_HINT_STYLE
if (FcPatternGetInteger (pattern,
#ifdef FC_HINT_STYLE
if (FcPatternGetInteger (pattern,
FC_HINT_STYLE, 0, &hintstyle) != FcResultMatch)
hintstyle = FC_HINT_FULL;
@ -1400,7 +1399,7 @@ _get_pattern_ft_options (FcPattern *pattern, cairo_ft_options_t *ret)
switch (hintstyle) {
case FC_HINT_NONE:
ft_options.base.hint_style = CAIRO_HINT_STYLE_NONE;
ft_options.base.hint_style = CAIRO_HINT_STYLE_NONE;
break;
case FC_HINT_SLIGHT:
ft_options.base.hint_style = CAIRO_HINT_STYLE_SLIGHT;
@ -1444,14 +1443,14 @@ _get_pattern_ft_options (FcPattern *pattern, cairo_ft_options_t *ret)
if (vertical_layout)
ft_options.load_flags |= FT_LOAD_VERTICAL_LAYOUT;
#ifndef FC_EMBOLDEN
#define FC_EMBOLDEN "embolden"
#endif
if (FcPatternGetBool (pattern,
FC_EMBOLDEN, 0, &embolden) != FcResultMatch)
embolden = FcFalse;
if (embolden)
ft_options.extra_flags |= CAIRO_FT_OPTIONS_EMBOLDEN;
@ -1468,7 +1467,7 @@ _cairo_ft_options_merge (cairo_ft_options_t *options,
/* clear load target mode */
load_flags &= ~(FT_LOAD_TARGET_(FT_LOAD_TARGET_MODE(other->load_flags)));
if (load_flags & FT_LOAD_NO_HINTING)
other->base.hint_style = CAIRO_HINT_STYLE_NONE;
@ -1479,7 +1478,7 @@ _cairo_ft_options_merge (cairo_ft_options_t *options,
}
if (other->base.antialias == CAIRO_ANTIALIAS_SUBPIXEL &&
(options->base.antialias == CAIRO_ANTIALIAS_DEFAULT ||
(options->base.antialias == CAIRO_ANTIALIAS_DEFAULT ||
options->base.antialias == CAIRO_ANTIALIAS_GRAY)) {
options->base.antialias = CAIRO_ANTIALIAS_SUBPIXEL;
options->base.subpixel_order = other->base.subpixel_order;
@ -1934,12 +1933,12 @@ _cairo_ft_scaled_glyph_init (void *abstract_font,
x2 = (metrics->horiBearingX + metrics->width + 63) & -64;
y1 = (-metrics->horiBearingY) & -64;
y2 = (-metrics->horiBearingY + metrics->height + 63) & -64;
advance = ((metrics->horiAdvance + 32) & -64);
fs_metrics.x_bearing = DOUBLE_FROM_26_6 (x1) * x_factor;
fs_metrics.y_bearing = DOUBLE_FROM_26_6 (y1) * y_factor;
fs_metrics.width = DOUBLE_FROM_26_6 (x2 - x1) * x_factor;
fs_metrics.height = DOUBLE_FROM_26_6 (y2 - y1) * y_factor;
@ -1950,12 +1949,12 @@ _cairo_ft_scaled_glyph_init (void *abstract_font,
x2 = (metrics->vertBearingX + metrics->width + 63) & -64;
y1 = (metrics->vertBearingY) & -64;
y2 = (metrics->vertBearingY + metrics->height + 63) & -64;
advance = ((metrics->vertAdvance + 32) & -64);
fs_metrics.x_bearing = DOUBLE_FROM_26_6 (x1) * x_factor;
fs_metrics.y_bearing = DOUBLE_FROM_26_6 (y1) * y_factor;
fs_metrics.width = DOUBLE_FROM_26_6 (x2 - x1) * x_factor;
fs_metrics.height = DOUBLE_FROM_26_6 (y2 - y1) * y_factor;
@ -1969,7 +1968,7 @@ _cairo_ft_scaled_glyph_init (void *abstract_font,
if (!vertical_layout) {
fs_metrics.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX) * x_factor;
fs_metrics.y_bearing = DOUBLE_FROM_26_6 (-metrics->horiBearingY) * y_factor;
if (hint_metrics || glyph->format != FT_GLYPH_FORMAT_OUTLINE)
fs_metrics.x_advance = DOUBLE_FROM_26_6 (metrics->horiAdvance) * x_factor;
else
@ -1978,7 +1977,7 @@ _cairo_ft_scaled_glyph_init (void *abstract_font,
} else {
fs_metrics.x_bearing = DOUBLE_FROM_26_6 (metrics->vertBearingX) * x_factor;
fs_metrics.y_bearing = DOUBLE_FROM_26_6 (metrics->vertBearingY) * y_factor;
fs_metrics.x_advance = 0 * x_factor;
if (hint_metrics || glyph->format != FT_GLYPH_FORMAT_OUTLINE)
fs_metrics.y_advance = DOUBLE_FROM_26_6 (metrics->vertAdvance) * y_factor;
@ -2154,7 +2153,7 @@ static const cairo_scaled_font_backend_t _cairo_ft_scaled_font_backend = {
_cairo_ft_scaled_glyph_init,
NULL, /* text_to_glyphs */
_cairo_ft_ucs4_to_index,
NULL, /* show_glyphs */
NULL, /* show_glyphs */
_cairo_ft_load_truetype_table,
_cairo_ft_index_to_ucs4
};
@ -2911,10 +2910,10 @@ cairo_bool_t
_cairo_ft_scaled_font_is_vertical (cairo_scaled_font_t *scaled_font)
{
cairo_ft_scaled_font_t *ft_scaled_font;
if (!_cairo_scaled_font_is_ft (scaled_font))
return FALSE;
ft_scaled_font = (cairo_ft_scaled_font_t *) scaled_font;
if (ft_scaled_font->ft_options.load_flags & FT_LOAD_VERTICAL_LAYOUT)
return TRUE;

View file

@ -56,6 +56,7 @@ typedef struct _cairo_gl_surface {
int width, height;
GLuint tex; /* GL texture object containing our data. */
GLuint depth_stencil_tex;
GLuint fb; /* GL framebuffer object wrapping our data. */
} cairo_gl_surface_t;

View file

@ -312,6 +312,10 @@ _cairo_gl_get_image_format_and_type (pixman_format_code_t pixman_format,
case PIXMAN_g1:
case PIXMAN_yuy2:
case PIXMAN_yv12:
#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,15,16)
case PIXMAN_x2r10g10b10:
case PIXMAN_a2r10g10b10:
#endif
default:
return CAIRO_INT_STATUS_UNSUPPORTED;
}
@ -766,6 +770,8 @@ _cairo_gl_surface_finish (void *abstract_surface)
glDeleteFramebuffersEXT (1, &surface->fb);
glDeleteTextures (1, &surface->tex);
if (surface->depth_stencil_tex)
glDeleteTextures (1, &surface->depth_stencil_tex);
if (surface->ctx->current_target == surface)
surface->ctx->current_target = NULL;
@ -1264,16 +1270,20 @@ _cairo_gl_surface_composite (cairo_operator_t op,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height)
unsigned int height,
cairo_region_t *clip_region)
{
cairo_gl_surface_t *dst = abstract_dst;
cairo_surface_attributes_t *src_attributes, *mask_attributes = NULL;
cairo_gl_context_t *ctx;
GLfloat vertices[4][2];
GLfloat texcoord_src[4][2];
GLfloat texcoord_mask[4][2];
struct gl_point {
GLfloat x, y;
} vertices_stack[8], texcoord_src_stack[8], texcoord_mask_stack[8];
struct gl_point *vertices = vertices_stack;
struct gl_point *texcoord_src = texcoord_src_stack;
struct gl_point *texcoord_mask = texcoord_mask_stack;
cairo_status_t status;
int i;
int num_vertices, i;
GLenum err;
cairo_gl_composite_setup_t setup;
@ -1345,27 +1355,62 @@ _cairo_gl_surface_composite (cairo_operator_t op,
}
}
vertices[0][0] = dst_x;
vertices[0][1] = dst_y;
vertices[1][0] = dst_x + width;
vertices[1][1] = dst_y;
vertices[2][0] = dst_x + width;
vertices[2][1] = dst_y + height;
vertices[3][0] = dst_x;
vertices[3][1] = dst_y + height;
if (clip_region != NULL) {
int num_rectangles;
num_rectangles = cairo_region_num_rectangles (clip_region);
if (num_rectangles * 4 > ARRAY_LENGTH (vertices_stack)) {
vertices = _cairo_malloc_ab (num_rectangles,
4*3*sizeof (vertices[0]));
if (unlikely (vertices == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CONTEXT_RELEASE;
}
texcoord_src = vertices + num_rectangles * 4;
texcoord_mask = texcoord_src + num_rectangles * 4;
}
for (i = 0; i < num_rectangles; i++) {
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (clip_region, i, &rect);
vertices[4*i + 0].x = rect.x;
vertices[4*i + 0].y = rect.y;
vertices[4*i + 1].x = rect.x + rect.width;
vertices[4*i + 1].y = rect.y;
vertices[4*i + 2].x = rect.x + rect.width;
vertices[4*i + 2].y = rect.y + rect.height;
vertices[4*i + 3].x = rect.x;
vertices[4*i + 3].y = rect.y + rect.height;
}
num_vertices = 4 * num_rectangles;
} else {
vertices[0].x = dst_x;
vertices[0].y = dst_y;
vertices[1].x = dst_x + width;
vertices[1].y = dst_y;
vertices[2].x = dst_x + width;
vertices[2].y = dst_y + height;
vertices[3].x = dst_x;
vertices[3].y = dst_y + height;
num_vertices = 4;
}
glVertexPointer (2, GL_FLOAT, sizeof (GLfloat) * 2, vertices);
glEnableClientState (GL_VERTEX_ARRAY);
if (setup.src.type == OPERAND_TEXTURE) {
for (i = 0; i < 4; i++) {
for (i = 0; i < num_vertices; i++) {
double s, t;
s = vertices[i][0];
t = vertices[i][1];
s = vertices[i].x;
t = vertices[i].y;
cairo_matrix_transform_point (&src_attributes->matrix, &s, &t);
texcoord_src[i][0] = s;
texcoord_src[i][1] = t;
texcoord_src[i].x = s;
texcoord_src[i].y = t;
}
glClientActiveTexture (GL_TEXTURE0);
@ -1375,14 +1420,14 @@ _cairo_gl_surface_composite (cairo_operator_t op,
if (mask != NULL) {
if (setup.mask.type == OPERAND_TEXTURE) {
for (i = 0; i < 4; i++) {
for (i = 0; i < num_vertices; i++) {
double s, t;
s = vertices[i][0];
t = vertices[i][1];
s = vertices[i].x;
t = vertices[i].y;
cairo_matrix_transform_point (&mask_attributes->matrix, &s, &t);
texcoord_mask[i][0] = s;
texcoord_mask[i][1] = t;
texcoord_mask[i].x = s;
texcoord_mask[i].y = t;
}
glClientActiveTexture (GL_TEXTURE1);
@ -1391,7 +1436,7 @@ _cairo_gl_surface_composite (cairo_operator_t op,
}
}
glDrawArrays (GL_TRIANGLE_FAN, 0, 4);
glDrawArrays (GL_QUADS, 0, num_vertices);
glDisable (GL_BLEND);
@ -1410,13 +1455,17 @@ _cairo_gl_surface_composite (cairo_operator_t op,
while ((err = glGetError ()))
fprintf (stderr, "GL error 0x%08x\n", (int) err);
CONTEXT_RELEASE:
_cairo_gl_context_release (ctx);
_cairo_gl_operand_destroy (&setup.src);
if (mask != NULL)
_cairo_gl_operand_destroy (&setup.mask);
return CAIRO_STATUS_SUCCESS;
if (vertices != vertices_stack)
free (vertices);
return status;
}
static cairo_int_status_t
@ -1429,7 +1478,8 @@ _cairo_gl_surface_composite_trapezoids (cairo_operator_t op,
unsigned int width,
unsigned int height,
cairo_trapezoid_t *traps,
int num_traps)
int num_traps,
cairo_region_t *clip_region)
{
cairo_gl_surface_t *dst = abstract_dst;
cairo_surface_pattern_t traps_pattern;
@ -1447,7 +1497,8 @@ _cairo_gl_surface_composite_trapezoids (cairo_operator_t op,
src_x, src_y,
0, 0,
dst_x, dst_y,
width, height);
width, height,
clip_region);
_cairo_pattern_fini (&traps_pattern.base);
@ -1737,6 +1788,7 @@ _cairo_gl_surface_span_renderer_finish (void *abstract_renderer)
glDisable (GL_TEXTURE_2D);
glDisable (GL_BLEND);
glDisable (GL_DEPTH_TEST);
return CAIRO_STATUS_SUCCESS;
}
@ -1756,27 +1808,112 @@ _cairo_gl_surface_check_span_renderer (cairo_operator_t op,
return TRUE;
}
static void
_cairo_gl_surface_ensure_depth_buffer (cairo_gl_surface_t *surface)
{
if (surface->depth_stencil_tex)
return;
glGenTextures (1, &surface->depth_stencil_tex);
glBindTexture (GL_TEXTURE_2D, surface->depth_stencil_tex);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D (GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8_EXT,
surface->width, surface->height, 0,
GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, NULL);
glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT,
GL_DEPTH_ATTACHMENT_EXT,
GL_TEXTURE_2D,
surface->depth_stencil_tex, 0);
glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT,
GL_STENCIL_ATTACHMENT_EXT,
GL_TEXTURE_2D,
surface->depth_stencil_tex, 0);
}
static cairo_status_t
_cairo_gl_surface_set_clip_region (cairo_gl_surface_t *surface,
cairo_region_t *clip_region)
{
GLfloat vertices_stack[CAIRO_STACK_ARRAY_LENGTH(GLfloat)], *vertices;
int num_rectangles, i, n;
if (clip_region == NULL)
return CAIRO_STATUS_SUCCESS;
num_rectangles = cairo_region_num_rectangles (clip_region);
vertices = vertices_stack;
if (num_rectangles * 8 > ARRAY_LENGTH (vertices_stack)) {
vertices = _cairo_malloc_ab (num_rectangles,
4*3*sizeof (vertices[0]));
if (unlikely (vertices == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
for (i = n = 0; i < num_rectangles; i++) {
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (clip_region, i, &rect);
vertices[n++] = rect.x;
vertices[n++] = rect.y;
vertices[n++] = rect.x + rect.width;
vertices[n++] = rect.y;
vertices[n++] = rect.x + rect.width;
vertices[n++] = rect.y + rect.height;
vertices[n++] = rect.x;
vertices[n++] = rect.y +rect. height;
}
_cairo_gl_surface_ensure_depth_buffer (surface);
glDisable (GL_BLEND);
glDepthFunc (GL_ALWAYS);
glEnable (GL_DEPTH_TEST);
glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glDepthMask (GL_TRUE);
glClear (GL_DEPTH_BUFFER_BIT);
glVertexPointer (2, GL_FLOAT, sizeof (GLfloat) * 2, vertices);
glEnableClientState (GL_VERTEX_ARRAY);
glDrawArrays (GL_QUADS, 0, 4 * num_rectangles);
glDisableClientState (GL_VERTEX_ARRAY);
glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDepthFunc (GL_EQUAL);
glDepthMask (GL_FALSE);
if (vertices != vertices_stack)
free (vertices);
return CAIRO_STATUS_SUCCESS;
}
static cairo_span_renderer_t *
_cairo_gl_surface_create_span_renderer (cairo_operator_t op,
const cairo_pattern_t *src,
void *abstract_dst,
cairo_antialias_t antialias,
const cairo_composite_rectangles_t *rects)
const cairo_composite_rectangles_t *rects,
cairo_region_t *clip_region)
{
cairo_gl_surface_t *dst = abstract_dst;
cairo_gl_surface_span_renderer_t *renderer = calloc (1, sizeof (*renderer));
cairo_gl_surface_span_renderer_t *renderer;
cairo_status_t status;
int width = rects->width;
int height = rects->height;
cairo_surface_attributes_t *src_attributes;
GLenum err;
if (renderer == NULL)
return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY);
if (!GLEW_ARB_vertex_buffer_object)
return _cairo_span_renderer_create_in_error (CAIRO_INT_STATUS_UNSUPPORTED);
renderer = calloc (1, sizeof (*renderer));
if (unlikely (renderer == NULL))
return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY);
renderer->base.destroy = _cairo_gl_surface_span_renderer_destroy;
renderer->base.finish = _cairo_gl_surface_span_renderer_finish;
renderer->base.render_row =
@ -1801,6 +1938,12 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t op,
_cairo_gl_set_destination (dst);
status = _cairo_gl_surface_set_clip_region (dst, clip_region);
if (unlikely (status)) {
_cairo_gl_surface_span_renderer_destroy (renderer);
return _cairo_span_renderer_create_in_error (status);
}
src_attributes = &renderer->setup.src.operand.texture.attributes;
status = _cairo_gl_set_operator (dst, op);
@ -1838,7 +1981,7 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t op,
return &renderer->base;
}
static cairo_int_status_t
static cairo_bool_t
_cairo_gl_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
@ -1849,7 +1992,7 @@ _cairo_gl_surface_get_extents (void *abstract_surface,
rectangle->width = surface->width;
rectangle->height = surface->height;
return CAIRO_STATUS_SUCCESS;
return TRUE;
}
static void
@ -1888,20 +2031,21 @@ static const cairo_surface_backend_t _cairo_gl_surface_backend = {
CAIRO_SURFACE_TYPE_GL,
_cairo_gl_surface_create_similar,
_cairo_gl_surface_finish,
_cairo_gl_surface_acquire_source_image,
_cairo_gl_surface_release_source_image,
_cairo_gl_surface_acquire_dest_image,
_cairo_gl_surface_release_dest_image,
_cairo_gl_surface_clone_similar,
_cairo_gl_surface_composite,
_cairo_gl_surface_fill_rectangles,
_cairo_gl_surface_composite_trapezoids,
_cairo_gl_surface_create_span_renderer,
_cairo_gl_surface_check_span_renderer,
NULL, /* copy_page */
NULL, /* show_page */
NULL, /* set_clip_region */
NULL, /* intersect_clip_path */
_cairo_gl_surface_get_extents,
NULL, /* old_show_glyphs */
_cairo_gl_surface_get_font_options,

View file

@ -27,6 +27,7 @@
#include "cairoint.h"
#include "cairo-glitz.h"
#include "cairo-glitz-private.h"
#include "cairo-region-private.h"
typedef struct _cairo_glitz_surface {
cairo_surface_t base;
@ -34,6 +35,7 @@ typedef struct _cairo_glitz_surface {
glitz_surface_t *surface;
glitz_format_t *format;
cairo_region_t *clip_region;
cairo_bool_t has_clip;
glitz_box_t *clip_boxes;
int num_clip_boxes;
@ -50,6 +52,7 @@ _cairo_glitz_surface_finish (void *abstract_surface)
if (surface->clip_boxes)
free (surface->clip_boxes);
cairo_region_destroy (surface->clip_region);
glitz_surface_destroy (surface->surface);
return CAIRO_STATUS_SUCCESS;
@ -106,43 +109,6 @@ _cairo_glitz_surface_create_similar (void *abstract_src,
return crsurface;
}
static cairo_status_t
_cairo_glitz_get_boxes_from_region (cairo_region_t *region,
glitz_box_t **boxes,
int *nboxes)
{
pixman_box32_t *pboxes;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
int n, i;
n = 0;
pboxes = pixman_region32_rectangles (&region->rgn, &n);
if (n == 0) {
*nboxes = 0;
return CAIRO_STATUS_SUCCESS;
}
if (n > *nboxes) {
*boxes = _cairo_malloc_ab (n, sizeof (glitz_box_t));
if (*boxes == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto done;
}
}
for (i = 0; i < n; i++) {
(*boxes)[i].x1 = pboxes[i].x1;
(*boxes)[i].y1 = pboxes[i].y1;
(*boxes)[i].x2 = pboxes[i].x2;
(*boxes)[i].y2 = pboxes[i].y2;
}
*nboxes = n;
done:
return status;
}
static cairo_status_t
_cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface,
cairo_rectangle_int_t *interest,
@ -463,6 +429,8 @@ _is_supported_operator (cairo_operator_t op)
case CAIRO_OPERATOR_ADD:
return TRUE;
default:
ASSERT_NOT_REACHED;
case CAIRO_OPERATOR_SATURATE:
/* nobody likes saturate, expect that it's required to do
* seamless polygons!
@ -485,6 +453,7 @@ _is_supported_operator (cairo_operator_t op)
return FALSE;
}
}
static glitz_operator_t
_glitz_operator (cairo_operator_t op)
{
@ -686,9 +655,9 @@ _cairo_glitz_pattern_acquire_surface (const cairo_pattern_t *pattern,
}
src = (cairo_glitz_surface_t *)
_cairo_surface_create_similar_scratch (&dst->base,
CAIRO_CONTENT_COLOR_ALPHA,
gradient->n_stops, 1);
_cairo_glitz_surface_create_similar (&dst->base,
CAIRO_CONTENT_COLOR_ALPHA,
gradient->n_stops, 1);
if (src->base.status) {
glitz_buffer_destroy (buffer);
free (data);
@ -914,6 +883,77 @@ _cairo_glitz_surface_set_attributes (cairo_glitz_surface_t *surface,
a->params, a->n_params);
}
static cairo_status_t
_cairo_glitz_get_boxes_from_region (cairo_region_t *region,
glitz_box_t **boxes,
int *nboxes)
{
pixman_box32_t *pboxes;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
int n, i;
n = 0;
pboxes = pixman_region32_rectangles (&region->rgn, &n);
if (n == 0) {
*nboxes = 0;
return CAIRO_STATUS_SUCCESS;
}
if (n > *nboxes) {
*boxes = _cairo_malloc_ab (n, sizeof (glitz_box_t));
if (*boxes == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto done;
}
}
for (i = 0; i < n; i++) {
(*boxes)[i].x1 = pboxes[i].x1;
(*boxes)[i].y1 = pboxes[i].y1;
(*boxes)[i].x2 = pboxes[i].x2;
(*boxes)[i].y2 = pboxes[i].y2;
}
*nboxes = n;
done:
return status;
}
static cairo_status_t
_cairo_glitz_surface_set_clip_region (void *abstract_surface,
cairo_region_t *region)
{
cairo_glitz_surface_t *surface = abstract_surface;
if (region == surface->clip_region)
return CAIRO_STATUS_SUCCESS;
cairo_region_destroy (surface->clip_region);
surface->clip_region = cairo_region_reference (region);
if (region != NULL) {
cairo_status_t status;
status = _cairo_glitz_get_boxes_from_region (region,
&surface->clip_boxes,
&surface->num_clip_boxes);
if (status)
return status;
glitz_surface_set_clip_region (surface->surface,
0, 0,
surface->clip_boxes,
surface->num_clip_boxes);
surface->has_clip = TRUE;
} else {
glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0);
surface->has_clip = FALSE;
}
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_glitz_surface_composite (cairo_operator_t op,
const cairo_pattern_t *src_pattern,
@ -926,7 +966,8 @@ _cairo_glitz_surface_composite (cairo_operator_t op,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height)
unsigned int height,
cairo_region_t *clip_region)
{
cairo_glitz_surface_attributes_t src_attr, mask_attr;
cairo_glitz_surface_t *dst = abstract_dst;
@ -940,6 +981,10 @@ _cairo_glitz_surface_composite (cairo_operator_t op,
if (_glitz_ensure_target (dst->surface))
return CAIRO_INT_STATUS_UNSUPPORTED;
status = _cairo_glitz_surface_set_clip_region (dst, clip_region);
if (status)
return status;
status = _cairo_glitz_pattern_acquire_surfaces (src_pattern, mask_pattern,
dst,
src_x, src_y,
@ -1006,7 +1051,8 @@ _cairo_glitz_surface_composite (cairo_operator_t op,
mask_width, mask_height,
src_x, src_y,
mask_x, mask_y,
dst_x, dst_y, width, height);
dst_x, dst_y, width, height,
clip_region);
}
if (mask)
@ -1037,11 +1083,15 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst,
glitz_rectangle_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (glitz_rectangle_t)];
glitz_rectangle_t *glitz_rects = stack_rects;
glitz_rectangle_t *current_rect;
cairo_status_t status;
int i;
if (! _is_supported_operator (op))
return CAIRO_INT_STATUS_UNSUPPORTED;
status = _cairo_glitz_surface_set_clip_region (dst, NULL);
assert (status == CAIRO_STATUS_SUCCESS);
if (n_rects > ARRAY_LENGTH (stack_rects)) {
glitz_rects = _cairo_malloc_ab (n_rects, sizeof (glitz_rectangle_t));
if (glitz_rects == NULL)
@ -1104,12 +1154,12 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst,
_cairo_surface_create_similar_solid (&dst->base,
CAIRO_CONTENT_COLOR_ALPHA,
1, 1,
(cairo_color_t *) color);
if (src->base.status)
{
(cairo_color_t *) color,
FALSE);
if (src == NULL || src->base.status) {
if (glitz_rects != stack_rects)
free (glitz_rects);
return src->base.status;
return src ? src->base.status : CAIRO_INT_STATUS_UNSUPPORTED;
}
glitz_surface_set_fill (src->surface, GLITZ_FILL_REPEAT);
@ -1153,7 +1203,8 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
unsigned int width,
unsigned int height,
cairo_trapezoid_t *traps,
int n_traps)
int n_traps,
cairo_region_t *clip_region)
{
cairo_glitz_surface_attributes_t attributes;
cairo_glitz_surface_t *dst = abstract_dst;
@ -1179,6 +1230,10 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
if (_glitz_ensure_target (dst->surface))
return CAIRO_INT_STATUS_UNSUPPORTED;
status = _cairo_glitz_surface_set_clip_region (dst, clip_region);
if (unlikely (status))
return status;
/* Convert traps to pixman traps */
if (n_traps > ARRAY_LENGTH (stack_traps)) {
pixman_traps = _cairo_malloc_ab (n_traps, sizeof (pixman_trapezoid_t));
@ -1321,7 +1376,7 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
n_traps, (pixman_trapezoid_t *) pixman_traps);
mask = (cairo_glitz_surface_t *)
_cairo_surface_create_similar_scratch (&dst->base,
_cairo_glitz_surface_create_similar (&dst->base,
CAIRO_CONTENT_ALPHA,
width, height);
status = mask->base.status;
@ -1378,7 +1433,8 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
src_x, src_y,
0, 0,
dst_x, dst_y,
width, height);
width, height,
clip_region);
}
FAIL:
@ -1393,35 +1449,7 @@ FAIL:
return status;
}
static cairo_int_status_t
_cairo_glitz_surface_set_clip_region (void *abstract_surface,
cairo_region_t *region)
{
cairo_glitz_surface_t *surface = abstract_surface;
if (region != NULL) {
cairo_status_t status;
status = _cairo_glitz_get_boxes_from_region (region,
&surface->clip_boxes,
&surface->num_clip_boxes);
if (status)
return status;
glitz_surface_set_clip_region (surface->surface,
0, 0,
surface->clip_boxes,
surface->num_clip_boxes);
surface->has_clip = TRUE;
} else {
glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0);
surface->has_clip = FALSE;
}
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
static cairo_bool_t
_cairo_glitz_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
@ -1432,7 +1460,7 @@ _cairo_glitz_surface_get_extents (void *abstract_surface,
rectangle->width = glitz_surface_get_width (surface->surface);
rectangle->height = glitz_surface_get_height (surface->surface);
return CAIRO_STATUS_SUCCESS;
return TRUE;
}
#define CAIRO_GLITZ_AREA_AVAILABLE 0
@ -2035,7 +2063,8 @@ _cairo_glitz_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font,
unsigned int width,
unsigned int height,
cairo_glyph_t *glyphs,
int num_glyphs)
int num_glyphs,
cairo_region_t *clip_region)
{
cairo_glitz_surface_attributes_t attributes;
cairo_glitz_surface_glyph_private_t *glyph_private;
@ -2078,6 +2107,10 @@ _cairo_glitz_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font,
if (_glitz_ensure_target (dst->surface))
return CAIRO_INT_STATUS_UNSUPPORTED;
status = _cairo_glitz_surface_set_clip_region (dst, NULL);
if (unlikely (status))
return status;
status = _cairo_glitz_pattern_acquire_surface (pattern, dst,
src_x, src_y,
width, height,
@ -2326,25 +2359,13 @@ _cairo_glitz_surface_is_similar (void *surface_a,
return drawable_a == drawable_b;
}
static cairo_status_t
_cairo_glitz_surface_reset (void *abstract_surface)
{
cairo_glitz_surface_t *surface = abstract_surface;
cairo_status_t status;
status = _cairo_glitz_surface_set_clip_region (surface, NULL);
if (status)
return status;
return CAIRO_STATUS_SUCCESS;
}
static const cairo_surface_backend_t cairo_glitz_surface_backend = {
CAIRO_SURFACE_TYPE_GLITZ,
_cairo_glitz_surface_create_similar,
_cairo_glitz_surface_finish,
_cairo_glitz_surface_acquire_source_image,
_cairo_glitz_surface_release_source_image,
_cairo_glitz_surface_acquire_dest_image,
_cairo_glitz_surface_release_dest_image,
_cairo_glitz_surface_clone_similar,
@ -2353,10 +2374,9 @@ static const cairo_surface_backend_t cairo_glitz_surface_backend = {
_cairo_glitz_surface_composite_trapezoids,
NULL, /* create_span_renderer */
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
_cairo_glitz_surface_set_clip_region,
NULL, /* intersect_clip_path */
_cairo_glitz_surface_get_extents,
_cairo_glitz_surface_old_show_glyphs,
NULL, /* get_font_options */
@ -2373,8 +2393,6 @@ static const cairo_surface_backend_t cairo_glitz_surface_backend = {
_cairo_glitz_surface_snapshot,
_cairo_glitz_surface_is_similar,
_cairo_glitz_surface_reset
};
static const cairo_surface_backend_t *
@ -2424,6 +2442,7 @@ cairo_glitz_surface_create (glitz_surface_t *surface)
crsurface->has_clip = FALSE;
crsurface->clip_boxes = NULL;
crsurface->num_clip_boxes = 0;
crsurface->clip_region = NULL;
return &crsurface->base;
}

View file

@ -100,7 +100,7 @@ _cairo_gstate_init (cairo_gstate_t *gstate,
_cairo_font_options_init_default (&gstate->font_options);
_cairo_clip_init (&gstate->clip, target);
_cairo_clip_init (&gstate->clip);
gstate->target = cairo_surface_reference (target);
gstate->parent_target = NULL;
@ -164,14 +164,7 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
_cairo_font_options_init_copy (&gstate->font_options , &other->font_options);
status = _cairo_clip_init_copy (&gstate->clip, &other->clip);
if (unlikely (status)) {
_cairo_stroke_style_fini (&gstate->stroke_style);
cairo_font_face_destroy (gstate->font_face);
cairo_scaled_font_destroy (gstate->scaled_font);
cairo_scaled_font_destroy (gstate->previous_scaled_font);
return status;
}
_cairo_clip_init_copy (&gstate->clip, &other->clip);
gstate->target = cairo_surface_reference (other->target);
/* parent_target is always set to NULL; it's only ever set by redirect_target */
@ -299,7 +292,7 @@ _cairo_gstate_restore (cairo_gstate_t **gstate, cairo_gstate_t **freelist)
cairo_status_t
_cairo_gstate_redirect_target (cairo_gstate_t *gstate, cairo_surface_t *child)
{
cairo_status_t status;
cairo_matrix_t matrix;
/* If this gstate is already redirected, this is an error; we need a
* new gstate to be able to redirect */
@ -315,18 +308,15 @@ _cairo_gstate_redirect_target (cairo_gstate_t *gstate, cairo_surface_t *child)
* since its ref is now owned by gstate->parent_target */
gstate->target = cairo_surface_reference (child);
_cairo_clip_reset (&gstate->clip);
status = _cairo_clip_init_deep_copy (&gstate->clip, &gstate->next->clip, child);
if (unlikely (status))
return status;
/* The clip is in surface backend coordinates for the previous target;
* translate it into the child's backend coordinates. */
_cairo_clip_translate (&gstate->clip,
_cairo_fixed_from_double (child->device_transform.x0 - gstate->parent_target->device_transform.x0),
_cairo_fixed_from_double (child->device_transform.y0 - gstate->parent_target->device_transform.y0));
return CAIRO_STATUS_SUCCESS;
cairo_matrix_init_translate (&matrix,
child->device_transform.x0 - gstate->parent_target->device_transform.x0,
child->device_transform.y0 - gstate->parent_target->device_transform.y0);
_cairo_clip_reset (&gstate->clip);
return _cairo_clip_init_copy_transformed (&gstate->clip,
&gstate->next->clip,
&matrix);
}
/**
@ -870,43 +860,63 @@ _cairo_gstate_copy_transformed_mask (cairo_gstate_t *gstate,
&gstate->ctm_inverse);
}
#define _gstate_get_clip(g) ((g)->clip.path ? &(g)->clip : NULL)
static cairo_bool_t
_clipped (const cairo_gstate_t *gstate)
{
cairo_rectangle_int_t extents;
if (gstate->clip.all_clipped)
return TRUE;
if (gstate->clip.path == NULL)
return FALSE;
if (_cairo_surface_get_extents (gstate->target, &extents)) {
if (! _cairo_rectangle_intersect (&extents,
&gstate->clip.path->extents))
{
return TRUE;
}
}
return FALSE;
}
cairo_status_t
_cairo_gstate_paint (cairo_gstate_t *gstate)
{
cairo_status_t status;
cairo_pattern_union_t pattern;
if (gstate->source->status)
if (unlikely (gstate->source->status))
return gstate->source->status;
status = _cairo_surface_set_clip (gstate->target, &gstate->clip);
if (unlikely (status))
return status;
if (_clipped (gstate))
return CAIRO_STATUS_SUCCESS;
_cairo_gstate_copy_transformed_source (gstate, &pattern.base);
return _cairo_surface_paint (gstate->target,
gstate->op,
&pattern.base,
NULL);
_gstate_get_clip (gstate));
}
cairo_status_t
_cairo_gstate_mask (cairo_gstate_t *gstate,
cairo_pattern_t *mask)
{
cairo_status_t status;
cairo_pattern_union_t source_pattern, mask_pattern;
if (mask->status)
if (unlikely (mask->status))
return mask->status;
if (gstate->source->status)
if (unlikely (gstate->source->status))
return gstate->source->status;
status = _cairo_surface_set_clip (gstate->target, &gstate->clip);
if (unlikely (status))
return status;
if (_clipped (gstate))
return CAIRO_STATUS_SUCCESS;
_cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
_cairo_gstate_copy_transformed_mask (gstate, &mask_pattern.base, mask);
@ -915,24 +925,22 @@ _cairo_gstate_mask (cairo_gstate_t *gstate,
gstate->op,
&source_pattern.base,
&mask_pattern.base,
NULL);
_gstate_get_clip (gstate));
}
cairo_status_t
_cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
{
cairo_status_t status;
cairo_pattern_union_t source_pattern;
if (gstate->source->status)
if (unlikely (gstate->source->status))
return gstate->source->status;
if (gstate->stroke_style.line_width <= 0.0)
return CAIRO_STATUS_SUCCESS;
status = _cairo_surface_set_clip (gstate->target, &gstate->clip);
if (unlikely (status))
return status;
if (_clipped (gstate))
return CAIRO_STATUS_SUCCESS;
_cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
@ -945,7 +953,7 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
&gstate->ctm_inverse,
gstate->tolerance,
gstate->antialias,
NULL);
_gstate_get_clip (gstate));
}
cairo_status_t
@ -1009,15 +1017,26 @@ BAIL:
cairo_status_t
_cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
{
cairo_status_t status;
cairo_pattern_union_t pattern;
if (gstate->source->status)
if (unlikely (gstate->source->status))
return gstate->source->status;
status = _cairo_surface_set_clip (gstate->target, &gstate->clip);
if (unlikely (status))
return status;
if (_clipped (gstate))
return CAIRO_STATUS_SUCCESS;
if (_cairo_path_fixed_fill_is_empty (path)) {
if (_cairo_operator_bounded_by_mask (gstate->op))
return CAIRO_STATUS_SUCCESS;
_cairo_pattern_init_solid (&pattern.solid,
CAIRO_COLOR_TRANSPARENT,
CAIRO_CONTENT_COLOR_ALPHA);
return _cairo_surface_paint (gstate->target,
CAIRO_OPERATOR_CLEAR,
&pattern.base,
_gstate_get_clip (gstate));
}
_cairo_gstate_copy_transformed_source (gstate, &pattern.base);
@ -1028,23 +1047,56 @@ _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
gstate->fill_rule,
gstate->tolerance,
gstate->antialias,
NULL);
_gstate_get_clip (gstate));
}
void
cairo_bool_t
_cairo_gstate_in_fill (cairo_gstate_t *gstate,
cairo_path_fixed_t *path,
double x,
double y,
cairo_bool_t *inside_ret)
double y)
{
_cairo_gstate_user_to_backend (gstate, &x, &y);
_cairo_path_fixed_in_fill (path,
gstate->fill_rule,
gstate->tolerance,
x, y,
inside_ret);
return _cairo_path_fixed_in_fill (path,
gstate->fill_rule,
gstate->tolerance,
x, y);
}
cairo_bool_t
_cairo_gstate_in_clip (cairo_gstate_t *gstate,
double x,
double y)
{
cairo_clip_path_t *clip_path;
if (gstate->clip.all_clipped)
return FALSE;
clip_path = gstate->clip.path;
if (clip_path == NULL)
return TRUE;
_cairo_gstate_user_to_backend (gstate, &x, &y);
if (x < clip_path->extents.x ||
x >= clip_path->extents.x + clip_path->extents.width ||
y < clip_path->extents.y ||
y >= clip_path->extents.y + clip_path->extents.height)
{
return FALSE;
}
do {
if (! _cairo_path_fixed_in_fill (&clip_path->path,
clip_path->fill_rule,
clip_path->tolerance,
x, y))
return FALSE;
} while ((clip_path = clip_path->prev) != NULL);
return TRUE;
}
cairo_status_t
@ -1179,26 +1231,31 @@ cairo_status_t
_cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
{
return _cairo_clip_clip (&gstate->clip,
path, gstate->fill_rule, gstate->tolerance,
gstate->antialias, gstate->target);
path, gstate->fill_rule,
gstate->tolerance, gstate->antialias);
}
static cairo_status_t
static cairo_bool_t
_cairo_gstate_int_clip_extents (cairo_gstate_t *gstate,
cairo_rectangle_int_t *extents)
{
cairo_status_t status;
const cairo_rectangle_int_t *clip_extents;
cairo_bool_t is_bounded;
status = _cairo_surface_get_extents (gstate->target, extents);
if (unlikely (status))
return status;
is_bounded = _cairo_surface_get_extents (gstate->target, extents);
status = _cairo_clip_intersect_to_rectangle (&gstate->clip, extents);
clip_extents = _cairo_clip_get_extents (&gstate->clip);
if (clip_extents != NULL) {
cairo_bool_t is_empty;
return status;
is_empty = _cairo_rectangle_intersect (extents, clip_extents);
is_bounded = TRUE;
}
return is_bounded;
}
cairo_status_t
cairo_bool_t
_cairo_gstate_clip_extents (cairo_gstate_t *gstate,
double *x1,
double *y1,
@ -1207,11 +1264,9 @@ _cairo_gstate_clip_extents (cairo_gstate_t *gstate,
{
cairo_rectangle_int_t extents;
double px1, py1, px2, py2;
cairo_status_t status;
status = _cairo_gstate_int_clip_extents (gstate, &extents);
if (unlikely (status))
return status;
if (! _cairo_gstate_int_clip_extents (gstate, &extents))
return FALSE;
px1 = extents.x;
py1 = extents.y;
@ -1231,7 +1286,7 @@ _cairo_gstate_clip_extents (cairo_gstate_t *gstate,
if (y2)
*y2 = py2;
return CAIRO_STATUS_SUCCESS;
return TRUE;
}
cairo_rectangle_list_t*
@ -1576,12 +1631,11 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
cairo_text_cluster_t *transformed_clusters;
cairo_status_t status;
if (gstate->source->status)
if (unlikely (gstate->source->status))
return gstate->source->status;
status = _cairo_surface_set_clip (gstate->target, &gstate->clip);
if (unlikely (status))
return status;
if (_clipped (gstate))
return CAIRO_STATUS_SUCCESS;
status = _cairo_gstate_ensure_scaled_font (gstate);
if (unlikely (status))
@ -1635,7 +1689,8 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
*
* Needless to say, do this only if show_text_glyphs is not available. */
if (cairo_surface_has_show_text_glyphs (gstate->target) ||
_cairo_scaled_font_get_max_scale (gstate->scaled_font) <= 10240) {
_cairo_scaled_font_get_max_scale (gstate->scaled_font) <= 10240)
{
status = _cairo_surface_show_text_glyphs (gstate->target,
gstate->op,
&source_pattern.base,
@ -1643,8 +1698,11 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
transformed_glyphs, num_glyphs,
transformed_clusters, num_clusters,
cluster_flags,
gstate->scaled_font, NULL);
} else {
gstate->scaled_font,
_gstate_get_clip (gstate));
}
else
{
cairo_path_fixed_t path;
_cairo_path_fixed_init (&path);
@ -1653,14 +1711,16 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
transformed_glyphs, num_glyphs,
&path);
if (status == CAIRO_STATUS_SUCCESS)
status = _cairo_surface_fill (gstate->target,
gstate->op,
&source_pattern.base,
&path,
CAIRO_FILL_RULE_WINDING,
gstate->tolerance,
gstate->scaled_font->options.antialias, NULL);
if (status == CAIRO_STATUS_SUCCESS) {
status = _cairo_surface_fill (gstate->target,
gstate->op,
&source_pattern.base,
&path,
CAIRO_FILL_RULE_WINDING,
gstate->tolerance,
gstate->scaled_font->options.antialias,
_gstate_get_clip (gstate));
}
_cairo_path_fixed_fini (&path);
}
@ -1765,17 +1825,12 @@ _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate,
cairo_matrix_t *device_transform = &gstate->target->device_transform;
cairo_bool_t drop = FALSE;
double x1 = 0, x2 = 0, y1 = 0, y2 = 0;
cairo_status_t status;
if (num_transformed_glyphs != NULL) {
cairo_rectangle_int_t surface_extents;
drop = TRUE;
status = _cairo_gstate_int_clip_extents (gstate, &surface_extents);
if (_cairo_status_is_error (status))
return status;
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
if (! _cairo_gstate_int_clip_extents (gstate, &surface_extents)) {
drop = FALSE; /* unbounded surface */
} else {
double scale10 = 10 * _cairo_scaled_font_get_max_scale (gstate->scaled_font);

View file

@ -37,6 +37,9 @@
#include "cairoint.h"
#include "cairo-clip-private.h"
#include "cairo-region-private.h"
static cairo_format_t
_cairo_format_from_pixman_format (pixman_format_code_t pixman_format)
{
@ -63,6 +66,14 @@ _cairo_format_from_pixman_format (pixman_format_code_t pixman_format)
#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,11,9)
case PIXMAN_x2b10g10r10:
case PIXMAN_a2b10g10r10:
#endif
#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,14,1)
case PIXMAN_b8g8r8x8:
case PIXMAN_b8g8r8a8:
#endif
#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,15,16)
case PIXMAN_x2r10g10b10:
case PIXMAN_a2r10g10b10:
#endif
default:
return CAIRO_FORMAT_INVALID;
@ -87,6 +98,12 @@ _cairo_content_from_pixman_format (pixman_format_code_t pixman_format)
case PIXMAN_a1b1g1r1:
#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,11,9)
case PIXMAN_a2b10g10r10:
#endif
#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,14,1)
case PIXMAN_b8g8r8a8:
#endif
#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,15,16)
case PIXMAN_a2r10g10b10:
#endif
return CAIRO_CONTENT_COLOR_ALPHA;
case PIXMAN_x8r8g8b8:
@ -112,6 +129,12 @@ _cairo_content_from_pixman_format (pixman_format_code_t pixman_format)
case PIXMAN_yv12:
#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,11,9)
case PIXMAN_x2b10g10r10:
#endif
#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,14,1)
case PIXMAN_b8g8r8x8:
#endif
#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,15,16)
case PIXMAN_x2r10g10b10:
#endif
return CAIRO_CONTENT_COLOR;
case PIXMAN_a8:
@ -143,7 +166,6 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image,
surface->format = _cairo_format_from_pixman_format (pixman_format);
surface->data = (unsigned char *) pixman_image_get_data (pixman_image);
surface->owns_data = FALSE;
surface->has_clip = FALSE;
surface->transparency = CAIRO_IMAGE_UNKNOWN;
surface->width = pixman_image_get_width (pixman_image);
@ -151,6 +173,8 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image,
surface->stride = pixman_image_get_stride (pixman_image);
surface->depth = pixman_image_get_depth (pixman_image);
surface->clip_region = NULL;
return &surface->base;
}
@ -725,6 +749,8 @@ _cairo_image_surface_finish (void *abstract_surface)
surface->data = NULL;
}
cairo_region_destroy (surface->clip_region);
return CAIRO_STATUS_SUCCESS;
}
@ -974,25 +1000,52 @@ _pixman_operator (cairo_operator_t op)
}
}
static cairo_status_t
_cairo_image_surface_set_clip_region (cairo_image_surface_t *surface,
cairo_region_t *region)
{
if (region == surface->clip_region)
return CAIRO_STATUS_SUCCESS;
if (cairo_region_equal (surface->clip_region, region))
return CAIRO_STATUS_SUCCESS;
cairo_region_destroy (surface->clip_region);
surface->clip_region = cairo_region_reference (region);
if (! pixman_image_set_clip_region32 (surface->pixman_image,
region ? &region->rgn : NULL))
{
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_image_surface_composite (cairo_operator_t op,
_cairo_image_surface_composite (cairo_operator_t op,
const cairo_pattern_t *src_pattern,
const cairo_pattern_t *mask_pattern,
void *abstract_dst,
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height)
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height,
cairo_region_t *clip_region)
{
cairo_surface_attributes_t src_attr, mask_attr;
cairo_surface_attributes_t src_attr, mask_attr;
cairo_image_surface_t *dst = abstract_dst;
cairo_image_surface_t *src;
cairo_image_surface_t *mask;
cairo_int_status_t status;
cairo_int_status_t status;
status = _cairo_image_surface_set_clip_region (dst, clip_region);
if (unlikely (status))
return status;
status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
&dst->base,
@ -1013,8 +1066,7 @@ _cairo_image_surface_composite (cairo_operator_t op,
if (unlikely (status))
goto CLEANUP_SURFACES;
if (mask)
{
if (mask) {
status = _cairo_image_surface_set_attributes (mask, &mask_attr,
dst_x + width / 2.,
dst_y + height / 2.);
@ -1031,9 +1083,7 @@ _cairo_image_surface_composite (cairo_operator_t op,
mask_y + mask_attr.y_offset,
dst_x, dst_y,
width, height);
}
else
{
} else {
pixman_image_composite (_pixman_operator (op),
src->pixman_image,
NULL,
@ -1045,7 +1095,7 @@ _cairo_image_surface_composite (cairo_operator_t op,
width, height);
}
if (! _cairo_operator_bounded_by_source (op))
if (! _cairo_operator_bounded_by_source (op)) {
status = _cairo_surface_composite_fixup_unbounded (&dst->base,
&src_attr, src->width, src->height,
mask ? &mask_attr : NULL,
@ -1053,7 +1103,9 @@ _cairo_image_surface_composite (cairo_operator_t op,
mask ? mask->height : 0,
src_x, src_y,
mask_x, mask_y,
dst_x, dst_y, width, height);
dst_x, dst_y, width, height,
clip_region);
}
CLEANUP_SURFACES:
if (mask)
@ -1078,7 +1130,7 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface,
pixman_rectangle16_t *pixman_rects = stack_rects;
int i;
cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
cairo_int_status_t status;
if (CAIRO_INJECT_FAULT ())
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
@ -1088,6 +1140,9 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface,
pixman_color.blue = color->blue_short;
pixman_color.alpha = color->alpha_short;
status = _cairo_image_surface_set_clip_region (surface, NULL);
assert (status == CAIRO_STATUS_SUCCESS);
if (num_rects > ARRAY_LENGTH (stack_rects)) {
pixman_rects = _cairo_malloc_ab (num_rects, sizeof (pixman_rectangle16_t));
if (unlikely (pixman_rects == NULL))
@ -1101,7 +1156,8 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface,
pixman_rects[i].height = rects[i].height;
}
/* XXX: pixman_fill_rectangles() should be implemented */
/* XXX: pixman_fill_region() should be implemented */
status = CAIRO_STATUS_SUCCESS;
if (! pixman_image_fill_rectangles (_pixman_operator (op),
surface->pixman_image,
&pixman_color,
@ -1165,7 +1221,8 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t op,
unsigned int width,
unsigned int height,
cairo_trapezoid_t *traps,
int num_traps)
int num_traps,
cairo_region_t *clip_region)
{
cairo_surface_attributes_t attributes;
cairo_image_surface_t *dst = abstract_dst;
@ -1186,22 +1243,26 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t op,
* contained within the surface is bounded by [dst_x,dst_y,width,height];
* the Cairo core code passes bounds based on the trapezoid extents.
*
* Currently the check surface->has_clip is needed for correct
* Currently the check clip_region == NULL is needed for correct
* functioning, since pixman_add_trapezoids() doesn't obey the
* surface clip, which is a libpixman bug , but there's no harm in
* falling through to the general case when the surface is clipped
* since libpixman would have to generate an intermediate mask anyways.
*/
if (op == CAIRO_OPERATOR_ADD &&
clip_region == NULL &&
_cairo_pattern_is_opaque_solid (pattern) &&
dst->base.content == CAIRO_CONTENT_ALPHA &&
! dst->has_clip &&
antialias != CAIRO_ANTIALIAS_NONE)
{
_pixman_add_trapezoids (dst->pixman_image, 0, 0, traps, num_traps);
return CAIRO_STATUS_SUCCESS;
}
status = _cairo_image_surface_set_clip_region (dst, clip_region);
if (unlikely (status))
return status;
status = _cairo_pattern_acquire_surface (pattern, &dst->base,
CAIRO_CONTENT_COLOR_ALPHA,
src_x, src_y, width, height,
@ -1238,14 +1299,16 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t op,
pixman_image_unref (mask);
if (! _cairo_operator_bounded_by_mask (op))
if (! _cairo_operator_bounded_by_mask (op)) {
status = _cairo_surface_composite_shape_fixup_unbounded (&dst->base,
&attributes,
src->width, src->height,
width, height,
src_x, src_y,
0, 0,
dst_x, dst_y, width, height);
dst_x, dst_y, width, height,
clip_region);
}
CLEANUP_SOURCE:
_cairo_pattern_release_surface (pattern, &src->base, &attributes);
@ -1382,7 +1445,7 @@ _cairo_image_surface_span_renderer_finish (void *abstract_renderer)
rects->dst.x, rects->dst.y,
width, height);
if (! _cairo_operator_bounded_by_mask (renderer->op))
if (! _cairo_operator_bounded_by_mask (renderer->op)) {
status = _cairo_surface_composite_shape_fixup_unbounded (
&dst->base,
src_attributes,
@ -1391,7 +1454,9 @@ _cairo_image_surface_span_renderer_finish (void *abstract_renderer)
rects->src.x, rects->src.y,
0, 0, /* mask.x, mask.y */
rects->dst.x, rects->dst.y,
rects->width, rects->height);
rects->width, rects->height,
dst->clip_region);
}
}
if (status != CAIRO_STATUS_SUCCESS)
return _cairo_span_renderer_set_error (abstract_renderer,
@ -1406,12 +1471,12 @@ _cairo_image_surface_check_span_renderer (cairo_operator_t op,
cairo_antialias_t antialias,
const cairo_composite_rectangles_t *rects)
{
return TRUE;
(void) op;
(void) pattern;
(void) abstract_dst;
(void) antialias;
(void) rects;
return TRUE;
}
static cairo_span_renderer_t *
@ -1419,22 +1484,25 @@ _cairo_image_surface_create_span_renderer (cairo_operator_t op,
const cairo_pattern_t *pattern,
void *abstract_dst,
cairo_antialias_t antialias,
const cairo_composite_rectangles_t *rects)
const cairo_composite_rectangles_t *rects,
cairo_region_t *clip_region)
{
cairo_image_surface_t *dst = abstract_dst;
cairo_image_surface_span_renderer_t *renderer
= calloc(1, sizeof(*renderer));
cairo_image_surface_span_renderer_t *renderer = calloc(1, sizeof(*renderer));
cairo_status_t status;
int width = rects->width;
int height = rects->height;
status = _cairo_image_surface_set_clip_region (dst, clip_region);
if (unlikely (status))
return _cairo_span_renderer_create_in_error (status);
if (renderer == NULL)
return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY);
renderer->base.destroy = _cairo_image_surface_span_renderer_destroy;
renderer->base.finish = _cairo_image_surface_span_renderer_finish;
renderer->base.render_row =
_cairo_image_surface_span_renderer_render_row;
renderer->base.render_row = _cairo_image_surface_span_renderer_render_row;
renderer->op = op;
renderer->pattern = pattern;
renderer->antialias = antialias;
@ -1475,21 +1543,7 @@ _cairo_image_surface_create_span_renderer (cairo_operator_t op,
return &renderer->base;
}
cairo_int_status_t
_cairo_image_surface_set_clip_region (void *abstract_surface,
cairo_region_t *region)
{
cairo_image_surface_t *surface = (cairo_image_surface_t *) abstract_surface;
if (! pixman_image_set_clip_region32 (surface->pixman_image, region? &region->rgn : NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
surface->has_clip = region != NULL;
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
static cairo_bool_t
_cairo_image_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
@ -1500,7 +1554,7 @@ _cairo_image_surface_get_extents (void *abstract_surface,
rectangle->width = surface->width;
rectangle->height = surface->height;
return CAIRO_STATUS_SUCCESS;
return TRUE;
}
static void
@ -1512,18 +1566,6 @@ _cairo_image_surface_get_font_options (void *abstract_surface,
cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON);
}
static cairo_status_t
_cairo_image_surface_reset (void *abstract_surface)
{
cairo_image_surface_t *surface = abstract_surface;
cairo_status_t status;
status = _cairo_image_surface_set_clip_region (surface, NULL);
assert (status == CAIRO_STATUS_SUCCESS);
return CAIRO_STATUS_SUCCESS;
}
/**
* _cairo_surface_is_image:
* @surface: a #cairo_surface_t
@ -1554,8 +1596,6 @@ const cairo_surface_backend_t _cairo_image_surface_backend = {
_cairo_image_surface_check_span_renderer,
NULL, /* copy_page */
NULL, /* show_page */
_cairo_image_surface_set_clip_region,
NULL, /* intersect_clip_path */
_cairo_image_surface_get_extents,
NULL, /* old_show_glyphs */
_cairo_image_surface_get_font_options,
@ -1571,8 +1611,6 @@ const cairo_surface_backend_t _cairo_image_surface_backend = {
NULL, /* show_glyphs */
NULL, /* snapshot */
NULL, /* is_similar */
_cairo_image_surface_reset
};
/* A convenience function for when one needs to coerce an image
@ -1600,7 +1638,8 @@ _cairo_image_surface_coerce (cairo_image_surface_t *surface,
_cairo_pattern_init_for_surface (&pattern, &surface->base);
status = _cairo_surface_paint (&clone->base,
CAIRO_OPERATOR_SOURCE,
&pattern.base, NULL);
&pattern.base,
NULL);
_cairo_pattern_fini (&pattern.base);
if (unlikely (status)) {

View file

@ -39,6 +39,7 @@
#include "cairoint.h"
#include "cairo-path-fixed-private.h"
#include "cairo-clip-private.h"
typedef enum {
/* The 5 basic drawing operations. */
@ -47,15 +48,6 @@ typedef enum {
CAIRO_COMMAND_STROKE,
CAIRO_COMMAND_FILL,
CAIRO_COMMAND_SHOW_TEXT_GLYPHS,
/* Other junk. For most of these, we should be able to assert that
* they never get called except as part of fallbacks for the 5
* basic drawing operations (which we implement already so the
* fallbacks should never get triggered). So the plan is to
* eliminate as many of these as possible. */
CAIRO_COMMAND_INTERSECT_CLIP_PATH
} cairo_command_type_t;
typedef enum {
@ -67,25 +59,23 @@ typedef enum {
typedef struct _cairo_command_header {
cairo_command_type_t type;
cairo_meta_region_type_t region;
cairo_rectangle_int_t extents;
cairo_operator_t op;
cairo_clip_t clip;
} 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_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_header_t header;
cairo_operator_t op;
cairo_pattern_union_t source;
cairo_path_fixed_t path;
cairo_stroke_style_t style;
@ -97,7 +87,6 @@ typedef struct _cairo_command_stroke {
typedef struct _cairo_command_fill {
cairo_command_header_t header;
cairo_operator_t op;
cairo_pattern_union_t source;
cairo_path_fixed_t path;
cairo_fill_rule_t fill_rule;
@ -107,7 +96,6 @@ typedef struct _cairo_command_fill {
typedef struct _cairo_command_show_text_glyphs {
cairo_command_header_t header;
cairo_operator_t op;
cairo_pattern_union_t source;
char *utf8;
int utf8_len;
@ -119,27 +107,14 @@ typedef struct _cairo_command_show_text_glyphs {
cairo_scaled_font_t *scaled_font;
} cairo_command_show_text_glyphs_t;
typedef struct _cairo_command_intersect_clip_path {
cairo_command_header_t header;
cairo_path_fixed_t *path_pointer;
cairo_path_fixed_t path;
cairo_fill_rule_t fill_rule;
double tolerance;
cairo_antialias_t antialias;
} cairo_command_intersect_clip_path_t;
typedef union _cairo_command {
cairo_command_header_t header;
/* The 5 basic drawing operations. */
cairo_command_paint_t paint;
cairo_command_mask_t mask;
cairo_command_stroke_t stroke;
cairo_command_fill_t fill;
cairo_command_show_text_glyphs_t show_text_glyphs;
/* The other junk. */
cairo_command_intersect_clip_path_t intersect_clip_path;
} cairo_command_t;
typedef struct _cairo_meta_surface {
@ -150,14 +125,15 @@ typedef struct _cairo_meta_surface {
/* A meta-surface is logically unbounded, but when used as a
* source we need to render it to an image, so we need a size at
* which to create that image. */
double width_pixels;
double height_pixels;
cairo_rectangle_t extents_pixels;
cairo_rectangle_int_t extents;
cairo_bool_t unbounded;
cairo_clip_t clip;
cairo_array_t commands;
cairo_surface_t *commands_owner;
cairo_bool_t is_clipped;
int replay_start_idx;
} cairo_meta_surface_t;
@ -181,6 +157,11 @@ _cairo_meta_surface_replay_region (cairo_surface_t *surface,
cairo_surface_t *target,
cairo_meta_region_type_t region);
cairo_private cairo_status_t
_cairo_meta_surface_get_bbox (cairo_meta_surface_t *meta,
cairo_box_t *bbox,
const cairo_matrix_t *transform);
cairo_private cairo_bool_t
_cairo_surface_is_meta (const cairo_surface_t *surface);

View file

@ -50,6 +50,12 @@
* that would have been obtained if the original operations applied to
* the meta surface had instead been applied to the target surface.
*
* A meta surface is logically unbounded, i.e. it has no implicit constraint
* on the size of the drawing surface. However, in practice this is rarely
* useful as you wish to replay against a particular target surface with
* known bounds. For this case, it is more efficient to specify the target
* extents to the meta surface upon creation.
*
* The recording phase of the meta surface is careful to snapshot all
* necessary objects (paths, patterns, etc.), in order to achieve
* accurate replay. The efficiency of the meta surface could be
@ -58,10 +64,13 @@
* copy-on-write implementation for _cairo_surface_snapshot.
*/
/* XXX Rename to recording surface */
#include "cairoint.h"
#include "cairo-analysis-surface-private.h"
#include "cairo-meta-surface-private.h"
#include "cairo-clip-private.h"
#include "cairo-surface-wrapper-private.h"
typedef enum {
CAIRO_META_REPLAY,
@ -82,8 +91,8 @@ static const cairo_surface_backend_t cairo_meta_surface_backend;
/**
* cairo_meta_surface_create:
* @content: the content of the meta surface
* @width_pixels: width of the surface, in pixels
* @height_pixels: height of the surface, in pixels
* @extents_pixels: the extents to record in pixels, can be %NULL to record
* unbounded operations.
*
* Creates a meta-surface which can be used to record all drawing operations
* at the highest level (that is, the level of paint, mask, stroke, fill
@ -105,50 +114,45 @@ static const cairo_surface_backend_t cairo_meta_surface_backend;
* Since 1.10
**/
cairo_surface_t *
cairo_meta_surface_create (cairo_content_t content,
double width_pixels,
double height_pixels)
cairo_meta_surface_create (cairo_content_t content,
const cairo_rectangle_t *extents)
{
cairo_meta_surface_t *meta;
cairo_status_t status;
meta = malloc (sizeof (cairo_meta_surface_t));
if (unlikely (meta == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
_cairo_surface_init (&meta->base, &cairo_meta_surface_backend,
content);
_cairo_surface_init (&meta->base, &cairo_meta_surface_backend, content);
meta->content = content;
meta->width_pixels = width_pixels;
meta->height_pixels = height_pixels;
/* unbounded -> 'infinite' extents */
if (width_pixels < 0) {
meta->extents.x = CAIRO_RECT_INT_MIN;
meta->extents.width = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN;
} else {
meta->extents.x = 0;
if (ceil (width_pixels) > CAIRO_RECT_INT_MAX)
meta->extents.width = CAIRO_RECT_INT_MAX;
else
meta->extents.width = ceil (width_pixels);
}
if (extents != NULL) {
meta->extents_pixels = *extents;
if (height_pixels < 0) {
meta->extents.y = CAIRO_RECT_INT_MIN;
meta->extents.height = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN;
/* XXX check for overflow */
meta->extents.x = floor (extents->x);
meta->extents.y = floor (extents->y);
meta->extents.width = ceil (extents->x + extents->width) - meta->extents.x;
meta->extents.height = ceil (extents->y + extents->height) - meta->extents.y;
status = _cairo_clip_init_rectangle (&meta->clip, &meta->extents);
if (unlikely (status)) {
free (meta);
return _cairo_surface_create_in_error (status);
}
meta->unbounded = FALSE;
} else {
meta->extents.y = 0;
if (ceil (height_pixels) > CAIRO_RECT_INT_MAX)
meta->extents.height = CAIRO_RECT_INT_MAX;
else
meta->extents.height = ceil (height_pixels);
meta->unbounded = TRUE;
_cairo_clip_init (&meta->clip);
}
_cairo_array_init (&meta->commands, sizeof (cairo_command_t *));
meta->commands_owner = NULL;
meta->is_clipped = FALSE;
meta->replay_start_idx = 0;
return &meta->base;
@ -161,14 +165,17 @@ _cairo_meta_surface_create_similar (void *abstract_surface,
int width,
int height)
{
return cairo_meta_surface_create (content, width, height);
cairo_rectangle_t extents;
extents.x = extents.y = 0;
extents.width = width;
extents.height = height;
return cairo_meta_surface_create (content, &extents);
}
static cairo_status_t
_cairo_meta_surface_finish (void *abstract_surface)
{
cairo_meta_surface_t *meta = abstract_surface;
cairo_command_t *command;
cairo_command_t **elements;
int i, num_elements;
@ -180,11 +187,11 @@ _cairo_meta_surface_finish (void *abstract_surface)
num_elements = meta->commands.num_elements;
elements = _cairo_array_index (&meta->commands, 0);
for (i = 0; i < num_elements; i++) {
command = elements[i];
cairo_command_t *command = elements[i];
_cairo_clip_reset (&command->header.clip);
switch (command->header.type) {
/* 5 basic drawing operations */
case CAIRO_COMMAND_PAINT:
_cairo_pattern_fini_snapshot (&command->paint.source.base);
free (command);
@ -218,19 +225,13 @@ _cairo_meta_surface_finish (void *abstract_surface)
free (command);
break;
/* Other junk. */
case CAIRO_COMMAND_INTERSECT_CLIP_PATH:
if (command->intersect_clip_path.path_pointer)
_cairo_path_fixed_fini (&command->intersect_clip_path.path);
free (command);
break;
default:
ASSERT_NOT_REACHED;
}
}
_cairo_array_fini (&meta->commands);
_cairo_clip_reset (&meta->clip);
return CAIRO_STATUS_SUCCESS;
}
@ -254,8 +255,12 @@ _cairo_meta_surface_acquire_source_image (void *abstract_surface,
}
image = _cairo_image_surface_create_with_content (surface->content,
ceil (surface->width_pixels),
ceil (surface->height_pixels));
surface->extents.width,
surface->extents.height);
cairo_surface_set_device_offset (image,
-surface->extents.x,
-surface->extents.y);
status = cairo_meta_surface_replay (&surface->base, image);
if (unlikely (status)) {
@ -282,21 +287,30 @@ _cairo_meta_surface_release_source_image (void *abstract_surface,
cairo_surface_destroy (&image->base);
}
static void
_draw_command_init (cairo_command_header_t *command,
cairo_command_type_t type,
cairo_meta_surface_t *meta)
static cairo_status_t
_command_init (cairo_meta_surface_t *meta,
cairo_command_header_t *command,
cairo_command_type_t type,
cairo_operator_t op,
cairo_clip_t *clip)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
command->type = type;
command->op = op;
command->region = CAIRO_META_REGION_ALL;
command->extents = meta->extents;
_cairo_clip_init_copy (&command->clip, clip);
if (meta->clip.path != NULL)
status = _cairo_clip_apply_clip (&command->clip, &meta->clip);
return status;
}
static cairo_int_status_t
_cairo_meta_surface_paint (void *abstract_surface,
cairo_operator_t op,
_cairo_meta_surface_paint (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_status_t status;
cairo_meta_surface_t *meta = abstract_surface;
@ -306,8 +320,10 @@ _cairo_meta_surface_paint (void *abstract_surface,
if (unlikely (command == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
_draw_command_init (&command->header, CAIRO_COMMAND_PAINT, meta);
command->op = op;
status = _command_init (meta,
&command->header, CAIRO_COMMAND_PAINT, op, clip);
if (unlikely (status))
goto CLEANUP_COMMAND;
status = _cairo_pattern_init_snapshot (&command->source.base, source);
if (unlikely (status))
@ -320,7 +336,7 @@ _cairo_meta_surface_paint (void *abstract_surface,
/* An optimisation that takes care to not replay what was done
* before surface is cleared. We don't erase recorded commands
* since we may have earlier snapshots of this surface. */
if (op == CAIRO_OPERATOR_CLEAR && !meta->is_clipped)
if (op == CAIRO_OPERATOR_CLEAR && clip == NULL)
meta->replay_start_idx = meta->commands.num_elements;
return CAIRO_STATUS_SUCCESS;
@ -337,7 +353,7 @@ _cairo_meta_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_status_t status;
cairo_meta_surface_t *meta = abstract_surface;
@ -347,8 +363,10 @@ _cairo_meta_surface_mask (void *abstract_surface,
if (unlikely (command == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
_draw_command_init (&command->header, CAIRO_COMMAND_MASK, meta);
command->op = op;
status = _command_init (meta,
&command->header, CAIRO_COMMAND_MASK, op, clip);
if (unlikely (status))
goto CLEANUP_COMMAND;
status = _cairo_pattern_init_snapshot (&command->source.base, source);
if (unlikely (status))
@ -383,7 +401,7 @@ _cairo_meta_surface_stroke (void *abstract_surface,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_status_t status;
cairo_meta_surface_t *meta = abstract_surface;
@ -393,8 +411,10 @@ _cairo_meta_surface_stroke (void *abstract_surface,
if (unlikely (command == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
_draw_command_init (&command->header, CAIRO_COMMAND_STROKE, meta);
command->op = op;
status = _command_init (meta,
&command->header, CAIRO_COMMAND_STROKE, op, clip);
if (unlikely (status))
goto CLEANUP_COMMAND;
status = _cairo_pattern_init_snapshot (&command->source.base, source);
if (unlikely (status))
@ -438,7 +458,7 @@ _cairo_meta_surface_fill (void *abstract_surface,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_status_t status;
cairo_meta_surface_t *meta = abstract_surface;
@ -448,8 +468,10 @@ _cairo_meta_surface_fill (void *abstract_surface,
if (unlikely (command == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
_draw_command_init (&command->header, CAIRO_COMMAND_FILL, meta);
command->op = op;
status =_command_init (meta,
&command->header, CAIRO_COMMAND_FILL, op, clip);
if (unlikely (status))
goto CLEANUP_COMMAND;
status = _cairo_pattern_init_snapshot (&command->source.base, source);
if (unlikely (status))
@ -496,7 +518,7 @@ _cairo_meta_surface_show_text_glyphs (void *abstract_surface,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_scaled_font_t *scaled_font,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_status_t status;
cairo_meta_surface_t *meta = abstract_surface;
@ -506,8 +528,11 @@ _cairo_meta_surface_show_text_glyphs (void *abstract_surface,
if (unlikely (command == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
_draw_command_init (&command->header, CAIRO_COMMAND_SHOW_TEXT_GLYPHS, meta);
command->op = op;
status = _command_init (meta,
&command->header, CAIRO_COMMAND_SHOW_TEXT_GLYPHS,
op, clip);
if (unlikely (status))
goto CLEANUP_COMMAND;
status = _cairo_pattern_init_snapshot (&command->source.base, source);
if (unlikely (status))
@ -594,82 +619,31 @@ _cairo_meta_surface_snapshot (void *abstract_other)
_cairo_surface_init (&meta->base, &cairo_meta_surface_backend,
other->base.content);
meta->width_pixels = other->width_pixels;
meta->height_pixels = other->height_pixels;
meta->extents_pixels = other->extents_pixels;
meta->extents = other->extents;
meta->unbounded = other->unbounded;
meta->replay_start_idx = other->replay_start_idx;
meta->content = other->content;
_cairo_array_init_snapshot (&meta->commands, &other->commands);
meta->commands_owner = cairo_surface_reference (&other->base);
_cairo_clip_init_copy (&meta->clip, &other->clip);
return &meta->base;
}
static cairo_int_status_t
_cairo_meta_surface_intersect_clip_path (void *dst,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias)
{
cairo_meta_surface_t *meta = dst;
cairo_command_intersect_clip_path_t *command;
cairo_status_t status;
command = malloc (sizeof (cairo_command_intersect_clip_path_t));
if (unlikely (command == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
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);
if (unlikely (status)) {
free (command);
return status;
}
command->path_pointer = &command->path;
meta->is_clipped = TRUE;
} else {
command->path_pointer = NULL;
meta->is_clipped = FALSE;
}
command->fill_rule = fill_rule;
command->tolerance = tolerance;
command->antialias = antialias;
status = _cairo_array_append (&meta->commands, &command);
if (unlikely (status)) {
if (path)
_cairo_path_fixed_fini (&command->path);
free (command);
return status;
}
return CAIRO_STATUS_SUCCESS;
}
/* Currently, we're using as the "size" of a meta surface the largest
* surface size against which the meta-surface is expected to be
* replayed, (as passed in to cairo_meta_surface_create()).
*/
static cairo_int_status_t
static cairo_bool_t
_cairo_meta_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
cairo_meta_surface_t *surface = abstract_surface;
if (surface->width_pixels < 0 || surface->height_pixels < 0)
return CAIRO_INT_STATUS_UNSUPPORTED;
if (surface->unbounded)
return FALSE;
rectangle->x = 0;
rectangle->y = 0;
rectangle->width = ceil (surface->width_pixels);
rectangle->height = ceil (surface->height_pixels);
return CAIRO_STATUS_SUCCESS;
*rectangle = surface->extents;
return TRUE;
}
/**
@ -702,8 +676,6 @@ static const cairo_surface_backend_t cairo_meta_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
NULL, /* set_clip_region */
_cairo_meta_surface_intersect_clip_path,
_cairo_meta_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
@ -726,7 +698,6 @@ static const cairo_surface_backend_t cairo_meta_surface_backend = {
_cairo_meta_surface_snapshot,
NULL, /* is_similar */
NULL, /* reset */
NULL, /* fill_stroke */
NULL, /* create_solid_pattern_surface */
NULL, /* can_repaint_solid_pattern_surface */
@ -735,32 +706,12 @@ static const cairo_surface_backend_t cairo_meta_surface_backend = {
_cairo_meta_surface_show_text_glyphs
};
static cairo_path_fixed_t *
_cairo_command_get_path (cairo_command_t *command)
{
switch (command->header.type) {
case CAIRO_COMMAND_PAINT:
case CAIRO_COMMAND_MASK:
case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
return NULL;
case CAIRO_COMMAND_STROKE:
return &command->stroke.path;
case CAIRO_COMMAND_FILL:
return &command->fill.path;
case CAIRO_COMMAND_INTERSECT_CLIP_PATH:
return command->intersect_clip_path.path_pointer;
}
ASSERT_NOT_REACHED;
return NULL;
}
cairo_int_status_t
_cairo_meta_surface_get_path (cairo_surface_t *surface,
cairo_path_fixed_t *path)
{
cairo_meta_surface_t *meta;
cairo_command_t *command, **elements;
cairo_command_t **elements;
int i, num_elements;
cairo_int_status_t status;
@ -773,12 +724,11 @@ _cairo_meta_surface_get_path (cairo_surface_t *surface,
num_elements = meta->commands.num_elements;
elements = _cairo_array_index (&meta->commands, 0);
for (i = meta->replay_start_idx; i < num_elements; i++) {
command = elements[i];
cairo_command_t *command = elements[i];
switch (command->header.type) {
case CAIRO_COMMAND_PAINT:
case CAIRO_COMMAND_MASK:
case CAIRO_COMMAND_INTERSECT_CLIP_PATH:
status = CAIRO_INT_STATUS_UNSUPPORTED;
break;
@ -804,7 +754,9 @@ _cairo_meta_surface_get_path (cairo_surface_t *surface,
}
case CAIRO_COMMAND_FILL:
{
status = _cairo_path_fixed_append (path, &command->fill.path, CAIRO_DIRECTION_FORWARD);
status = _cairo_path_fixed_append (path,
&command->fill.path, CAIRO_DIRECTION_FORWARD,
0, 0);
break;
}
case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
@ -827,6 +779,7 @@ _cairo_meta_surface_get_path (cairo_surface_t *surface,
return _cairo_surface_set_error (surface, status);
}
#define _clip(c) ((c)->header.clip.path ? &(c)->header.clip : NULL)
static cairo_status_t
_cairo_meta_surface_replay_internal (cairo_surface_t *surface,
cairo_surface_t *target,
@ -834,209 +787,155 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface,
cairo_meta_region_type_t region)
{
cairo_meta_surface_t *meta;
cairo_command_t *command, **elements;
cairo_command_t **elements;
int i, num_elements;
cairo_int_status_t status, status2;
cairo_clip_t clip, *old_clip;
cairo_bool_t has_device_transform = _cairo_surface_has_device_transform (target);
cairo_matrix_t *device_transform = &target->device_transform;
cairo_path_fixed_t path_copy, *dev_path;
cairo_int_status_t status;
cairo_surface_wrapper_t wrapper;
if (surface->status)
if (unlikely (surface->status))
return surface->status;
if (target->status)
if (unlikely (target->status))
return _cairo_surface_set_error (surface, target->status);
_cairo_surface_wrapper_init (&wrapper, target);
meta = (cairo_meta_surface_t *) surface;
status = CAIRO_STATUS_SUCCESS;
_cairo_clip_init (&clip, target);
old_clip = _cairo_surface_get_clip (target);
num_elements = meta->commands.num_elements;
elements = _cairo_array_index (&meta->commands, 0);
for (i = meta->replay_start_idx; i < num_elements; i++) {
command = elements[i];
cairo_command_t *command = elements[i];
if (type == CAIRO_META_REPLAY && 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->header.type != CAIRO_COMMAND_INTERSECT_CLIP_PATH) {
status = _cairo_surface_set_clip (target, &clip);
if (unlikely (status))
break;
}
dev_path = _cairo_command_get_path (command);
if (dev_path && has_device_transform) {
status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
if (unlikely (status))
break;
_cairo_path_fixed_transform (&path_copy, device_transform);
dev_path = &path_copy;
}
switch (command->header.type) {
case CAIRO_COMMAND_PAINT:
status = _cairo_surface_paint (target,
command->paint.op,
&command->paint.source.base, &command->header.extents);
status = _cairo_surface_wrapper_paint (&wrapper,
command->header.op,
&command->paint.source.base,
_clip (command));
break;
case CAIRO_COMMAND_MASK:
status = _cairo_surface_mask (target,
command->mask.op,
&command->mask.source.base,
&command->mask.mask.base, &command->header.extents);
status = _cairo_surface_wrapper_mask (&wrapper,
command->header.op,
&command->mask.source.base,
&command->mask.mask.base,
_clip (command));
break;
case CAIRO_COMMAND_STROKE:
{
cairo_matrix_t dev_ctm = command->stroke.ctm;
cairo_matrix_t dev_ctm_inverse = command->stroke.ctm_inverse;
if (has_device_transform) {
cairo_matrix_multiply (&dev_ctm, &dev_ctm, device_transform);
cairo_matrix_multiply (&dev_ctm_inverse,
&target->device_transform_inverse,
&dev_ctm_inverse);
}
status = _cairo_surface_stroke (target,
command->stroke.op,
&command->stroke.source.base,
dev_path,
&command->stroke.style,
&dev_ctm,
&dev_ctm_inverse,
command->stroke.tolerance,
command->stroke.antialias, &command->header.extents);
status = _cairo_surface_wrapper_stroke (&wrapper,
command->header.op,
&command->stroke.source.base,
&command->stroke.path,
&command->stroke.style,
&command->stroke.ctm,
&command->stroke.ctm_inverse,
command->stroke.tolerance,
command->stroke.antialias,
_clip (command));
break;
}
case CAIRO_COMMAND_FILL:
{
cairo_command_t *stroke_command;
if (type != CAIRO_META_CREATE_REGIONS)
stroke_command = (i < num_elements - 1) ? elements[i + 1] : NULL;
else
stroke_command = NULL;
stroke_command = NULL;
if (type != CAIRO_META_CREATE_REGIONS && i < num_elements - 1)
stroke_command = elements[i + 1];
if (stroke_command != NULL &&
type == CAIRO_META_REPLAY && region != CAIRO_META_REGION_ALL)
type == CAIRO_META_REPLAY &&
region != CAIRO_META_REGION_ALL)
{
if (stroke_command->header.region != region)
stroke_command = NULL;
}
if (stroke_command != NULL &&
stroke_command->header.type == CAIRO_COMMAND_STROKE &&
_cairo_path_fixed_is_equal (dev_path, _cairo_command_get_path (stroke_command))) {
cairo_matrix_t dev_ctm;
cairo_matrix_t dev_ctm_inverse;
dev_ctm = stroke_command->stroke.ctm;
dev_ctm_inverse = stroke_command->stroke.ctm_inverse;
if (has_device_transform) {
cairo_matrix_multiply (&dev_ctm, &dev_ctm, device_transform);
cairo_matrix_multiply (&dev_ctm_inverse,
&surface->device_transform_inverse,
&dev_ctm_inverse);
}
status = _cairo_surface_fill_stroke (target,
command->fill.op,
&command->fill.source.base,
command->fill.fill_rule,
command->fill.tolerance,
command->fill.antialias,
dev_path,
stroke_command->stroke.op,
&stroke_command->stroke.source.base,
&stroke_command->stroke.style,
&dev_ctm,
&dev_ctm_inverse,
stroke_command->stroke.tolerance,
stroke_command->stroke.antialias,
&stroke_command->header.extents);
_cairo_path_fixed_is_equal (&command->fill.path,
&stroke_command->stroke.path))
{
status = _cairo_surface_wrapper_fill_stroke (&wrapper,
command->header.op,
&command->fill.source.base,
command->fill.fill_rule,
command->fill.tolerance,
command->fill.antialias,
&command->fill.path,
stroke_command->header.op,
&stroke_command->stroke.source.base,
&stroke_command->stroke.style,
&stroke_command->stroke.ctm,
&stroke_command->stroke.ctm_inverse,
stroke_command->stroke.tolerance,
stroke_command->stroke.antialias,
_clip (command));
i++;
} else
status = _cairo_surface_fill (target,
command->fill.op,
&command->fill.source.base,
dev_path,
command->fill.fill_rule,
command->fill.tolerance,
command->fill.antialias, &command->header.extents);
}
else
{
status = _cairo_surface_wrapper_fill (&wrapper,
command->header.op,
&command->fill.source.base,
&command->fill.path,
command->fill.fill_rule,
command->fill.tolerance,
command->fill.antialias,
_clip (command));
}
break;
}
case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
{
cairo_glyph_t *glyphs = command->show_text_glyphs.glyphs;
cairo_glyph_t *dev_glyphs;
int i, num_glyphs = command->show_text_glyphs.num_glyphs;
cairo_glyph_t *glyphs_copy;
int num_glyphs = command->show_text_glyphs.num_glyphs;
/* show_text_glyphs is special because _cairo_surface_show_text_glyphs is allowed
* to modify the glyph array that's passed in. We must always
* copy the array before handing it to the backend.
*/
dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
if (unlikely (dev_glyphs == NULL)) {
glyphs_copy = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
if (unlikely (glyphs_copy == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
break;
}
if (has_device_transform) {
for (i = 0; i < num_glyphs; i++) {
dev_glyphs[i] = glyphs[i];
cairo_matrix_transform_point (device_transform,
&dev_glyphs[i].x,
&dev_glyphs[i].y);
}
} else {
memcpy (dev_glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
}
memcpy (glyphs_copy, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
status = _cairo_surface_show_text_glyphs (target,
command->show_text_glyphs.op,
&command->show_text_glyphs.source.base,
command->show_text_glyphs.utf8, command->show_text_glyphs.utf8_len,
dev_glyphs, num_glyphs,
command->show_text_glyphs.clusters, command->show_text_glyphs.num_clusters,
command->show_text_glyphs.cluster_flags,
command->show_text_glyphs.scaled_font, &command->header.extents);
free (dev_glyphs);
status = _cairo_surface_wrapper_show_text_glyphs (&wrapper,
command->header.op,
&command->show_text_glyphs.source.base,
command->show_text_glyphs.utf8, command->show_text_glyphs.utf8_len,
glyphs_copy, num_glyphs,
command->show_text_glyphs.clusters, command->show_text_glyphs.num_clusters,
command->show_text_glyphs.cluster_flags,
command->show_text_glyphs.scaled_font,
_clip (command));
free (glyphs_copy);
break;
}
case CAIRO_COMMAND_INTERSECT_CLIP_PATH:
/* XXX Meta surface clipping is broken and requires some
* cairo-gstate.c rewriting. Work around it for now. */
if (dev_path == NULL)
_cairo_clip_reset (&clip);
else
status = _cairo_clip_clip (&clip, dev_path,
command->intersect_clip_path.fill_rule,
command->intersect_clip_path.tolerance,
command->intersect_clip_path.antialias,
target);
break;
default:
ASSERT_NOT_REACHED;
}
if (dev_path == &path_copy)
_cairo_path_fixed_fini (&path_copy);
if (type == CAIRO_META_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;
} else {
assert (_cairo_status_is_error (status));
}
}
@ -1044,10 +943,14 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface,
break;
}
_cairo_clip_reset (&clip);
status2 = _cairo_surface_set_clip (target, old_clip);
if (status == CAIRO_STATUS_SUCCESS)
status = status2;
/* free up any caches */
for (i = meta->replay_start_idx; i < num_elements; i++) {
cairo_command_t *command = elements[i];
_cairo_clip_drop_cache (&command->header.clip);
}
_cairo_surface_wrapper_fini (&wrapper);
return _cairo_surface_set_error (surface, status);
}
@ -1104,6 +1007,33 @@ _cairo_meta_surface_replay_region (cairo_surface_t *surface,
region);
}
static cairo_status_t
_meta_surface_get_ink_bbox (cairo_meta_surface_t *surface,
cairo_box_t *bbox,
const cairo_matrix_t *transform)
{
cairo_surface_t *null_surface;
cairo_surface_t *analysis_surface;
cairo_status_t status;
null_surface = _cairo_null_surface_create (surface->content);
analysis_surface = _cairo_analysis_surface_create (null_surface);
cairo_surface_destroy (null_surface);
status = analysis_surface->status;
if (unlikely (status))
return status;
if (transform != NULL)
_cairo_analysis_surface_set_ctm (analysis_surface, transform);
status = cairo_meta_surface_replay (&surface->base, analysis_surface);
_cairo_analysis_surface_get_bounding_box (analysis_surface, bbox);
cairo_surface_destroy (analysis_surface);
return status;
}
/**
* cairo_meta_surface_ink_extents:
* @surface: a #cairo_meta_surface_t
@ -1114,7 +1044,7 @@ _cairo_meta_surface_replay_region (cairo_surface_t *surface,
*
* Measures the extents of the operations stored within the meta-surface.
* This is useful to compute the required size of an image surface (or
* equivalent) into which to replay the full sequence of drawing operaitions.
* equivalent) into which to replay the full sequence of drawing operations.
*
* Since: 1.10
**/
@ -1125,8 +1055,6 @@ cairo_meta_surface_ink_extents (cairo_surface_t *surface,
double *width,
double *height)
{
cairo_surface_t *null_surface;
cairo_surface_t *analysis_surface;
cairo_status_t status;
cairo_box_t bbox;
@ -1137,17 +1065,11 @@ cairo_meta_surface_ink_extents (cairo_surface_t *surface,
goto DONE;
}
null_surface = _cairo_null_surface_create (CAIRO_CONTENT_COLOR_ALPHA);
analysis_surface = _cairo_analysis_surface_create (null_surface, -1, -1);
cairo_surface_destroy (null_surface);
status = analysis_surface->status;
status = _meta_surface_get_ink_bbox ((cairo_meta_surface_t *) surface,
&bbox,
NULL);
if (unlikely (status))
goto DONE;
status = cairo_meta_surface_replay (surface, analysis_surface);
_cairo_analysis_surface_get_bounding_box (analysis_surface, &bbox);
cairo_surface_destroy (analysis_surface);
status = _cairo_surface_set_error (surface, status);
DONE:
if (x0)
@ -1159,3 +1081,19 @@ DONE:
if (height)
*height = _cairo_fixed_to_double (bbox.p2.y - bbox.p1.y);
}
cairo_status_t
_cairo_meta_surface_get_bbox (cairo_meta_surface_t *surface,
cairo_box_t *bbox,
const cairo_matrix_t *transform)
{
if (! surface->unbounded) {
_cairo_box_from_rectangle (bbox, &surface->extents);
if (transform != NULL)
_cairo_matrix_transform_bounding_box_fixed (transform, bbox, NULL);
return CAIRO_STATUS_SUCCESS;
}
return _meta_surface_get_ink_bbox (surface, bbox, transform);
}

View file

@ -716,26 +716,18 @@ _cairo_os2_surface_release_dest_image (void *abstract_surface
DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields);
}
static cairo_int_status_t
static cairo_bool_t
_cairo_os2_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
cairo_os2_surface_t *local_os2_surface;
local_os2_surface = (cairo_os2_surface_t *) abstract_surface;
if ((!local_os2_surface) ||
(local_os2_surface->base.backend != &cairo_os2_surface_backend))
{
/* Invalid parameter (wrong surface)! */
return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
}
rectangle->x = 0;
rectangle->y = 0;
rectangle->width = local_os2_surface->bitmap_info.cx;
rectangle->height = local_os2_surface->bitmap_info.cy;
return CAIRO_STATUS_SUCCESS;
return TRUE;
}
/**
@ -1327,8 +1319,6 @@ static const cairo_surface_backend_t cairo_os2_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
NULL, /* set_clip_region */
NULL, /* intersect_clip_path */
_cairo_os2_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */

View file

@ -149,8 +149,6 @@ struct _cairo_paginated_surface_backend {
cairo_private cairo_surface_t *
_cairo_paginated_surface_create (cairo_surface_t *target,
cairo_content_t content,
int width,
int height,
const cairo_paginated_surface_backend_t *backend);
cairo_private cairo_surface_t *

View file

@ -48,14 +48,6 @@ typedef struct _cairo_paginated_surface {
cairo_content_t content;
/* XXX: These shouldn't actually exist. We inherit this ugliness
* from _cairo_meta_surface_create. The width/height parameters
* from that function also should not exist. The fix that will
* allow us to remove all of these is to fix acquire_source_image
* to pass an interest rectangle. */
int width;
int height;
/* Paginated-surface specific functions for the target */
const cairo_paginated_surface_backend_t *backend;
@ -66,7 +58,6 @@ typedef struct _cairo_paginated_surface {
int page_num;
cairo_bool_t page_is_blank;
} cairo_paginated_surface_t;
#endif /* CAIRO_PAGINATED_SURFACE_H */

View file

@ -60,17 +60,36 @@ _cairo_paginated_surface_create_similar (void *abstract_surface,
int width,
int height)
{
cairo_paginated_surface_t *surface = abstract_surface;
return cairo_surface_create_similar (surface->target, content,
width, height);
cairo_rectangle_t rect;
rect.x = rect.y = 0.;
rect.width = width;
rect.height = height;
return cairo_meta_surface_create (content, &rect);
}
static cairo_surface_t *
_create_meta_surface_for_target (cairo_surface_t *target,
cairo_content_t content)
{
cairo_rectangle_int_t rect;
if (_cairo_surface_get_extents (target, &rect)) {
cairo_rectangle_t meta_extents;
meta_extents.x = rect.x;
meta_extents.y = rect.y;
meta_extents.width = rect.width;
meta_extents.height = rect.height;
return cairo_meta_surface_create (content, &meta_extents);
} else {
return cairo_meta_surface_create (content, NULL);
}
}
/* XXX The integer width,height here should be doubles and all uses updated */
cairo_surface_t *
_cairo_paginated_surface_create (cairo_surface_t *target,
cairo_content_t content,
int width,
int height,
const cairo_paginated_surface_backend_t *backend)
{
cairo_paginated_surface_t *surface;
@ -87,18 +106,15 @@ _cairo_paginated_surface_create (cairo_surface_t *target,
/* Override surface->base.type with target's type so we don't leak
* evidence of the paginated wrapper out to the user. */
surface->base.type = cairo_surface_get_type (target);
surface->base.type = target->type;
surface->target = cairo_surface_reference (target);
surface->content = content;
surface->width = width;
surface->height = height;
surface->backend = backend;
surface->meta = cairo_meta_surface_create (content, width, height);
status = cairo_surface_status (surface->meta);
surface->meta = _create_meta_surface_for_target (target, content);
status = surface->meta->status;
if (unlikely (status))
goto FAIL_CLEANUP_SURFACE;
@ -132,31 +148,6 @@ _cairo_paginated_surface_get_target (cairo_surface_t *surface)
return paginated_surface->target;
}
cairo_status_t
_cairo_paginated_surface_set_size (cairo_surface_t *surface,
int width,
int height)
{
cairo_paginated_surface_t *paginated_surface;
cairo_status_t status;
assert (_cairo_surface_is_paginated (surface));
paginated_surface = (cairo_paginated_surface_t *) surface;
paginated_surface->width = width;
paginated_surface->height = height;
cairo_surface_destroy (paginated_surface->meta);
paginated_surface->meta = cairo_meta_surface_create (paginated_surface->content,
width, height);
status = cairo_surface_status (paginated_surface->meta);
if (unlikely (status))
return _cairo_surface_set_error (surface, status);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_paginated_surface_finish (void *abstract_surface)
{
@ -168,18 +159,11 @@ _cairo_paginated_surface_finish (void *abstract_surface)
status = cairo_surface_status (abstract_surface);
}
if (status == CAIRO_STATUS_SUCCESS) {
cairo_surface_finish (surface->target);
status = cairo_surface_status (surface->target);
}
if (status == CAIRO_STATUS_SUCCESS) {
cairo_surface_finish (surface->meta);
status = cairo_surface_status (surface->meta);
}
cairo_surface_destroy (surface->target);
cairo_surface_finish (surface->meta);
if (status == CAIRO_STATUS_SUCCESS)
status = cairo_surface_status (surface->meta);
cairo_surface_destroy (surface->meta);
return status;
@ -210,13 +194,14 @@ _cairo_paginated_surface_acquire_source_image (void *abstract_surface,
void **image_extra)
{
cairo_paginated_surface_t *surface = abstract_surface;
cairo_bool_t is_bounded;
cairo_surface_t *image;
cairo_status_t status;
cairo_rectangle_int_t extents;
status = _cairo_surface_get_extents (surface->target, &extents);
if (unlikely (status))
return status;
is_bounded = _cairo_surface_get_extents (surface->target, &extents);
if (! is_bounded)
return CAIRO_INT_STATUS_UNSUPPORTED;
image = _cairo_paginated_surface_create_image_surface (surface,
extents.width,
@ -248,11 +233,11 @@ _paint_fallback_image (cairo_paginated_surface_t *surface,
{
double x_scale = surface->base.x_fallback_resolution / surface->target->x_resolution;
double y_scale = surface->base.y_fallback_resolution / surface->target->y_resolution;
cairo_matrix_t matrix;
int x, y, width, height;
cairo_status_t status;
cairo_surface_t *image;
cairo_surface_pattern_t pattern;
cairo_clip_t clip;
x = rect->x;
y = rect->y;
@ -271,15 +256,21 @@ _paint_fallback_image (cairo_paginated_surface_t *surface,
goto CLEANUP_IMAGE;
_cairo_pattern_init_for_surface (&pattern, image);
cairo_matrix_init (&matrix, x_scale, 0, 0, y_scale, -x*x_scale, -y*y_scale);
cairo_pattern_set_matrix (&pattern.base, &matrix);
cairo_matrix_init (&pattern.base.matrix,
x_scale, 0, 0, y_scale, -x*x_scale, -y*y_scale);
/* the fallback should be rendered at native resolution, so disable
* filtering (if possible) to avoid introducing potential artifacts. */
pattern.base.filter = CAIRO_FILTER_NEAREST;
status = _cairo_clip_init_rectangle (&clip, rect);
if (unlikely (status))
goto CLEANUP_IMAGE;
status = _cairo_surface_paint (surface->target,
CAIRO_OPERATOR_SOURCE,
&pattern.base, NULL);
&pattern.base, &clip);
_cairo_clip_reset (&clip);
_cairo_pattern_fini (&pattern.base);
CLEANUP_IMAGE:
@ -295,12 +286,11 @@ _paint_page (cairo_paginated_surface_t *surface)
cairo_status_t status;
cairo_bool_t has_supported, has_page_fallback, has_finegrained_fallback;
if (surface->target->status)
if (unlikely (surface->target->status))
return surface->target->status;
analysis = _cairo_analysis_surface_create (surface->target,
surface->width, surface->height);
if (analysis->status)
analysis = _cairo_analysis_surface_create (surface->target);
if (unlikely (analysis->status))
return _cairo_surface_set_error (surface->target, analysis->status);
surface->backend->set_paginated_mode (surface->target,
@ -365,16 +355,19 @@ _paint_page (cairo_paginated_surface_t *surface)
}
if (has_page_fallback) {
cairo_rectangle_int_t rect;
cairo_rectangle_int_t extents;
cairo_bool_t is_bounded;
surface->backend->set_paginated_mode (surface->target,
CAIRO_PAGINATED_MODE_FALLBACK);
rect.x = 0;
rect.y = 0;
rect.width = surface->width;
rect.height = surface->height;
status = _paint_fallback_image (surface, &rect);
is_bounded = _cairo_surface_get_extents (surface->target, &extents);
if (! is_bounded) {
status = CAIRO_INT_STATUS_UNSUPPORTED;
goto FAIL;
}
status = _paint_fallback_image (surface, &extents);
if (unlikely (status))
goto FAIL;
}
@ -386,15 +379,6 @@ _paint_page (cairo_paginated_surface_t *surface)
surface->backend->set_paginated_mode (surface->target,
CAIRO_PAGINATED_MODE_FALLBACK);
/* 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 (unlikely (status))
goto FAIL;
region = _cairo_analysis_surface_get_unsupported (analysis);
num_rects = cairo_region_num_rectangles (region);
@ -402,9 +386,7 @@ _paint_page (cairo_paginated_surface_t *surface)
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (region, i, &rect);
status = _paint_fallback_image (surface, &rect);
if (unlikely (status))
goto FAIL;
}
@ -445,7 +427,7 @@ _cairo_paginated_surface_copy_page (void *abstract_surface)
surface->page_num++;
/* XXX: It might make sense to add some suport here for calling
/* XXX: It might make sense to add some support here for calling
* cairo_surface_copy_page on the target surface. It would be an
* optimization for the output, but the interaction with image
* fallbacks gets tricky. For now, we just let the target see a
@ -471,20 +453,19 @@ _cairo_paginated_surface_show_page (void *abstract_surface)
return status;
cairo_surface_show_page (surface->target);
status = cairo_surface_status (surface->target);
status = surface->target->status;
if (unlikely (status))
return status;
status = cairo_surface_status (surface->meta);
status = surface->meta->status;
if (unlikely (status))
return status;
cairo_surface_destroy (surface->meta);
surface->meta = cairo_meta_surface_create (surface->content,
surface->width,
surface->height);
status = cairo_surface_status (surface->meta);
surface->meta = _create_meta_surface_for_target (surface->target,
surface->content);
status = surface->meta->status;
if (unlikely (status))
return status;
@ -494,21 +475,7 @@ _cairo_paginated_surface_show_page (void *abstract_surface)
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_paginated_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_paginated_surface_t *surface = abstract_surface;
return _cairo_surface_intersect_clip_path (surface->meta,
path, fill_rule,
tolerance, antialias);
}
static cairo_int_status_t
static cairo_bool_t
_cairo_paginated_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
@ -530,7 +497,7 @@ static cairo_int_status_t
_cairo_paginated_surface_paint (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_paginated_surface_t *surface = abstract_surface;
@ -540,7 +507,7 @@ _cairo_paginated_surface_paint (void *abstract_surface,
surface->page_is_blank = FALSE;
return _cairo_surface_paint (surface->meta, op, source, NULL);
return _cairo_surface_paint (surface->meta, op, source, clip);
}
static cairo_int_status_t
@ -548,11 +515,17 @@ _cairo_paginated_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_paginated_surface_t *surface = abstract_surface;
return _cairo_surface_mask (surface->meta, op, source, mask, NULL);
/* Optimize away erasing of nothing. */
if (surface->page_is_blank && op == CAIRO_OPERATOR_CLEAR)
return CAIRO_STATUS_SUCCESS;
surface->page_is_blank = FALSE;
return _cairo_surface_mask (surface->meta, op, source, mask, clip);
}
static cairo_int_status_t
@ -565,7 +538,7 @@ _cairo_paginated_surface_stroke (void *abstract_surface,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_paginated_surface_t *surface = abstract_surface;
@ -578,7 +551,8 @@ _cairo_paginated_surface_stroke (void *abstract_surface,
return _cairo_surface_stroke (surface->meta, op, source,
path, style,
ctm, ctm_inverse,
tolerance, antialias, NULL);
tolerance, antialias,
clip);
}
static cairo_int_status_t
@ -589,7 +563,7 @@ _cairo_paginated_surface_fill (void *abstract_surface,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_paginated_surface_t *surface = abstract_surface;
@ -601,7 +575,8 @@ _cairo_paginated_surface_fill (void *abstract_surface,
return _cairo_surface_fill (surface->meta, op, source,
path, fill_rule,
tolerance, antialias, NULL);
tolerance, antialias,
clip);
}
static cairo_bool_t
@ -614,20 +589,19 @@ _cairo_paginated_surface_has_show_text_glyphs (void *abstract_surface)
static cairo_int_status_t
_cairo_paginated_surface_show_text_glyphs (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const char *utf8,
int utf8_len,
cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_operator_t op,
const cairo_pattern_t *source,
const char *utf8,
int utf8_len,
cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_scaled_font_t *scaled_font,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_paginated_surface_t *surface = abstract_surface;
cairo_int_status_t status;
/* Optimize away erasing of nothing. */
if (surface->page_is_blank && op == CAIRO_OPERATOR_CLEAR)
@ -635,24 +609,13 @@ _cairo_paginated_surface_show_text_glyphs (void *abstract_surface,
surface->page_is_blank = FALSE;
/* Since this is a "wrapping" surface, we're calling back into
* _cairo_surface_show_text_glyphs from within a call to the same.
* Since _cairo_surface_show_text_glyphs acquires a mutex, we release
* and re-acquire the mutex around this nested call.
*
* Yes, this is ugly, but we consider it pragmatic as compared to
* adding locking code to all 18 surface-backend-specific
* show_glyphs functions, (which would get less testing and likely
* lead to bugs).
*/
status = _cairo_surface_show_text_glyphs (surface->meta, op, source,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters,
cluster_flags,
scaled_font, NULL);
return status;
return _cairo_surface_show_text_glyphs (surface->meta, op, source,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters,
cluster_flags,
scaled_font,
clip);
}
static cairo_surface_t *
@ -679,8 +642,6 @@ static const cairo_surface_backend_t cairo_paginated_surface_backend = {
NULL, /* check_span_renderer */
_cairo_paginated_surface_copy_page,
_cairo_paginated_surface_show_page,
NULL, /* set_clip_region */
_cairo_paginated_surface_intersect_clip_path,
_cairo_paginated_surface_get_extents,
NULL, /* old_show_glyphs */
_cairo_paginated_surface_get_font_options,
@ -695,7 +656,6 @@ static const cairo_surface_backend_t cairo_paginated_surface_backend = {
NULL, /* show_glyphs */
_cairo_paginated_surface_snapshot,
NULL, /* is_similar */
NULL, /* reset */
NULL, /* fill_stroke */
NULL, /* create_solid_pattern_surface */
NULL, /* can_repaint_solid_pattern_surface */

View file

@ -173,7 +173,7 @@ _cairo_path_bounder_close_path (void *closure)
* the control points of the curves, not the flattened path).
*/
void
_cairo_path_fixed_approximate_clip_extents (cairo_path_fixed_t *path,
_cairo_path_fixed_approximate_clip_extents (const cairo_path_fixed_t *path,
cairo_rectangle_int_t *extents)
{
cairo_path_bounder_t bounder;
@ -203,7 +203,7 @@ _cairo_path_fixed_approximate_clip_extents (cairo_path_fixed_t *path,
* Bezier, but we continue to ignore winding.
*/
void
_cairo_path_fixed_approximate_fill_extents (cairo_path_fixed_t *path,
_cairo_path_fixed_approximate_fill_extents (const cairo_path_fixed_t *path,
cairo_rectangle_int_t *extents)
{
cairo_path_bounder_t bounder;
@ -229,9 +229,37 @@ _cairo_path_fixed_approximate_fill_extents (cairo_path_fixed_t *path,
_cairo_path_bounder_fini (&bounder);
}
void
_cairo_path_fixed_fill_extents (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_rectangle_int_t *extents)
{
cairo_path_bounder_t bounder;
cairo_status_t status;
_cairo_path_bounder_init (&bounder);
status = _cairo_path_fixed_interpret_flat (path, CAIRO_DIRECTION_FORWARD,
_cairo_path_bounder_move_to,
_cairo_path_bounder_line_to,
_cairo_path_bounder_close_path,
&bounder, tolerance);
assert (status == CAIRO_STATUS_SUCCESS);
if (bounder.has_point) {
_cairo_box_round_to_rectangle (&bounder.extents, extents);
} else {
extents->x = extents->y = 0;
extents->width = extents->height = 0;
}
_cairo_path_bounder_fini (&bounder);
}
/* Adjusts the fill extents (above) by the device-space pen. */
void
_cairo_path_fixed_approximate_stroke_extents (cairo_path_fixed_t *path,
_cairo_path_fixed_approximate_stroke_extents (const cairo_path_fixed_t *path,
cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
cairo_rectangle_int_t *extents)
@ -268,8 +296,37 @@ _cairo_path_fixed_approximate_stroke_extents (cairo_path_fixed_t *path,
_cairo_path_bounder_fini (&bounder);
}
cairo_status_t
_cairo_path_fixed_stroke_extents (const cairo_path_fixed_t *path,
cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_rectangle_int_t *extents)
{
cairo_traps_t traps;
cairo_box_t bbox;
cairo_status_t status;
_cairo_traps_init (&traps);
status = _cairo_path_fixed_stroke_to_traps (path,
stroke_style,
ctm,
ctm_inverse,
tolerance,
&traps);
_cairo_traps_extents (&traps, &bbox);
_cairo_traps_fini (&traps);
_cairo_box_round_to_rectangle (&bbox, extents);
return status;
}
void
_cairo_path_fixed_bounds (cairo_path_fixed_t *path,
_cairo_path_fixed_bounds (const cairo_path_fixed_t *path,
double *x1, double *y1,
double *x2, double *y2)
{

View file

@ -125,12 +125,12 @@ _cairo_filler_close_path (void *closure)
}
static cairo_int_status_t
_cairo_path_fixed_fill_rectangle (cairo_path_fixed_t *path,
_cairo_path_fixed_fill_rectangle (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
cairo_traps_t *traps);
cairo_status_t
_cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path,
_cairo_path_fixed_fill_to_traps (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_traps_t *traps)
@ -138,6 +138,8 @@ _cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path,
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_filler_t filler;
traps->maybe_region = path->maybe_fill_region;
/* Before we do anything else, we use a special-case filler for
* a device-axis aligned rectangle if possible. */
status = _cairo_path_fixed_fill_rectangle (path, fill_rule, traps);
@ -181,12 +183,15 @@ BAIL:
* this function will return %CAIRO_INT_STATUS_UNSUPPORTED.
*/
static cairo_int_status_t
_cairo_path_fixed_fill_rectangle (cairo_path_fixed_t *path,
_cairo_path_fixed_fill_rectangle (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
cairo_traps_t *traps)
{
cairo_box_t box;
if (! path->is_rectilinear)
return CAIRO_INT_STATUS_UNSUPPORTED;
if (_cairo_path_fixed_is_box (path, &box)) {
if (box.p1.x > box.p2.x) {
cairo_fixed_t t;

View file

@ -81,12 +81,26 @@ struct _cairo_path_fixed {
cairo_point_t current_point;
unsigned int has_current_point : 1;
unsigned int has_curve_to : 1;
unsigned int is_box : 1;
unsigned int is_region : 1;
unsigned int is_rectilinear : 1;
unsigned int maybe_fill_region : 1;
unsigned int is_empty_fill : 1;
cairo_path_buf_fixed_t buf;
};
cairo_private void
_cairo_path_fixed_translate (cairo_path_fixed_t *path,
cairo_fixed_t offx,
cairo_fixed_t offy);
cairo_private cairo_status_t
_cairo_path_fixed_append (cairo_path_fixed_t *path,
const cairo_path_fixed_t *other,
cairo_direction_t dir,
cairo_fixed_t tx,
cairo_fixed_t ty);
cairo_private unsigned long
_cairo_path_fixed_hash (const cairo_path_fixed_t *path);
@ -98,14 +112,14 @@ _cairo_path_fixed_equal (const cairo_path_fixed_t *a,
const cairo_path_fixed_t *b);
typedef struct _cairo_path_fixed_iter {
cairo_path_buf_t *buf;
const cairo_path_buf_t *buf;
unsigned int n_op;
unsigned int n_point;
} cairo_path_fixed_iter_t;
cairo_private void
_cairo_path_fixed_iter_init (cairo_path_fixed_iter_t *iter,
cairo_path_fixed_t *path);
const cairo_path_fixed_t *path);
cairo_private cairo_bool_t
_cairo_path_fixed_iter_is_fill_box (cairo_path_fixed_iter_t *_iter,
@ -115,13 +129,19 @@ cairo_private cairo_bool_t
_cairo_path_fixed_iter_at_end (const cairo_path_fixed_iter_t *iter);
static inline cairo_bool_t
_cairo_path_fixed_is_region (cairo_path_fixed_t *path)
_cairo_path_fixed_fill_is_empty (const cairo_path_fixed_t *path)
{
return path->is_empty_fill;
}
static inline cairo_bool_t
_cairo_path_fixed_maybe_fill_region (const cairo_path_fixed_t *path)
{
#if WATCH_PATH
fprintf (stderr, "_cairo_path_fixed_is_region () = %s\n",
path->is_region ? "true" : "false");
fprintf (stderr, "_cairo_path_fixed_maybe_fill_region () = %s\n",
path->maybe_fill_region ? "true" : "false");
#endif
return path->is_region;
return path->maybe_fill_region;
}
#endif /* CAIRO_PATH_FIXED_PRIVATE_H */

View file

@ -96,25 +96,32 @@ _cairo_path_fixed_init (cairo_path_fixed_t *path)
path->last_move_point = path->current_point;
path->has_current_point = FALSE;
path->has_curve_to = FALSE;
path->is_region = TRUE;
path->is_box = TRUE;
path->is_rectilinear = TRUE;
path->maybe_fill_region = TRUE;
path->is_empty_fill = TRUE;
}
cairo_status_t
_cairo_path_fixed_init_copy (cairo_path_fixed_t *path,
cairo_path_fixed_t *other)
const cairo_path_fixed_t *other)
{
cairo_path_buf_t *buf, *other_buf;
unsigned int num_points, num_ops, buf_size;
_cairo_path_fixed_init (path);
VG (VALGRIND_MAKE_MEM_UNDEFINED (path, sizeof (cairo_path_fixed_t)));
cairo_list_init (&path->buf.base.link);
path->buf.base.op = path->buf.op;
path->buf.base.points = path->buf.points;
path->current_point = other->current_point;
path->has_current_point = other->has_current_point;
path->last_move_point = other->last_move_point;
path->has_current_point = other->has_current_point;
path->has_curve_to = other->has_curve_to;
path->is_box = other->is_box;
path->is_region = other->is_region;
path->is_rectilinear = other->is_rectilinear;
path->maybe_fill_region = other->maybe_fill_region;
path->is_empty_fill = other->is_empty_fill;
path->buf.base.num_ops = other->buf.base.num_ops;
path->buf.base.num_points = other->buf.base.num_points;
@ -214,9 +221,10 @@ _cairo_path_fixed_equal (const cairo_path_fixed_t *a,
return TRUE;
/* use the flags to quickly differentiate based on contents */
if (a->has_curve_to != b->has_curve_to ||
a->is_region != b->is_region ||
a->is_box != b->is_box)
if (a->is_empty_fill != b->is_empty_fill ||
a->has_curve_to != b->has_curve_to ||
a->maybe_fill_region != b->maybe_fill_region ||
a->is_rectilinear != b->is_rectilinear)
{
return FALSE;
}
@ -378,15 +386,16 @@ _cairo_path_fixed_move_to (cairo_path_fixed_t *path,
if (unlikely (status))
return status;
if (path->has_current_point && path->is_box) {
if (path->has_current_point && path->is_rectilinear) {
/* a move-to is first an implicit close */
path->is_box = path->current_point.x == path->last_move_point.x ||
path->current_point.y == path->last_move_point.y;
path->is_region &= path->is_box;
path->is_rectilinear = path->current_point.x == path->last_move_point.x ||
path->current_point.y == path->last_move_point.y;
path->maybe_fill_region &= path->is_rectilinear;
}
if (path->is_region) {
path->is_region = _cairo_fixed_is_integer (x) &&
_cairo_fixed_is_integer (y);
if (path->maybe_fill_region) {
path->maybe_fill_region =
_cairo_fixed_is_integer (path->last_move_point.x) &&
_cairo_fixed_is_integer (path->last_move_point.y);
}
}
@ -437,14 +446,18 @@ _cairo_path_fixed_line_to (cairo_path_fixed_t *path,
status = _cairo_path_fixed_move_to (path, point.x, point.y);
} else {
status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_LINE_TO, &point, 1);
if (path->is_box) {
path->is_box = path->current_point.x == x ||
path->current_point.y == y;
path->is_region &= path->is_box;
if (path->is_rectilinear) {
path->is_rectilinear = path->current_point.x == x ||
path->current_point.y == y;
path->maybe_fill_region &= path->is_rectilinear;
}
if (path->is_region) {
path->is_region = _cairo_fixed_is_integer (x) &&
_cairo_fixed_is_integer (y);
if (path->maybe_fill_region) {
path->maybe_fill_region = _cairo_fixed_is_integer (x) &&
_cairo_fixed_is_integer (y);
}
if (path->is_empty_fill) {
path->is_empty_fill = path->current_point.x == x &&
path->current_point.y == y;
}
}
@ -495,9 +508,10 @@ _cairo_path_fixed_curve_to (cairo_path_fixed_t *path,
path->current_point = point[2];
path->has_current_point = TRUE;
path->is_empty_fill = FALSE;
path->has_curve_to = TRUE;
path->is_box = FALSE;
path->is_region = FALSE;
path->is_rectilinear = FALSE;
path->maybe_fill_region = FALSE;
return CAIRO_STATUS_SUCCESS;
}
@ -732,49 +746,77 @@ _cairo_path_fixed_interpret (const cairo_path_fixed_t *path,
return CAIRO_STATUS_SUCCESS;
}
typedef struct _cairo_path_fixed_append_closure {
cairo_point_t offset;
cairo_path_fixed_t *path;
} cairo_path_fixed_append_closure_t;
static cairo_status_t
_append_move_to (void *closure,
_append_move_to (void *abstract_closure,
const cairo_point_t *point)
{
return _cairo_path_fixed_move_to (closure, point->x, point->y);
cairo_path_fixed_append_closure_t *closure = abstract_closure;
return _cairo_path_fixed_move_to (closure->path,
point->x + closure->offset.x,
point->y + closure->offset.y);
}
static cairo_status_t
_append_line_to (void *closure,
_append_line_to (void *abstract_closure,
const cairo_point_t *point)
{
return _cairo_path_fixed_line_to (closure, point->x, point->y);
cairo_path_fixed_append_closure_t *closure = abstract_closure;
return _cairo_path_fixed_line_to (closure->path,
point->x + closure->offset.x,
point->y + closure->offset.y);
}
static cairo_status_t
_append_curve_to (void *closure,
_append_curve_to (void *abstract_closure,
const cairo_point_t *p0,
const cairo_point_t *p1,
const cairo_point_t *p2)
{
return _cairo_path_fixed_curve_to (closure,
p0->x, p0->y,
p1->x, p1->y,
p2->x, p2->y);
cairo_path_fixed_append_closure_t *closure = abstract_closure;
return _cairo_path_fixed_curve_to (closure->path,
p0->x + closure->offset.x,
p0->y + closure->offset.y,
p1->x + closure->offset.x,
p1->y + closure->offset.y,
p2->x + closure->offset.x,
p2->y + closure->offset.y);
}
static cairo_status_t
_append_close_path (void *closure)
_append_close_path (void *abstract_closure)
{
return _cairo_path_fixed_close_path (closure);
cairo_path_fixed_append_closure_t *closure = abstract_closure;
return _cairo_path_fixed_close_path (closure->path);
}
cairo_status_t
_cairo_path_fixed_append (cairo_path_fixed_t *path,
const cairo_path_fixed_t *other,
cairo_direction_t dir)
_cairo_path_fixed_append (cairo_path_fixed_t *path,
const cairo_path_fixed_t *other,
cairo_direction_t dir,
cairo_fixed_t tx,
cairo_fixed_t ty)
{
cairo_path_fixed_append_closure_t closure;
closure.path = path;
closure.offset.x = tx;
closure.offset.y = ty;
return _cairo_path_fixed_interpret (other, dir,
_append_move_to,
_append_line_to,
_append_curve_to,
_append_close_path,
path);
&closure);
}
static void
@ -787,6 +829,13 @@ _cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path,
cairo_path_buf_t *buf;
unsigned int i;
if (path->maybe_fill_region) {
path->maybe_fill_region = _cairo_fixed_is_integer (offx) &&
_cairo_fixed_is_integer (offy) &&
_cairo_fixed_is_integer (scalex) &&
_cairo_fixed_is_integer (scaley);
}
cairo_path_foreach_buf_start (buf, path) {
for (i = 0; i < buf->num_points; i++) {
if (scalex != CAIRO_FIXED_ONE)
@ -800,6 +849,36 @@ _cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path,
} cairo_path_foreach_buf_end (buf, path);
}
void
_cairo_path_fixed_translate (cairo_path_fixed_t *path,
cairo_fixed_t offx,
cairo_fixed_t offy)
{
cairo_path_buf_t *buf;
unsigned int i;
if (offx == 0 && offy == 0)
return;
if (path->maybe_fill_region &&
! (_cairo_fixed_is_integer (offx) && _cairo_fixed_is_integer (offy)))
{
path->maybe_fill_region = FALSE;
}
path->last_move_point.x += offx;
path->last_move_point.y += offx;
path->current_point.x += offx;
path->current_point.y += offx;
cairo_path_foreach_buf_start (buf, path) {
for (i = 0; i < buf->num_points; i++) {
buf->points[i].x += offx;
buf->points[i].y += offy;
}
} cairo_path_foreach_buf_end (buf, path);
}
/**
* _cairo_path_fixed_transform:
* @path: a #cairo_path_fixed_t to be transformed
@ -811,12 +890,14 @@ _cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path,
**/
void
_cairo_path_fixed_transform (cairo_path_fixed_t *path,
cairo_matrix_t *matrix)
const cairo_matrix_t *matrix)
{
cairo_path_buf_t *buf;
unsigned int i;
double dx, dy;
/* XXX current_point, last_move_to */
if (matrix->yx == 0.0 && matrix->xy == 0.0) {
/* Fast path for the common case of scale+transform */
_cairo_path_fixed_offset_and_scale (path,
@ -827,6 +908,7 @@ _cairo_path_fixed_transform (cairo_path_fixed_t *path,
return;
}
path->maybe_fill_region = FALSE;
cairo_path_foreach_buf_start (buf, path) {
for (i = 0; i < buf->num_points; i++) {
dx = _cairo_fixed_to_double (buf->points[i].x);
@ -841,20 +923,22 @@ _cairo_path_fixed_transform (cairo_path_fixed_t *path,
}
cairo_bool_t
_cairo_path_fixed_is_equal (cairo_path_fixed_t *path,
cairo_path_fixed_t *other)
_cairo_path_fixed_is_equal (const cairo_path_fixed_t *path,
const cairo_path_fixed_t *other)
{
cairo_path_buf_t *path_buf, *other_buf;
const cairo_path_buf_t *path_buf, *other_buf;
if (path->current_point.x != other->current_point.x ||
path->current_point.y != other->current_point.y ||
path->has_current_point != other->has_current_point ||
path->has_curve_to != other->has_curve_to ||
path->is_box != other->is_box ||
path->is_region != other->is_region ||
path->is_rectilinear != other->is_rectilinear ||
path->maybe_fill_region != other->maybe_fill_region ||
path->last_move_point.x != other->last_move_point.x ||
path->last_move_point.y != other->last_move_point.y)
{
return FALSE;
}
other_buf = cairo_path_head (other);
cairo_path_foreach_buf_start (path_buf, path) {
@ -970,25 +1054,16 @@ _cairo_path_fixed_interpret_flat (const cairo_path_fixed_t *path,
&flattener);
}
cairo_bool_t
_cairo_path_fixed_is_empty (cairo_path_fixed_t *path)
{
if (cairo_path_head (path)->num_ops == 0)
return TRUE;
return FALSE;
}
/*
* Check whether the given path contains a single rectangle.
*/
cairo_bool_t
_cairo_path_fixed_is_box (cairo_path_fixed_t *path,
_cairo_path_fixed_is_box (const cairo_path_fixed_t *path,
cairo_box_t *box)
{
cairo_path_buf_t *buf = cairo_path_head (path);
const cairo_path_buf_t *buf = cairo_path_head (path);
if (! path->is_box)
if (! path->is_rectilinear)
return FALSE;
/* Do we have the right number of ops? */
@ -1058,12 +1133,12 @@ _cairo_path_fixed_is_box (cairo_path_fixed_t *path,
* </programlisting></informalexample>
*/
cairo_bool_t
_cairo_path_fixed_is_rectangle (cairo_path_fixed_t *path,
_cairo_path_fixed_is_rectangle (const cairo_path_fixed_t *path,
cairo_box_t *box)
{
cairo_path_buf_t *buf;
const cairo_path_buf_t *buf;
if (!_cairo_path_fixed_is_box (path, box))
if (! _cairo_path_fixed_is_box (path, box))
return FALSE;
buf = cairo_path_head (path);
@ -1075,7 +1150,7 @@ _cairo_path_fixed_is_rectangle (cairo_path_fixed_t *path,
void
_cairo_path_fixed_iter_init (cairo_path_fixed_iter_t *iter,
cairo_path_fixed_t *path)
const cairo_path_fixed_t *path)
{
iter->buf = cairo_path_head (path);
iter->n_op = 0;

View file

@ -38,10 +38,10 @@
typedef struct cairo_in_fill {
double tolerance;
cairo_bool_t on_edge;
int winding;
cairo_fixed_t x, y;
cairo_bool_t on_edge;
cairo_bool_t has_current_point;
cairo_point_t current_point;
@ -54,12 +54,12 @@ _cairo_in_fill_init (cairo_in_fill_t *in_fill,
double x,
double y)
{
in_fill->on_edge = FALSE;
in_fill->winding = 0;
in_fill->tolerance = tolerance;
in_fill->x = _cairo_fixed_from_double (x);
in_fill->y = _cairo_fixed_from_double (y);
in_fill->on_edge = FALSE;
in_fill->has_current_point = FALSE;
in_fill->current_point.x = 0;
@ -142,7 +142,7 @@ _cairo_in_fill_add_edge (cairo_in_fill_t *in_fill,
return;
if ((p1->x <= in_fill->x && p2->x <= in_fill->x) ||
edge_compare_for_y_against_x (p1, p2, in_fill->y, in_fill->x) <= 0)
edge_compare_for_y_against_x (p1, p2, in_fill->y, in_fill->x) < 0)
{
in_fill->winding += dir;
}
@ -243,16 +243,19 @@ _cairo_in_fill_close_path (void *closure)
return CAIRO_STATUS_SUCCESS;
}
void
_cairo_path_fixed_in_fill (cairo_path_fixed_t *path,
cairo_bool_t
_cairo_path_fixed_in_fill (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
double x,
double y,
cairo_bool_t *is_inside)
double y)
{
cairo_in_fill_t in_fill;
cairo_status_t status;
cairo_bool_t is_inside;
if (path->is_empty_fill)
return FALSE;
_cairo_in_fill_init (&in_fill, tolerance, x, y);
@ -268,19 +271,21 @@ _cairo_path_fixed_in_fill (cairo_path_fixed_t *path,
_cairo_in_fill_close_path (&in_fill);
if (in_fill.on_edge) {
*is_inside = TRUE;
is_inside = TRUE;
} else switch (fill_rule) {
case CAIRO_FILL_RULE_EVEN_ODD:
*is_inside = in_fill.winding & 1;
is_inside = in_fill.winding & 1;
break;
case CAIRO_FILL_RULE_WINDING:
*is_inside = in_fill.winding != 0;
is_inside = in_fill.winding != 0;
break;
default:
ASSERT_NOT_REACHED;
*is_inside = FALSE;
is_inside = FALSE;
break;
}
_cairo_in_fill_fini (&in_fill);
return is_inside;
}

View file

@ -1140,13 +1140,13 @@ _cairo_stroker_close_path (void *closure)
}
static cairo_int_status_t
_cairo_path_fixed_stroke_rectilinear (cairo_path_fixed_t *path,
_cairo_path_fixed_stroke_rectilinear (const cairo_path_fixed_t *path,
cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
cairo_traps_t *traps);
cairo_status_t
_cairo_path_fixed_stroke_to_traps (cairo_path_fixed_t *path,
_cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t *path,
cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
@ -1737,7 +1737,7 @@ _cairo_rectilinear_stroker_close_path (void *closure)
}
static cairo_int_status_t
_cairo_path_fixed_stroke_rectilinear (cairo_path_fixed_t *path,
_cairo_path_fixed_stroke_rectilinear (const cairo_path_fixed_t *path,
cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
cairo_traps_t *traps)
@ -1755,7 +1755,7 @@ _cairo_path_fixed_stroke_rectilinear (cairo_path_fixed_t *path,
* UNSUPPORTED from _cairo_rectilinear_stroker_line_to if any
* non-rectilinear line_to is encountered.
*/
if (path->has_curve_to)
if (! path->is_rectilinear)
return CAIRO_INT_STATUS_UNSUPPORTED;
if (stroke_style->line_join != CAIRO_LINE_JOIN_MITER)
return CAIRO_INT_STATUS_UNSUPPORTED;

View file

@ -1686,10 +1686,6 @@ _cairo_pattern_acquire_surface_for_solid (const cairo_solid_pattern_t *patt
pattern,
dst))
{
status = _cairo_surface_reset (solid_surface_cache.cache[i].surface);
if (unlikely (status))
goto UNLOCK;
goto DONE;
}
@ -1698,10 +1694,6 @@ _cairo_pattern_acquire_surface_for_solid (const cairo_solid_pattern_t *patt
pattern,
dst))
{
status = _cairo_surface_reset (solid_surface_cache.cache[i].surface);
if (unlikely (status))
goto UNLOCK;
goto DONE;
}
}
@ -1717,11 +1709,6 @@ _cairo_pattern_acquire_surface_for_solid (const cairo_solid_pattern_t *patt
dst))
{
/* Reuse the surface instead of evicting */
status = _cairo_surface_reset (surface);
if (unlikely (status))
goto EVICT;
status = _cairo_surface_repaint_solid_pattern_surface (dst, surface, pattern);
if (unlikely (status))
goto EVICT;
@ -1738,14 +1725,21 @@ _cairo_pattern_acquire_surface_for_solid (const cairo_solid_pattern_t *patt
if (surface == NULL) {
/* Not cached, need to create new */
surface = _cairo_surface_create_solid_pattern_surface (dst, pattern);
if (surface->status) {
if (surface == NULL) {
status = CAIRO_INT_STATUS_UNSUPPORTED;
goto UNLOCK;
}
if (unlikely (surface->status)) {
status = surface->status;
goto UNLOCK;
}
if (! _cairo_surface_is_similar (surface, dst, pattern->content)) {
/* in the rare event of a substitute surface being returned (e.g.
* malloc failure) don't cache the fallback surface */
if (unlikely (! _cairo_surface_is_similar (surface,
dst, pattern->content)))
{
/* In the rare event of a substitute surface being returned,
* don't cache the fallback.
*/
*out = surface;
goto NOCACHE;
}
@ -1953,6 +1947,7 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat
double pad;
cairo_bool_t is_identity;
cairo_bool_t is_empty;
cairo_bool_t is_bounded;
cairo_int_status_t status;
surface = cairo_surface_reference (pattern->surface);
@ -2010,9 +2005,8 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat
cairo_surface_t *src;
int w, h;
status = _cairo_surface_get_extents (surface, &extents);
if (unlikely (status))
goto BAIL;
is_bounded = _cairo_surface_get_extents (surface, &extents);
assert (is_bounded);
status = _cairo_surface_clone_similar (dst, surface, content,
extents.x, extents.y,
@ -2045,8 +2039,13 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat
}
cairo_surface_destroy (surface);
surface = cairo_surface_create_similar (dst, dst->content, w, h);
if (surface->status) {
surface = _cairo_surface_create_similar_solid (dst,
dst->content, w, h,
CAIRO_COLOR_TRANSPARENT,
FALSE);
if (surface == NULL)
return CAIRO_INT_STATUS_UNSUPPORTED;
if (unlikely (surface->status)) {
cairo_surface_destroy (src);
return surface->status;
}
@ -2092,10 +2091,6 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat
attr->extend = CAIRO_EXTEND_REPEAT;
}
status = _cairo_surface_get_extents (surface, &extents);
if (unlikely (status))
goto BAIL;
/* We first transform the rectangle to the coordinate space of the
* source surface so that we only need to clone that portion of the
* surface that will be read.
@ -2118,36 +2113,38 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat
sampled_area.x += tx;
sampled_area.y += ty;
if (attr->extend != CAIRO_EXTEND_REPEAT) {
/* Never acquire a larger area than the source itself */
is_empty = _cairo_rectangle_intersect (&extents, &sampled_area);
} else {
int trim = 0;
if ( _cairo_surface_get_extents (surface, &extents)) {
if (attr->extend != CAIRO_EXTEND_REPEAT) {
/* Never acquire a larger area than the source itself */
is_empty = _cairo_rectangle_intersect (&extents, &sampled_area);
} else {
int trim = 0;
if (sampled_area.x >= extents.x &&
sampled_area.x + (int) sampled_area.width <= extents.x + (int) extents.width)
{
/* source is horizontally contained within extents, trim */
extents.x = sampled_area.x;
extents.width = sampled_area.width;
trim |= 0x1;
if (sampled_area.x >= extents.x &&
sampled_area.x + (int) sampled_area.width <= extents.x + (int) extents.width)
{
/* source is horizontally contained within extents, trim */
extents.x = sampled_area.x;
extents.width = sampled_area.width;
trim |= 0x1;
}
if (sampled_area.y >= extents.y &&
sampled_area.y + (int) sampled_area.height <= extents.y + (int) extents.height)
{
/* source is vertically contained within extents, trim */
extents.y = sampled_area.y;
extents.height = sampled_area.height;
trim |= 0x2;
}
if (trim == 0x3) {
/* source is wholly contained within extents, drop the REPEAT */
attr->extend = CAIRO_EXTEND_NONE;
}
is_empty = extents.width == 0 || extents.height == 0;
}
if (sampled_area.y >= extents.y &&
sampled_area.y + (int) sampled_area.height <= extents.y + (int) extents.height)
{
/* source is vertically contained within extents, trim */
extents.y = sampled_area.y;
extents.height = sampled_area.height;
trim |= 0x2;
}
if (trim == 0x3) {
/* source is wholly contained within extents, drop the REPEAT */
attr->extend = CAIRO_EXTEND_NONE;
}
is_empty = extents.width == 0 || extents.height == 0;
}
/* XXX can we use is_empty? */
@ -2237,7 +2234,7 @@ _cairo_pattern_acquire_surface (const cairo_pattern_t *pattern,
{
cairo_status_t status;
if (pattern->status) {
if (unlikely (pattern->status)) {
*surface_out = NULL;
return pattern->status;
}
@ -2371,9 +2368,9 @@ _cairo_pattern_acquire_surfaces (const cairo_pattern_t *src,
cairo_int_status_t status;
cairo_pattern_union_t src_tmp;
if (src->status)
if (unlikely (src->status))
return src->status;
if (mask && mask->status)
if (unlikely (mask != NULL && mask->status))
return mask->status;
/* If src and mask are both solid, then the mask alpha can be
@ -2441,7 +2438,7 @@ _cairo_pattern_acquire_surfaces (const cairo_pattern_t *src,
* "infinite" extents, though it would be possible to optimize these
* with a little more work.
**/
cairo_status_t
void
_cairo_pattern_get_extents (const cairo_pattern_t *pattern,
cairo_rectangle_int_t *extents)
{
@ -2457,11 +2454,8 @@ _cairo_pattern_get_extents (const cairo_pattern_t *pattern,
double x1, y1, x2, y2;
double pad;
status = _cairo_surface_get_extents (surface, &surface_extents);
if (status == CAIRO_INT_STATUS_UNSUPPORTED)
if (! _cairo_surface_get_extents (surface, &surface_extents))
goto UNBOUNDED;
if (unlikely (status))
return status;
/* The filter can effectively enlarge the extents of the
* pattern, so extend as necessary.
@ -2497,8 +2491,7 @@ _cairo_pattern_get_extents (const cairo_pattern_t *pattern,
extents->x = x1; extents->width = x2 - x1;
extents->y = y1; extents->height = y2 - y1;
return CAIRO_STATUS_SUCCESS;
return;
}
/* XXX: We could optimize gradients with pattern->extend of NONE
@ -2508,12 +2501,7 @@ _cairo_pattern_get_extents (const cairo_pattern_t *pattern,
UNBOUNDED:
/* unbounded patterns -> 'infinite' extents */
extents->x = CAIRO_RECT_INT_MIN;
extents->y = CAIRO_RECT_INT_MIN;
extents->width = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN;
extents->height = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN;
return CAIRO_STATUS_SUCCESS;
_cairo_unbounded_rectangle_init (extents);
}
@ -2749,6 +2737,9 @@ _cairo_pattern_equal (const cairo_pattern_t *a, const cairo_pattern_t *b)
if (a->status || b->status)
return FALSE;
if (a == b)
return TRUE;
if (a->type != b->type)
return FALSE;

View file

@ -45,6 +45,7 @@
#include "cairo-pdf.h"
#include "cairo-surface-private.h"
#include "cairo-surface-clipper-private.h"
#include "cairo-pdf-operators-private.h"
#include "cairo-path-fixed-private.h"
@ -174,6 +175,8 @@ struct _cairo_pdf_surface {
cairo_bool_t is_knockout;
} group_stream;
cairo_surface_clipper_t clipper;
cairo_pdf_operators_t pdf_operators;
cairo_paginated_mode_t paginated_mode;
cairo_bool_t select_pattern_gstate_saved;

View file

@ -50,6 +50,7 @@
#include "cairo-output-stream-private.h"
#include "cairo-paginated-private.h"
#include "cairo-scaled-font-subsets-private.h"
#include "cairo-surface-clipper-private.h"
#include "cairo-type3-glyph-surface-private.h"
#include <time.h>
@ -243,6 +244,34 @@ _cairo_pdf_surface_set_size_internal (cairo_pdf_surface_t *surface,
&surface->cairo_to_pdf);
}
static cairo_status_t
_cairo_pdf_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias)
{
cairo_pdf_surface_t *surface = cairo_container_of (clipper,
cairo_pdf_surface_t,
clipper);
cairo_int_status_t status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (unlikely (status))
return status;
if (path == NULL) {
_cairo_output_stream_printf (surface->output, "Q q\n");
surface->current_pattern_is_solid_color = FALSE;
_cairo_pdf_operators_reset (&surface->pdf_operators);
return CAIRO_STATUS_SUCCESS;
}
return _cairo_pdf_operators_clip (&surface->pdf_operators, path, fill_rule);
}
static cairo_surface_t *
_cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
double width,
@ -313,6 +342,9 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
surface->current_operator = CAIRO_OPERATOR_OVER;
surface->header_emitted = FALSE;
_cairo_surface_clipper_init (&surface->clipper,
_cairo_pdf_surface_clipper_intersect_clip_path);
_cairo_pdf_operators_init (&surface->pdf_operators,
surface->output,
&surface->cairo_to_pdf,
@ -325,7 +357,6 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
surface->paginated_surface = _cairo_paginated_surface_create (
&surface->base,
CAIRO_CONTENT_COLOR_ALPHA,
width, height,
&cairo_pdf_surface_paginated_backend);
status = surface->paginated_surface->status;
@ -572,11 +603,6 @@ cairo_pdf_surface_set_size (cairo_surface_t *surface,
_cairo_pdf_surface_set_size_internal (pdf_surface,
width_in_points,
height_in_points);
status = _cairo_paginated_surface_set_size (pdf_surface->paginated_surface,
width_in_points,
height_in_points);
if (unlikely (status))
status = _cairo_surface_set_error (surface, status);
}
static void
@ -981,9 +1007,9 @@ _get_jpx_image_info (cairo_surface_t *source,
static cairo_int_status_t
_get_jpeg_image_info (cairo_surface_t *source,
cairo_image_info_t *info,
const unsigned char **mime_data,
unsigned int *mime_data_length)
cairo_image_info_t *info,
const unsigned char **mime_data,
unsigned int *mime_data_length)
{
cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG,
mime_data, mime_data_length);
@ -998,52 +1024,48 @@ _get_source_surface_size (cairo_surface_t *source,
int *width,
int *height)
{
cairo_image_surface_t *image;
void *image_extra;
cairo_status_t status;
cairo_rectangle_int_t extents;
cairo_image_info_t info;
const unsigned char *mime_data;
unsigned int mime_data_length;
if (_cairo_surface_is_meta (source)) {
cairo_rectangle_int_t extents;
cairo_meta_surface_t *meta_surface = (cairo_meta_surface_t *) source;
cairo_box_t bbox;
status = _cairo_surface_get_extents (source, &extents);
status = _cairo_meta_surface_get_bbox (meta_surface, &bbox, NULL);
if (unlikely (status))
return status;
_cairo_box_round_to_rectangle (&bbox, &extents);
*width = extents.width;
*height = extents.height;
return status;
return CAIRO_STATUS_SUCCESS;
}
status = _get_jpx_image_info (source, &info, &mime_data, &mime_data_length);
if (status == CAIRO_STATUS_SUCCESS) {
if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
*width = info.width;
*height = info.height;
} else if (_cairo_status_is_error (status)) {
return status;
}
status = _get_jpeg_image_info (source, &info, &mime_data, &mime_data_length);
if (status == CAIRO_STATUS_SUCCESS) {
if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
*width = info.width;
*height = info.height;
} else if (_cairo_status_is_error (status)) {
return status;
}
status = _cairo_surface_acquire_source_image (source, &image, &image_extra);
if (unlikely (status))
return status;
if (! _cairo_surface_get_extents (source, &extents))
return CAIRO_INT_STATUS_UNSUPPORTED;
*width = image->width;
*height = image->height;
*width = extents.width;
*height = extents.height;
_cairo_surface_release_source_image (source, image, image_extra);
return status;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
@ -1123,7 +1145,7 @@ _cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface,
static cairo_status_t
_cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface,
const cairo_pattern_t *pattern,
cairo_rectangle_int_t *extents,
cairo_clip_t *clip,
cairo_pdf_resource_t *pattern_res,
cairo_pdf_resource_t *gstate_res)
{
@ -1182,8 +1204,8 @@ _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface,
pdf_pattern.width = surface->width;
pdf_pattern.height = surface->height;
if (extents) {
pdf_pattern.extents = *extents;
if (clip != NULL) {
pdf_pattern.extents = clip->path->extents;
} else {
pdf_pattern.extents.x = 0;
pdf_pattern.extents.y = 0;
@ -1540,15 +1562,6 @@ _cairo_pdf_surface_close_content_stream (cairo_pdf_surface_t *surface)
return _cairo_output_stream_get_status (surface->output);
}
static cairo_surface_t *
_cairo_pdf_surface_create_similar (void *abstract_surface,
cairo_content_t content,
int width,
int height)
{
return cairo_meta_surface_create (content, width, height);
}
static void
_cairo_pdf_source_surface_entry_pluck (void *entry, void *closure)
{
@ -1653,6 +1666,8 @@ _cairo_pdf_surface_finish (void *abstract_surface)
surface->font_subsets = NULL;
}
_cairo_surface_clipper_reset (&surface->clipper);
return status;
}
@ -2090,7 +2105,7 @@ _cairo_pdf_surface_emit_padded_image_surface (cairo_pdf_surface_t *surface,
return status;
pad_image = &image->base;
if (cairo_pattern_get_extend (&pattern->base) == CAIRO_EXTEND_PAD) {
if (pattern->base.extend == CAIRO_EXTEND_PAD) {
cairo_box_t box;
cairo_rectangle_int_t rect;
cairo_surface_pattern_t pad_pattern;
@ -2121,7 +2136,8 @@ _cairo_pdf_surface_emit_padded_image_surface (cairo_pdf_surface_t *surface,
0, 0,
0, 0,
rect.width,
rect.height);
rect.height,
NULL);
_cairo_pattern_fini (&pad_pattern.base);
if (unlikely (status))
goto BAIL;
@ -2173,19 +2189,18 @@ _cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t *surface,
{
double old_width, old_height;
cairo_paginated_mode_t old_paginated_mode;
cairo_clip_t *old_clip;
cairo_rectangle_int_t meta_extents;
cairo_bool_t is_bounded;
cairo_status_t status;
int alpha = 0;
status = _cairo_surface_get_extents (meta_surface, &meta_extents);
if (unlikely (status))
return status;
is_bounded = _cairo_surface_get_extents (meta_surface, &meta_extents);
assert (is_bounded);
old_width = surface->width;
old_height = surface->height;
old_paginated_mode = surface->paginated_mode;
old_clip = _cairo_surface_get_clip (&surface->base);
_cairo_pdf_surface_set_size_internal (surface,
meta_extents.width,
meta_extents.height);
@ -2217,10 +2232,6 @@ _cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t *surface,
if (unlikely (status))
return status;
status = _cairo_surface_set_clip (&surface->base, old_clip);
if (unlikely (status))
return status;
status = _cairo_pdf_surface_close_content_stream (surface);
_cairo_pdf_surface_set_size_internal (surface,
@ -2264,7 +2275,7 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface,
int bbox_x, bbox_y;
char draw_surface[200];
if (cairo_pattern_get_extend (&pattern->base) == CAIRO_EXTEND_PAD &&
if (pattern->base.extend == CAIRO_EXTEND_PAD &&
! _cairo_surface_is_meta (pattern->surface))
{
status = _cairo_pdf_surface_emit_padded_image_surface (surface,
@ -3249,7 +3260,7 @@ _cairo_pdf_surface_select_operator (cairo_pdf_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->output,
@ -3405,7 +3416,7 @@ _cairo_pdf_surface_show_page (void *abstract_surface)
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
static cairo_bool_t
_cairo_pdf_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
@ -3421,32 +3432,7 @@ _cairo_pdf_surface_get_extents (void *abstract_surface,
rectangle->width = (int) ceil (surface->width);
rectangle->height = (int) ceil (surface->height);
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_pdf_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_pdf_surface_t *surface = abstract_surface;
cairo_int_status_t status;
if (path == NULL) {
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->output, "Q q\n");
surface->current_pattern_is_solid_color = FALSE;
_cairo_pdf_operators_reset (&surface->pdf_operators);
return CAIRO_STATUS_SUCCESS;
}
return _cairo_pdf_operators_clip (&surface->pdf_operators, path, fill_rule);
return TRUE;
}
static void
@ -5227,7 +5213,7 @@ static cairo_int_status_t
_cairo_pdf_surface_paint (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_pdf_surface_t *surface = abstract_surface;
cairo_status_t status;
@ -5244,17 +5230,21 @@ _cairo_pdf_surface_paint (void *abstract_surface,
assert (_cairo_pdf_surface_operation_supported (surface, op, source));
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status))
return status;
pattern_res.id = 0;
gstate_res.id = 0;
status = _cairo_pdf_surface_add_pdf_pattern (surface, source, extents,
status = _cairo_pdf_surface_add_pdf_pattern (surface, source, clip,
&pattern_res, &gstate_res);
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
return CAIRO_STATUS_SUCCESS;
if (unlikely (status))
return status;
status = _cairo_pdf_surface_select_operator (surface, op);
if (status)
if (unlikely (status))
return status;
if (gstate_res.id != 0) {
@ -5292,7 +5282,8 @@ _cairo_pdf_surface_paint (void *abstract_surface,
gstate_res.id,
group->group_res.id);
} else {
status = _cairo_pdf_surface_select_pattern (surface, source, pattern_res, FALSE);
status = _cairo_pdf_surface_select_pattern (surface, source,
pattern_res, FALSE);
if (unlikely (status))
return status;
@ -5313,7 +5304,7 @@ _cairo_pdf_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_pdf_surface_t *surface = abstract_surface;
cairo_pdf_smask_group_t *group;
@ -5341,6 +5332,10 @@ _cairo_pdf_surface_mask (void *abstract_surface,
assert (_cairo_pdf_surface_operation_supported (surface, op, source));
assert (_cairo_pdf_surface_operation_supported (surface, op, mask));
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status))
return status;
group = _cairo_pdf_surface_create_smask_group (surface);
if (unlikely (group == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
@ -5381,7 +5376,7 @@ _cairo_pdf_surface_mask (void *abstract_surface,
return status;
status = _cairo_pdf_surface_select_operator (surface, op);
if (status)
if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->output,
@ -5402,7 +5397,7 @@ _cairo_pdf_surface_stroke (void *abstract_surface,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_pdf_surface_t *surface = abstract_surface;
cairo_status_t status;
@ -5414,17 +5409,21 @@ _cairo_pdf_surface_stroke (void *abstract_surface,
assert (_cairo_pdf_surface_operation_supported (surface, op, source));
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status))
return status;
pattern_res.id = 0;
gstate_res.id = 0;
status = _cairo_pdf_surface_add_pdf_pattern (surface, source, extents,
status = _cairo_pdf_surface_add_pdf_pattern (surface, source, clip,
&pattern_res, &gstate_res);
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
return CAIRO_STATUS_SUCCESS;
if (unlikely (status))
return status;
status = _cairo_pdf_surface_select_operator (surface, op);
if (status)
if (unlikely (status))
return status;
if (gstate_res.id != 0) {
@ -5499,7 +5498,7 @@ _cairo_pdf_surface_fill (void *abstract_surface,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_pdf_surface_t *surface = abstract_surface;
cairo_status_t status;
@ -5516,17 +5515,21 @@ _cairo_pdf_surface_fill (void *abstract_surface,
assert (_cairo_pdf_surface_operation_supported (surface, op, source));
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status))
return status;
pattern_res.id = 0;
gstate_res.id = 0;
status = _cairo_pdf_surface_add_pdf_pattern (surface, source, extents,
status = _cairo_pdf_surface_add_pdf_pattern (surface, source, clip,
&pattern_res, &gstate_res);
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
return CAIRO_STATUS_SUCCESS;
if (unlikely (status))
return status;
status = _cairo_pdf_surface_select_operator (surface, op);
if (status)
if (unlikely (status))
return status;
if (gstate_res.id != 0) {
@ -5604,7 +5607,7 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface,
cairo_matrix_t *stroke_ctm_inverse,
double stroke_tolerance,
cairo_antialias_t stroke_antialias,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_pdf_surface_t *surface = abstract_surface;
cairo_status_t status;
@ -5632,14 +5635,18 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface,
if (fill_op != stroke_op)
return CAIRO_INT_STATUS_UNSUPPORTED;
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status))
return status;
status = _cairo_pdf_surface_select_operator (surface, fill_op);
if (status)
if (unlikely (status))
return status;
fill_pattern_res.id = 0;
gstate_res.id = 0;
status = _cairo_pdf_surface_add_pdf_pattern (surface, fill_source,
extents,
clip,
&fill_pattern_res,
&gstate_res);
if (unlikely (status))
@ -5651,7 +5658,7 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface,
gstate_res.id = 0;
status = _cairo_pdf_surface_add_pdf_pattern (surface,
stroke_source,
extents,
clip,
&stroke_pattern_res,
&gstate_res);
if (unlikely (status))
@ -5705,7 +5712,7 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_scaled_font_t *scaled_font,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_pdf_surface_t *surface = abstract_surface;
cairo_status_t status;
@ -5717,17 +5724,21 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface,
assert (_cairo_pdf_surface_operation_supported (surface, op, source));
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status))
return status;
pattern_res.id = 0;
gstate_res.id = 0;
status = _cairo_pdf_surface_add_pdf_pattern (surface, source, extents,
status = _cairo_pdf_surface_add_pdf_pattern (surface, source, clip,
&pattern_res, &gstate_res);
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
return CAIRO_STATUS_SUCCESS;
if (unlikely (status))
return status;
status = _cairo_pdf_surface_select_operator (surface, op);
if (status)
if (unlikely (status))
return status;
if (gstate_res.id != 0) {
@ -5840,7 +5851,7 @@ _cairo_pdf_surface_set_paginated_mode (void *abstract_surface,
static const cairo_surface_backend_t cairo_pdf_surface_backend = {
CAIRO_SURFACE_TYPE_PDF,
_cairo_pdf_surface_create_similar,
NULL, /* create similar: handled by wrapper */
_cairo_pdf_surface_finish,
NULL, /* acquire_source_image */
NULL, /* release_source_image */
@ -5854,8 +5865,6 @@ static const cairo_surface_backend_t cairo_pdf_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* _cairo_pdf_surface_copy_page */
_cairo_pdf_surface_show_page,
NULL, /* set_clip_region */
_cairo_pdf_surface_intersect_clip_path,
_cairo_pdf_surface_get_extents,
NULL, /* old_show_glyphs */
_cairo_pdf_surface_get_font_options,
@ -5874,7 +5883,6 @@ static const cairo_surface_backend_t cairo_pdf_surface_backend = {
NULL, /* snapshot */
NULL, /* is_compatible */
NULL, /* reset */
_cairo_pdf_surface_fill_stroke,
NULL, /* create_solid_pattern_surface */
NULL, /* can_repaint_solid_pattern_surface */

View file

@ -44,6 +44,7 @@
#include "cairo-ps.h"
#include "cairo-surface-private.h"
#include "cairo-surface-clipper-private.h"
#include "cairo-pdf-operators-private.h"
#include <time.h>
@ -65,6 +66,7 @@ typedef struct cairo_ps_surface {
cairo_content_t content;
double width;
double height;
cairo_rectangle_int_t page_bbox;
int bbox_x1, bbox_y1, bbox_x2, bbox_y2;
cairo_matrix_t cairo_to_ps;
@ -97,6 +99,8 @@ typedef struct cairo_ps_surface {
cairo_ps_level_t ps_level;
cairo_ps_level_t ps_level_used;
cairo_surface_clipper_t clipper;
cairo_pdf_operators_t pdf_operators;
cairo_surface_t *paginated_surface;
} cairo_ps_surface_t;

View file

@ -61,6 +61,7 @@
#include "cairo-scaled-font-subsets-private.h"
#include "cairo-paginated-private.h"
#include "cairo-meta-surface-private.h"
#include "cairo-surface-clipper-private.h"
#include "cairo-output-stream-private.h"
#include "cairo-type3-glyph-surface-private.h"
#include "cairo-image-info-private.h"
@ -73,6 +74,13 @@
#define DEBUG_PS 0
#if DEBUG_PS
#define DEBUG_FALLBACK(s) \
fprintf (stderr, "%s::%d -- %s\n", __FUNCTION__, __LINE__, (s))
#else
#define DEBUG_FALLBACK(s)
#endif
#ifndef HAVE_CTIME_R
#define ctime_r(T, BUF) ctime (T)
#endif
@ -700,6 +708,74 @@ _cairo_ps_surface_emit_footer (cairo_ps_surface_t *surface)
"%%%%EOF\n");
}
static cairo_bool_t
_path_covers_bbox (cairo_ps_surface_t *surface,
cairo_path_fixed_t *path)
{
cairo_box_t box;
if (_cairo_path_fixed_is_rectangle (path, &box)) {
cairo_rectangle_int_t rect;
_cairo_box_round_to_rectangle (&box, &rect);
/* skip trivial whole-page clips */
if (_cairo_rectangle_intersect (&rect, &surface->page_bbox)) {
if (rect.x == surface->page_bbox.x &&
rect.width == surface->page_bbox.width &&
rect.y == surface->page_bbox.y &&
rect.height == surface->page_bbox.height)
{
return TRUE;
}
}
}
return FALSE;
}
static cairo_status_t
_cairo_ps_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias)
{
cairo_ps_surface_t *surface = cairo_container_of (clipper,
cairo_ps_surface_t,
clipper);
cairo_output_stream_t *stream = surface->stream;
cairo_status_t status;
assert (surface->paginated_mode != CAIRO_PAGINATED_MODE_ANALYZE);
#if DEBUG_PS
_cairo_output_stream_printf (stream,
"%% _cairo_ps_surface_intersect_clip_path\n");
#endif
if (path == NULL) {
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (unlikely (status))
return status;
_cairo_output_stream_printf (stream, "Q q\n");
surface->current_pattern_is_solid_color = FALSE;
_cairo_pdf_operators_reset (&surface->pdf_operators);
return CAIRO_STATUS_SUCCESS;
}
if (_path_covers_bbox (surface, path))
return CAIRO_STATUS_SUCCESS;
return _cairo_pdf_operators_clip (&surface->pdf_operators,
path,
fill_rule);
}
static cairo_surface_t *
_cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
double width,
@ -756,6 +832,9 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
surface->use_string_datasource = FALSE;
surface->current_pattern_is_solid_color = FALSE;
_cairo_surface_clipper_init (&surface->clipper,
_cairo_ps_surface_clipper_intersect_clip_path);
_cairo_pdf_operators_init (&surface->pdf_operators,
surface->stream,
&surface->cairo_to_ps,
@ -771,7 +850,6 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
surface->paginated_surface = _cairo_paginated_surface_create (
&surface->base,
CAIRO_CONTENT_COLOR_ALPHA,
width, height,
&cairo_ps_surface_paginated_backend);
status = surface->paginated_surface->status;
if (status == CAIRO_STATUS_SUCCESS) {
@ -1083,11 +1161,6 @@ cairo_ps_surface_set_size (cairo_surface_t *surface,
cairo_matrix_init (&ps_surface->cairo_to_ps, 1, 0, 0, -1, 0, height_in_points);
_cairo_pdf_operators_set_cairo_to_pdf_matrix (&ps_surface->pdf_operators,
&ps_surface->cairo_to_ps);
status = _cairo_paginated_surface_set_size (ps_surface->paginated_surface,
width_in_points,
height_in_points);
if (unlikely (status))
status = _cairo_surface_set_error (surface, status);
}
/**
@ -1288,15 +1361,6 @@ cairo_ps_surface_dsc_begin_page_setup (cairo_surface_t *surface)
}
}
static cairo_surface_t *
_cairo_ps_surface_create_similar (void *abstract_surface,
cairo_content_t content,
int width,
int height)
{
return cairo_meta_surface_create (content, width, height);
}
static cairo_status_t
_cairo_ps_surface_finish (void *abstract_surface)
{
@ -1346,6 +1410,8 @@ CLEANUP:
free (comments[i]);
_cairo_array_fini (&surface->dsc_page_setup_comments);
_cairo_surface_clipper_reset (&surface->clipper);
return status;
}
@ -1369,8 +1435,11 @@ _cairo_ps_surface_end_page (cairo_ps_surface_t *surface)
if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->stream,
"Q\n");
if (surface->clipper.clip.path != NULL) {
_cairo_output_stream_printf (surface->stream, "Q Q\n");
_cairo_surface_clipper_reset (&surface->clipper);
} else
_cairo_output_stream_printf (surface->stream, "Q\n");
return CAIRO_STATUS_SUCCESS;
}
@ -1448,8 +1517,6 @@ _cairo_ps_surface_analyze_surface_pattern_transparency (cairo_ps_surface_t
static cairo_bool_t
surface_pattern_supported (const cairo_surface_pattern_t *pattern)
{
cairo_extend_t extend;
if (_cairo_surface_is_meta (pattern->surface))
return TRUE;
@ -1465,24 +1532,7 @@ surface_pattern_supported (const cairo_surface_pattern_t *pattern)
return FALSE;
*/
/* Cast away the const, trusting get_extend not to muck with it.
* And I really wish I had a way to cast away just the const, and
* not potentially coerce this pointer to an incorrect type at the
* same time. :-(
*/
extend = cairo_pattern_get_extend ((cairo_pattern_t*)&pattern->base);
switch (extend) {
case CAIRO_EXTEND_NONE:
case CAIRO_EXTEND_REPEAT:
case CAIRO_EXTEND_REFLECT:
/* There's no point returning FALSE for EXTEND_PAD, as the image
* surface does not currently implement it either */
case CAIRO_EXTEND_PAD:
return TRUE;
}
ASSERT_NOT_REACHED;
return FALSE;
return TRUE;
}
static cairo_bool_t
@ -1567,10 +1617,11 @@ _cairo_ps_surface_analyze_operation (cairo_ps_surface_t *surface,
}
if (! pattern_supported (surface, pattern))
{
return CAIRO_INT_STATUS_UNSUPPORTED;
}
if (!(op == CAIRO_OPERATOR_SOURCE ||
op == CAIRO_OPERATOR_OVER))
if (! (op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_OVER))
return CAIRO_INT_STATUS_UNSUPPORTED;
if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
@ -1596,7 +1647,6 @@ _cairo_ps_surface_analyze_operation (cairo_ps_surface_t *surface,
* render stage and we blend the transparency into the white
* background to convert the pattern to opaque.
*/
if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
@ -1606,8 +1656,8 @@ _cairo_ps_surface_analyze_operation (cairo_ps_surface_t *surface,
if (_cairo_pattern_is_opaque (pattern))
return CAIRO_STATUS_SUCCESS;
else
return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
}
static cairo_bool_t
@ -1824,7 +1874,8 @@ _cairo_ps_surface_flatten_image_transparency (cairo_ps_surface_t *surface,
0, 0,
0, 0,
image->width,
image->height);
image->height,
NULL);
if (unlikely (status))
goto fail;
@ -2109,6 +2160,7 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
data_compressed,
data_compressed_size,
FALSE);
_cairo_output_stream_printf (surface->stream, "\n");
} else {
status = CAIRO_STATUS_SUCCESS;
}
@ -2221,31 +2273,31 @@ _cairo_ps_surface_emit_meta_surface (cairo_ps_surface_t *surface,
double old_width, old_height;
cairo_matrix_t old_cairo_to_ps;
cairo_content_t old_content;
cairo_clip_t *old_clip;
cairo_rectangle_int_t meta_extents;
cairo_box_t bbox;
cairo_status_t status;
status = _cairo_surface_get_extents (meta_surface, &meta_extents);
if (unlikely (status))
return status;
old_content = surface->content;
old_width = surface->width;
old_height = surface->height;
old_cairo_to_ps = surface->cairo_to_ps;
old_clip = _cairo_surface_get_clip (&surface->base);
surface->width = meta_extents.width;
surface->height = meta_extents.height;
status =
_cairo_meta_surface_get_bbox ((cairo_meta_surface_t *) meta_surface,
&bbox,
NULL);
if (unlikely (status))
return status;
/* XXX is this still necessary? */
surface->width = _cairo_fixed_to_double (bbox.p2.x - bbox.p1.x);
surface->height = _cairo_fixed_to_double (bbox.p2.y - bbox.p1.y);
surface->current_pattern_is_solid_color = FALSE;
_cairo_pdf_operators_reset (&surface->pdf_operators);
cairo_matrix_init (&surface->cairo_to_ps, 1, 0, 0, -1, 0, surface->height);
_cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
&surface->cairo_to_ps);
_cairo_output_stream_printf (surface->stream,
" q\n"
" 0 0 %f %f rectclip\n",
surface->width,
surface->height);
_cairo_output_stream_printf (surface->stream, " q\n");
if (cairo_surface_get_content (meta_surface) == CAIRO_CONTENT_COLOR) {
surface->content = CAIRO_CONTENT_COLOR;
@ -2265,17 +2317,13 @@ _cairo_ps_surface_emit_meta_surface (cairo_ps_surface_t *surface,
if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->stream,
" Q\n");
_cairo_output_stream_printf (surface->stream, " Q\n");
surface->content = old_content;
surface->width = old_width;
surface->height = old_height;
surface->current_pattern_is_solid_color = FALSE;
_cairo_pdf_operators_reset (&surface->pdf_operators);
surface->cairo_to_ps = old_cairo_to_ps;
status = _cairo_surface_set_clip (&surface->base, old_clip);
if (unlikely (status))
return status;
_cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
&surface->cairo_to_ps);
@ -2331,11 +2379,11 @@ _cairo_ps_surface_acquire_surface (cairo_ps_surface_t *surface,
cairo_rectangle_int_t *extents,
int *width,
int *height,
int *origin_x,
int *origin_y)
int *origin_x,
int *origin_y)
{
cairo_status_t status;
cairo_surface_t *pad_image;
cairo_surface_t *pad_image;
int x = 0;
int y = 0;
@ -2343,15 +2391,18 @@ _cairo_ps_surface_acquire_surface (cairo_ps_surface_t *surface,
surface->image = NULL;
if (_cairo_surface_is_meta (pattern->surface)) {
cairo_surface_t *meta_surface = pattern->surface;
cairo_rectangle_int_t pattern_extents;
cairo_meta_surface_t *meta_surface = (cairo_meta_surface_t *) pattern->surface;
cairo_box_t bbox;
cairo_rectangle_int_t extents;
status = _cairo_surface_get_extents (meta_surface, &pattern_extents);
status = _cairo_meta_surface_get_bbox (meta_surface, &bbox, NULL);
if (unlikely (status))
return status;
*width = pattern_extents.width;
*height = pattern_extents.height;
_cairo_box_round_to_rectangle (&bbox, &extents);
*width = extents.width;
*height =extents.height;
return CAIRO_STATUS_SUCCESS;
} else {
status = _cairo_surface_acquire_source_image (pattern->surface,
&surface->acquired_image,
@ -2391,7 +2442,8 @@ _cairo_ps_surface_acquire_surface (cairo_ps_surface_t *surface,
0, 0,
0, 0,
rect.width,
rect.height);
rect.height,
NULL);
_cairo_pattern_fini (&pad_pattern.base);
if (unlikely (status)) {
if (pad_image != &surface->acquired_image->base)
@ -2406,13 +2458,11 @@ _cairo_ps_surface_acquire_surface (cairo_ps_surface_t *surface,
*height = surface->image->height;
*origin_x = x;
*origin_y = y;
return CAIRO_STATUS_SUCCESS;
}
return CAIRO_STATUS_SUCCESS;
BAIL:
_cairo_ps_surface_release_surface (surface, pattern);
return status;
}
@ -2428,10 +2478,9 @@ _cairo_ps_surface_emit_surface (cairo_ps_surface_t *surface,
if (_cairo_surface_is_meta (pattern->surface)) {
cairo_surface_t *meta_surface = pattern->surface;
status = _cairo_ps_surface_emit_meta_surface (surface,
meta_surface);
status = _cairo_ps_surface_emit_meta_surface (surface, meta_surface);
} else {
if (cairo_pattern_get_extend (&pattern->base) != CAIRO_EXTEND_PAD) {
if (pattern->base.extend != CAIRO_EXTEND_PAD) {
status = _cairo_ps_surface_emit_jpeg_image (surface, pattern->surface,
width, height);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
@ -2540,7 +2589,6 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
int pattern_height = 0; /* squelch bogus compiler warning */
double xstep, ystep;
cairo_matrix_t cairo_p2d, ps_p2d;
cairo_rectangle_int_t surface_extents;
cairo_bool_t old_use_string_datasource;
int origin_x = 0;
int origin_y = 0;
@ -2550,12 +2598,6 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
/* cairo_pattern_set_matrix ensures the matrix is invertible */
assert (status == CAIRO_STATUS_SUCCESS);
ps_p2d = surface->cairo_to_ps;
cairo_matrix_multiply (&ps_p2d, &cairo_p2d, &ps_p2d);
cairo_matrix_translate (&ps_p2d, -origin_x, -origin_y);
cairo_matrix_translate (&ps_p2d, 0.0, pattern_height);
cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
status = _cairo_ps_surface_acquire_surface (surface,
pattern,
extents,
@ -2669,17 +2711,13 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
_cairo_output_stream_printf (surface->stream,
">>\n");
status = _cairo_surface_get_extents (&surface->base, &surface_extents);
if (unlikely (status))
return status;
cairo_p2d = pattern->base.matrix;
status = cairo_matrix_invert (&cairo_p2d);
/* cairo_pattern_set_matrix ensures the matrix is invertible */
assert (status == CAIRO_STATUS_SUCCESS);
cairo_matrix_init_identity (&ps_p2d);
cairo_matrix_translate (&ps_p2d, 0.0, surface_extents.height);
cairo_matrix_translate (&ps_p2d, 0.0, surface->height);
cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
cairo_matrix_multiply (&ps_p2d, &cairo_p2d, &ps_p2d);
cairo_matrix_translate (&ps_p2d, 0.0, pattern_height);
@ -3163,43 +3201,7 @@ _cairo_ps_surface_emit_pattern (cairo_ps_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_ps_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_ps_surface_t *surface = abstract_surface;
cairo_output_stream_t *stream = surface->stream;
cairo_status_t status;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return CAIRO_STATUS_SUCCESS;
#if DEBUG_PS
_cairo_output_stream_printf (stream,
"%% _cairo_ps_surface_intersect_clip_path\n");
#endif
if (path == NULL) {
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (unlikely (status))
return status;
_cairo_output_stream_printf (stream, "Q q\n");
surface->current_pattern_is_solid_color = FALSE;
_cairo_pdf_operators_reset (&surface->pdf_operators);
return CAIRO_STATUS_SUCCESS;
}
return _cairo_pdf_operators_clip (&surface->pdf_operators,
path,
fill_rule);
}
static cairo_int_status_t
static cairo_bool_t
_cairo_ps_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
@ -3215,7 +3217,7 @@ _cairo_ps_surface_get_extents (void *abstract_surface,
rectangle->width = (int) ceil (surface->width);
rectangle->height = (int) ceil (surface->height);
return CAIRO_STATUS_SUCCESS;
return TRUE;
}
static void
@ -3229,11 +3231,26 @@ _cairo_ps_surface_get_font_options (void *abstract_surface,
cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_GRAY);
}
static cairo_bool_t
_rectangle_intersect_clip (cairo_rectangle_int_t *extents, cairo_clip_t *clip)
{
const cairo_rectangle_int_t *clip_extents;
clip_extents = NULL;
if (clip != NULL)
clip_extents = _cairo_clip_get_extents (clip);
if (clip_extents != NULL)
return _cairo_rectangle_intersect (extents, clip_extents);
return TRUE;
}
static cairo_int_status_t
_cairo_ps_surface_paint (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_rectangle_int_t *paint_extents)
cairo_clip_t *clip)
{
cairo_ps_surface_t *surface = abstract_surface;
cairo_output_stream_t *stream = surface->stream;
@ -3250,11 +3267,11 @@ _cairo_ps_surface_paint (void *abstract_surface,
"%% _cairo_ps_surface_paint\n");
#endif
status = _cairo_surface_get_extents (&surface->base, &extents);
if (unlikely (status))
return status;
extents = surface->page_bbox;
if (! _rectangle_intersect_clip (&extents, clip))
return CAIRO_STATUS_SUCCESS;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status))
return status;
@ -3262,28 +3279,25 @@ _cairo_ps_surface_paint (void *abstract_surface,
(source->extend == CAIRO_EXTEND_NONE ||
source->extend == CAIRO_EXTEND_PAD))
{
_cairo_output_stream_printf (stream, "q 0 0 %d %d rectclip\n",
extents.width,
extents.height);
_cairo_output_stream_printf (stream, "q\n");
status = _cairo_ps_surface_paint_surface (surface,
(cairo_surface_pattern_t *) source,
paint_extents, op);
&extents, op);
if (unlikely (status))
return status;
_cairo_output_stream_printf (stream, "Q\n");
} else {
status = _cairo_ps_surface_emit_pattern (surface, source, paint_extents, op);
status = _cairo_ps_surface_emit_pattern (surface, source, &extents, op);
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
return CAIRO_STATUS_SUCCESS;
if (unlikely (status))
return status;
_cairo_output_stream_printf (stream, "0 0 %d %d rectfill\n",
extents.width,
extents.height);
_cairo_output_stream_printf (stream, "%d %d %d %d rectfill\n",
extents.x, extents.y,
extents.width, extents.height);
}
return CAIRO_STATUS_SUCCESS;
@ -3299,10 +3313,11 @@ _cairo_ps_surface_stroke (void *abstract_surface,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_ps_surface_t *surface = abstract_surface;
cairo_int_status_t status;
cairo_rectangle_int_t extents;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return _cairo_ps_surface_analyze_operation (surface, op, source);
@ -3314,7 +3329,15 @@ _cairo_ps_surface_stroke (void *abstract_surface,
"%% _cairo_ps_surface_stroke\n");
#endif
status = _cairo_ps_surface_emit_pattern (surface, source, extents, op);
extents = surface->page_bbox;
if (! _rectangle_intersect_clip (&extents, clip))
return CAIRO_STATUS_SUCCESS;
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status))
return status;
status = _cairo_ps_surface_emit_pattern (surface, source, &extents, op);
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
return CAIRO_STATUS_SUCCESS;
@ -3336,10 +3359,11 @@ _cairo_ps_surface_fill (void *abstract_surface,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_ps_surface_t *surface = abstract_surface;
cairo_int_status_t status;
cairo_rectangle_int_t extents;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return _cairo_ps_surface_analyze_operation (surface, op, source);
@ -3351,14 +3375,22 @@ _cairo_ps_surface_fill (void *abstract_surface,
"%% _cairo_ps_surface_fill\n");
#endif
extents = surface->page_bbox;
if (! _rectangle_intersect_clip (&extents, clip))
return CAIRO_STATUS_SUCCESS;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (unlikely (status))
return status;
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status))
return status;
if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
(source->extend == CAIRO_EXTEND_NONE ||
source->extend == CAIRO_EXTEND_PAD))
{
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->stream, "q\n");
status = _cairo_pdf_operators_clip (&surface->pdf_operators,
@ -3369,14 +3401,14 @@ _cairo_ps_surface_fill (void *abstract_surface,
status = _cairo_ps_surface_paint_surface (surface,
(cairo_surface_pattern_t *) source,
extents, op);
&extents, op);
if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->stream, "Q\n");
_cairo_pdf_operators_reset (&surface->pdf_operators);
} else {
status = _cairo_ps_surface_emit_pattern (surface, source, extents, op);
status = _cairo_ps_surface_emit_pattern (surface, source, &extents, op);
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
return CAIRO_STATUS_SUCCESS;
@ -3398,11 +3430,12 @@ _cairo_ps_surface_show_glyphs (void *abstract_surface,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip,
int *remaining_glyphs)
{
cairo_ps_surface_t *surface = abstract_surface;
cairo_status_t status;
cairo_rectangle_int_t extents;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return _cairo_ps_surface_analyze_operation (surface, op, source);
@ -3417,7 +3450,15 @@ _cairo_ps_surface_show_glyphs (void *abstract_surface,
if (num_glyphs <= 0)
return CAIRO_STATUS_SUCCESS;
status = _cairo_ps_surface_emit_pattern (surface, source, extents, op);
extents = surface->page_bbox;
if (! _rectangle_intersect_clip (&extents, clip))
return CAIRO_STATUS_SUCCESS;
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status))
return status;
status = _cairo_ps_surface_emit_pattern (surface, source, &extents, op);
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
return CAIRO_STATUS_SUCCESS;
@ -3439,6 +3480,11 @@ _cairo_ps_surface_set_paginated_mode (void *abstract_surface,
cairo_ps_surface_t *surface = abstract_surface;
surface->paginated_mode = paginated_mode;
if (surface->clipper.clip.path != NULL) {
_cairo_output_stream_printf (surface->stream, "Q\n");
_cairo_surface_clipper_reset (&surface->clipper);
}
}
static cairo_int_status_t
@ -3462,6 +3508,11 @@ _cairo_ps_surface_set_bounding_box (void *abstract_surface,
y2 = (int) ceil (surface->height);
}
surface->page_bbox.x = x1;
surface->page_bbox.y = y1;
surface->page_bbox.width = x2 - x1;
surface->page_bbox.height = y2 - y1;
_cairo_output_stream_printf (surface->stream,
"%%%%Page: %d %d\n",
surface->num_pages,
@ -3486,7 +3537,11 @@ _cairo_ps_surface_set_bounding_box (void *abstract_surface,
_cairo_output_stream_printf (surface->stream,
"%%%%EndPageSetup\n"
"q\n");
"q %d %d %d %d rectclip q\n",
surface->page_bbox.x,
surface->page_bbox.y,
surface->page_bbox.width,
surface->page_bbox.height);
if (surface->num_pages == 1) {
surface->bbox_x1 = x1;
@ -3517,7 +3572,7 @@ _cairo_ps_surface_supports_fine_grained_fallbacks (void *abstract_surface)
static const cairo_surface_backend_t cairo_ps_surface_backend = {
CAIRO_SURFACE_TYPE_PS,
_cairo_ps_surface_create_similar,
NULL, /* create similar: handled by wrapper */
_cairo_ps_surface_finish,
NULL, /* acquire_source_image */
NULL, /* release_source_image */
@ -3531,8 +3586,6 @@ static const cairo_surface_backend_t cairo_ps_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* cairo_ps_surface_copy_page */
_cairo_ps_surface_show_page,
NULL, /* set_clip_region */
_cairo_ps_surface_intersect_clip_path,
_cairo_ps_surface_get_extents,
NULL, /* old_show_glyphs */
_cairo_ps_surface_get_font_options,

View file

@ -39,6 +39,9 @@
#include "cairoint.h"
#include "cairo-types-private.h"
#include "cairo-clip-private.h"
#include "cairo-surface-clipper-private.h"
#include "cairo-region-private.h"
#include "cairo-qt.h"
@ -65,6 +68,8 @@
#include <sys/time.h>
#define ENABLE_FAST_FILL 1 /* Enable workaround slow regional Qt paths */
#if 0
#define D(x) x
static const char *
@ -104,14 +109,9 @@ _opstr (cairo_operator_t op)
#define DOT_LENGTH 1.0
#define DASH_LENGTH 3.0
typedef struct {
struct cairo_qt_surface_t {
cairo_surface_t base;
bool has_clipping;
// if this is true, calls to intersect_clip_path won't
// update the clip_bounds rect
bool no_update_clip_bounds;
cairo_bool_t supports_porter_duff;
#if defined(Q_WS_X11) && CAIRO_HAS_XLIB_XRENDER_SURFACE
@ -131,11 +131,10 @@ typedef struct {
QRect window;
QRect clip_bounds;
cairo_surface_clipper_t clipper;
cairo_surface_t *image_equiv;
} cairo_qt_surface_t;
};
/* Will be true if we ever try to create a QPixmap and end
* up with one without an alpha channel.
@ -186,6 +185,21 @@ _qpainter_compositionmode_from_cairo_op (cairo_operator_t op)
default:
case CAIRO_OPERATOR_ADD:
case CAIRO_OPERATOR_SATURATE:
case CAIRO_OPERATOR_MULTIPLY:
case CAIRO_OPERATOR_SCREEN:
case CAIRO_OPERATOR_OVERLAY:
case CAIRO_OPERATOR_DARKEN:
case CAIRO_OPERATOR_LIGHTEN:
case CAIRO_OPERATOR_COLOR_DODGE:
case CAIRO_OPERATOR_COLOR_BURN:
case CAIRO_OPERATOR_HARD_LIGHT:
case CAIRO_OPERATOR_SOFT_LIGHT:
case CAIRO_OPERATOR_DIFFERENCE:
case CAIRO_OPERATOR_EXCLUSION:
case CAIRO_OPERATOR_HSL_HUE:
case CAIRO_OPERATOR_HSL_SATURATION:
case CAIRO_OPERATOR_HSL_COLOR:
case CAIRO_OPERATOR_HSL_LUMINOSITY:
ASSERT_NOT_REACHED;
}
}
@ -211,12 +225,27 @@ _op_is_supported (cairo_qt_surface_t *qs, cairo_operator_t op)
case CAIRO_OPERATOR_XOR:
return TRUE;
case CAIRO_OPERATOR_ADD:
case CAIRO_OPERATOR_SATURATE:
return FALSE;
default:
ASSERT_NOT_REACHED;
case CAIRO_OPERATOR_ADD:
case CAIRO_OPERATOR_SATURATE:
case CAIRO_OPERATOR_MULTIPLY:
case CAIRO_OPERATOR_SCREEN:
case CAIRO_OPERATOR_OVERLAY:
case CAIRO_OPERATOR_DARKEN:
case CAIRO_OPERATOR_LIGHTEN:
case CAIRO_OPERATOR_COLOR_DODGE:
case CAIRO_OPERATOR_COLOR_BURN:
case CAIRO_OPERATOR_HARD_LIGHT:
case CAIRO_OPERATOR_SOFT_LIGHT:
case CAIRO_OPERATOR_DIFFERENCE:
case CAIRO_OPERATOR_EXCLUSION:
case CAIRO_OPERATOR_HSL_HUE:
case CAIRO_OPERATOR_HSL_SATURATION:
case CAIRO_OPERATOR_HSL_COLOR:
case CAIRO_OPERATOR_HSL_LUMINOSITY:
return FALSE;
}
} else {
return op == CAIRO_OPERATOR_OVER;
@ -458,6 +487,8 @@ _cairo_qt_surface_finish (void *abstract_surface)
if (qs->image_equiv)
cairo_surface_destroy (qs->image_equiv);
_cairo_surface_clipper_reset (&qs->clipper);
#if defined(Q_WS_X11) && CAIRO_HAS_XLIB_XRENDER_SURFACE
if (qs->xlib_equiv)
cairo_surface_destroy (qs->xlib_equiv);
@ -655,7 +686,7 @@ _cairo_qt_surface_clone_similar (void *abstract_surface,
return (cairo_status_t) CAIRO_INT_STATUS_UNSUPPORTED;
}
static cairo_int_status_t
static cairo_bool_t
_cairo_qt_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *extents)
{
@ -666,25 +697,40 @@ _cairo_qt_surface_get_extents (void *abstract_surface,
extents->width = qs->window.width();
extents->height = qs->window.height();
return CAIRO_INT_STATUS_SUCCESS;
return TRUE;
}
static cairo_int_status_t
_cairo_qt_surface_intersect_clip_path (void *abstract_surface,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias)
static cairo_status_t
_cairo_qt_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias)
{
cairo_qt_surface_t *qs = (cairo_qt_surface_t *) abstract_surface;
cairo_qt_surface_t *qs = cairo_container_of (clipper,
cairo_qt_surface_t,
clipper);
QPainterPath qpath;
cairo_status_t status;
D(fprintf(stderr, "q[%p] intersect_clip_path %s\n", abstract_surface, path ? "(path)" : "(clear)"));
// XXX Antialiasing is ignored
status = _cairo_quartz_cairo_path_to_qpainterpath (path,
&qpath,
fill_rule);
if (unlikely (status))
return status;
if (!qs->p)
return CAIRO_INT_STATUS_UNSUPPORTED;
qs->p->setClipPath (qpath, Qt::IntersectClip);
return CAIRO_STATUS_SUCCESS;
}
if (path == NULL) {
//fprintf (stderr, "clip clear\n");
static void
_cairo_qt_surface_set_clip_region (cairo_qt_surface_t *qs,
cairo_region_t *clip_region)
{
_cairo_surface_clipper_reset (&qs->clipper);
if (clip_region == NULL) {
// How the clip path is reset depends on whether we own p or not
if (qs->pixmap || qs->image) {
// we own p
@ -693,10 +739,38 @@ _cairo_qt_surface_intersect_clip_path (void *abstract_surface,
qs->p->restore ();
qs->p->save ();
}
} else {
QRegion qr;
int num_rects = cairo_region_num_rectangles (clip_region);
for (int i = 0; i < num_rects; ++i) {
cairo_rectangle_int_t rect;
if (!qs->no_update_clip_bounds) {
qs->clip_bounds.setRect(0, 0, 0, 0);
qs->has_clipping = false;
cairo_region_get_rectangle (clip_region, i, &rect);
QRect r(rect.x, rect.y, rect.width, rect.height);
qr = qr.unite(r);
}
qs->p->setClipRegion (qr, Qt::IntersectClip);
}
}
static cairo_int_status_t
_cairo_qt_surface_set_clip (cairo_qt_surface_t *qs,
cairo_clip_t *clip)
{
D(fprintf(stderr, "q[%p] intersect_clip_path %s\n", abstract_surface, path ? "(path)" : "(clear)"));
if (clip == NULL) {
_cairo_surface_clipper_reset (&qs->clipper);
// How the clip path is reset depends on whether we own p or not
if (qs->pixmap || qs->image) {
// we own p
qs->p->setClipping (false);
} else {
qs->p->restore ();
qs->p->save ();
}
return CAIRO_INT_STATUS_SUCCESS;
@ -711,125 +785,21 @@ _cairo_qt_surface_intersect_clip_path (void *abstract_surface,
// we do a bunch of work here to try to get rectangles or regions
// down to Qt for clipping.
QRect clip_bounds;
cairo_region_t *clip_region = NULL;
// First check if it's an integer-aligned single rectangle
cairo_box_t box;
if (_cairo_path_fixed_is_box (path, &box) &&
_cairo_fixed_is_integer (box.p1.x) &&
_cairo_fixed_is_integer (box.p1.y) &&
_cairo_fixed_is_integer (box.p2.x) &&
_cairo_fixed_is_integer (box.p2.y))
{
QRect r(_cairo_fixed_integer_part(box.p1.x),
_cairo_fixed_integer_part(box.p1.y),
_cairo_fixed_integer_part(box.p2.x - box.p1.x),
_cairo_fixed_integer_part(box.p2.y - box.p1.y));
r = r.normalized();
clip_bounds = r;
qs->p->setClipRect (r, Qt::IntersectClip);
} else {
// Then if it's not an integer-aligned rectangle, check
// if we can extract a region (a set of rectangles) out.
// We use cairo to convert the path to traps.
cairo_traps_t traps;
cairo_int_status_t status;
cairo_region_t *region = NULL;
_cairo_traps_init (&traps);
cairo_int_status_t status;
status = _cairo_clip_get_region (clip, &clip_region);
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
// We weren't able to extract a region from the traps.
// Just hand the path down to QPainter.
status = (cairo_int_status_t)
_cairo_path_fixed_fill_to_traps (path,
fill_rule, tolerance, &traps);
if (status) {
_cairo_traps_fini (&traps);
return status;
}
status = _cairo_traps_extract_region (&traps, &region);
_cairo_traps_fini (&traps);
if (_cairo_status_is_error ((cairo_status_t) status))
return status;
if (status == CAIRO_INT_STATUS_SUCCESS) {
#if 0
cairo_box_int_t *boxes;
int n_boxes;
QRegion qr;
_cairo_region_get_boxes (&region, &n_boxes, &boxes);
for (int i = 0; i < n_boxes; i++) {
QRect r(boxes[i].p1.x,
boxes[i].p1.y,
boxes[i].p2.x - boxes[i].p1.x,
boxes[i].p2.y - boxes[i].p1.y);
if (i == 0)
clip_bounds = r;
else
clip_bounds = clip_bounds.united(r);
qr = qr.unite(r);
}
_cairo_region_boxes_fini (&region, boxes);
#else
int n_boxes;
QRegion qr;
n_boxes = cairo_region_num_rectangles (region);
for (int i = 0; i < n_boxes; ++i) {
cairo_rectangle_int_t box;
cairo_region_get_rectangle (region, i, &box);
QRect r(box.x, box.y, box.width, box.height);
if (0 == i)
clip_bounds = r;
else
clip_bounds = clip_bounds.united(r);
qr = qr.unite(r);
}
#endif
_cairo_region_fini (region);
qs->p->setClipRegion (qr, Qt::IntersectClip);
} else {
// We weren't able to extract a region from the traps.
// Just hand the path down to QPainter.
QPainterPath qpath;
cairo_status_t status;
status = _cairo_quartz_cairo_path_to_qpainterpath (path,
&qpath,
fill_rule);
assert (status == CAIRO_STATUS_SUCCESS);
clip_bounds = qpath.boundingRect().toAlignedRect();
// XXX Antialiasing is ignored
qs->p->setClipPath (qpath, Qt::IntersectClip);
}
_cairo_surface_clipper_set_clip (&qs->clipper, clip);
} else if (status == CAIRO_INT_STATUS_SUCCESS) {
_cairo_qt_surface_set_clip_region (qs, clip_region);
status = CAIRO_INT_STATUS_SUCCESS;
}
if (!qs->no_update_clip_bounds) {
clip_bounds = qs->p->worldTransform().mapRect(clip_bounds);
if (qs->has_clipping) {
qs->clip_bounds = qs->clip_bounds.intersect(clip_bounds);
} else {
qs->clip_bounds = clip_bounds;
qs->has_clipping = true;
}
}
return CAIRO_INT_STATUS_SUCCESS;
return status;
}
/**
@ -1156,10 +1126,12 @@ _cairo_qt_fast_fill (cairo_qt_surface_t *qs,
double tolerance = 0.0,
cairo_antialias_t antialias = CAIRO_ANTIALIAS_NONE)
{
#if ENABLE_FAST_FILL
QImage *qsSrc_image = NULL;
QPixmap *qsSrc_pixmap = NULL;
std::auto_ptr<QImage> qsSrc_image_d;
if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
cairo_surface_pattern_t *spattern = (cairo_surface_pattern_t*) source;
if (spattern->surface->type == CAIRO_SURFACE_TYPE_QT) {
@ -1190,7 +1162,6 @@ _cairo_qt_fast_fill (cairo_qt_surface_t *qs,
}
QMatrix sourceMatrix = _qmatrix_from_cairo_matrix (source->matrix);
cairo_int_status_t status;
// We can draw this faster by clipping and calling drawImage/drawPixmap.
// Use our own clipping function so that we can get the
@ -1201,14 +1172,29 @@ _cairo_qt_fast_fill (cairo_qt_surface_t *qs,
qs->p->save();
if (path) {
qs->no_update_clip_bounds = true;
status = _cairo_qt_surface_intersect_clip_path (qs, path, fill_rule, tolerance, antialias);
qs->no_update_clip_bounds = false;
cairo_int_status_t status;
if (status != CAIRO_INT_STATUS_SUCCESS) {
qs->p->restore();
return false;
}
cairo_clip_t clip, old_clip = qs->clipper.clip;
_cairo_clip_init_copy (&clip, &qs->clipper.clip);
status = (cairo_int_status_t) _cairo_clip_clip (&clip,
path,
fill_rule,
tolerance,
antialias);
if (unlikely (status)) {
qs->p->restore();
return false;
}
status = _cairo_qt_surface_set_clip (qs, &clip);
if (unlikely (status)) {
qs->p->restore();
return false;
}
_cairo_clip_reset (&clip);
qs->clipper.clip = old_clip;
}
qs->p->setWorldMatrix (sourceMatrix.inverted(), true);
@ -1242,16 +1228,19 @@ _cairo_qt_fast_fill (cairo_qt_surface_t *qs,
qs->p->restore();
return true;
#else
return false;
#endif
}
static cairo_int_status_t
_cairo_qt_surface_paint (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
Q_UNUSED(extents);
cairo_qt_surface_t *qs = (cairo_qt_surface_t *) abstract_surface;
cairo_int_status_t status;
D(fprintf(stderr, "q[%p] paint op:%s\n", abstract_surface, _opstr(op)));
@ -1261,6 +1250,10 @@ _cairo_qt_surface_paint (void *abstract_surface,
if (! _op_is_supported (qs, op))
return CAIRO_INT_STATUS_UNSUPPORTED;
status = _cairo_qt_surface_set_clip (qs, clip);
if (unlikely (status))
return status;
if (qs->supports_porter_duff)
qs->p->setCompositionMode (_qpainter_compositionmode_from_cairo_op (op));
@ -1283,9 +1276,8 @@ _cairo_qt_surface_fill (void *abstract_surface,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t * extents)
cairo_clip_t *clip)
{
Q_UNUSED(extents);
cairo_qt_surface_t *qs = (cairo_qt_surface_t *) abstract_surface;
D(fprintf(stderr, "q[%p] fill op:%s\n", abstract_surface, _opstr(op)));
@ -1296,6 +1288,10 @@ _cairo_qt_surface_fill (void *abstract_surface,
if (! _op_is_supported (qs, op))
return CAIRO_INT_STATUS_UNSUPPORTED;
cairo_int_status_t status = _cairo_qt_surface_set_clip (qs, clip);
if (unlikely (status))
return status;
if (qs->supports_porter_duff)
qs->p->setCompositionMode (_qpainter_compositionmode_from_cairo_op (op));
@ -1333,9 +1329,8 @@ _cairo_qt_surface_stroke (void *abstract_surface,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
Q_UNUSED(extents);
cairo_qt_surface_t *qs = (cairo_qt_surface_t *) abstract_surface;
D(fprintf(stderr, "q[%p] stroke op:%s\n", abstract_surface, _opstr(op)));
@ -1346,6 +1341,10 @@ _cairo_qt_surface_stroke (void *abstract_surface,
if (! _op_is_supported (qs, op))
return CAIRO_INT_STATUS_UNSUPPORTED;
cairo_int_status_t int_status = _cairo_qt_surface_set_clip (qs, clip);
if (unlikely (int_status))
return int_status;
QPainterPath qpath;
cairo_status_t status;
@ -1387,8 +1386,8 @@ _cairo_qt_surface_show_glyphs (void *abstract_surface,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip,
int *remaining_glyphs)
{
cairo_qt_surface_t *qs = (cairo_qt_surface_t *) abstract_surface;
@ -1404,37 +1403,6 @@ _cairo_qt_surface_show_glyphs (void *abstract_surface,
glyphs[i].y -= qs->redir_offset.y();
}
if (qs->has_clipping != qs->xlib_has_clipping ||
qs->clip_bounds != qs->xlib_clip_bounds)
{
cairo_status_t status;
status = _cairo_surface_reset_clip (qs->xlib_equiv);
assert (status == CAIRO_STATUS_SUCCESS);
if (qs->has_clipping) {
cairo_region_t region;
cairo_rectangle_int_t rect = {
qs->clip_bounds.x() - qs->redir_offset.x(),
qs->clip_bounds.y() - qs->redir_offset.y(),
qs->clip_bounds.width(),
qs->clip_bounds.height()
};
_cairo_region_init_rectangle (&region, &rect);
status = _cairo_surface_set_clip_region (qs->xlib_equiv,
&region,
++qs->xlib_clip_serial);
_cairo_region_fini (&region);
if (status)
return (cairo_int_status_t) status;
}
qs->xlib_has_clipping = qs->has_clipping;
qs->xlib_clip_bounds = qs->clip_bounds;
}
return (cairo_int_status_t)
_cairo_surface_show_text_glyphs (qs->xlib_equiv,
op, source,
@ -1443,7 +1411,7 @@ _cairo_qt_surface_show_glyphs (void *abstract_surface,
NULL, 0,
(cairo_text_cluster_flags_t) 0,
scaled_font,
extents);
clip);
}
#endif
@ -1452,12 +1420,11 @@ _cairo_qt_surface_show_glyphs (void *abstract_surface,
static cairo_int_status_t
_cairo_qt_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_rectangle_int_t *extents)
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_clip_t *clip)
{
Q_UNUSED(extents);
cairo_qt_surface_t *qs = (cairo_qt_surface_t *) abstract_surface;
D(fprintf(stderr, "q[%p] mask op:%s\n", abstract_surface, _opstr(op)));
@ -1471,7 +1438,7 @@ _cairo_qt_surface_mask (void *abstract_surface,
qs->p->setOpacity (solid_mask->color.alpha);
result = _cairo_qt_surface_paint (abstract_surface, op, source, 0);
result = _cairo_qt_surface_paint (abstract_surface, op, source, clip);
qs->p->setOpacity (1.0);
@ -1498,7 +1465,8 @@ _cairo_qt_surface_composite (cairo_operator_t op,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height)
unsigned int height,
cairo_region_t *clip_region)
{
cairo_qt_surface_t *qs = (cairo_qt_surface_t *) abstract_surface;
@ -1508,6 +1476,8 @@ _cairo_qt_surface_composite (cairo_operator_t op,
if (! _op_is_supported (qs, op))
return CAIRO_INT_STATUS_UNSUPPORTED;
_cairo_qt_surface_set_clip_region (qs, clip_region);
D(fprintf(stderr, "q[%p] composite op:%s src:%p [%d %d] dst [%d %d] dim [%d %d]\n",
abstract_surface, _opstr(op), (void*)pattern,
src_x, src_y, dst_x, dst_y, width, height));
@ -1618,8 +1588,6 @@ static const cairo_surface_backend_t cairo_qt_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
NULL, /* set_clip_region */
_cairo_qt_surface_intersect_clip_path,
_cairo_qt_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
@ -1636,7 +1604,6 @@ static const cairo_surface_backend_t cairo_qt_surface_backend = {
NULL, /* snapshot */
NULL, /* is_similar */
NULL, /* reset */
NULL, /* fill_stroke */
NULL, /* create_solid_pattern_surface */
NULL, /* can_repaint_solid_pattern_surface */
@ -1728,6 +1695,10 @@ cairo_qt_surface_create (QPainter *painter)
qs->window = painter->window();
_cairo_surface_clipper_init (&qs->clipper,
_cairo_qt_surface_clipper_intersect_clip_path);
#if defined(Q_WS_X11) && CAIRO_HAS_XLIB_XRENDER_SURFACE
qs->xlib_equiv = _cairo_qt_create_xlib_surface (qs);
#endif

View file

@ -58,9 +58,8 @@ _cairo_quartz_image_surface_create_similar (void *asurface,
int height)
{
cairo_surface_t *result;
cairo_surface_t *isurf = cairo_image_surface_create (_cairo_format_from_content (content),
width,
height);
cairo_surface_t *isurf =
_cairo_image_surface_create_for_content (content, width, height);
if (cairo_surface_status(isurf))
return isurf;
@ -108,18 +107,16 @@ _cairo_quartz_image_surface_acquire_dest_image (void *asurface,
*image_extra = NULL;
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
static cairo_bool_t
_cairo_quartz_image_surface_get_extents (void *asurface,
cairo_rectangle_int_t *extents)
{
cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface;
*extents = surface->extents;
return CAIRO_STATUS_SUCCESS;
return TRUE;
}
/* we assume some drawing happened to the image buffer; make sure it's
@ -168,8 +165,6 @@ static const cairo_surface_backend_t cairo_quartz_image_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
NULL, /* set_clip_region */
NULL, /* intersect_clip_path */
_cairo_quartz_image_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
@ -185,7 +180,6 @@ static const cairo_surface_backend_t cairo_quartz_image_surface_backend = {
NULL, /* surface_show_glyphs */
NULL, /* snapshot */
NULL, /* is_similar */
NULL, /* reset */
NULL /* fill_stroke */
};

View file

@ -42,6 +42,7 @@
#if CAIRO_HAS_QUARTZ_SURFACE
#include "cairo-quartz.h"
#include "cairo-surface-clipper-private.h"
typedef struct cairo_quartz_surface {
cairo_surface_t base;
@ -52,6 +53,7 @@ typedef struct cairo_quartz_surface {
void *imageData;
cairo_surface_t *imageSurfaceEquiv;
cairo_surface_clipper_t clipper;
cairo_rectangle_int_t extents;
/* These are stored while drawing operations are in place, set up

View file

@ -38,6 +38,7 @@
#include "cairoint.h"
#include "cairo-quartz-private.h"
#include "cairo-surface-clipper-private.h"
#include <dlfcn.h>
@ -837,7 +838,8 @@ _cairo_surface_to_cgimage (cairo_surface_t *target,
}
if (stype != CAIRO_SURFACE_TYPE_IMAGE) {
status = _cairo_surface_acquire_source_image (source, &isurf, &image_extra);
status = _cairo_surface_acquire_source_image (source,
&isurf, &image_extra);
if (status)
return status;
} else {
@ -848,12 +850,11 @@ _cairo_surface_to_cgimage (cairo_surface_t *target,
*image_out = NULL;
} else {
cairo_image_surface_t *isurf_snap = NULL;
isurf_snap = (cairo_image_surface_t*) _cairo_surface_snapshot ((cairo_surface_t*) isurf);
if (isurf_snap == NULL)
return CAIRO_STATUS_NO_MEMORY;
if (isurf_snap->base.type != CAIRO_SURFACE_TYPE_IMAGE)
return CAIRO_STATUS_SURFACE_TYPE_MISMATCH;
isurf_snap = (cairo_image_surface_t*)
_cairo_surface_snapshot (&isurf->base);
if (isurf_snap->base.status)
return isurf_snap->base.status;
image = _cairo_quartz_create_cgimage (isurf_snap->format,
isurf_snap->width,
@ -868,10 +869,10 @@ _cairo_surface_to_cgimage (cairo_surface_t *target,
*image_out = image;
}
if ((cairo_surface_t*) isurf != source)
if (&isurf->base != source)
_cairo_surface_release_source_image (source, isurf, image_extra);
return status;
return CAIRO_STATUS_SUCCESS;
}
/* Generic #cairo_pattern_t -> CGPattern function */
@ -942,6 +943,7 @@ _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (cairo_quartz_surface_t
SurfacePatternDrawInfo *info;
float rw, rh;
cairo_status_t status;
cairo_bool_t is_bounded;
cairo_matrix_t m;
@ -952,9 +954,8 @@ _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (cairo_quartz_surface_t
spattern = (cairo_surface_pattern_t *) apattern;
pat_surf = spattern->surface;
status = _cairo_surface_get_extents (pat_surf, &extents);
if (status)
return status;
is_bounded = _cairo_surface_get_extents (pat_surf, &extents);
assert (is_bounded);
status = _cairo_surface_to_cgimage ((cairo_surface_t*) dest, pat_surf, &image);
if (status != CAIRO_STATUS_SUCCESS)
@ -1042,9 +1043,7 @@ _cairo_quartz_setup_fallback_source (cairo_quartz_surface_t *surface,
double x0, y0, w, h;
cairo_surface_t *fallback;
cairo_t *fallback_cr;
CGImageRef img;
cairo_pattern_t *source_copy;
cairo_status_t status;
@ -1070,20 +1069,38 @@ _cairo_quartz_setup_fallback_source (cairo_quartz_surface_t *surface,
fallback = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, (int) w, (int) h);
cairo_surface_set_device_offset (fallback, -x0, -y0);
/* Paint the source onto our temporary */
fallback_cr = cairo_create (fallback);
cairo_set_operator (fallback_cr, CAIRO_OPERATOR_SOURCE);
#if 0
{
cairo_t *fallback_cr;
cairo_pattern_t *source_copy;
/* Use a copy of the pattern because it is const and could be allocated
* on the stack */
status = _cairo_pattern_create_copy (&source_copy, source);
cairo_set_source (fallback_cr, source_copy);
cairo_pattern_destroy (source_copy);
/* Paint the source onto our temporary */
fallback_cr = cairo_create (fallback);
cairo_set_operator (fallback_cr, CAIRO_OPERATOR_SOURCE);
cairo_paint (fallback_cr);
cairo_destroy (fallback_cr);
/* Use a copy of the pattern because it is const and could be allocated
* on the stack */
status = _cairo_pattern_create_copy (&source_copy, source);
cairo_set_source (fallback_cr, source_copy);
cairo_pattern_destroy (source_copy);
status = _cairo_surface_to_cgimage ((cairo_surface_t*) surface, fallback, &img);
cairo_paint (fallback_cr);
cairo_destroy (fallback_cr);
}
#else
{
cairo_pattern_union_t pattern;
_cairo_pattern_init_static_copy (&pattern, source);
_cairo_pattern_transform (pattern_copy,
&fallback->device_transform_inverse);
status = _cairo_surface_paint (fallback,
CAIRO_OPERATOR_SOURCE,
&pattern.base, NULL);
}
#endif
status = _cairo_surface_to_cgimage (&surface->base, fallback, &img);
if (status == CAIRO_STATUS_SUCCESS && img == NULL)
return DO_NOTHING;
if (status)
@ -1251,6 +1268,7 @@ _cairo_quartz_setup_source (cairo_quartz_surface_t *surface,
CGAffineTransform xform;
CGRect srcRect;
cairo_fixed_t fw, fh;
cairo_bool_t is_bounded;
status = _cairo_surface_to_cgimage ((cairo_surface_t *) surface, pat_surf, &img);
if (status == CAIRO_STATUS_SUCCESS && img == NULL)
@ -1263,9 +1281,8 @@ _cairo_quartz_setup_source (cairo_quartz_surface_t *surface,
cairo_matrix_invert(&m);
_cairo_quartz_cairo_matrix_to_quartz (&m, &surface->sourceTransform);
status = _cairo_surface_get_extents (pat_surf, &extents);
if (status)
return DO_UNSUPPORTED;
is_bounded = _cairo_surface_get_extents (pat_surf, &extents);
assert (is_bounded);
if (source->extend == CAIRO_EXTEND_NONE) {
surface->sourceImageRect = CGRectMake (0, 0, extents.width, extents.height);
@ -1485,6 +1502,7 @@ _cairo_quartz_surface_finish (void *abstract_surface)
/* Restore our saved gstate that we use to reset clipping */
CGContextRestoreGState (surface->cgContext);
_cairo_surface_clipper_reset (&surface->clipper);
CGContextRelease (surface->cgContext);
@ -1700,22 +1718,21 @@ FINISH:
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
static cairo_bool_t
_cairo_quartz_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *extents)
{
cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
*extents = surface->extents;
return CAIRO_STATUS_SUCCESS;
return TRUE;
}
static cairo_int_status_t
_cairo_quartz_surface_paint (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
@ -1729,6 +1746,10 @@ _cairo_quartz_surface_paint (void *abstract_surface,
if (op == CAIRO_OPERATOR_DEST)
return CAIRO_STATUS_SUCCESS;
rv = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (rv))
return rv;
CGContextSetCompositeOperation (surface->cgContext, _cairo_quartz_cairo_operator_to_quartz (op));
action = _cairo_quartz_setup_source (surface, source);
@ -1771,7 +1792,7 @@ _cairo_quartz_surface_fill (void *abstract_surface,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
@ -1790,7 +1811,7 @@ _cairo_quartz_surface_fill (void *abstract_surface,
/* Check whether the path would be a no-op */
/* XXX handle unbounded ops */
if (_cairo_path_fixed_is_empty(path) ||
if (_cairo_path_fixed_fill_is_empty(path) ||
(_cairo_path_fixed_is_box(path, &box) &&
box.p1.x == box.p2.x &&
box.p1.y == box.p2.y))
@ -1798,6 +1819,10 @@ _cairo_quartz_surface_fill (void *abstract_surface,
return CAIRO_STATUS_SUCCESS;
}
rv = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (rv))
return rv;
CGContextSaveGState (surface->cgContext);
CGContextSetShouldAntialias (surface->cgContext, (antialias != CAIRO_ANTIALIAS_NONE));
@ -1879,7 +1904,7 @@ _cairo_quartz_surface_stroke (void *abstract_surface,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
@ -1896,6 +1921,10 @@ _cairo_quartz_surface_stroke (void *abstract_surface,
if (op == CAIRO_OPERATOR_DEST)
return CAIRO_STATUS_SUCCESS;
rv = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (rv))
return rv;
CGContextSaveGState (surface->cgContext);
// Turning antialiasing off used to cause misrendering with
@ -2024,7 +2053,7 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
CGAffineTransform textTransform, ctm;
#define STATIC_BUF_SIZE 64
@ -2055,6 +2084,10 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface,
if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_QUARTZ)
return CAIRO_INT_STATUS_UNSUPPORTED;
rv = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (rv))
return rv;
CGContextSaveGState (surface->cgContext);
action = _cairo_quartz_setup_source (surface, source);
@ -2239,10 +2272,10 @@ _cairo_quartz_surface_mask_with_surface (cairo_quartz_surface_t *surface,
cairo_surface_t *pat_surf = mask->surface;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
CGAffineTransform ctm, mask_matrix;
cairo_bool_t is_bounded;
status = _cairo_surface_get_extents (pat_surf, &mask_extents);
if (status)
return status;
is_bounded = _cairo_surface_get_extents (pat_surf, &mask_extents);
assert (is_bounded);
// everything would be masked out, so do nothing
if (mask_extents.width == 0 || mask_extents.height == 0)
@ -2347,7 +2380,7 @@ _cairo_quartz_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
@ -2357,6 +2390,10 @@ _cairo_quartz_surface_mask (void *abstract_surface,
if (IS_EMPTY(surface))
return CAIRO_STATUS_SUCCESS;
rv = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (rv))
return rv;
if (mask->type == CAIRO_PATTERN_TYPE_SOLID) {
/* This is easy; we just need to paint with the alpha. */
cairo_solid_pattern_t *solid_mask = (cairo_solid_pattern_t *) mask;
@ -2387,14 +2424,15 @@ _cairo_quartz_surface_mask (void *abstract_surface,
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_quartz_surface_intersect_clip_path (void *abstract_surface,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias)
static cairo_status_t
_cairo_quartz_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias)
{
cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
cairo_quartz_surface_t *surface =
cairo_container_of (clipper, cairo_quartz_surface_t, clipper);
quartz_stroke_t stroke;
cairo_status_t status;
@ -2455,8 +2493,6 @@ static const struct _cairo_surface_backend cairo_quartz_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
NULL, /* set_clip_region */
_cairo_quartz_surface_intersect_clip_path,
_cairo_quartz_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
@ -2477,7 +2513,6 @@ static const struct _cairo_surface_backend cairo_quartz_surface_backend = {
_cairo_quartz_surface_snapshot,
NULL, /* is_similar */
NULL, /* reset */
NULL /* fill_stroke */
};
@ -2501,6 +2536,9 @@ _cairo_quartz_surface_create_internal (CGContextRef cgContext,
_cairo_surface_init(&surface->base, &cairo_quartz_surface_backend,
content);
_cairo_surface_clipper_init (&surface->clipper,
_cairo_quartz_surface_intersect_clip_path);
/* Save our extents */
surface->extents.x = surface->extents.y = 0;
surface->extents.width = width;

View file

@ -0,0 +1,73 @@
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Owen Taylor <otaylor@redhat.com>
* Vladimir Vukicevic <vladimir@pobox.com>
* Søren Sandmann <sandmann@daimi.au.dk>
*/
#ifndef CAIRO_REGION_PRIVATE_H
#define CAIRO_REGION_PRIVATE_H
#include "cairo-types-private.h"
#include "cairo-reference-count-private.h"
#include <pixman.h>
CAIRO_BEGIN_DECLS
struct _cairo_region {
cairo_reference_count_t ref_count;
cairo_status_t status;
pixman_region32_t rgn;
};
cairo_private void
_cairo_region_init (cairo_region_t *region);
cairo_private void
_cairo_region_init_rectangle (cairo_region_t *region,
const cairo_rectangle_int_t *rectangle);
cairo_private cairo_status_t
_cairo_region_init_rectangles (cairo_region_t *region,
const cairo_rectangle_int_t *rects,
int count);
cairo_private void
_cairo_region_fini (cairo_region_t *region);
CAIRO_END_DECLS
#endif /* CAIRO_REGION_PRIVATE_H */

View file

@ -38,7 +38,13 @@
#include "cairoint.h"
#include "cairo-region-private.h"
/* XXX need to update pixman headers to be const as appropriate */
#define CONST_CAST (pixman_region32_t *)
static const cairo_region_t _cairo_region_nil = {
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
CAIRO_STATUS_NO_MEMORY, /* status */
};
@ -82,6 +88,7 @@ _cairo_region_init (cairo_region_t *region)
VG (VALGRIND_MAKE_MEM_UNDEFINED (region, sizeof (cairo_region_t)));
region->status = CAIRO_STATUS_SUCCESS;
CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 0);
pixman_region32_init (&region->rgn);
}
@ -92,6 +99,7 @@ _cairo_region_init_rectangle (cairo_region_t *region,
VG (VALGRIND_MAKE_MEM_UNDEFINED (region, sizeof (cairo_region_t)));
region->status = CAIRO_STATUS_SUCCESS;
CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 0);
pixman_region32_init_rect (&region->rgn,
rectangle->x, rectangle->y,
rectangle->width, rectangle->height);
@ -100,6 +108,7 @@ _cairo_region_init_rectangle (cairo_region_t *region,
void
_cairo_region_fini (cairo_region_t *region)
{
assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&region->ref_count));
pixman_region32_fini (&region->rgn);
VG (VALGRIND_MAKE_MEM_NOACCESS (region, sizeof (cairo_region_t)));
}
@ -127,6 +136,7 @@ cairo_region_create (void)
return (cairo_region_t *) &_cairo_region_nil;
region->status = CAIRO_STATUS_SUCCESS;
CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 1);
pixman_region32_init (&region->rgn);
@ -134,29 +144,23 @@ cairo_region_create (void)
}
slim_hidden_def (cairo_region_create);
cairo_region_t *
cairo_region_create_rectangles (cairo_rectangle_int_t *rects,
int count)
cairo_status_t
_cairo_region_init_rectangles (cairo_region_t *region,
const cairo_rectangle_int_t *rects,
int count)
{
pixman_box32_t stack_pboxes[CAIRO_STACK_ARRAY_LENGTH (pixman_box32_t)];
pixman_box32_t *pboxes = stack_pboxes;
cairo_region_t *region;
cairo_status_t status;
int i;
region = _cairo_malloc (sizeof (cairo_region_t));
if (!region)
return (cairo_region_t *)&_cairo_region_nil;
region->status = CAIRO_STATUS_SUCCESS;
status = CAIRO_STATUS_SUCCESS;
CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 0);
if (count > ARRAY_LENGTH (stack_pboxes)) {
pboxes = _cairo_malloc_ab (count, sizeof (pixman_box32_t));
if (unlikely (pboxes == NULL)) {
free (region);
return (cairo_region_t *)&_cairo_region_nil;
}
if (unlikely (pboxes == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
for (i = 0; i < count; i++) {
@ -166,15 +170,35 @@ cairo_region_create_rectangles (cairo_rectangle_int_t *rects,
pboxes[i].y2 = rects[i].y + rects[i].height;
}
if (! pixman_region32_init_rects (&region->rgn, pboxes, count)) {
free (region);
region = (cairo_region_t *)&_cairo_region_nil;
}
if (! pixman_region32_init_rects (&region->rgn, pboxes, count))
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
if (pboxes != stack_pboxes)
free (pboxes);
return region->status = status;
}
cairo_region_t *
cairo_region_create_rectangles (const cairo_rectangle_int_t *rects,
int count)
{
cairo_region_t *region;
cairo_status_t status;
region = _cairo_malloc (sizeof (cairo_region_t));
if (unlikely (region == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_region_t *) &_cairo_region_nil;
}
status = _cairo_region_init_rectangles (region, rects, count);
if (unlikely (status)) {
cairo_region_destroy (region);
return (cairo_region_t *) &_cairo_region_nil;
}
CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 1);
return region;
}
slim_hidden_def (cairo_region_create_rectangles);
@ -199,10 +223,11 @@ cairo_region_create_rectangle (const cairo_rectangle_int_t *rectangle)
cairo_region_t *region;
region = _cairo_malloc (sizeof (cairo_region_t));
if (region == NULL)
if (unlikely (region == NULL))
return (cairo_region_t *) &_cairo_region_nil;
region->status = CAIRO_STATUS_SUCCESS;
CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 1);
pixman_region32_init_rect (&region->rgn,
rectangle->x, rectangle->y,
@ -227,18 +252,20 @@ slim_hidden_def (cairo_region_create_rectangle);
* Since: 1.10
**/
cairo_region_t *
cairo_region_copy (cairo_region_t *original)
cairo_region_copy (const cairo_region_t *original)
{
cairo_region_t *copy;
if (original->status)
if (original != NULL && original->status)
return (cairo_region_t *) &_cairo_region_nil;
copy = cairo_region_create ();
if (copy->status)
if (unlikely (copy->status))
return copy;
if (! pixman_region32_copy (&copy->rgn, &original->rgn)) {
if (original != NULL &&
! pixman_region32_copy (&copy->rgn, CONST_CAST &original->rgn))
{
cairo_region_destroy (copy);
return (cairo_region_t *) &_cairo_region_nil;
}
@ -247,6 +274,31 @@ cairo_region_copy (cairo_region_t *original)
}
slim_hidden_def (cairo_region_copy);
/**
* cairo_region_reference:
* @region: a #cairo_region_t
*
* Increases the reference count on @region by one. This prevents
* @region from being destroyed until a matching call to
* cairo_region_destroy() is made.
*
* Return value: the referenced #cairo_region_t.
*
* Since: 1.10
**/
cairo_region_t *
cairo_region_reference (cairo_region_t *region)
{
if (region == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (&region->ref_count))
return NULL;
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&region->ref_count));
_cairo_reference_count_inc (&region->ref_count);
return region;
}
slim_hidden_def (cairo_region_reference);
/**
* cairo_region_destroy:
* @region: a #cairo_region_t
@ -260,10 +312,15 @@ slim_hidden_def (cairo_region_copy);
void
cairo_region_destroy (cairo_region_t *region)
{
if (region == (cairo_region_t *) &_cairo_region_nil)
if (region == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (&region->ref_count))
return;
pixman_region32_fini (&region->rgn);
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&region->ref_count));
if (! _cairo_reference_count_dec_and_test (&region->ref_count))
return;
_cairo_region_fini (region);
free (region);
}
slim_hidden_def (cairo_region_destroy);
@ -279,12 +336,12 @@ slim_hidden_def (cairo_region_destroy);
* Since: 1.10
**/
int
cairo_region_num_rectangles (cairo_region_t *region)
cairo_region_num_rectangles (const cairo_region_t *region)
{
if (region->status)
return 0;
return pixman_region32_n_rects (&region->rgn);
return pixman_region32_n_rects (CONST_CAST &region->rgn);
}
slim_hidden_def (cairo_region_num_rectangles);
@ -299,7 +356,7 @@ slim_hidden_def (cairo_region_num_rectangles);
* Since: 1.10
**/
void
cairo_region_get_rectangle (cairo_region_t *region,
cairo_region_get_rectangle (const cairo_region_t *region,
int nth,
cairo_rectangle_int_t *rectangle)
{
@ -311,7 +368,7 @@ cairo_region_get_rectangle (cairo_region_t *region,
return;
}
pbox = pixman_region32_rectangles (&region->rgn, NULL) + nth;
pbox = pixman_region32_rectangles (CONST_CAST &region->rgn, NULL) + nth;
rectangle->x = pbox->x1;
rectangle->y = pbox->y1;
@ -330,7 +387,7 @@ slim_hidden_def (cairo_region_get_rectangle);
* Since: 1.10
**/
void
cairo_region_get_extents (cairo_region_t *region,
cairo_region_get_extents (const cairo_region_t *region,
cairo_rectangle_int_t *extents)
{
pixman_box32_t *pextents;
@ -341,7 +398,7 @@ cairo_region_get_extents (cairo_region_t *region,
return;
}
pextents = pixman_region32_extents (&region->rgn);
pextents = pixman_region32_extents (CONST_CAST &region->rgn);
extents->x = pextents->x1;
extents->y = pextents->y1;
@ -362,7 +419,7 @@ slim_hidden_def (cairo_region_get_extents);
* Since: 1.10
**/
cairo_status_t
cairo_region_status (cairo_region_t *region)
cairo_region_status (const cairo_region_t *region)
{
return region->status;
}
@ -564,12 +621,12 @@ slim_hidden_def (cairo_region_union_rectangle);
* Since: 1.10
**/
cairo_bool_t
cairo_region_is_empty (cairo_region_t *region)
cairo_region_is_empty (const cairo_region_t *region)
{
if (region->status)
return TRUE;
return ! pixman_region32_not_empty (&region->rgn);
return ! pixman_region32_not_empty (CONST_CAST &region->rgn);
}
slim_hidden_def (cairo_region_is_empty);
@ -610,7 +667,7 @@ slim_hidden_def (cairo_region_translate);
* Since: 1.10
**/
cairo_region_overlap_t
cairo_region_contains_rectangle (cairo_region_t *region,
cairo_region_contains_rectangle (const cairo_region_t *region,
const cairo_rectangle_int_t *rectangle)
{
pixman_box32_t pbox;
@ -624,7 +681,8 @@ cairo_region_contains_rectangle (cairo_region_t *region,
pbox.x2 = rectangle->x + rectangle->width;
pbox.y2 = rectangle->y + rectangle->height;
poverlap = pixman_region32_contains_rectangle (&region->rgn, &pbox);
poverlap = pixman_region32_contains_rectangle (CONST_CAST &region->rgn,
&pbox);
switch (poverlap) {
default:
case PIXMAN_REGION_OUT: return CAIRO_REGION_OVERLAP_OUT;
@ -647,14 +705,44 @@ slim_hidden_def (cairo_region_contains_rectangle);
* Since: 1.10
**/
cairo_bool_t
cairo_region_contains_point (cairo_region_t *region,
cairo_region_contains_point (const cairo_region_t *region,
int x, int y)
{
pixman_box32_t box;
if (region->status)
return FALSE;
return pixman_region32_contains_point (&region->rgn, x, y, &box);
return pixman_region32_contains_point (CONST_CAST &region->rgn, x, y, &box);
}
slim_hidden_def (cairo_region_contains_point);
/**
* cairo_region_equal:
* @region_a: a #cairo_region_t
* @region_b: a #cairo_region_t
*
* Compares whether region_a is equivalent to region_b.
*
* Return value: %TRUE if both regions contained the same coverage,
* %FALSE if it is not.
*
* Since: 1.10
**/
cairo_bool_t
cairo_region_equal (const cairo_region_t *a,
const cairo_region_t *b)
{
/* error objects are never equal */
if ((a != NULL && a->status) || (b != NULL && b->status))
return FALSE;
if (a == b)
return TRUE;
if (a == NULL || b == NULL)
return FALSE;
return pixman_region32_equal (CONST_CAST &a->rgn, CONST_CAST &b->rgn);
}
slim_hidden_def (cairo_region_equal);

View file

@ -1969,18 +1969,19 @@ _cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t *scaled_font,
}
cairo_status_t
_cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
cairo_operator_t op,
_cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
cairo_operator_t op,
const cairo_pattern_t *pattern,
cairo_surface_t *surface,
int source_x,
int source_y,
int dest_x,
int dest_y,
unsigned int width,
unsigned int height,
cairo_glyph_t *glyphs,
int num_glyphs)
cairo_surface_t *surface,
int source_x,
int source_y,
int dest_x,
int dest_y,
unsigned int width,
unsigned int height,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_region_t *clip_region)
{
cairo_status_t status;
cairo_surface_t *mask = NULL;
@ -2008,7 +2009,9 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
source_x, source_y,
dest_x, dest_y,
width, height,
glyphs, num_glyphs, &remaining_glyphs);
glyphs, num_glyphs,
clip_region,
&remaining_glyphs);
glyphs += num_glyphs - remaining_glyphs;
num_glyphs = remaining_glyphs;
if (remaining_glyphs == 0)
@ -2088,7 +2091,8 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
0, 0,
0, 0,
0, 0,
width, height);
width, height,
NULL);
_cairo_pattern_fini (&mask_pattern.base);
@ -2116,7 +2120,8 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
0, 0,
x - dest_x, y - dest_y,
glyph_surface->width,
glyph_surface->height);
glyph_surface->height,
NULL);
_cairo_pattern_fini (&glyph_pattern.base);
@ -2134,7 +2139,8 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
source_x, source_y,
0, 0,
dest_x, dest_y,
width, height);
width, height,
clip_region);
_cairo_pattern_fini (&mask_pattern.base);
@ -2148,58 +2154,6 @@ CLEANUP_MASK:
return _cairo_scaled_font_set_error (scaled_font, status);
}
typedef struct _cairo_scaled_glyph_path_closure {
cairo_point_t offset;
cairo_path_fixed_t *path;
} cairo_scaled_glyph_path_closure_t;
static cairo_status_t
_scaled_glyph_path_move_to (void *abstract_closure,
const cairo_point_t *point)
{
cairo_scaled_glyph_path_closure_t *closure = abstract_closure;
return _cairo_path_fixed_move_to (closure->path,
point->x + closure->offset.x,
point->y + closure->offset.y);
}
static cairo_status_t
_scaled_glyph_path_line_to (void *abstract_closure,
const cairo_point_t *point)
{
cairo_scaled_glyph_path_closure_t *closure = abstract_closure;
return _cairo_path_fixed_line_to (closure->path,
point->x + closure->offset.x,
point->y + closure->offset.y);
}
static cairo_status_t
_scaled_glyph_path_curve_to (void *abstract_closure,
const cairo_point_t *p0,
const cairo_point_t *p1,
const cairo_point_t *p2)
{
cairo_scaled_glyph_path_closure_t *closure = abstract_closure;
return _cairo_path_fixed_curve_to (closure->path,
p0->x + closure->offset.x,
p0->y + closure->offset.y,
p1->x + closure->offset.x,
p1->y + closure->offset.y,
p2->x + closure->offset.x,
p2->y + closure->offset.y);
}
static cairo_status_t
_scaled_glyph_path_close_path (void *abstract_closure)
{
cairo_scaled_glyph_path_closure_t *closure = abstract_closure;
return _cairo_path_fixed_close_path (closure->path);
}
/* Add a single-device-unit rectangle to a path. */
static cairo_status_t
_add_unit_rectangle_to_path (cairo_path_fixed_t *path, int x, int y)
@ -2309,14 +2263,13 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
{
cairo_status_t status;
int i;
cairo_scaled_glyph_path_closure_t closure;
cairo_path_fixed_t glyph_path_static;
cairo_path_fixed_t *glyph_path;
status = scaled_font->status;
if (unlikely (status))
return status;
closure.path = path;
_cairo_scaled_font_freeze_cache (scaled_font);
for (i = 0; i < num_glyphs; i++) {
cairo_scaled_glyph_t *scaled_glyph;
@ -2325,14 +2278,12 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
glyphs[i].index,
CAIRO_SCALED_GLYPH_INFO_PATH,
&scaled_glyph);
if (status == CAIRO_STATUS_SUCCESS)
if (status == CAIRO_STATUS_SUCCESS) {
glyph_path = scaled_glyph->path;
else if (status != CAIRO_INT_STATUS_UNSUPPORTED)
goto BAIL;
/* If the font is incapable of providing a path, then we'll
* have to trace our own from a surface. */
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
} else if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
/* If the font is incapable of providing a path, then we'll
* have to trace our own from a surface.
*/
status = _cairo_scaled_glyph_lookup (scaled_font,
glyphs[i].index,
CAIRO_SCALED_GLYPH_INFO_SURFACE,
@ -2340,31 +2291,22 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
if (unlikely (status))
goto BAIL;
glyph_path = _cairo_path_fixed_create ();
if (unlikely (glyph_path == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL;
}
_cairo_path_fixed_init (&glyph_path_static);
glyph_path = &glyph_path_static;
status = _trace_mask_to_path (scaled_glyph->surface, glyph_path);
if (unlikely (status)) {
_cairo_path_fixed_destroy (glyph_path);
if (unlikely (status))
goto BAIL;
}
} else {
goto BAIL;
}
closure.offset.x = _cairo_fixed_from_double (glyphs[i].x);
closure.offset.y = _cairo_fixed_from_double (glyphs[i].y);
status = _cairo_path_fixed_append (path,
glyph_path, CAIRO_DIRECTION_FORWARD,
_cairo_fixed_from_double (glyphs[i].x),
_cairo_fixed_from_double (glyphs[i].y));
status = _cairo_path_fixed_interpret (glyph_path,
CAIRO_DIRECTION_FORWARD,
_scaled_glyph_path_move_to,
_scaled_glyph_path_line_to,
_scaled_glyph_path_curve_to,
_scaled_glyph_path_close_path,
&closure);
if (glyph_path != scaled_glyph->path)
_cairo_path_fixed_destroy (glyph_path);
_cairo_path_fixed_fini (glyph_path);
if (unlikely (status))
goto BAIL;

File diff suppressed because it is too large Load diff

View file

@ -53,6 +53,16 @@ cairo_script_surface_create_for_stream (cairo_write_func_t write_func,
double width,
double height);
cairo_public cairo_surface_t *
cairo_script_surface_create_for_target (cairo_surface_t *surface,
cairo_write_func_t write_func,
void *closure);
cairo_public void
cairo_script_surface_write_comment (cairo_surface_t *abstract_surface,
const char *comment,
int len);
typedef enum {
CAIRO_SCRIPT_MODE_BINARY,
CAIRO_SCRIPT_MODE_ASCII

View file

@ -132,13 +132,14 @@ _cairo_span_renderer_set_error (void *abstract_renderer,
cairo_status_t error);
cairo_private cairo_status_t
_cairo_path_fixed_fill_using_spans (
cairo_operator_t op,
const cairo_pattern_t *pattern,
cairo_path_fixed_t *path,
cairo_surface_t *dst,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
const cairo_composite_rectangles_t *rects);
_cairo_path_fixed_fill_using_spans (cairo_operator_t op,
const cairo_pattern_t *pattern,
cairo_path_fixed_t *path,
cairo_surface_t *dst,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
const cairo_composite_rectangles_t *rects,
cairo_region_t *clip_region);
#endif /* CAIRO_SPANS_PRIVATE_H */

View file

@ -149,19 +149,19 @@ _create_scan_converter (cairo_fill_rule_t fill_rule,
}
cairo_status_t
_cairo_path_fixed_fill_using_spans (
cairo_operator_t op,
const cairo_pattern_t *pattern,
cairo_path_fixed_t *path,
cairo_surface_t *dst,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
const cairo_composite_rectangles_t *rects)
_cairo_path_fixed_fill_using_spans (cairo_operator_t op,
const cairo_pattern_t *pattern,
cairo_path_fixed_t *path,
cairo_surface_t *dst,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
const cairo_composite_rectangles_t *rects,
cairo_region_t *clip_region)
{
cairo_status_t status;
cairo_span_renderer_t *renderer = _cairo_surface_create_span_renderer (
op, pattern, dst, antialias, rects);
op, pattern, dst, antialias, rects, clip_region);
cairo_scan_converter_t *converter = _create_scan_converter (
fill_rule, antialias, rects);

View file

@ -110,13 +110,13 @@ _cairo_stroke_style_max_distance_from_path (const cairo_stroke_style_t *style,
style_expansion = M_SQRT1_2;
if (style->line_join == CAIRO_LINE_JOIN_MITER &&
style_expansion < style->miter_limit)
style_expansion < M_SQRT2 * style->miter_limit)
{
style_expansion = style->miter_limit;
style_expansion = M_SQRT2 * style->miter_limit;
}
style_expansion *= style->line_width;
*dx = style_expansion * (fabs (ctm->xx) + fabs (ctm->xy));
*dy = style_expansion * (fabs (ctm->yy) + fabs (ctm->yx));
*dx = style_expansion * hypot (ctm->xx, ctm->xy);
*dy = style_expansion * hypot (ctm->yy, ctm->yx);
}

View file

@ -0,0 +1,72 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.u>
*/
#ifndef CAIRO_SURFACE_CLIPPER_PRIVATE_H
#define CAIRO_SURFACE_CLIPPER_PRIVATE_H
#include "cairo-types-private.h"
#include "cairo-clip-private.h"
CAIRO_BEGIN_DECLS
typedef struct _cairo_surface_clipper cairo_surface_clipper_t;
typedef cairo_status_t
(*cairo_surface_clipper_intersect_clip_path_func_t) (cairo_surface_clipper_t *,
cairo_path_fixed_t *,
cairo_fill_rule_t,
double,
cairo_antialias_t);
struct _cairo_surface_clipper {
cairo_clip_t clip;
cairo_bool_t is_clipped;
cairo_surface_clipper_intersect_clip_path_func_t intersect_clip_path;
};
cairo_private cairo_status_t
_cairo_surface_clipper_set_clip (cairo_surface_clipper_t *clipper,
cairo_clip_t *clip);
cairo_private void
_cairo_surface_clipper_init (cairo_surface_clipper_t *clipper,
cairo_surface_clipper_intersect_clip_path_func_t intersect);
cairo_private void
_cairo_surface_clipper_reset (cairo_surface_clipper_t *clipper);
CAIRO_END_DECLS
#endif /* CAIRO_SURFACE_CLIPPER_PRIVATE_H */

138
src/cairo-surface-clipper.c Normal file
View file

@ -0,0 +1,138 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
#include "cairo-surface-clipper-private.h"
/* A collection of routines to facilitate vector surface clipping */
static cairo_status_t
_cairo_surface_clipper_intersect_clip_path_recursive (cairo_surface_clipper_t *clipper,
cairo_clip_path_t *clip_path)
{
cairo_status_t status;
if (clip_path->prev != NULL) {
status =
_cairo_surface_clipper_intersect_clip_path_recursive (clipper,
clip_path->prev);
if (unlikely (status))
return status;
}
return clipper->intersect_clip_path (clipper,
&clip_path->path,
clip_path->fill_rule,
clip_path->tolerance,
clip_path->antialias);
}
cairo_status_t
_cairo_surface_clipper_set_clip (cairo_surface_clipper_t *clipper,
cairo_clip_t *clip)
{
cairo_status_t status;
cairo_bool_t clear;
/* XXX as we cache a reference to the path, and compare every time,
* we may in future need to install a notification if the clip->path
* is every modified (e.g. cairo_clip_translate).
*/
if (clip == NULL && clipper->clip.path == NULL)
return CAIRO_STATUS_SUCCESS;
if (clip != NULL && clip->path == clipper->clip.path)
return CAIRO_STATUS_SUCCESS;
if (clip != NULL && clipper->clip.path != NULL &&
_cairo_path_fixed_equal (&clip->path->path, &clipper->clip.path->path))
{
return CAIRO_STATUS_SUCCESS;
}
/* all clipped out state should never propagate this far */
assert (clip == NULL || clip->path != NULL);
/* Check whether this clip is a continuation of the previous.
* If not, we have to remove the current clip and rebuild.
*/
clear = clip == NULL || clip->path->prev != clipper->clip.path;
_cairo_clip_reset (&clipper->clip);
_cairo_clip_init_copy (&clipper->clip, clip);
if (clear) {
clipper->is_clipped = FALSE;
status = clipper->intersect_clip_path (clipper, NULL, 0, 0, 0);
if (unlikely (status))
return status;
if (clip != NULL && clip->path != NULL) {
status =
_cairo_surface_clipper_intersect_clip_path_recursive (clipper,
clip->path);
clipper->is_clipped = TRUE;
}
} else {
cairo_clip_path_t *path = clip->path;
clipper->is_clipped = TRUE;
status = clipper->intersect_clip_path (clipper,
&path->path,
path->fill_rule,
path->tolerance,
path->antialias);
}
return status;
}
void
_cairo_surface_clipper_init (cairo_surface_clipper_t *clipper,
cairo_surface_clipper_intersect_clip_path_func_t func)
{
_cairo_clip_init (&clipper->clip);
clipper->is_clipped = FALSE;
clipper->intersect_clip_path = func;
}
void
_cairo_surface_clipper_reset (cairo_surface_clipper_t *clipper)
{
_cairo_clip_reset (&clipper->clip);
clipper->is_clipped = FALSE;
}

View file

@ -44,13 +44,15 @@
cairo_private cairo_status_t
_cairo_surface_fallback_paint (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source);
const cairo_pattern_t *source,
cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_surface_fallback_mask (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask);
const cairo_pattern_t *mask,
cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_surface_fallback_stroke (cairo_surface_t *surface,
@ -61,7 +63,8 @@ _cairo_surface_fallback_stroke (cairo_surface_t *surface,
cairo_matrix_t *ctm,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias);
cairo_antialias_t antialias,
cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_surface_fallback_fill (cairo_surface_t *surface,
@ -70,7 +73,8 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias);
cairo_antialias_t antialias,
cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_surface_fallback_show_glyphs (cairo_surface_t *surface,
@ -78,7 +82,8 @@ _cairo_surface_fallback_show_glyphs (cairo_surface_t *surface,
const cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font);
cairo_scaled_font_t *scaled_font,
cairo_clip_t *clip);
cairo_private cairo_surface_t *
_cairo_surface_fallback_snapshot (cairo_surface_t *surface);
@ -95,7 +100,8 @@ _cairo_surface_fallback_composite (cairo_operator_t op,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height);
unsigned int height,
cairo_region_t *clip_region);
cairo_private cairo_status_t
_cairo_surface_fallback_fill_rectangles (cairo_surface_t *surface,
@ -116,7 +122,8 @@ _cairo_surface_fallback_composite_trapezoids (cairo_operator_t op,
unsigned int width,
unsigned int height,
cairo_trapezoid_t *traps,
int num_traps);
int num_traps,
cairo_region_t *clip_region);
cairo_private cairo_status_t
_cairo_surface_fallback_clone_similar (cairo_surface_t *surface,

File diff suppressed because it is too large Load diff

View file

@ -42,6 +42,7 @@
#include "cairo-types-private.h"
#include "cairo-reference-count-private.h"
#include "cairo-clip-private.h"
typedef void (*cairo_surface_func_t) (cairo_surface_t *);
@ -77,24 +78,6 @@ struct _cairo_surface {
double x_fallback_resolution;
double y_fallback_resolution;
cairo_clip_t *clip;
/*
* Each time a clip region is modified, it gets the next value in this
* sequence. This means that clip regions for this surface are uniquely
* identified and updates to the clip can be readily identified
*/
unsigned int next_clip_serial;
/*
* The serial number of the current clip. This is set when
* the surface clipping is set. The gstate can then cheaply
* check whether the surface clipping is already correct before
* performing a rendering operation.
*
* The special value '0' is reserved for the unclipped case.
*/
unsigned int current_clip_serial;
/* A "snapshot" surface is immutable. See _cairo_surface_snapshot. */
cairo_surface_t *snapshot_of;
cairo_surface_func_t snapshot_detach;

View file

@ -0,0 +1,156 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005 Red Hat, Inc.
* Copyright © 2009 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.u>
*/
#ifndef CAIRO_SURFACE_WRAPPER_PRIVATE_H
#define CAIRO_SURFACE_WRAPPER_PRIVATE_H
#include "cairo-types-private.h"
CAIRO_BEGIN_DECLS
struct _cairo_surface_wrapper {
cairo_surface_t *target;
/* any other information? */
};
cairo_private void
_cairo_surface_wrapper_init (cairo_surface_wrapper_t *wrapper,
cairo_surface_t *target);
cairo_private void
_cairo_surface_wrapper_fini (cairo_surface_wrapper_t *wrapper);
cairo_private cairo_status_t
_cairo_surface_wrapper_acquire_source_image (cairo_surface_wrapper_t *wrapper,
cairo_image_surface_t **image_out,
void **image_extra);
cairo_private void
_cairo_surface_wrapper_release_source_image (cairo_surface_wrapper_t *wrapper,
cairo_image_surface_t *image,
void *image_extra);
cairo_private cairo_status_t
_cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_stroke_style_t *stroke_style,
cairo_matrix_t *ctm,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
cairo_operator_t fill_op,
const cairo_pattern_t *fill_source,
cairo_fill_rule_t fill_rule,
double fill_tolerance,
cairo_antialias_t fill_antialias,
cairo_path_fixed_t *path,
cairo_operator_t stroke_op,
const cairo_pattern_t *stroke_source,
cairo_stroke_style_t *stroke_style,
cairo_matrix_t *stroke_ctm,
cairo_matrix_t *stroke_ctm_inverse,
double stroke_tolerance,
cairo_antialias_t stroke_antialias,
cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
const cairo_pattern_t *source,
const char *utf8,
int utf8_len,
cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_scaled_font_t *scaled_font,
cairo_clip_t *clip);
cairo_private cairo_surface_t *
_cairo_surface_wrapper_create_similar (cairo_surface_wrapper_t *wrapper,
cairo_content_t content,
int width,
int height);
cairo_private cairo_bool_t
_cairo_surface_wrapper_get_extents (cairo_surface_wrapper_t *wrapper,
cairo_rectangle_int_t *extents);
cairo_private cairo_bool_t
_cairo_surface_wrapper_has_show_text_glyphs (cairo_surface_wrapper_t *wrapper);
static inline cairo_bool_t
_cairo_surface_wrapper_is_active (cairo_surface_wrapper_t *wrapper)
{
return wrapper->target != (cairo_surface_t *) 0;
}
CAIRO_END_DECLS
#endif /* CAIRO_SURFACE_WRAPPER_PRIVATE_H */

449
src/cairo-surface-wrapper.c Normal file
View file

@ -0,0 +1,449 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
* Copyright © 2007 Adrian Johnson
* Copyright © 2009 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
#include "cairo-surface-wrapper-private.h"
/* A collection of routines to facilitate surface wrapping */
static cairo_bool_t
_cairo_surface_wrapper_needs_device_transform (cairo_surface_wrapper_t *wrapper,
cairo_matrix_t *matrix)
{
if (_cairo_matrix_is_identity (&wrapper->target->device_transform))
return FALSE;
*matrix = wrapper->target->device_transform;
return TRUE;
}
cairo_status_t
_cairo_surface_wrapper_acquire_source_image (cairo_surface_wrapper_t *wrapper,
cairo_image_surface_t **image_out,
void **image_extra)
{
if (unlikely (wrapper->target->status))
return wrapper->target->status;
return _cairo_surface_acquire_source_image (wrapper->target,
image_out, image_extra);
}
void
_cairo_surface_wrapper_release_source_image (cairo_surface_wrapper_t *wrapper,
cairo_image_surface_t *image,
void *image_extra)
{
_cairo_surface_release_source_image (wrapper->target, image, image_extra);
}
cairo_status_t
_cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_clip_t *clip)
{
cairo_status_t status;
cairo_matrix_t device_transform;
cairo_clip_t clip_copy, *dev_clip = clip;
if (unlikely (wrapper->target->status))
return wrapper->target->status;
if (clip && clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
if (clip != NULL &&
_cairo_surface_wrapper_needs_device_transform (wrapper,
&device_transform))
{
status = _cairo_clip_init_copy_transformed (&clip_copy, clip,
&device_transform);
if (unlikely (status))
goto FINISH;
dev_clip = &clip_copy;
}
status = _cairo_surface_paint (wrapper->target, op, source, dev_clip);
FINISH:
if (dev_clip != clip)
_cairo_clip_reset (dev_clip);
return status;
}
cairo_status_t
_cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_clip_t *clip)
{
cairo_status_t status;
cairo_matrix_t device_transform;
cairo_clip_t clip_copy, *dev_clip = clip;
if (unlikely (wrapper->target->status))
return wrapper->target->status;
if (clip && clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
if (clip != NULL &&
_cairo_surface_wrapper_needs_device_transform (wrapper,
&device_transform))
{
status = _cairo_clip_init_copy_transformed (&clip_copy, clip,
&device_transform);
if (unlikely (status))
goto FINISH;
dev_clip = &clip_copy;
}
status = _cairo_surface_mask (wrapper->target, op, source, mask, dev_clip);
FINISH:
if (dev_clip != clip)
_cairo_clip_reset (dev_clip);
return status;
}
cairo_status_t
_cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_stroke_style_t *stroke_style,
cairo_matrix_t *ctm,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
{
cairo_status_t status;
cairo_matrix_t device_transform;
cairo_path_fixed_t path_copy, *dev_path = path;
cairo_clip_t clip_copy, *dev_clip = clip;
cairo_matrix_t dev_ctm = *ctm;
cairo_matrix_t dev_ctm_inverse = *ctm_inverse;
if (unlikely (wrapper->target->status))
return wrapper->target->status;
if (clip && clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
if (_cairo_surface_wrapper_needs_device_transform (wrapper,
&device_transform))
{
status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
if (unlikely (status))
goto FINISH;
_cairo_path_fixed_transform (&path_copy, &device_transform);
dev_path = &path_copy;
if (clip != NULL) {
status = _cairo_clip_init_copy_transformed (&clip_copy, clip,
&device_transform);
if (unlikely (status))
goto FINISH;
dev_clip = &clip_copy;
}
cairo_matrix_multiply (&dev_ctm, &dev_ctm, &device_transform);
status = cairo_matrix_invert (&device_transform);
assert (status == CAIRO_STATUS_SUCCESS);
cairo_matrix_multiply (&dev_ctm_inverse,
&device_transform,
&dev_ctm_inverse);
}
status = _cairo_surface_stroke (wrapper->target, op, source,
dev_path, stroke_style,
&dev_ctm, &dev_ctm_inverse,
tolerance, antialias,
dev_clip);
FINISH:
if (dev_path != path)
_cairo_path_fixed_fini (dev_path);
if (dev_clip != clip)
_cairo_clip_reset (dev_clip);
return status;
}
cairo_status_t
_cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
cairo_operator_t fill_op,
const cairo_pattern_t *fill_source,
cairo_fill_rule_t fill_rule,
double fill_tolerance,
cairo_antialias_t fill_antialias,
cairo_path_fixed_t *path,
cairo_operator_t stroke_op,
const cairo_pattern_t *stroke_source,
cairo_stroke_style_t *stroke_style,
cairo_matrix_t *stroke_ctm,
cairo_matrix_t *stroke_ctm_inverse,
double stroke_tolerance,
cairo_antialias_t stroke_antialias,
cairo_clip_t *clip)
{
cairo_status_t status;
cairo_matrix_t device_transform;
cairo_path_fixed_t path_copy, *dev_path = path;
cairo_clip_t clip_copy, *dev_clip = clip;
cairo_matrix_t dev_ctm = *stroke_ctm;
cairo_matrix_t dev_ctm_inverse = *stroke_ctm_inverse;
if (unlikely (wrapper->target->status))
return wrapper->target->status;
if (clip && clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
if (_cairo_surface_wrapper_needs_device_transform (wrapper,
&device_transform))
{
status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
if (unlikely (status))
goto FINISH;
_cairo_path_fixed_transform (&path_copy, &device_transform);
dev_path = &path_copy;
if (clip != NULL) {
status = _cairo_clip_init_copy_transformed (&clip_copy, clip,
&device_transform);
if (unlikely (status))
goto FINISH;
dev_clip = &clip_copy;
}
cairo_matrix_multiply (&dev_ctm, &dev_ctm, &device_transform);
status = cairo_matrix_invert (&device_transform);
assert (status == CAIRO_STATUS_SUCCESS);
cairo_matrix_multiply (&dev_ctm_inverse,
&device_transform,
&dev_ctm_inverse);
}
status = _cairo_surface_fill_stroke (wrapper->target,
fill_op, fill_source, fill_rule,
fill_tolerance, fill_antialias,
dev_path,
stroke_op, stroke_source,
stroke_style,
&dev_ctm, &dev_ctm_inverse,
stroke_tolerance, stroke_antialias,
dev_clip);
FINISH:
if (dev_path != path)
_cairo_path_fixed_fini (dev_path);
if (dev_clip != clip)
_cairo_clip_reset (dev_clip);
return status;
}
cairo_status_t
_cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
{
cairo_status_t status;
cairo_matrix_t device_transform;
cairo_path_fixed_t path_copy, *dev_path = path;
cairo_clip_t clip_copy, *dev_clip = clip;
if (unlikely (wrapper->target->status))
return wrapper->target->status;
if (clip && clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
if (_cairo_surface_wrapper_needs_device_transform (wrapper,
&device_transform))
{
status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
if (unlikely (status))
goto FINISH;
_cairo_path_fixed_transform (&path_copy, &device_transform);
dev_path = &path_copy;
if (clip != NULL) {
status = _cairo_clip_init_copy_transformed (&clip_copy, clip,
&device_transform);
if (unlikely (status))
goto FINISH;
dev_clip = &clip_copy;
}
}
status = _cairo_surface_fill (wrapper->target, op, source,
dev_path, fill_rule,
tolerance, antialias,
dev_clip);
FINISH:
if (dev_path != path)
_cairo_path_fixed_fini (dev_path);
if (dev_clip != clip)
_cairo_clip_reset (dev_clip);
return status;
}
cairo_status_t
_cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
const cairo_pattern_t *source,
const char *utf8,
int utf8_len,
cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_scaled_font_t *scaled_font,
cairo_clip_t *clip)
{
cairo_status_t status;
cairo_matrix_t device_transform;
cairo_clip_t clip_copy, *dev_clip = clip;
cairo_glyph_t *dev_glyphs = glyphs;
if (unlikely (wrapper->target->status))
return wrapper->target->status;
if (glyphs == NULL || num_glyphs == 0)
return CAIRO_STATUS_SUCCESS;
if (clip && clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
if (_cairo_surface_wrapper_needs_device_transform (wrapper,
&device_transform))
{
int i;
if (clip != NULL) {
dev_clip = &clip_copy;
status = _cairo_clip_init_copy_transformed (&clip_copy, clip,
&device_transform);
if (unlikely (status))
goto FINISH;
}
dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
if (dev_glyphs == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto FINISH;
}
for (i = 0; i < num_glyphs; i++) {
dev_glyphs[i] = glyphs[i];
cairo_matrix_transform_point (&device_transform,
&dev_glyphs[i].x,
&dev_glyphs[i].y);
}
}
status = _cairo_surface_show_text_glyphs (wrapper->target, op, source,
utf8, utf8_len,
dev_glyphs, num_glyphs,
clusters, num_clusters,
cluster_flags,
scaled_font,
dev_clip);
FINISH:
if (dev_clip != clip)
_cairo_clip_reset (dev_clip);
if (dev_glyphs != glyphs)
free (dev_glyphs);
return status;
}
cairo_surface_t *
_cairo_surface_wrapper_create_similar (cairo_surface_wrapper_t *wrapper,
cairo_content_t content,
int width,
int height)
{
return _cairo_surface_create_similar_solid (wrapper->target,
content, width, height,
CAIRO_COLOR_TRANSPARENT,
TRUE);
}
cairo_bool_t
_cairo_surface_wrapper_get_extents (cairo_surface_wrapper_t *wrapper,
cairo_rectangle_int_t *extents)
{
return _cairo_surface_get_extents (wrapper->target, extents);
}
cairo_bool_t
_cairo_surface_wrapper_has_show_text_glyphs (cairo_surface_wrapper_t *wrapper)
{
return cairo_surface_has_show_text_glyphs (wrapper->target);
}
void
_cairo_surface_wrapper_init (cairo_surface_wrapper_t *wrapper,
cairo_surface_t *target)
{
wrapper->target = cairo_surface_reference (target);
}
void
_cairo_surface_wrapper_fini (cairo_surface_wrapper_t *wrapper)
{
cairo_surface_destroy (wrapper->target);
}

File diff suppressed because it is too large Load diff

View file

@ -44,6 +44,7 @@
#include "cairo-svg.h"
#include "cairo-surface-private.h"
#include "cairo-surface-clipper-private.h"
typedef struct cairo_svg_document cairo_svg_document_t;
@ -52,8 +53,6 @@ typedef struct cairo_svg_surface {
cairo_content_t content;
unsigned int id;
double width;
double height;
@ -62,6 +61,7 @@ typedef struct cairo_svg_surface {
cairo_output_stream_t *xml_node;
cairo_array_t page_set;
cairo_surface_clipper_t clipper;
unsigned int clip_level;
unsigned int base_clip;
cairo_bool_t is_base_clip_emitted;

View file

@ -49,6 +49,7 @@
#include "cairo-path-fixed-private.h"
#include "cairo-paginated-private.h"
#include "cairo-scaled-font-subsets-private.h"
#include "cairo-surface-clipper-private.h"
#include "cairo-svg-surface-private.h"
typedef struct cairo_svg_page cairo_svg_page_t;
@ -63,6 +64,11 @@ static const cairo_svg_version_t _cairo_svg_versions[] =
#define CAIRO_SVG_VERSION_LAST ARRAY_LENGTH (_cairo_svg_versions)
static void
_cairo_svg_surface_emit_path (cairo_output_stream_t *output,
cairo_path_fixed_t *path,
cairo_matrix_t *ctm_inverse);
static cairo_bool_t
_cairo_svg_version_has_page_set_support (cairo_svg_version_t version)
{
@ -99,7 +105,6 @@ struct cairo_svg_document {
cairo_output_stream_t *xml_node_defs;
cairo_output_stream_t *xml_node_glyphs;
unsigned int surface_id;
unsigned int linear_pattern_id;
unsigned int radial_pattern_id;
unsigned int pattern_id;
@ -109,18 +114,11 @@ struct cairo_svg_document {
cairo_bool_t alpha_filter;
cairo_array_t meta_snapshots;
cairo_svg_version_t svg_version;
cairo_scaled_font_subsets_t *font_subsets;
};
typedef struct {
unsigned int id;
cairo_meta_surface_t *meta;
} cairo_meta_snapshot_t;
static cairo_status_t
_cairo_svg_document_create (cairo_output_stream_t *stream,
double width,
@ -278,8 +276,8 @@ _extract_svg_surface (cairo_surface_t *surface,
* Since: 1.2
**/
void
cairo_svg_surface_restrict_to_version (cairo_surface_t *abstract_surface,
cairo_svg_version_t version)
cairo_svg_surface_restrict_to_version (cairo_surface_t *abstract_surface,
cairo_svg_version_t version)
{
cairo_svg_surface_t *surface = NULL; /* hide compiler warning */
cairo_status_t status;
@ -306,7 +304,7 @@ cairo_svg_surface_restrict_to_version (cairo_surface_t *abstract_surface,
**/
void
cairo_svg_get_versions (cairo_svg_version_t const **versions,
int *num_versions)
int *num_versions)
{
if (versions != NULL)
*versions = _cairo_svg_versions;
@ -336,6 +334,73 @@ cairo_svg_version_to_string (cairo_svg_version_t version)
return _cairo_svg_version_strings[version];
}
static cairo_bool_t
_cliprect_covers_surface (cairo_svg_surface_t *surface,
cairo_path_fixed_t *path)
{
cairo_box_t box;
if (_cairo_path_fixed_is_rectangle (path, &box)) {
if (box.p1.x <= 0 &&
box.p1.y <= 0 &&
_cairo_fixed_to_double (box.p2.x) >= surface->width &&
_cairo_fixed_to_double (box.p2.y) >= surface->height)
{
return TRUE;
}
}
return FALSE;
}
static cairo_status_t
_cairo_svg_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias)
{
cairo_svg_surface_t *surface = cairo_container_of (clipper,
cairo_svg_surface_t,
clipper);
cairo_svg_document_t *document = surface->document;
unsigned int i;
if (path == NULL) {
for (i = 0; i < surface->clip_level; i++)
_cairo_output_stream_printf (surface->xml_node, "</g>\n");
surface->clip_level = 0;
return CAIRO_STATUS_SUCCESS;
}
/* skip trivial whole-page clips */
if (_cliprect_covers_surface (surface, path))
return CAIRO_STATUS_SUCCESS;
_cairo_output_stream_printf (document->xml_node_defs,
"<clipPath id=\"clip%d\">\n"
" <path ",
document->clip_id);
_cairo_svg_surface_emit_path (document->xml_node_defs, path, NULL);
_cairo_output_stream_printf (document->xml_node_defs,
"/>\n"
"</clipPath>\n");
_cairo_output_stream_printf (surface->xml_node,
"<g clip-path=\"url(#clip%d)\" "
"clip-rule=\"%s\">\n",
document->clip_id,
fill_rule == CAIRO_FILL_RULE_EVEN_ODD ?
"evenodd" : "nonzero");
document->clip_id++;
surface->clip_level++;
return CAIRO_STATUS_SUCCESS;
}
static cairo_surface_t *
_cairo_svg_surface_create_for_document (cairo_svg_document_t *document,
cairo_content_t content,
@ -359,8 +424,9 @@ _cairo_svg_surface_create_for_document (cairo_svg_document_t *document,
surface->document = _cairo_svg_document_reference (document);
surface->clip_level = 0;
_cairo_surface_clipper_init (&surface->clipper,
_cairo_svg_surface_clipper_intersect_clip_path);
surface->id = document->surface_id++;
surface->base_clip = document->clip_id++;
surface->is_base_clip_emitted = FALSE;
@ -388,8 +454,6 @@ _cairo_svg_surface_create_for_document (cairo_svg_document_t *document,
paginated = _cairo_paginated_surface_create (&surface->base,
surface->content,
surface->width,
surface->height,
&cairo_svg_surface_paginated_backend);
status = paginated->status;
if (status == CAIRO_STATUS_SUCCESS) {
@ -457,7 +521,7 @@ _cairo_svg_surface_store_page (cairo_svg_surface_t *surface)
return NULL;
}
page.surface_id = surface->id;
page.surface_id = surface->base.unique_id;
page.clip_level = surface->clip_level;
page.xml_node = surface->xml_node;
@ -468,11 +532,13 @@ _cairo_svg_surface_store_page (cairo_svg_surface_t *surface)
surface->xml_node = stream;
surface->clip_level = 0;
for (i = 0; i < page.clip_level; i++)
_cairo_output_stream_printf (page.xml_node, "</g>\n");
return _cairo_array_index (&surface->page_set, surface->page_set.num_elements - 1);
_cairo_surface_clipper_reset (&surface->clipper);
return _cairo_array_index (&surface->page_set,
surface->page_set.num_elements - 1);
}
static cairo_int_status_t
@ -486,7 +552,6 @@ _cairo_svg_surface_copy_page (void *abstract_surface)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
_cairo_memory_stream_copy (page->xml_node, surface->xml_node);
surface->clip_level = page->clip_level;
return CAIRO_STATUS_SUCCESS;
}
@ -596,7 +661,7 @@ _cairo_svg_path_close_path (void *closure)
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
static void
_cairo_svg_surface_emit_path (cairo_output_stream_t *output,
cairo_path_fixed_t *path,
cairo_matrix_t *ctm_inverse)
@ -615,12 +680,9 @@ _cairo_svg_surface_emit_path (cairo_output_stream_t *output,
_cairo_svg_path_curve_to,
_cairo_svg_path_close_path,
&info);
if (unlikely (status))
return status;
assert (status == CAIRO_STATUS_SUCCESS);
_cairo_output_stream_printf (output, "\"");
return status;
}
static cairo_int_status_t
@ -642,9 +704,8 @@ _cairo_svg_document_emit_outline_glyph_data (cairo_svg_document_t *document,
_cairo_output_stream_printf (document->xml_node_glyphs,
"<path style=\"stroke:none;\" ");
status = _cairo_svg_surface_emit_path (document->xml_node_glyphs, scaled_glyph->path, NULL);
if (unlikely (status))
return status;
_cairo_svg_surface_emit_path (document->xml_node_glyphs,
scaled_glyph->path, NULL);
_cairo_output_stream_printf (document->xml_node_glyphs,
"/>\n");
@ -847,22 +908,7 @@ _cairo_svg_surface_operation_supported (cairo_svg_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *pattern)
{
if (_cairo_svg_surface_analyze_operation (surface, op, pattern)
!= CAIRO_INT_STATUS_UNSUPPORTED)
{
return TRUE;
} else {
return FALSE;
}
}
static cairo_surface_t *
_cairo_svg_surface_create_similar (void *abstract_src,
cairo_content_t content,
int width,
int height)
{
return cairo_meta_surface_create (content, width, height);
return _cairo_svg_surface_analyze_operation (surface, op, pattern) != CAIRO_INT_STATUS_UNSUPPORTED;
}
static cairo_status_t
@ -893,6 +939,8 @@ _cairo_svg_surface_finish (void *abstract_surface)
}
_cairo_array_fini (&surface->page_set);
_cairo_surface_clipper_reset (&surface->clipper);
status2 = _cairo_svg_document_destroy (document);
if (status == CAIRO_STATUS_SUCCESS)
status = status2;
@ -900,6 +948,7 @@ _cairo_svg_surface_finish (void *abstract_surface)
return status;
}
static void
_cairo_svg_surface_emit_alpha_filter (cairo_svg_document_t *document)
{
@ -1120,112 +1169,139 @@ _cairo_svg_surface_emit_operator_for_style (cairo_output_stream_t *output,
}
static cairo_status_t
_cairo_svg_surface_emit_composite_image_pattern (cairo_output_stream_t *output,
cairo_svg_surface_t *svg_surface,
cairo_operator_t op,
cairo_surface_pattern_t *pattern,
int pattern_id,
const cairo_matrix_t *parent_matrix,
const char *extra_attributes)
_cairo_svg_surface_emit_surface (cairo_svg_document_t *document,
cairo_surface_t *surface)
{
cairo_rectangle_int_t extents;
cairo_bool_t is_bounded;
cairo_status_t status;
cairo_matrix_t p2u;
status = _cairo_surface_get_extents (pattern->surface, &extents);
if (_cairo_user_data_array_get_data (&surface->user_data,
(cairo_user_data_key_t *) document))
{
return CAIRO_STATUS_SUCCESS;
}
is_bounded = _cairo_surface_get_extents (surface, &extents);
assert (is_bounded);
_cairo_output_stream_printf (document->xml_node_defs,
"<image id=\"image%d\" width=\"%d\" height=\"%d\"",
surface->unique_id,
extents.width, extents.height);
_cairo_output_stream_printf (document->xml_node_defs, " xlink:href=\"");
status = _cairo_surface_base64_encode (surface,
document->xml_node_defs);
if (unlikely (status))
return status;
_cairo_output_stream_printf (document->xml_node_defs, "\"/>\n");
/* and tag it */
return _cairo_user_data_array_set_data (&surface->user_data,
(cairo_user_data_key_t *) document,
document, NULL);
}
static cairo_status_t
_cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t *output,
cairo_svg_surface_t *svg_surface,
cairo_operator_t op,
cairo_surface_pattern_t *pattern,
int pattern_id,
const cairo_matrix_t *parent_matrix,
const char *extra_attributes)
{
cairo_status_t status;
cairo_matrix_t p2u;
p2u = pattern->base.matrix;
status = cairo_matrix_invert (&p2u);
/* cairo_pattern_set_matrix ensures the matrix is invertible */
assert (status == CAIRO_STATUS_SUCCESS);
status = _cairo_svg_surface_emit_surface (svg_surface->document,
pattern->surface);
if (unlikely (status))
return status;
if (pattern_id != invalid_pattern_id) {
cairo_rectangle_int_t extents;
cairo_bool_t is_bounded;
is_bounded = _cairo_surface_get_extents (pattern->surface, &extents);
assert (is_bounded);
_cairo_output_stream_printf (output,
"<pattern id=\"pattern%d\" "
"patternUnits=\"userSpaceOnUse\" "
"width=\"%d\" height=\"%d\"",
"width=\"%d\" height=\"%d\" ",
pattern_id,
extents.width, extents.height);
_cairo_svg_surface_emit_transform (output, " patternTransform", &p2u, parent_matrix);
_cairo_output_stream_printf (output, ">\n");
_cairo_svg_surface_emit_transform (output,
" patternTransform",
&p2u, parent_matrix);
_cairo_output_stream_printf (output, ">\n ");
}
_cairo_output_stream_printf (output,
" <image width=\"%d\" height=\"%d\"",
extents.width, extents.height);
if (pattern_id == invalid_pattern_id) {
_cairo_svg_surface_emit_operator (output, svg_surface, op);
_cairo_svg_surface_emit_transform (output, " transform", &p2u, parent_matrix);
}
"<use xlink:href=\"#image%d\"",
pattern->surface->unique_id);
if (extra_attributes)
_cairo_output_stream_printf (output, " %s", extra_attributes);
_cairo_output_stream_printf (output, " xlink:href=\"");
if (pattern_id == invalid_pattern_id) {
_cairo_svg_surface_emit_operator (output, svg_surface, op);
_cairo_svg_surface_emit_transform (output,
" transform",
&p2u, parent_matrix);
}
_cairo_output_stream_printf (output, "/>\n");
status = _cairo_surface_base64_encode (pattern->surface, output);
_cairo_output_stream_printf (output, "\"/>\n");
if (pattern_id != invalid_pattern_id)
_cairo_output_stream_printf (output, "</pattern>\n");
return status;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_svg_surface_emit_meta_surface (cairo_svg_document_t *document,
cairo_meta_surface_t *surface,
int *id)
cairo_meta_surface_t *source)
{
cairo_status_t status;
cairo_surface_t *paginated_surface;
cairo_svg_surface_t *svg_surface;
cairo_meta_snapshot_t new_snapshot;
cairo_array_t *page_set;
cairo_output_stream_t *contents;
cairo_meta_surface_t *meta;
cairo_meta_snapshot_t *snapshot;
unsigned int num_elements;
unsigned int i;
/* search in already emitted meta snapshots */
num_elements = document->meta_snapshots.num_elements;
for (i = 0; i < num_elements; i++) {
snapshot = _cairo_array_index (&document->meta_snapshots, i);
meta = snapshot->meta;
if (meta->commands.num_elements == surface->commands.num_elements &&
_cairo_array_index (&meta->commands, 0) == _cairo_array_index (&surface->commands, 0)) {
*id = snapshot->id;
return CAIRO_STATUS_SUCCESS;
}
if (_cairo_user_data_array_get_data (&source->base.user_data,
(cairo_user_data_key_t *) document))
{
return CAIRO_STATUS_SUCCESS;
}
meta = (cairo_meta_surface_t *) _cairo_surface_snapshot (&surface->base);
if (unlikely (meta->base.status))
return meta->base.status;
paginated_surface = _cairo_svg_surface_create_for_document (document,
meta->content,
meta->width_pixels,
meta->height_pixels);
if (paginated_surface->status) {
cairo_surface_destroy (&meta->base);
source->content,
source->extents_pixels.width,
source->extents_pixels.height);
if (unlikely (paginated_surface->status))
return paginated_surface->status;
}
svg_surface = (cairo_svg_surface_t *) _cairo_paginated_surface_get_target (paginated_surface);
svg_surface = (cairo_svg_surface_t *)
_cairo_paginated_surface_get_target (paginated_surface);
cairo_surface_set_fallback_resolution (paginated_surface,
document->owner->x_fallback_resolution,
document->owner->y_fallback_resolution);
cairo_surface_set_device_offset (&svg_surface->base,
-source->extents_pixels.x,
-source->extents_pixels.y);
status = cairo_meta_surface_replay (&meta->base, paginated_surface);
status = cairo_meta_surface_replay (&source->base, paginated_surface);
if (unlikely (status)) {
cairo_surface_destroy (&meta->base);
cairo_surface_destroy (paginated_surface);
return status;
}
@ -1233,21 +1309,11 @@ _cairo_svg_surface_emit_meta_surface (cairo_svg_document_t *document,
cairo_surface_show_page (paginated_surface);
status = cairo_surface_status (paginated_surface);
if (unlikely (status)) {
cairo_surface_destroy (&meta->base);
cairo_surface_destroy (paginated_surface);
return status;
}
new_snapshot.meta = meta;
new_snapshot.id = svg_surface->id;
status = _cairo_array_append (&document->meta_snapshots, &new_snapshot);
if (unlikely (status)) {
cairo_surface_destroy (&meta->base);
cairo_surface_destroy (paginated_surface);
return status;
}
if (!svg_surface->is_base_clip_emitted) {
if (! svg_surface->is_base_clip_emitted) {
svg_surface->is_base_clip_emitted = TRUE;
_cairo_output_stream_printf (document->xml_node_defs,
"<clipPath id=\"clip%d\">\n"
@ -1258,19 +1324,19 @@ _cairo_svg_surface_emit_meta_surface (cairo_svg_document_t *document,
svg_surface->height);
}
if (meta->content == CAIRO_CONTENT_ALPHA) {
if (source->content == CAIRO_CONTENT_ALPHA) {
_cairo_svg_surface_emit_alpha_filter (document);
_cairo_output_stream_printf (document->xml_node_defs,
"<g id=\"surface%d\" "
"clip-path=\"url(#clip%d)\" "
"filter=\"url(#alpha)\">\n",
svg_surface->id,
source->base.unique_id,
svg_surface->base_clip);
} else {
_cairo_output_stream_printf (document->xml_node_defs,
"<g id=\"surface%d\" "
"clip-path=\"url(#clip%d)\">\n",
svg_surface->id,
source->base.unique_id,
svg_surface->base_clip);
}
@ -1293,19 +1359,16 @@ _cairo_svg_surface_emit_meta_surface (cairo_svg_document_t *document,
_cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
*id = new_snapshot.id;
status = cairo_surface_status (paginated_surface);
cairo_surface_destroy (paginated_surface);
/* FIXME: cairo_paginated_surface doesn't take a ref to the
* passed in target surface so we can't call destroy here.
* cairo_paginated_surface should be fixed, but for now just
* work around it. */
if (unlikely (status))
return status;
/* cairo_surface_destroy (svg_surface); */
return status;
/* and tag it */
return _cairo_user_data_array_set_data (&source->base.user_data,
(cairo_user_data_key_t *) document,
document, NULL);
}
static cairo_status_t
@ -1321,7 +1384,6 @@ _cairo_svg_surface_emit_composite_meta_pattern (cairo_output_stream_t *output,
cairo_meta_surface_t *meta_surface;
cairo_matrix_t p2u;
cairo_status_t status;
int id = 0;
p2u = pattern->base.matrix;
status = cairo_matrix_invert (&p2u);
@ -1329,8 +1391,7 @@ _cairo_svg_surface_emit_composite_meta_pattern (cairo_output_stream_t *output,
assert (status == CAIRO_STATUS_SUCCESS);
meta_surface = (cairo_meta_surface_t *) pattern->surface;
status = _cairo_svg_surface_emit_meta_surface (document, meta_surface, &id);
status = _cairo_svg_surface_emit_meta_surface (document, meta_surface);
if (unlikely (status))
return status;
@ -1340,15 +1401,15 @@ _cairo_svg_surface_emit_composite_meta_pattern (cairo_output_stream_t *output,
"patternUnits=\"userSpaceOnUse\" "
"width=\"%d\" height=\"%d\"",
pattern_id,
(int) ceil (meta_surface->width_pixels),
(int) ceil (meta_surface->height_pixels));
meta_surface->extents.width,
meta_surface->extents.height);
_cairo_svg_surface_emit_transform (output, " patternTransform", &p2u, parent_matrix);
_cairo_output_stream_printf (output, ">\n");
}
_cairo_output_stream_printf (output,
"<use xlink:href=\"#surface%d\"",
id);
meta_surface->base.unique_id);
if (pattern_id == invalid_pattern_id) {
_cairo_svg_surface_emit_operator (output, surface, op);
@ -1377,12 +1438,18 @@ _cairo_svg_surface_emit_composite_pattern (cairo_output_stream_t *output,
{
if (_cairo_surface_is_meta (pattern->surface)) {
return _cairo_svg_surface_emit_composite_meta_pattern (output, surface, op, pattern,
pattern_id, parent_matrix, extra_attributes);
return _cairo_svg_surface_emit_composite_meta_pattern (output, surface,
op, pattern,
pattern_id,
parent_matrix,
extra_attributes);
}
return _cairo_svg_surface_emit_composite_image_pattern (output, surface, op, pattern,
pattern_id, parent_matrix, extra_attributes);
return _cairo_svg_surface_emit_composite_surface_pattern (output, surface,
op, pattern,
pattern_id,
parent_matrix,
extra_attributes);
}
static cairo_status_t
@ -1716,7 +1783,9 @@ _cairo_svg_surface_emit_radial_pattern (cairo_svg_surface_t *surface,
document->radial_pattern_id,
x1, y1,
x1, y1, r1);
_cairo_svg_surface_emit_transform (document->xml_node_defs, "gradientTransform", &p2u, parent_matrix);
_cairo_svg_surface_emit_transform (document->xml_node_defs,
"gradientTransform",
&p2u, parent_matrix);
_cairo_output_stream_printf (document->xml_node_defs, ">\n");
if (extend == CAIRO_EXTEND_NONE || n_stops < 1)
@ -1981,11 +2050,15 @@ _cairo_svg_surface_fill_stroke (void *abstract_surface,
cairo_matrix_t *stroke_ctm_inverse,
double stroke_tolerance,
cairo_antialias_t stroke_antialias,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_svg_surface_t *surface = abstract_surface;
cairo_status_t status;
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->xml_node, "<path style=\"");
status = _cairo_svg_surface_emit_fill_style (surface->xml_node, surface, fill_op,
fill_source, fill_rule, stroke_ctm_inverse);
@ -1999,9 +2072,7 @@ _cairo_svg_surface_fill_stroke (void *abstract_surface,
_cairo_output_stream_printf (surface->xml_node, "\" ");
status = _cairo_svg_surface_emit_path (surface->xml_node, path, stroke_ctm_inverse);
if (unlikely (status))
return status;
_cairo_svg_surface_emit_path (surface->xml_node, path, stroke_ctm_inverse);
_cairo_svg_surface_emit_transform (surface->xml_node, " transform", stroke_ctm, NULL);
_cairo_output_stream_printf (surface->xml_node, "/>\n");
@ -2017,7 +2088,7 @@ _cairo_svg_surface_fill (void *abstract_surface,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_svg_surface_t *surface = abstract_surface;
cairo_status_t status;
@ -2027,6 +2098,10 @@ _cairo_svg_surface_fill (void *abstract_surface,
assert (_cairo_svg_surface_operation_supported (surface, op, source));
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->xml_node, "<path style=\" stroke:none;");
status = _cairo_svg_surface_emit_fill_style (surface->xml_node, surface, op, source, fill_rule, NULL);
if (unlikely (status))
@ -2034,16 +2109,14 @@ _cairo_svg_surface_fill (void *abstract_surface,
_cairo_output_stream_printf (surface->xml_node, "\" ");
status = _cairo_svg_surface_emit_path (surface->xml_node, path, NULL);
if (unlikely (status))
return status;
_cairo_svg_surface_emit_path (surface->xml_node, path, NULL);
_cairo_output_stream_printf (surface->xml_node, "/>\n");
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
static cairo_bool_t
_cairo_svg_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
@ -2053,13 +2126,13 @@ _cairo_svg_surface_get_extents (void *abstract_surface,
rectangle->y = 0;
/* XXX: The conversion to integers here is pretty bogus, (not to
* mention the aribitray limitation of width to a short(!). We
* mention the arbitrary limitation of width to a short(!). We
* may need to come up with a better interface for get_size.
*/
rectangle->width = (int) ceil (surface->width);
rectangle->height = (int) ceil (surface->height);
return CAIRO_STATUS_SUCCESS;
return TRUE;
}
static cairo_status_t
@ -2106,52 +2179,63 @@ static cairo_int_status_t
_cairo_svg_surface_paint (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_status_t status;
cairo_svg_surface_t *surface = abstract_surface;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return _cairo_svg_surface_analyze_operation (surface, op, source);
assert (_cairo_svg_surface_operation_supported (surface, op, source));
/* Emulation of clear and source operators, when no clipping region
* is defined. We just delete existing content of surface root node,
* and exit early if operator is clear.
* XXX: optimization of SOURCE operator doesn't work, since analyze
* above always return FALSE. In order to make it work, we need a way
* to know if there's an active clipping path.
* Optimization of CLEAR works because of a test in paginated surface,
* and an optimization in meta surface. */
if (surface->clip_level == 0 && op == CAIRO_OPERATOR_CLEAR) {
status = _cairo_output_stream_destroy (surface->xml_node);
if (unlikely (status)) {
surface->xml_node = NULL;
return status;
}
surface->xml_node = _cairo_memory_stream_create ();
if (_cairo_output_stream_get_status (surface->xml_node)) {
status = _cairo_output_stream_destroy (surface->xml_node);
surface->xml_node = NULL;
return status;
}
if (op == CAIRO_OPERATOR_CLEAR) {
if (surface->content == CAIRO_CONTENT_COLOR) {
_cairo_output_stream_printf (surface->xml_node,
"<rect "
"width=\"%f\" height=\"%f\" "
"style=\"opacity:1;"
"stroke:none;"
"fill:rgb(0,0,0);\"/>\n",
surface->width, surface->height);
}
*/
if ((op == CAIRO_OPERATOR_CLEAR || op == CAIRO_OPERATOR_SOURCE) &&
clip == NULL)
{
switch (surface->paginated_mode) {
case CAIRO_PAGINATED_MODE_FALLBACK:
ASSERT_NOT_REACHED;
case CAIRO_PAGINATED_MODE_ANALYZE:
return CAIRO_STATUS_SUCCESS;
case CAIRO_PAGINATED_MODE_RENDER:
status = _cairo_output_stream_destroy (surface->xml_node);
if (unlikely (status)) {
surface->xml_node = NULL;
return status;
}
surface->xml_node = _cairo_memory_stream_create ();
if (_cairo_output_stream_get_status (surface->xml_node)) {
status = _cairo_output_stream_destroy (surface->xml_node);
surface->xml_node = NULL;
return status;
}
if (op == CAIRO_OPERATOR_CLEAR) {
if (surface->content == CAIRO_CONTENT_COLOR) {
_cairo_output_stream_printf (surface->xml_node,
"<rect "
"width=\"%f\" height=\"%f\" "
"style=\"opacity:1;"
"stroke:none;"
"fill:rgb(0,0,0);\"/>\n",
surface->width, surface->height);
}
return CAIRO_STATUS_SUCCESS;
}
break;
}
} else {
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return _cairo_svg_surface_analyze_operation (surface, op, source);
assert (_cairo_svg_surface_operation_supported (surface, op, source));
}
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status))
return status;
return _cairo_svg_surface_emit_paint (surface->xml_node,
surface, op, source, 0, NULL);
}
@ -2161,7 +2245,7 @@ _cairo_svg_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_status_t status;
cairo_svg_surface_t *surface = abstract_surface;
@ -2189,6 +2273,10 @@ _cairo_svg_surface_mask (void *abstract_surface,
assert (_cairo_svg_surface_operation_supported (surface, op, source));
assert (_cairo_svg_surface_operation_supported (surface, CAIRO_OPERATOR_OVER, mask));
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status))
return status;
if (mask->type == CAIRO_PATTERN_TYPE_SURFACE) {
const cairo_surface_pattern_t *surface_pattern = (const cairo_surface_pattern_t*) mask;
cairo_content_t content = cairo_surface_get_content (surface_pattern->surface);
@ -2249,7 +2337,7 @@ _cairo_svg_surface_stroke (void *abstract_dst,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_svg_surface_t *surface = abstract_dst;
cairo_status_t status;
@ -2259,6 +2347,10 @@ _cairo_svg_surface_stroke (void *abstract_dst,
assert (_cairo_svg_surface_operation_supported (surface, op, source));
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->xml_node, "<path style=\"fill:none;");
status = _cairo_svg_surface_emit_stroke_style (surface->xml_node, surface, op,
source, stroke_style, ctm_inverse);
@ -2267,9 +2359,7 @@ _cairo_svg_surface_stroke (void *abstract_dst,
_cairo_output_stream_printf (surface->xml_node, "\" ");
status = _cairo_svg_surface_emit_path (surface->xml_node, path, ctm_inverse);
if (unlikely (status))
return status;
_cairo_svg_surface_emit_path (surface->xml_node, path, ctm_inverse);
_cairo_svg_surface_emit_transform (surface->xml_node, " transform", ctm, NULL);
_cairo_output_stream_printf (surface->xml_node, "/>\n");
@ -2284,8 +2374,8 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip,
int *remaining_glyphs)
{
cairo_svg_surface_t *surface = abstract_surface;
cairo_svg_document_t *document = surface->document;
@ -2302,6 +2392,10 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface,
if (num_glyphs <= 0)
return CAIRO_STATUS_SUCCESS;
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status))
return status;
/* FIXME it's probably possible to apply a pattern of a gradient to
* a group of symbols, but I don't know how yet. Gradients or patterns
* are translated by x and y properties of use element. */
@ -2349,7 +2443,9 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface,
FALLBACK:
_cairo_path_fixed_init (&path);
status = _cairo_scaled_font_glyph_path (scaled_font,(cairo_glyph_t *) glyphs, num_glyphs, &path);
status = _cairo_scaled_font_glyph_path (scaled_font,
(cairo_glyph_t *) glyphs,
num_glyphs, &path);
if (unlikely (status)) {
_cairo_path_fixed_fini (&path);
@ -2357,58 +2453,15 @@ FALLBACK:
}
status = _cairo_svg_surface_fill (abstract_surface, op, pattern,
&path, CAIRO_FILL_RULE_WINDING, 0.0, CAIRO_ANTIALIAS_SUBPIXEL, NULL);
&path, CAIRO_FILL_RULE_WINDING,
0.0, CAIRO_ANTIALIAS_SUBPIXEL,
clip);
_cairo_path_fixed_fini (&path);
return status;
}
static cairo_int_status_t
_cairo_svg_surface_intersect_clip_path (void *dst,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias)
{
cairo_svg_surface_t *surface = dst;
cairo_svg_document_t *document = surface->document;
cairo_status_t status;
unsigned int i;
if (path == NULL) {
for (i = 0; i < surface->clip_level; i++)
_cairo_output_stream_printf (surface->xml_node, "</g>\n");
surface->clip_level = 0;
return CAIRO_STATUS_SUCCESS;
}
_cairo_output_stream_printf (document->xml_node_defs,
"<clipPath id=\"clip%d\">\n"
" <path ",
document->clip_id);
status = _cairo_svg_surface_emit_path (document->xml_node_defs, path, NULL);
if (unlikely (status))
return status;
_cairo_output_stream_printf (document->xml_node_defs,
"/>\n"
"</clipPath>\n");
_cairo_output_stream_printf (surface->xml_node,
"<g clip-path=\"url(#clip%d)\" "
"clip-rule=\"%s\">\n",
document->clip_id,
fill_rule == CAIRO_FILL_RULE_EVEN_ODD ?
"evenodd" : "nonzero");
document->clip_id++;
surface->clip_level++;
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_svg_surface_get_font_options (void *abstract_surface,
cairo_font_options_t *options)
@ -2422,7 +2475,7 @@ _cairo_svg_surface_get_font_options (void *abstract_surface,
static const cairo_surface_backend_t cairo_svg_surface_backend = {
CAIRO_SURFACE_TYPE_SVG,
_cairo_svg_surface_create_similar,
NULL, /* create_similar: handled by wrapper */
_cairo_svg_surface_finish,
NULL, /* acquire_source_image */
NULL, /* release_source_image */
@ -2436,8 +2489,6 @@ static const cairo_surface_backend_t cairo_svg_surface_backend = {
NULL, /* check_span_renderer */
_cairo_svg_surface_copy_page,
_cairo_svg_surface_show_page,
NULL, /* set_clip_region */
_cairo_svg_surface_intersect_clip_path,
_cairo_svg_surface_get_extents,
NULL, /* _cairo_svg_surface_old_show_glyphs, */
_cairo_svg_surface_get_font_options,
@ -2452,7 +2503,6 @@ static const cairo_surface_backend_t cairo_svg_surface_backend = {
_cairo_svg_surface_show_glyphs,
NULL, /* snapshot */
NULL, /* is_similar */
NULL, /* reset */
_cairo_svg_surface_fill_stroke
};
@ -2487,7 +2537,6 @@ _cairo_svg_document_create (cairo_output_stream_t *output_stream,
document->width = width;
document->height = height;
document->surface_id = 0;
document->linear_pattern_id = 0;
document->radial_pattern_id = 0;
document->pattern_id = 0;
@ -2507,9 +2556,6 @@ _cairo_svg_document_create (cairo_output_stream_t *output_stream,
document->alpha_filter = FALSE;
_cairo_array_init (&document->meta_snapshots,
sizeof (cairo_meta_snapshot_t));
document->svg_version = version;
*document_out = document;
@ -2560,7 +2606,6 @@ _cairo_svg_document_finish (cairo_svg_document_t *document)
{
cairo_status_t status, status2;
cairo_output_stream_t *output = document->output_stream;
cairo_meta_snapshot_t *snapshot;
cairo_svg_page_t *page;
unsigned int i;
@ -2662,16 +2707,6 @@ _cairo_svg_document_finish (cairo_svg_document_t *document)
if (status == CAIRO_STATUS_SUCCESS)
status = status2;
for (i = 0; i < document->meta_snapshots.num_elements; i++) {
snapshot = _cairo_array_index (&document->meta_snapshots, i);
cairo_surface_finish (&snapshot->meta->base);
status2 = cairo_surface_status (&snapshot->meta->base);
cairo_surface_destroy (&snapshot->meta->base);
if (status == CAIRO_STATUS_SUCCESS)
status = status2;
}
_cairo_array_fini (&document->meta_snapshots);
document->finished = TRUE;
return status;

View file

@ -39,6 +39,8 @@
#include "cairoint.h"
#include "cairo-region-private.h"
/* private functions */
static int
@ -51,6 +53,8 @@ _cairo_traps_init (cairo_traps_t *traps)
traps->status = CAIRO_STATUS_SUCCESS;
traps->maybe_region = 1;
traps->num_traps = 0;
traps->traps_size = ARRAY_LENGTH (traps->traps_embedded);
@ -83,6 +87,8 @@ _cairo_traps_clear (cairo_traps_t *traps)
{
traps->status = CAIRO_STATUS_SUCCESS;
traps->maybe_region = 1;
traps->num_traps = 0;
traps->extents.p1.x = traps->extents.p1.y = INT32_MAX;
traps->extents.p2.x = traps->extents.p2.y = INT32_MIN;
@ -616,14 +622,18 @@ _cairo_traps_extents (const cairo_traps_t *traps,
* or %CAIRO_STATUS_NO_MEMORY
**/
cairo_int_status_t
_cairo_traps_extract_region (const cairo_traps_t *traps,
cairo_region_t **region)
_cairo_traps_extract_region (cairo_traps_t *traps,
cairo_region_t **region)
{
cairo_rectangle_int_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)];
cairo_rectangle_int_t *rects = stack_rects;
cairo_int_status_t status;
int i, rect_count;
/* we only treat this a hint... */
if (! traps->maybe_region)
return CAIRO_INT_STATUS_UNSUPPORTED;
for (i = 0; i < traps->num_traps; i++) {
if (traps->traps[i].left.p1.x != traps->traps[i].left.p2.x ||
traps->traps[i].right.p1.x != traps->traps[i].right.p2.x ||
@ -632,6 +642,7 @@ _cairo_traps_extract_region (const cairo_traps_t *traps,
! _cairo_fixed_is_integer (traps->traps[i].left.p1.x) ||
! _cairo_fixed_is_integer (traps->traps[i].right.p1.x))
{
traps->maybe_region = FALSE;
return CAIRO_INT_STATUS_UNSUPPORTED;
}
}
@ -655,7 +666,7 @@ _cairo_traps_extract_region (const cairo_traps_t *traps,
*/
if (x1 == x2 || y1 == y2)
continue;
rects[rect_count].x = x1;
rects[rect_count].y = y1;
rects[rect_count].width = x2 - x1;
@ -663,18 +674,13 @@ _cairo_traps_extract_region (const cairo_traps_t *traps,
rect_count++;
}
*region = cairo_region_create_rectangles (rects, rect_count);
status = cairo_region_status (*region);
status = (*region)->status;
if (rects != stack_rects)
free (rects);
if (unlikely (status)) {
cairo_region_destroy (*region);
*region = NULL;
}
return status;
}

View file

@ -42,6 +42,7 @@
#if CAIRO_HAS_FONT_SUBSET
#include "cairo-surface-private.h"
#include "cairo-surface-clipper-private.h"
#include "cairo-pdf-operators-private.h"
typedef cairo_status_t (*cairo_type3_glyph_surface_emit_image_t) (cairo_image_surface_t *image,
@ -55,16 +56,18 @@ typedef struct cairo_type3_glyph_surface {
cairo_pdf_operators_t pdf_operators;
cairo_matrix_t cairo_to_pdf;
cairo_type3_glyph_surface_emit_image_t emit_image;
cairo_surface_clipper_t clipper;
} cairo_type3_glyph_surface_t;
cairo_private cairo_surface_t *
_cairo_type3_glyph_surface_create (cairo_scaled_font_t *scaled_font,
_cairo_type3_glyph_surface_create (cairo_scaled_font_t *scaled_font,
cairo_output_stream_t *stream,
cairo_type3_glyph_surface_emit_image_t emit_image,
cairo_scaled_font_subsets_t *font_subsets);
cairo_scaled_font_subsets_t *font_subsets);
cairo_private void
_cairo_type3_glyph_surface_set_font_subsets_callback (void *abstract_surface,
_cairo_type3_glyph_surface_set_font_subsets_callback (void *abstract_surface,
cairo_pdf_operators_use_font_subset_t use_font_subset,
void *closure);

View file

@ -42,9 +42,31 @@
#include "cairo-output-stream-private.h"
#include "cairo-meta-surface-private.h"
#include "cairo-analysis-surface-private.h"
#include "cairo-surface-clipper-private.h"
static const cairo_surface_backend_t cairo_type3_glyph_surface_backend;
static cairo_status_t
_cairo_type3_glyph_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias)
{
cairo_type3_glyph_surface_t *surface = cairo_container_of (clipper,
cairo_type3_glyph_surface_t,
clipper);
if (path == NULL) {
_cairo_output_stream_printf (surface->stream, "Q q\n");
return CAIRO_STATUS_SUCCESS;
}
return _cairo_pdf_operators_clip (&surface->pdf_operators,
path,
fill_rule);
}
cairo_surface_t *
_cairo_type3_glyph_surface_create (cairo_scaled_font_t *scaled_font,
cairo_output_stream_t *stream,
@ -81,6 +103,9 @@ _cairo_type3_glyph_surface_create (cairo_scaled_font_t *scaled_font,
&surface->cairo_to_pdf,
font_subsets);
_cairo_surface_clipper_init (&surface->clipper,
_cairo_type3_glyph_surface_clipper_intersect_clip_path);
return &surface->base;
}
@ -155,30 +180,11 @@ _cairo_type3_glyph_surface_finish (void *abstract_surface)
return _cairo_pdf_operators_fini (&surface->pdf_operators);
}
static cairo_int_status_t
_cairo_type3_glyph_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_type3_glyph_surface_t *surface = abstract_surface;
if (path == NULL) {
_cairo_output_stream_printf (surface->stream, "Q q\n");
return CAIRO_STATUS_SUCCESS;
}
return _cairo_pdf_operators_clip (&surface->pdf_operators,
path,
fill_rule);
}
static cairo_int_status_t
_cairo_type3_glyph_surface_paint (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_type3_glyph_surface_t *surface = abstract_surface;
const cairo_surface_pattern_t *pattern;
@ -189,8 +195,13 @@ _cairo_type3_glyph_surface_paint (void *abstract_surface,
if (source->type != CAIRO_PATTERN_TYPE_SURFACE)
return CAIRO_INT_STATUS_IMAGE_FALLBACK;
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status))
return status;
pattern = (const cairo_surface_pattern_t *) source;
status = _cairo_surface_acquire_source_image (pattern->surface, &image, &image_extra);
status = _cairo_surface_acquire_source_image (pattern->surface,
&image, &image_extra);
if (unlikely (status))
goto fail;
@ -209,9 +220,11 @@ _cairo_type3_glyph_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
return _cairo_type3_glyph_surface_paint (abstract_surface, op, mask, extents);
return _cairo_type3_glyph_surface_paint (abstract_surface,
op, mask,
clip);
}
static cairo_int_status_t
@ -224,9 +237,14 @@ _cairo_type3_glyph_surface_stroke (void *abstract_surface,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_type3_glyph_surface_t *surface = abstract_surface;
cairo_int_status_t status;
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status))
return status;
return _cairo_pdf_operators_stroke (&surface->pdf_operators,
path,
@ -243,16 +261,18 @@ _cairo_type3_glyph_surface_fill (void *abstract_surface,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_type3_glyph_surface_t *surface = abstract_surface;
cairo_int_status_t status;
status = _cairo_pdf_operators_fill (&surface->pdf_operators,
path,
fill_rule);
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status))
return status;
return status;
return _cairo_pdf_operators_fill (&surface->pdf_operators,
path,
fill_rule);
}
static cairo_int_status_t
@ -262,8 +282,8 @@ _cairo_type3_glyph_surface_show_glyphs (void *abstract_surface,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip,
int *remaining_glyphs)
{
cairo_type3_glyph_surface_t *surface = abstract_surface;
cairo_int_status_t status;
@ -271,8 +291,14 @@ _cairo_type3_glyph_surface_show_glyphs (void *abstract_surface,
cairo_matrix_t new_ctm, ctm_inverse;
int i;
for (i = 0; i < num_glyphs; i++)
cairo_matrix_transform_point (&surface->cairo_to_pdf, &glyphs[i].x, &glyphs[i].y);
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status))
return status;
for (i = 0; i < num_glyphs; i++) {
cairo_matrix_transform_point (&surface->cairo_to_pdf,
&glyphs[i].x, &glyphs[i].y);
}
/* We require the matrix to be invertable. */
ctm_inverse = scaled_font->ctm;
@ -316,8 +342,6 @@ static const cairo_surface_backend_t cairo_type3_glyph_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* cairo_type3_glyph_surface_copy_page */
NULL, /* _cairo_type3_glyph_surface_show_page */
NULL, /* set_clip_region */
_cairo_type3_glyph_surface_intersect_clip_path,
NULL, /* _cairo_type3_glyph_surface_get_extents */
NULL, /* old_show_glyphs */
NULL, /* _cairo_type3_glyph_surface_get_font_options */

View file

@ -41,6 +41,7 @@
#include "cairo.h"
#include "cairo-fixed-type-private.h"
#include "cairo-list-private.h"
#include "cairo-reference-count-private.h"
typedef struct _cairo_array cairo_array_t;
@ -63,6 +64,7 @@ typedef struct _cairo_scaled_font_backend cairo_scaled_font_backend_t;
typedef struct _cairo_scaled_font_subsets cairo_scaled_font_subsets_t;
typedef struct _cairo_solid_pattern cairo_solid_pattern_t;
typedef struct _cairo_surface_backend cairo_surface_backend_t;
typedef struct _cairo_surface_wrapper cairo_surface_wrapper_t;
typedef struct _cairo_unscaled_font_backend cairo_unscaled_font_backend_t;
typedef struct _cairo_xlib_screen_info cairo_xlib_screen_info_t;
@ -167,6 +169,7 @@ typedef enum _cairo_internal_surface_type {
CAIRO_INTERNAL_SURFACE_TYPE_TEST_META,
CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED,
CAIRO_INTERNAL_SURFACE_TYPE_TEST_WRAPPING,
CAIRO_INTERNAL_SURFACE_TYPE_NULL,
CAIRO_INTERNAL_SURFACE_TYPE_TYPE3_GLYPH
} cairo_internal_surface_type_t;
@ -237,12 +240,6 @@ typedef enum _cairo_direction {
CAIRO_DIRECTION_REVERSE
} cairo_direction_t;
typedef enum _cairo_clip_mode {
CAIRO_CLIP_MODE_PATH,
CAIRO_CLIP_MODE_REGION,
CAIRO_CLIP_MODE_MASK
} cairo_clip_mode_t;
typedef struct _cairo_edge {
cairo_line_t edge;
int dir;

View file

@ -85,7 +85,7 @@ _cairo_user_scaled_font_create_meta_context (cairo_user_scaled_font_t *scaled_fo
CAIRO_CONTENT_COLOR_ALPHA :
CAIRO_CONTENT_ALPHA;
meta_surface = cairo_meta_surface_create (content, -1, -1);
meta_surface = cairo_meta_surface_create (content, NULL);
cr = cairo_create (meta_surface);
cairo_surface_destroy (meta_surface);
@ -114,11 +114,11 @@ _cairo_user_scaled_glyph_init (void *abstract_font,
cr = _cairo_user_scaled_font_create_meta_context (scaled_font);
if (face->scaled_font_methods.render_glyph)
if (face->scaled_font_methods.render_glyph) {
status = face->scaled_font_methods.render_glyph ((cairo_scaled_font_t *)scaled_font,
_cairo_scaled_glyph_index(scaled_glyph),
cr, &extents);
else
} else
status = CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
if (status == CAIRO_STATUS_SUCCESS)
@ -141,27 +141,16 @@ _cairo_user_scaled_glyph_init (void *abstract_font,
/* set metrics */
if (extents.width == 0.) {
/* Compute extents.x/y/width/height from meta_surface, in font space */
cairo_box_t bbox;
double x1, y1, x2, y2;
double x_scale, y_scale;
cairo_surface_t *null_surface;
cairo_surface_t *analysis_surface;
null_surface = _cairo_null_surface_create (cairo_surface_get_content (meta_surface));
analysis_surface = _cairo_analysis_surface_create (null_surface, -1, -1);
cairo_surface_destroy (null_surface);
status = analysis_surface->status;
if (unlikely (status))
return status;
_cairo_analysis_surface_set_ctm (analysis_surface,
&scaled_font->extent_scale);
status = cairo_meta_surface_replay (meta_surface, analysis_surface);
_cairo_analysis_surface_get_bounding_box (analysis_surface, &bbox);
cairo_surface_destroy (analysis_surface);
/* Compute extents.x/y/width/height from meta_surface,
* in font space.
*/
status = _cairo_meta_surface_get_bbox ((cairo_meta_surface_t *) meta_surface,
&bbox,
&scaled_font->extent_scale);
if (unlikely (status))
return status;
@ -231,7 +220,6 @@ _cairo_user_scaled_glyph_init (void *abstract_font,
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = _cairo_meta_surface_get_path (meta_surface, path);
if (unlikely (status)) {
_cairo_path_fixed_destroy (path);
return status;

View file

@ -40,6 +40,7 @@
#include "cairo-path-fixed-private.h"
#include "cairo-meta-surface-private.h"
#include "cairo-surface-clipper-private.h"
#include "cairo-cache-private.h"
#include <pixman.h>
@ -94,7 +95,7 @@ struct _cairo_vg_surface {
cairo_cache_entry_t snapshot_cache_entry;
cairo_bool_t clipped;
cairo_surface_clipper_t clipper;
unsigned long target_id;
};
@ -397,21 +398,21 @@ _vg_surface_create_similar (void *abstract_surface,
return cairo_vg_surface_create (surface->context, content, width, height);
}
static cairo_int_status_t
_vg_surface_intersect_clip_path (void *abstract_surface,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias)
static cairo_status_t
_vg_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias)
{
cairo_vg_surface_t *surface = abstract_surface;
cairo_vg_surface_t *surface = cairo_container_of (clipper,
cairo_vg_surface_t,
clipper);
cairo_vg_surface_t *mask;
cairo_rectangle_int_t extents, clip_extents;
cairo_solid_pattern_t white;
cairo_status_t status;
if (path == NULL) {
surface->clipped = FALSE;
vgMask (VG_INVALID_HANDLE,
VG_FILL_MASK, 0, 0, surface->width, surface->height);
vgSeti (VG_MASKING, VG_FALSE);
@ -419,16 +420,6 @@ _vg_surface_intersect_clip_path (void *abstract_surface,
return CAIRO_STATUS_SUCCESS;
}
extents.x = extents.y = 0;
extents.width = surface->width;
extents.height = surface->height;
_cairo_path_fixed_approximate_clip_extents (path, &clip_extents);
if (! _cairo_rectangle_intersect (&clip_extents, &extents))
surface->clipped = TRUE;
if (surface->clipped)
return CAIRO_STATUS_SUCCESS;
mask = (cairo_vg_surface_t *)
_vg_surface_create_similar (surface, CAIRO_CONTENT_ALPHA,
surface->width, surface->height);
@ -456,7 +447,7 @@ _vg_surface_intersect_clip_path (void *abstract_surface,
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
static cairo_bool_t
_vg_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *extents)
{
@ -467,7 +458,7 @@ _vg_surface_get_extents (void *abstract_surface,
extents->width = surface->width;
extents->height = surface->height;
return CAIRO_STATUS_SUCCESS;
return TRUE;
}
#define MAX_SEG 16 /* max number of knots to upload in a batch */
@ -589,7 +580,7 @@ _vg_close_path (void *closure)
static void
_vg_path_from_cairo (vg_path_t *vg_path,
cairo_path_fixed_t *path)
const cairo_path_fixed_t *path)
{
cairo_status_t status;
@ -805,7 +796,7 @@ _vg_setup_linear_source (cairo_vg_context_t *context,
static cairo_status_t
_vg_setup_radial_source (cairo_vg_context_t *context,
cairo_radial_pattern_t *rpat)
const cairo_radial_pattern_t *rpat)
{
VGfloat radial[5];
@ -832,7 +823,7 @@ _vg_setup_radial_source (cairo_vg_context_t *context,
static cairo_status_t
_vg_setup_solid_source (cairo_vg_context_t *context,
cairo_solid_pattern_t *spat)
const cairo_solid_pattern_t *spat)
{
VGfloat color[] = {
spat->color.red,
@ -960,7 +951,7 @@ _vg_surface_remove_from_cache (cairo_surface_t *abstract_surface)
static cairo_status_t
_vg_setup_surface_source (cairo_vg_context_t *context,
cairo_surface_pattern_t *spat)
const cairo_surface_pattern_t *spat)
{
cairo_surface_t *snapshot;
cairo_vg_surface_t *clone;
@ -1077,7 +1068,7 @@ _vg_surface_stroke (void *abstract_surface,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_vg_surface_t *surface = abstract_surface;
cairo_vg_context_t *context;
@ -1086,9 +1077,6 @@ _vg_surface_stroke (void *abstract_surface,
VGfloat strokeTransform[9];
vg_path_t vg_path;
if (surface->clipped)
return CAIRO_STATUS_SUCCESS;
if (! _vg_is_supported_operator (op))
return CAIRO_INT_STATUS_UNSUPPORTED;
@ -1105,6 +1093,12 @@ _vg_surface_stroke (void *abstract_surface,
return status;
}
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status)) {
_vg_context_unlock (context);
return status;
}
vg_path.path = vgCreatePath (VG_PATH_FORMAT_STANDARD,
VG_PATH_DATATYPE_F,
1, 0, 0, 0,
@ -1148,16 +1142,13 @@ _vg_surface_fill (void *abstract_surface,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_vg_surface_t *surface = abstract_surface;
cairo_vg_context_t *context;
cairo_status_t status;
vg_path_t vg_path;
if (surface->clipped)
return CAIRO_STATUS_SUCCESS;
if (op == CAIRO_OPERATOR_DEST)
return CAIRO_STATUS_SUCCESS;
@ -1177,6 +1168,12 @@ _vg_surface_fill (void *abstract_surface,
return status;
}
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status)) {
_vg_context_unlock (context);
return status;
}
vg_path.path = vgCreatePath (VG_PATH_FORMAT_STANDARD,
VG_PATH_DATATYPE_F,
1, 0,
@ -1208,15 +1205,12 @@ static cairo_int_status_t
_vg_surface_paint (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_vg_surface_t *surface = abstract_surface;
cairo_vg_context_t *context;
cairo_status_t status;
if (surface->clipped)
return CAIRO_STATUS_SUCCESS;
if (op == CAIRO_OPERATOR_DEST)
return CAIRO_STATUS_SUCCESS;
@ -1236,6 +1230,12 @@ _vg_surface_paint (void *abstract_surface,
return status;
}
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status)) {
_vg_context_unlock (context);
return status;
}
vgSeti (VG_BLEND_MODE, _vg_operator (op));
vgSetPaint (context->paint, VG_FILL_PATH);
@ -1273,14 +1273,11 @@ _vg_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_vg_surface_t *surface = abstract_surface;
cairo_status_t status;
if (surface->clipped)
return CAIRO_STATUS_SUCCESS;
if (! _vg_is_supported_operator (op))
return CAIRO_INT_STATUS_UNSUPPORTED;
@ -1291,7 +1288,7 @@ _vg_surface_mask (void *abstract_surface,
double alpha = context->alpha;
context->alpha = solid->color.alpha;
status = _vg_surface_paint (abstract_surface, op, source, extents);
status = _vg_surface_paint (abstract_surface, op, source, clip);
context->alpha = alpha;
_vg_context_unlock (context);
@ -1312,14 +1309,14 @@ _vg_surface_get_font_options (void *abstract_surface,
}
static cairo_int_status_t
_vg_surface_show_glyphs (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs,
cairo_rectangle_int_t *extents)
_vg_surface_show_glyphs (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
cairo_clip_t *clip,
int *remaining_glyphs)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_path_fixed_t path;
@ -1342,7 +1339,7 @@ _vg_surface_show_glyphs (void *abstract_surface,
CAIRO_FILL_RULE_WINDING,
CAIRO_GSTATE_TOLERANCE_DEFAULT,
CAIRO_ANTIALIAS_SUBPIXEL,
extents);
clip);
BAIL:
_cairo_path_fixed_fini (&path);
return status;
@ -1510,12 +1507,6 @@ _vg_surface_release_dest_image (void *abstract_surface,
cairo_vg_surface_t *surface = abstract_surface;
cairo_bool_t needs_unpremultiply;
/* XXX clipping is incorrect
* We can either composite through the current clip mask using fill,
* or what for the clipping overhaul patches, due to land any time
* soon now...
*/
_vg_format_to_pixman (surface->format, &needs_unpremultiply);
if (needs_unpremultiply) {
unpremultiply_argb (image->data,
@ -1545,6 +1536,8 @@ _vg_surface_finish (void *abstract_surface)
surface->snapshot_cache_entry.hash = 0;
}
_cairo_surface_clipper_reset (&surface->clipper);
if (surface->own_image)
vgDestroyImage (surface->image);
@ -1561,20 +1554,21 @@ static const cairo_surface_backend_t cairo_vg_surface_backend = {
CAIRO_SURFACE_TYPE_VG,
_vg_surface_create_similar,
_vg_surface_finish,
_vg_surface_acquire_source_image,
_vg_surface_release_source_image,
_vg_surface_acquire_dest_image,
_vg_surface_release_dest_image,
NULL, /* clone_similar */
NULL, /* composite */
NULL, /* fill_rectangles */
NULL, /* composite_trapezoids */
NULL, /* create_span_renderer */
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
NULL, /* set_clip_region */
_vg_surface_intersect_clip_path,
_vg_surface_get_extents,
NULL, /* old_show_glyphs */
_vg_surface_get_font_options, /* get_font_options */
@ -1591,7 +1585,6 @@ static const cairo_surface_backend_t cairo_vg_surface_backend = {
NULL, /* snapshot */
NULL, /* is_similar */
NULL, /* reset */
};
static cairo_surface_t *
@ -1617,15 +1610,14 @@ _vg_surface_create_internal (cairo_vg_context_t *context,
surface->width = width;
surface->height = height;
surface->clipped = FALSE;
_cairo_surface_clipper_init (&surface->clipper,
_vg_surface_clipper_intersect_clip_path);
surface->snapshot_cache_entry.hash = 0;
surface->target_id = 0;
/* Force an initial "clip", that resets the mask */
_vg_surface_intersect_clip_path (surface, NULL, 0, 0.0, 0);
CHECK_VG_ERRORS();
return &surface->base;
}

View file

@ -1360,6 +1360,7 @@ _cairo_win32_scaled_font_show_glyphs (void *abstract_font,
unsigned int height,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_region_t *clip_region,
int *remaining_glyphs)
{
cairo_win32_scaled_font_t *scaled_font = abstract_font;
@ -1381,15 +1382,17 @@ _cairo_win32_scaled_font_show_glyphs (void *abstract_font,
*/
COLORREF new_color;
status = _cairo_win32_surface_set_clip_region (surface, clip_region);
if (unlikely (status))
return status;
new_color = RGB (((int)solid_pattern->color.red_short) >> 8,
((int)solid_pattern->color.green_short) >> 8,
((int)solid_pattern->color.blue_short) >> 8);
status = _draw_glyphs_on_surface (surface, scaled_font, new_color,
0, 0,
glyphs, num_glyphs);
return status;
return _draw_glyphs_on_surface (surface, scaled_font, new_color,
0, 0,
glyphs, num_glyphs);
} else {
/* Otherwise, we need to draw using software fallbacks. We create a mask
* surface by drawing the the glyphs onto a DIB, black-on-white then
@ -1458,7 +1461,8 @@ _cairo_win32_scaled_font_show_glyphs (void *abstract_font,
source_x, source_y,
0, 0,
dest_x, dest_y,
width, height);
width, height,
clip_region);
_cairo_pattern_fini (&mask.base);

View file

@ -53,6 +53,7 @@
#include "cairo-meta-surface-private.h"
#include "cairo-scaled-font-subsets-private.h"
#include "cairo-image-info-private.h"
#include "cairo-surface-clipper-private.h"
#include <windows.h>
@ -128,7 +129,7 @@ analyze_surface_pattern_transparency (cairo_surface_pattern_t *pattern)
cairo_image_surface_t *image;
void *image_extra;
cairo_int_status_t status;
int x, y;
cairo_image_transparency_t transparency;
status = _cairo_surface_acquire_source_image (pattern->surface,
&image,
@ -136,38 +137,20 @@ analyze_surface_pattern_transparency (cairo_surface_pattern_t *pattern)
if (status)
return status;
if (image->base.status)
return image->base.status;
if (image->format == CAIRO_FORMAT_RGB24) {
transparency = _cairo_image_analyze_transparency (image);
switch (transparency) {
case CAIRO_IMAGE_UNKNOWN:
ASSERT_NOT_REACHED;
case CAIRO_IMAGE_IS_OPAQUE:
status = CAIRO_STATUS_SUCCESS;
goto RELEASE_SOURCE;
}
break;
if (image->format != CAIRO_FORMAT_ARGB32) {
/* If the surface does not support the image format, assume
* that it does have alpha. The image will be converted to
* rgb24 when the surface blends the image into the page
* color to remove the transparency. */
case CAIRO_IMAGE_HAS_BILEVEL_ALPHA:
case CAIRO_IMAGE_HAS_ALPHA:
status = CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
goto RELEASE_SOURCE;
break;
}
for (y = 0; y < image->height; y++) {
int a;
uint32_t *pixel = (uint32_t *) (image->data + y * image->stride);
for (x = 0; x < image->width; x++, pixel++) {
a = (*pixel & 0xff000000) >> 24;
if (a != 255) {
status = CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
goto RELEASE_SOURCE;
}
}
}
status = CAIRO_STATUS_SUCCESS;
RELEASE_SOURCE:
_cairo_surface_release_source_image (pattern->surface, image, image_extra);
return status;
@ -176,8 +159,6 @@ RELEASE_SOURCE:
static cairo_bool_t
surface_pattern_supported (const cairo_surface_pattern_t *pattern)
{
cairo_extend_t extend;
if (_cairo_surface_is_meta (pattern->surface))
return TRUE;
@ -187,19 +168,7 @@ surface_pattern_supported (const cairo_surface_pattern_t *pattern)
return FALSE;
}
extend = cairo_pattern_get_extend ((cairo_pattern_t*)&pattern->base);
switch (extend) {
case CAIRO_EXTEND_NONE:
case CAIRO_EXTEND_REPEAT:
case CAIRO_EXTEND_REFLECT:
/* There's no point returning FALSE for EXTEND_PAD, as the image
* surface does not currently implement it either */
case CAIRO_EXTEND_PAD:
return TRUE;
}
ASSERT_NOT_REACHED;
return FALSE;
return TRUE;
}
static cairo_bool_t
@ -390,7 +359,8 @@ _cairo_win32_printing_surface_paint_meta_pattern (cairo_win32_surface_t *surfa
XFORM xform;
int x_tile, y_tile, left, right, top, bottom;
RECT clip;
cairo_surface_t *meta_surface = pattern->surface;
cairo_meta_surface_t *meta_surface = (cairo_meta_surface_t *) pattern->surface;
cairo_box_t bbox;
extend = cairo_pattern_get_extend (&pattern->base);
@ -406,7 +376,7 @@ _cairo_win32_printing_surface_paint_meta_pattern (cairo_win32_surface_t *surfa
SaveDC (surface->dc);
_cairo_matrix_to_win32_xform (&p2d, &xform);
status = _cairo_surface_get_extents (meta_surface, &meta_extents);
status = _cairo_meta_surface_get_bbox (meta_surface, &bbox, NULL);
if (status)
return status;
@ -415,10 +385,10 @@ _cairo_win32_printing_surface_paint_meta_pattern (cairo_win32_surface_t *surfa
return status;
if (extend == CAIRO_EXTEND_REPEAT || extend == CAIRO_EXTEND_REFLECT) {
left = (int) floor((double)clip.left/meta_extents.width);
right = (int) ceil((double)clip.right/meta_extents.width);
top = (int) floor((double)clip.top/meta_extents.height);
bottom = (int) ceil((double)clip.bottom/meta_extents.height);
left = (int) floor (clip.left / _cairo_fixed_to_double (bbox.p2.x - bbox.p1.x));
right = (int) ceil (clip.right / _cairo_fixed_to_double (bbox.p2.x - bbox.p1.x));
top = (int) floor (clip.top / _cairo_fixed_to_double (bbox.p2.y - bbox.p1.y));
bottom = (int) ceil (clip.bottom / _cairo_fixed_to_double (bbox.p2.y - bbox.p1.y));
} else {
left = 0;
right = 1;
@ -427,7 +397,7 @@ _cairo_win32_printing_surface_paint_meta_pattern (cairo_win32_surface_t *surfa
}
old_content = surface->content;
if (cairo_surface_get_content (meta_surface) == CAIRO_CONTENT_COLOR) {
if (meta_surface->base.content == CAIRO_CONTENT_COLOR) {
cairo_pattern_t *source;
cairo_solid_pattern_t black;
@ -490,7 +460,8 @@ _cairo_win32_printing_surface_paint_meta_pattern (cairo_win32_surface_t *surfa
SelectClipPath (surface->dc, RGN_AND);
SaveDC (surface->dc); /* Allow clip path to be reset during replay */
status = _cairo_meta_surface_replay_region (meta_surface, &surface->base,
status = _cairo_meta_surface_replay_region (&meta_surface->base,
&surface->base,
CAIRO_META_REGION_NATIVE);
assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
/* Restore both the clip save and our earlier path SaveDC */
@ -594,7 +565,6 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surf
cairo_extend_t extend;
cairo_image_surface_t *image;
void *image_extra;
cairo_surface_t *opaque_surface;
cairo_image_surface_t *opaque_image = NULL;
BITMAPINFO bi;
cairo_matrix_t m;
@ -651,13 +621,15 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surf
&mime_size,
&mime_info);
}
if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
if (_cairo_status_is_error (status))
return status;
use_mime = (status == CAIRO_STATUS_SUCCESS);
if (!use_mime && image->format != CAIRO_FORMAT_RGB24) {
cairo_surface_pattern_t opaque_pattern;
cairo_surface_t *opaque_surface;
cairo_surface_pattern_t image_pattern;
cairo_solid_pattern_t background_pattern;
opaque_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
image->width,
@ -667,36 +639,27 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surf
goto CLEANUP_OPAQUE_IMAGE;
}
_cairo_pattern_init_for_surface (&opaque_pattern, &image->base);
status = _cairo_surface_fill_rectangle (opaque_surface,
CAIRO_OPERATOR_SOURCE,
background_color,
0, 0,
image->width, image->height);
if (status) {
_cairo_pattern_fini (&opaque_pattern.base);
_cairo_pattern_init_solid (&background_pattern,
background_color,
CAIRO_CONTENT_COLOR);
status = _cairo_surface_paint (opaque_surface,
CAIRO_OPERATOR_SOURCE,
&background_pattern.base,
NULL);
if (status)
goto CLEANUP_OPAQUE_IMAGE;
}
status = _cairo_surface_composite (CAIRO_OPERATOR_OVER,
&opaque_pattern.base,
NULL,
opaque_surface,
0, 0,
0, 0,
0, 0,
image->width,
image->height);
if (status) {
_cairo_pattern_fini (&opaque_pattern.base);
_cairo_pattern_init_for_surface (&image_pattern, &image->base);
status = _cairo_surface_paint (opaque_surface,
CAIRO_OPERATOR_OVER,
&image_pattern.base,
NULL);
_cairo_pattern_fini (&image_pattern.base);
if (status)
goto CLEANUP_OPAQUE_IMAGE;
}
_cairo_pattern_fini (&opaque_pattern.base);
opaque_image = (cairo_image_surface_t *) opaque_surface;
} else {
opaque_surface = &image->base;
opaque_image = image;
}
@ -767,7 +730,7 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surf
CLEANUP_OPAQUE_IMAGE:
if (opaque_image != image)
cairo_surface_destroy (opaque_surface);
cairo_surface_destroy (&opaque_image->base);
CLEANUP_IMAGE:
_cairo_surface_release_source_image (pattern->surface, image, image_extra);
@ -1085,17 +1048,15 @@ _cairo_win32_printing_surface_emit_path (cairo_win32_surface_t *surface,
cairo_path_fixed_t *path)
{
win32_path_info_t path_info;
cairo_status_t status;
path_info.surface = surface;
status = _cairo_path_fixed_interpret (path,
CAIRO_DIRECTION_FORWARD,
_cairo_win32_printing_surface_path_move_to,
_cairo_win32_printing_surface_path_line_to,
_cairo_win32_printing_surface_path_curve_to,
_cairo_win32_printing_surface_path_close_path,
&path_info);
return status;
return _cairo_path_fixed_interpret (path,
CAIRO_DIRECTION_FORWARD,
_cairo_win32_printing_surface_path_move_to,
_cairo_win32_printing_surface_path_line_to,
_cairo_win32_printing_surface_path_curve_to,
_cairo_win32_printing_surface_path_close_path,
&path_info);
}
static cairo_int_status_t
@ -1109,14 +1070,16 @@ _cairo_win32_printing_surface_show_page (void *abstract_surface)
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_win32_printing_surface_intersect_clip_path (void *abstract_surface,
static cairo_status_t
_cairo_win32_printing_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias)
{
cairo_win32_surface_t *surface = abstract_surface;
cairo_win32_surface_t *surface = cairo_container_of (clipper,
cairo_win32_surface_t,
clipper);
cairo_status_t status;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
@ -1164,10 +1127,15 @@ static cairo_int_status_t
_cairo_win32_printing_surface_paint (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_win32_surface_t *surface = abstract_surface;
cairo_solid_pattern_t clear;
cairo_status_t status;
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (status)
return status;
if (op == CAIRO_OPERATOR_CLEAR) {
_cairo_win32_printing_surface_init_clear_color (surface, &clear);
@ -1242,7 +1210,7 @@ _cairo_win32_printing_surface_stroke (void *abstract_surface,
cairo_matrix_t *stroke_ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_win32_surface_t *surface = abstract_surface;
cairo_int_status_t status;
@ -1258,6 +1226,10 @@ _cairo_win32_printing_surface_stroke (void *abstract_surface,
cairo_matrix_t mat;
double scale;
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (status)
return status;
if (op == CAIRO_OPERATOR_CLEAR) {
_cairo_win32_printing_surface_init_clear_color (surface, &clear);
source = (cairo_pattern_t*) &clear;
@ -1364,12 +1336,16 @@ _cairo_win32_printing_surface_fill (void *abstract_surface,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
cairo_win32_surface_t *surface = abstract_surface;
cairo_int_status_t status;
cairo_solid_pattern_t clear;
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (status)
return status;
if (op == CAIRO_OPERATOR_CLEAR) {
_cairo_win32_printing_surface_init_clear_color (surface, &clear);
source = (cairo_pattern_t*) &clear;
@ -1423,8 +1399,8 @@ _cairo_win32_printing_surface_show_glyphs (void *abstract_surfac
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip,
int *remaining_glyphs)
{
cairo_win32_surface_t *surface = abstract_surface;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
@ -1435,6 +1411,10 @@ _cairo_win32_printing_surface_show_glyphs (void *abstract_surfac
cairo_bool_t old_has_ctm;
cairo_solid_pattern_t clear;
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (status)
return status;
if (op == CAIRO_OPERATOR_CLEAR) {
_cairo_win32_printing_surface_init_clear_color (surface, &clear);
source = (cairo_pattern_t*) &clear;
@ -1547,8 +1527,8 @@ _cairo_win32_printing_surface_show_glyphs (void *abstract_surfac
status = _cairo_win32_surface_show_glyphs (surface, op,
source, glyphs,
num_glyphs, scaled_font,
remaining_glyphs,
extents);
clip,
remaining_glyphs);
if (surface->has_ctm)
cairo_scaled_font_destroy (scaled_font);
@ -1607,7 +1587,12 @@ _cairo_win32_printing_surface_create_similar (void *abstract_surface,
int width,
int height)
{
return cairo_meta_surface_create (content, width, height);
cairo_rectangle_t extents;
extents.x = extents.y = 0;
extents.width = width;
extents.height = height;
return cairo_meta_surface_create (content, &extents);
}
static cairo_int_status_t
@ -1698,6 +1683,9 @@ cairo_win32_printing_surface_create (HDC hdc)
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
}
_cairo_surface_clipper_init (&surface->clipper,
_cairo_win32_printing_surface_clipper_intersect_clip_path);
surface->image = NULL;
surface->format = CAIRO_FORMAT_RGB24;
surface->content = CAIRO_CONTENT_COLOR_ALPHA;
@ -1725,13 +1713,12 @@ cairo_win32_printing_surface_create (HDC hdc)
_cairo_win32_printing_surface_init_ps_mode (surface);
_cairo_win32_printing_surface_init_image_support (surface);
_cairo_surface_init (&surface->base, &cairo_win32_printing_surface_backend,
_cairo_surface_init (&surface->base,
&cairo_win32_printing_surface_backend,
CAIRO_CONTENT_COLOR_ALPHA);
paginated = _cairo_paginated_surface_create (&surface->base,
CAIRO_CONTENT_COLOR_ALPHA,
surface->extents.width,
surface->extents.height,
&cairo_win32_surface_paginated_backend);
/* paginated keeps the only reference to surface now, drop ours */
@ -1762,8 +1749,6 @@ static const cairo_surface_backend_t cairo_win32_printing_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* copy_page */
_cairo_win32_printing_surface_show_page,
NULL, /* set_clip_region */
_cairo_win32_printing_surface_intersect_clip_path,
_cairo_win32_surface_get_extents,
NULL, /* old_show_glyphs */
_cairo_win32_printing_surface_get_font_options,
@ -1779,7 +1764,6 @@ static const cairo_surface_backend_t cairo_win32_printing_surface_backend = {
_cairo_win32_printing_surface_show_glyphs,
NULL, /* snapshot */
NULL, /* is_similar */
NULL, /* reset */
NULL, /* fill_stroke */
};

View file

@ -38,6 +38,7 @@
#include "cairo-win32.h"
#include "cairoint.h"
#include "cairo-surface-clipper-private.h"
#ifndef SHADEBLENDCAPS
#define SHADEBLENDCAPS 120
@ -81,6 +82,10 @@ typedef struct _cairo_win32_surface {
cairo_rectangle_int_t clip_rect;
HRGN initial_clip_rgn;
cairo_bool_t had_simple_clip;
cairo_region_t *clip_region;
/* For path clipping to the printing-surface */
cairo_surface_clipper_t clipper;
/* Surface DC flags */
uint32_t flags;
@ -137,13 +142,17 @@ _cairo_surface_is_win32_printing (cairo_surface_t *surface);
cairo_status_t
_cairo_win32_surface_finish (void *abstract_surface);
cairo_int_status_t
cairo_bool_t
_cairo_win32_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle);
uint32_t
_cairo_win32_flags_for_dc (HDC dc);
cairo_status_t
_cairo_win32_surface_set_clip_region (void *abstract_surface,
cairo_region_t *region);
cairo_int_status_t
_cairo_win32_surface_show_glyphs (void *surface,
cairo_operator_t op,
@ -151,8 +160,8 @@ _cairo_win32_surface_show_glyphs (void *surface,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs,
cairo_rectangle_int_t *extents);
cairo_clip_t *clip,
int *remaining_glyphs);
cairo_surface_t *
_cairo_win32_surface_create_similar (void *abstract_src,

View file

@ -468,7 +468,8 @@ _cairo_win32_surface_clone_similar (void *abstract_surface,
src_x, src_y,
0, 0,
0, 0,
width, height);
width, height,
NULL);
_cairo_pattern_fini (&pattern.base);
@ -693,6 +694,91 @@ _cairo_win32_surface_release_dest_image (void *abstract_surfa
cairo_surface_destroy ((cairo_surface_t *)local);
}
cairo_status_t
_cairo_win32_surface_set_clip_region (void *abstract_surface,
cairo_region_t *region)
{
cairo_win32_surface_t *surface = abstract_surface;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
if (surface->clip_region == region)
return CAIRO_STATUS_SUCCESS;
cairo_region_destroy (surface->clip_region);
surface->clip_region = cairo_region_reference (region);
/* The semantics we want is that any clip set by cairo combines
* is intersected with the clip on device context that the
* surface was created for. To implement this, we need to
* save the original clip when first setting a clip on surface.
*/
/* Clear any clip set by cairo, return to the original first */
status = _cairo_win32_restore_initial_clip (surface);
/* Then combine any new region with it */
if (region) {
cairo_rectangle_int_t extents;
int num_rects;
RGNDATA *data;
size_t data_size;
RECT *rects;
int i;
HRGN gdi_region;
/* Create a GDI region for the cairo region */
cairo_region_get_extents (region, &extents);
num_rects = cairo_region_num_rectangles (region);
/* XXX see notes in _cairo_win32_save_initial_clip --
* this code will interact badly with a HDC which had an initial
* world transform -- we should probably manually transform the
* region rects, because SelectClipRgn takes device units, not
* logical units (unlike IntersectClipRect).
*/
data_size = sizeof (RGNDATAHEADER) + num_rects * sizeof (RECT);
data = malloc (data_size);
if (!data)
return _cairo_error(CAIRO_STATUS_NO_MEMORY);
rects = (RECT *)data->Buffer;
data->rdh.dwSize = sizeof (RGNDATAHEADER);
data->rdh.iType = RDH_RECTANGLES;
data->rdh.nCount = num_rects;
data->rdh.nRgnSize = num_rects * sizeof (RECT);
data->rdh.rcBound.left = extents.x;
data->rdh.rcBound.top = extents.y;
data->rdh.rcBound.right = extents.x + extents.width;
data->rdh.rcBound.bottom = extents.y + extents.height;
for (i = 0; i < num_rects; i++) {
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (region, i, &rect);
rects[i].left = rect.x;
rects[i].top = rect.y;
rects[i].right = rect.x + rect.width;
rects[i].bottom = rect.y + rect.height;
}
gdi_region = ExtCreateRegion (NULL, data_size, data);
free (data);
if (!gdi_region)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
/* AND the new region into our DC */
if (ExtSelectClipRgn (surface->dc, gdi_region, RGN_AND) == ERROR)
status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region");
DeleteObject (gdi_region);
}
return status;
}
#if !defined(AC_SRC_OVER)
#define AC_SRC_OVER 0x00
#pragma pack(1)
@ -889,7 +975,8 @@ _cairo_win32_surface_composite (cairo_operator_t op,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height)
unsigned int height,
cairo_region_t *clip_region)
{
cairo_win32_surface_t *dst = abstract_dst;
cairo_win32_surface_t *src;
@ -1030,7 +1117,7 @@ _cairo_win32_surface_composite (cairo_operator_t op,
fflush (stderr);
#endif
/* If the src recangle doesn't wholly lie within the src extents,
/* If the src rectangle doesn't wholly lie within the src extents,
* fudge things. We really need to do fixup on the unpainted
* region -- e.g. the SOURCE operator is broken for areas outside
* of the extents, because it won't clear that area to transparent
@ -1150,6 +1237,10 @@ _cairo_win32_surface_composite (cairo_operator_t op,
fflush (stderr);
#endif
status = _cairo_win32_surface_set_clip_region (dst, clip_region);
if (status)
return status;
/* If we need to repeat, we turn the repeated blit into
* a bunch of piece-by-piece blits.
*/
@ -1283,7 +1374,8 @@ UNSUPPORTED:
src_x, src_y,
mask_x, mask_y,
dst_x, dst_y,
width, height);
width, height,
clip_region);
}
return CAIRO_INT_STATUS_UNSUPPORTED;
@ -1387,6 +1479,10 @@ _cairo_win32_surface_fill_rectangles (void *abstract_surface,
if (surface->format != CAIRO_FORMAT_RGB24)
return CAIRO_INT_STATUS_UNSUPPORTED;
status = _cairo_win32_surface_set_clip_region (surface, NULL);
if (status)
return status;
/* Optimize for no destination alpha (surface->pixman_image is non-NULL for all
* surfaces with alpha.)
*/
@ -1432,133 +1528,20 @@ _cairo_win32_surface_fill_rectangles (void *abstract_surface,
return status;
}
static cairo_int_status_t
_cairo_win32_surface_set_clip_region (void *abstract_surface,
cairo_region_t *region)
{
cairo_win32_surface_t *surface = abstract_surface;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
/* If we are in-memory, then we set the clip on the image surface
* as well as on the underlying GDI surface.
*/
if (surface->image) {
unsigned int serial;
serial = _cairo_surface_allocate_clip_serial (surface->image);
status = _cairo_surface_set_clip_region (surface->image, region, serial);
if (status)
return status;
}
/* The semantics we want is that any clip set by cairo combines
* is intersected with the clip on device context that the
* surface was created for. To implement this, we need to
* save the original clip when first setting a clip on surface.
*/
/* Clear any clip set by cairo, return to the original first */
status = _cairo_win32_restore_initial_clip (surface);
/* Then combine any new region with it */
if (region) {
cairo_rectangle_int_t extents;
int num_rects;
RGNDATA *data;
size_t data_size;
RECT *rects;
int i;
HRGN gdi_region;
cairo_rectangle_int_t rect0;
/* Create a GDI region for the cairo region */
cairo_region_get_extents (region, &extents);
num_rects = cairo_region_num_rectangles (region);
if (num_rects == 1)
cairo_region_get_rectangle (region, 0, &rect0);
if (num_rects == 1 &&
rect0.x == 0 &&
rect0.y == 0 &&
rect0.width == surface->extents.width &&
rect0.width == surface->extents.height)
{
gdi_region = NULL;
SelectClipRgn (surface->dc, NULL);
IntersectClipRect (surface->dc,
rect0.x,
rect0.y,
rect0.x + rect0.width,
rect0.y + rect0.height);
} else {
/* XXX see notes in _cairo_win32_save_initial_clip --
* this code will interact badly with a HDC which had an initial
* world transform -- we should probably manually transform the
* region rects, because SelectClipRgn takes device units, not
* logical units (unlike IntersectClipRect).
*/
data_size = sizeof (RGNDATAHEADER) + num_rects * sizeof (RECT);
data = malloc (data_size);
if (!data)
return _cairo_error(CAIRO_STATUS_NO_MEMORY);
rects = (RECT *)data->Buffer;
data->rdh.dwSize = sizeof (RGNDATAHEADER);
data->rdh.iType = RDH_RECTANGLES;
data->rdh.nCount = num_rects;
data->rdh.nRgnSize = num_rects * sizeof (RECT);
data->rdh.rcBound.left = extents.x;
data->rdh.rcBound.top = extents.y;
data->rdh.rcBound.right = extents.x + extents.width;
data->rdh.rcBound.bottom = extents.y + extents.height;
for (i = 0; i < num_rects; i++) {
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (region, i, &rect);
rects[i].left = rect.x;
rects[i].top = rect.y;
rects[i].right = rect.x + rect.width;
rects[i].bottom = rect.y + rect.height;
}
gdi_region = ExtCreateRegion (NULL, data_size, data);
free (data);
if (!gdi_region)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
/* AND the new region into our DC */
if (ExtSelectClipRgn (surface->dc, gdi_region, RGN_AND) == ERROR)
status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region");
DeleteObject (gdi_region);
}
}
return status;
}
cairo_int_status_t
cairo_bool_t
_cairo_win32_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
cairo_win32_surface_t *surface = abstract_surface;
*rectangle = surface->extents;
return CAIRO_STATUS_SUCCESS;
return TRUE;
}
static cairo_status_t
_cairo_win32_surface_flush (void *abstract_surface)
{
return _cairo_surface_reset_clip (abstract_surface);
return _cairo_win32_surface_set_clip_region (abstract_surface, NULL);
}
#define STACK_GLYPH_SIZE 256
@ -1570,8 +1553,8 @@ _cairo_win32_surface_show_glyphs (void *surface,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip,
int *remaining_glyphs)
{
#if CAIRO_HAS_WIN32_FONT
cairo_win32_surface_t *dst = surface;
@ -1611,11 +1594,19 @@ _cairo_win32_surface_show_glyphs (void *surface,
/* If we have a fallback mask clip set on the dst, we have
* to go through the fallback path, but only if we're not
* doing this for printing */
if (dst->base.clip &&
!(dst->flags & CAIRO_WIN32_SURFACE_FOR_PRINTING) &&
(dst->base.clip->mode != CAIRO_CLIP_MODE_REGION ||
dst->base.clip->surface != NULL))
return CAIRO_INT_STATUS_UNSUPPORTED;
if (clip != NULL) {
if ((dst->flags & CAIRO_WIN32_SURFACE_FOR_PRINTING) == 0) {
cairo_region_t *clip_region;
cairo_status_t status;
status = _cairo_clip_get_region (clip, &clip_region);
assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO);
if (status)
return status;
_cairo_win32_surface_set_clip_region (surface, clip_region);
}
}
solid_pattern = (cairo_solid_pattern_t *)source;
color = RGB(((int)solid_pattern->color.red_short) >> 8,
@ -1957,19 +1948,6 @@ _cairo_win32_surface_is_similar (void *surface_a,
return a->dc == b->dc;
}
static cairo_status_t
_cairo_win32_surface_reset (void *abstract_surface)
{
cairo_win32_surface_t *surface = abstract_surface;
cairo_status_t status;
status = _cairo_win32_surface_set_clip_region (surface, NULL);
if (status)
return status;
return CAIRO_STATUS_SUCCESS;
}
typedef struct _cairo_win32_surface_span_renderer {
cairo_span_renderer_t base;
@ -1979,6 +1957,7 @@ typedef struct _cairo_win32_surface_span_renderer {
cairo_image_surface_t *mask;
cairo_win32_surface_t *dst;
cairo_region_t *clip_region;
cairo_composite_rectangles_t composite_rectangles;
} cairo_win32_surface_span_renderer_t;
@ -2031,18 +2010,20 @@ _cairo_win32_surface_span_renderer_finish (void *abstract_renderer)
rects->src.y,
0, 0, /* mask.x, mask.y */
rects->dst.x, rects->dst.y,
rects->width, rects->height);
rects->width, rects->height,
renderer->clip_region);
} else {
/* otherwise go through the fallback_composite path which
* will do the appropriate surface acquisition */
status = _cairo_surface_fallback_composite (
renderer->op,
renderer->pattern, mask_pattern, dst,
renderer->pattern, mask_pattern, &dst->base,
rects->src.x,
rects->src.y,
0, 0, /* mask.x, mask.y */
rects->dst.x, rects->dst.y,
rects->width, rects->height);
rects->width, rects->height,
renderer->clip_region);
}
cairo_pattern_destroy (mask_pattern);
@ -2073,15 +2054,16 @@ _cairo_win32_surface_create_span_renderer (cairo_operator_t op,
const cairo_pattern_t *pattern,
void *abstract_dst,
cairo_antialias_t antialias,
const cairo_composite_rectangles_t *rects)
const cairo_composite_rectangles_t *rects,
cairo_region_t *clip_region)
{
cairo_win32_surface_t *dst = abstract_dst;
cairo_win32_surface_span_renderer_t *renderer
= calloc(1, sizeof(*renderer));
cairo_win32_surface_span_renderer_t *renderer;
cairo_status_t status;
int width = rects->width;
int height = rects->height;
renderer = calloc(1, sizeof(*renderer));
if (renderer == NULL)
return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY);
@ -2093,6 +2075,7 @@ _cairo_win32_surface_create_span_renderer (cairo_operator_t op,
renderer->pattern = pattern;
renderer->antialias = antialias;
renderer->dst = dst;
renderer->clip_region = clip_region;
renderer->composite_rectangles = *rects;
@ -2128,8 +2111,6 @@ static const cairo_surface_backend_t cairo_win32_surface_backend = {
_cairo_win32_surface_check_span_renderer,
NULL, /* copy_page */
NULL, /* show_page */
_cairo_win32_surface_set_clip_region,
NULL, /* intersect_clip_path */
_cairo_win32_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
@ -2146,8 +2127,6 @@ static const cairo_surface_backend_t cairo_win32_surface_backend = {
NULL, /* snapshot */
_cairo_win32_surface_is_similar,
_cairo_win32_surface_reset
};
/* Notes:

View file

@ -75,6 +75,7 @@ typedef struct cairo_xcb_surface {
cairo_bool_t have_clip_rects;
xcb_rectangle_t *clip_rects;
int num_clip_rects;
cairo_region_t *clip_region;
xcb_render_picture_t src_picture, dst_picture;
xcb_render_pictforminfo_t xrender_format;
@ -166,6 +167,93 @@ _xcb_render_format_to_content (xcb_render_pictforminfo_t *xrender_format)
return CAIRO_CONTENT_COLOR;
}
static void
_cairo_xcb_surface_set_gc_clip_rects (cairo_xcb_surface_t *surface)
{
if (surface->have_clip_rects)
xcb_set_clip_rectangles(surface->dpy, XCB_CLIP_ORDERING_YX_SORTED, surface->gc,
0, 0,
surface->num_clip_rects,
surface->clip_rects );
}
static void
_cairo_xcb_surface_set_picture_clip_rects (cairo_xcb_surface_t *surface)
{
if (surface->have_clip_rects)
xcb_render_set_picture_clip_rectangles (surface->dpy, surface->dst_picture,
0, 0,
surface->num_clip_rects,
surface->clip_rects);
}
static cairo_status_t
_cairo_xcb_surface_set_clip_region (void *abstract_surface,
cairo_region_t *region)
{
cairo_xcb_surface_t *surface = abstract_surface;
if (region == surface->clip_region)
return CAIRO_STATUS_SUCCESS;
cairo_region_destroy (surface->clip_region);
region = cairo_region_reference (region);
if (surface->clip_rects) {
free (surface->clip_rects);
surface->clip_rects = NULL;
}
surface->have_clip_rects = FALSE;
surface->num_clip_rects = 0;
if (region == NULL) {
uint32_t none[] = { XCB_NONE };
if (surface->gc)
xcb_change_gc (surface->dpy, surface->gc, XCB_GC_CLIP_MASK, none);
if (surface->xrender_format.id != XCB_NONE && surface->dst_picture)
xcb_render_change_picture (surface->dpy, surface->dst_picture,
XCB_RENDER_CP_CLIP_MASK, none);
} else {
xcb_rectangle_t *rects = NULL;
int n_rects, i;
n_rects = cairo_region_num_rectangles (region);
if (n_rects > 0) {
rects = _cairo_malloc_ab (n_rects, sizeof(xcb_rectangle_t));
if (rects == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} else {
rects = NULL;
}
for (i = 0; i < n_rects; i++) {
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (region, i, &rect);
rects[i].x = rect.x;
rects[i].y = rect.y;
rects[i].width = rect.width;
rects[i].height = rect.height;
}
surface->have_clip_rects = TRUE;
surface->clip_rects = rects;
surface->num_clip_rects = n_rects;
if (surface->gc)
_cairo_xcb_surface_set_gc_clip_rects (surface);
if (surface->dst_picture)
_cairo_xcb_surface_set_picture_clip_rects (surface);
}
return CAIRO_STATUS_SUCCESS;
}
static cairo_surface_t *
_cairo_xcb_surface_create_similar (void *abstract_src,
cairo_content_t content,
@ -223,6 +311,7 @@ _cairo_xcb_surface_finish (void *abstract_surface)
xcb_free_gc (surface->dpy, surface->gc);
free (surface->clip_rects);
cairo_region_destroy (surface->clip_region);
surface->dpy = NULL;
@ -475,26 +564,6 @@ _cairo_xcb_surface_ensure_src_picture (cairo_xcb_surface_t *surface)
}
}
static void
_cairo_xcb_surface_set_picture_clip_rects (cairo_xcb_surface_t *surface)
{
if (surface->have_clip_rects)
xcb_render_set_picture_clip_rectangles (surface->dpy, surface->dst_picture,
0, 0,
surface->num_clip_rects,
surface->clip_rects);
}
static void
_cairo_xcb_surface_set_gc_clip_rects (cairo_xcb_surface_t *surface)
{
if (surface->have_clip_rects)
xcb_set_clip_rectangles(surface->dpy, XCB_CLIP_ORDERING_YX_SORTED, surface->gc,
0, 0,
surface->num_clip_rects,
surface->clip_rects );
}
static void
_cairo_xcb_surface_ensure_dst_picture (cairo_xcb_surface_t *surface)
{
@ -1124,7 +1193,8 @@ _cairo_xcb_surface_composite (cairo_operator_t op,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height)
unsigned int height,
cairo_region_t *clip_region)
{
cairo_surface_attributes_t src_attr, mask_attr;
cairo_xcb_surface_t *dst = abstract_dst;
@ -1163,6 +1233,10 @@ _cairo_xcb_surface_composite (cairo_operator_t op,
goto BAIL;
}
status = _cairo_xcb_surface_set_clip_region (dst, clip_region);
if (unlikely (status))
goto BAIL;
status = _cairo_xcb_surface_set_attributes (src, &src_attr);
if (status)
goto BAIL;
@ -1257,7 +1331,8 @@ _cairo_xcb_surface_composite (cairo_operator_t op,
mask ? mask->height : 0,
src_x, src_y,
mask_x, mask_y,
dst_x, dst_y, width, height);
dst_x, dst_y, width, height,
clip_region);
BAIL:
if (mask)
@ -1279,6 +1354,7 @@ _cairo_xcb_surface_fill_rectangles (void *abstract_surface,
xcb_render_color_t render_color;
xcb_rectangle_t static_xrects[16];
xcb_rectangle_t *xrects = static_xrects;
cairo_status_t status;
int i;
if (!CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE (surface))
@ -1289,6 +1365,9 @@ _cairo_xcb_surface_fill_rectangles (void *abstract_surface,
render_color.blue = color->blue_short;
render_color.alpha = color->alpha_short;
status = _cairo_xcb_surface_set_clip_region (surface, NULL);
assert (status == CAIRO_STATUS_SUCCESS);
if (num_rects > ARRAY_LENGTH(static_xrects)) {
xrects = _cairo_malloc_ab (num_rects, sizeof(xcb_rectangle_t));
if (xrects == NULL)
@ -1415,7 +1494,8 @@ _cairo_xcb_surface_composite_trapezoids (cairo_operator_t op,
unsigned int width,
unsigned int height,
cairo_trapezoid_t *traps,
int num_traps)
int num_traps,
cairo_region_t *clip_region)
{
cairo_surface_attributes_t attributes;
cairo_xcb_surface_t *dst = abstract_dst;
@ -1475,6 +1555,11 @@ _cairo_xcb_surface_composite_trapezoids (cairo_operator_t op,
render_src_y = src_y + render_reference_y - dst_y;
_cairo_xcb_surface_ensure_dst_picture (dst);
status = _cairo_xcb_surface_set_clip_region (dst, clip_region);
if (unlikely (status))
goto BAIL;
status = _cairo_xcb_surface_set_attributes (src, &attributes);
if (status)
goto BAIL;
@ -1516,7 +1601,8 @@ _cairo_xcb_surface_composite_trapezoids (cairo_operator_t op,
width, height,
src_x, src_y,
0, 0,
dst_x, dst_y, width, height);
dst_x, dst_y, width, height,
clip_region);
} else {
xcb_render_trapezoid_t xtraps_stack[16];
@ -1562,68 +1648,7 @@ _cairo_xcb_surface_composite_trapezoids (cairo_operator_t op,
return status;
}
static cairo_int_status_t
_cairo_xcb_surface_set_clip_region (void *abstract_surface,
cairo_region_t *region)
{
cairo_xcb_surface_t *surface = abstract_surface;
if (surface->clip_rects) {
free (surface->clip_rects);
surface->clip_rects = NULL;
}
surface->have_clip_rects = FALSE;
surface->num_clip_rects = 0;
if (region == NULL) {
uint32_t none[] = { XCB_NONE };
if (surface->gc)
xcb_change_gc (surface->dpy, surface->gc, XCB_GC_CLIP_MASK, none);
if (surface->xrender_format.id != XCB_NONE && surface->dst_picture)
xcb_render_change_picture (surface->dpy, surface->dst_picture,
XCB_RENDER_CP_CLIP_MASK, none);
} else {
xcb_rectangle_t *rects = NULL;
int n_rects, i;
n_rects = cairo_region_num_rectangles (region);
if (n_rects > 0) {
rects = _cairo_malloc_ab (n_rects, sizeof(xcb_rectangle_t));
if (rects == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} else {
rects = NULL;
}
for (i = 0; i < n_rects; i++) {
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (region, i, &rect);
rects[i].x = rect.x;
rects[i].y = rect.y;
rects[i].width = rect.width;
rects[i].height = rect.height;
}
surface->have_clip_rects = TRUE;
surface->clip_rects = rects;
surface->num_clip_rects = n_rects;
if (surface->gc)
_cairo_xcb_surface_set_gc_clip_rects (surface);
if (surface->dst_picture)
_cairo_xcb_surface_set_picture_clip_rects (surface);
}
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
static cairo_bool_t
_cairo_xcb_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
@ -1635,7 +1660,7 @@ _cairo_xcb_surface_get_extents (void *abstract_surface,
rectangle->width = surface->width;
rectangle->height = surface->height;
return CAIRO_STATUS_SUCCESS;
return TRUE;
}
/* XXX: _cairo_xcb_surface_get_font_options */
@ -1654,8 +1679,8 @@ _cairo_xcb_surface_show_glyphs (void *abstract_dst,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs,
cairo_rectangle_int_t *extents);
cairo_clip_t *clip,
int *remaining_glyphs);
static cairo_bool_t
_cairo_xcb_surface_is_similar (void *surface_a,
@ -1682,40 +1707,29 @@ _cairo_xcb_surface_is_similar (void *surface_a,
return a->xrender_format.id == xrender_format->id;
}
static cairo_status_t
_cairo_xcb_surface_reset (void *abstract_surface)
{
cairo_xcb_surface_t *surface = abstract_surface;
cairo_status_t status;
status = _cairo_xcb_surface_set_clip_region (surface, NULL);
if (status)
return status;
return CAIRO_STATUS_SUCCESS;
}
/* XXX: move this to the bottom of the file, XCB and Xlib */
static const cairo_surface_backend_t cairo_xcb_surface_backend = {
CAIRO_SURFACE_TYPE_XCB,
_cairo_xcb_surface_create_similar,
_cairo_xcb_surface_finish,
_cairo_xcb_surface_acquire_source_image,
_cairo_xcb_surface_release_source_image,
_cairo_xcb_surface_acquire_dest_image,
_cairo_xcb_surface_release_dest_image,
_cairo_xcb_surface_clone_similar,
_cairo_xcb_surface_composite,
_cairo_xcb_surface_fill_rectangles,
_cairo_xcb_surface_composite_trapezoids,
NULL, /* create_span_renderer */
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
_cairo_xcb_surface_set_clip_region,
NULL, /* intersect_clip_path */
_cairo_xcb_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
@ -1733,8 +1747,6 @@ static const cairo_surface_backend_t cairo_xcb_surface_backend = {
_cairo_xcb_surface_snapshot,
_cairo_xcb_surface_is_similar,
_cairo_xcb_surface_reset
};
/**
@ -1853,8 +1865,9 @@ _cairo_xcb_surface_create_internal (xcb_connection_t *dpy,
surface->have_clip_rects = FALSE;
surface->clip_rects = NULL;
surface->num_clip_rects = 0;
surface->clip_region = NULL;
return (cairo_surface_t *) surface;
return &surface->base;
}
static xcb_screen_t *
@ -2463,8 +2476,8 @@ _cairo_xcb_surface_show_glyphs (void *abstract_dst,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip,
int *remaining_glyphs)
{
cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
cairo_xcb_surface_t *dst = abstract_dst;
@ -2474,6 +2487,7 @@ _cairo_xcb_surface_show_glyphs (void *abstract_dst,
cairo_xcb_surface_t *src = NULL;
cairo_solid_pattern_t solid_pattern;
cairo_region_t *clip_region = NULL;
if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (dst) || dst->xrender_format.id == XCB_NONE)
return CAIRO_INT_STATUS_UNSUPPORTED;
@ -2497,10 +2511,12 @@ _cairo_xcb_surface_show_glyphs (void *abstract_dst,
* fallback clip masking, we have to go through the full
* fallback path.
*/
if (dst->base.clip &&
(dst->base.clip->mode != CAIRO_CLIP_MODE_REGION ||
dst->base.clip->surface != NULL))
return CAIRO_INT_STATUS_UNSUPPORTED;
if (clip != NULL) {
status = _cairo_clip_get_region (clip, &clip_region);
assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO);
if (status)
return status;
}
operation = _categorize_composite_operation (dst, op, src_pattern, TRUE);
if (operation == DO_UNSUPPORTED)
@ -2564,6 +2580,10 @@ _cairo_xcb_surface_show_glyphs (void *abstract_dst,
goto BAIL;
}
status = _cairo_xcb_surface_set_clip_region (dst, clip_region);
if (unlikely (status))
goto BAIL;
status = _cairo_xcb_surface_set_attributes (src, &attributes);
if (status)
goto BAIL;

View file

@ -85,11 +85,11 @@ struct _cairo_xlib_surface {
Picture dst_picture, src_picture;
unsigned int clip_dirty;
cairo_bool_t have_clip_rects;
cairo_bool_t gc_has_clip_rects;
XRectangle embedded_clip_rects[8];
XRectangle *clip_rects;
int num_clip_rects;
cairo_region_t *clip_region;
XRenderPictFormat *xrender_format;
cairo_filter_t filter;

File diff suppressed because it is too large Load diff

View file

@ -44,6 +44,10 @@
#define CAIRO_TOLERANCE_MINIMUM _cairo_fixed_to_double(1)
#if !defined(INFINITY)
#define INFINITY HUGE_VAL
#endif
static const cairo_t _cairo_nil = {
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
CAIRO_STATUS_NO_MEMORY, /* status */
@ -57,7 +61,8 @@ static const cairo_t _cairo_nil = {
FALSE, /* has_current_point */
FALSE, /* has_curve_to */
FALSE, /* is_box */
FALSE, /* is_region */
FALSE, /* maybe_fill_region */
TRUE, /* is_empty_fill */
{{{NULL,NULL}}} /* link */
}}
};
@ -496,25 +501,28 @@ cairo_push_group_with_content (cairo_t *cr, cairo_content_t content)
{
cairo_status_t status;
cairo_rectangle_int_t extents;
const cairo_rectangle_int_t *clip_extents;
cairo_surface_t *parent_surface, *group_surface = NULL;
cairo_bool_t is_empty;
if (unlikely (cr->status))
return;
parent_surface = _cairo_gstate_get_target (cr->gstate);
/* Get the extents that we'll use in creating our new group surface */
status = _cairo_surface_get_extents (parent_surface, &extents);
if (unlikely (status))
goto bail;
status = _cairo_clip_intersect_to_rectangle (_cairo_gstate_get_clip (cr->gstate), &extents);
if (unlikely (status))
goto bail;
group_surface = cairo_surface_create_similar (parent_surface,
content,
extents.width,
extents.height);
status = cairo_surface_status (group_surface);
/* Get the extents that we'll use in creating our new group surface */
is_empty = _cairo_surface_get_extents (parent_surface, &extents);
clip_extents = _cairo_clip_get_extents (_cairo_gstate_get_clip (cr->gstate));
if (clip_extents != NULL)
is_empty = _cairo_rectangle_intersect (&extents, clip_extents);
group_surface = _cairo_surface_create_similar_solid (parent_surface,
content,
extents.width,
extents.height,
CAIRO_COLOR_TRANSPARENT,
TRUE);
status = group_surface->status;
if (unlikely (status))
goto bail;
@ -2340,7 +2348,7 @@ cairo_in_stroke (cairo_t *cr, double x, double y)
cairo_bool_t inside = FALSE;
if (unlikely (cr->status))
return 0;
return FALSE;
status = _cairo_gstate_in_stroke (cr->gstate,
cr->path,
@ -2370,16 +2378,10 @@ cairo_in_stroke (cairo_t *cr, double x, double y)
cairo_bool_t
cairo_in_fill (cairo_t *cr, double x, double y)
{
cairo_bool_t inside;
if (unlikely (cr->status))
return 0;
return FALSE;
_cairo_gstate_in_fill (cr->gstate,
cr->path,
x, y, &inside);
return inside;
return _cairo_gstate_in_fill (cr->gstate, cr->path, x, y);
}
/**
@ -2600,8 +2602,6 @@ cairo_clip_extents (cairo_t *cr,
double *x1, double *y1,
double *x2, double *y2)
{
cairo_status_t status;
if (unlikely (cr->status)) {
if (x1)
*x1 = 0.0;
@ -2615,9 +2615,38 @@ cairo_clip_extents (cairo_t *cr,
return;
}
status = _cairo_gstate_clip_extents (cr->gstate, x1, y1, x2, y2);
if (unlikely (status))
_cairo_set_error (cr, status);
if (! _cairo_gstate_clip_extents (cr->gstate, x1, y1, x2, y2)) {
*x1 = -INFINITY;
*y1 = -INFINITY;
*x2 = +INFINITY;
*y2 = +INFINITY;
}
}
/**
* cairo_in_clip:
* @cr: a cairo context
* @x: X coordinate of the point to test
* @y: Y coordinate of the point to test
*
* Tests whether the given point is inside the area that would be
* visible through the current clip, i.e. the area that would be filled by
* a cairo_paint() operation.
*
* See cairo_clip(), and cairo_clip_preserve().
*
* Return value: A non-zero value if the point is inside, or zero if
* outside.
*
* Since: 1.10
**/
cairo_bool_t
cairo_in_clip (cairo_t *cr, double x, double y)
{
if (unlikely (cr->status))
return FALSE;
return _cairo_gstate_in_clip (cr->gstate, x, y);
}
static cairo_rectangle_list_t *

View file

@ -788,6 +788,9 @@ cairo_in_stroke (cairo_t *cr, double x, double y);
cairo_public cairo_bool_t
cairo_in_fill (cairo_t *cr, double x, double y);
cairo_public cairo_bool_t
cairo_in_clip (cairo_t *cr, double x, double y);
/* Rectangular extents */
cairo_public void
cairo_stroke_extents (cairo_t *cr,
@ -2169,8 +2172,7 @@ cairo_image_surface_create_from_png_stream (cairo_read_func_t read_func,
cairo_public cairo_surface_t *
cairo_meta_surface_create (cairo_content_t content,
double width_pixels,
double height_pixels);
const cairo_rectangle_t *extents);
cairo_public void
cairo_meta_surface_ink_extents (cairo_surface_t *surface,
@ -2451,39 +2453,45 @@ cairo_public cairo_region_t *
cairo_region_create_rectangle (const cairo_rectangle_int_t *rectangle);
cairo_public cairo_region_t *
cairo_region_create_rectangles (cairo_rectangle_int_t *rects,
cairo_region_create_rectangles (const cairo_rectangle_int_t *rects,
int count);
cairo_public cairo_region_t *
cairo_region_copy (cairo_region_t *original);
cairo_region_copy (const cairo_region_t *original);
cairo_public cairo_region_t *
cairo_region_reference (cairo_region_t *);
cairo_public void
cairo_region_destroy (cairo_region_t *region);
cairo_public cairo_bool_t
cairo_region_equal (const cairo_region_t *a, const cairo_region_t *b);
cairo_public cairo_status_t
cairo_region_status (cairo_region_t *region);
cairo_region_status (const cairo_region_t *region);
cairo_public void
cairo_region_get_extents (cairo_region_t *region,
cairo_region_get_extents (const cairo_region_t *region,
cairo_rectangle_int_t *extents);
cairo_public int
cairo_region_num_rectangles (cairo_region_t *region);
cairo_region_num_rectangles (const cairo_region_t *region);
cairo_public void
cairo_region_get_rectangle (cairo_region_t *region,
cairo_region_get_rectangle (const cairo_region_t *region,
int nth_rectangle,
cairo_rectangle_int_t *rectangle);
cairo_public cairo_bool_t
cairo_region_is_empty (cairo_region_t *region);
cairo_region_is_empty (const cairo_region_t *region);
cairo_public cairo_region_overlap_t
cairo_region_contains_rectangle (cairo_region_t *region,
cairo_region_contains_rectangle (const cairo_region_t *region,
const cairo_rectangle_int_t *rectangle);
cairo_public cairo_bool_t
cairo_region_contains_point (cairo_region_t *region, int x, int y);
cairo_region_contains_point (const cairo_region_t *region, int x, int y);
cairo_public void
cairo_region_translate (cairo_region_t *region, int dx, int dy);

View file

@ -125,7 +125,7 @@ _cairo_win32_tmpfile (void);
#define STRINGIFY(macro_or_string) STRINGIFY_ARG (macro_or_string)
#define STRINGIFY_ARG(contents) #contents
#ifdef __GNUC__
#if defined (__GNUC__)
#define cairo_container_of(ptr, type, member) ({ \
const __typeof__ (((type *) 0)->member) *mptr__ = (ptr); \
(type *) ((char *) mptr__ - offsetof (type, member)); \
@ -252,6 +252,15 @@ cairo_private void
_cairo_box_round_to_rectangle (const cairo_box_t *box,
cairo_rectangle_int_t *rectangle);
static inline void
_cairo_unbounded_rectangle_init (cairo_rectangle_int_t *rect)
{
rect->x = CAIRO_RECT_INT_MIN;
rect->y = CAIRO_RECT_INT_MIN;
rect->width = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN;
rect->height = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN;
}
cairo_private cairo_bool_t
_cairo_rectangle_intersect (cairo_rectangle_int_t *dst,
const cairo_rectangle_int_t *src);
@ -489,6 +498,7 @@ struct _cairo_scaled_font_backend {
unsigned int height,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_region_t *clip_region,
int *remaining_glyphs);
cairo_warn cairo_int_status_t
@ -615,6 +625,7 @@ struct _cairo_surface_backend {
int *clone_offset_y,
cairo_surface_t **clone_out);
/* XXX remove to a separate cairo_surface_compositor_t */
/* XXX: dst should be the first argument for consistency */
cairo_warn cairo_int_status_t
(*composite) (cairo_operator_t op,
@ -628,7 +639,8 @@ struct _cairo_surface_backend {
int dst_x,
int dst_y,
unsigned int width,
unsigned int height);
unsigned int height,
cairo_region_t *clip_region);
cairo_warn cairo_int_status_t
(*fill_rectangles) (void *surface,
@ -650,14 +662,16 @@ struct _cairo_surface_backend {
unsigned int width,
unsigned int height,
cairo_trapezoid_t *traps,
int num_traps);
int num_traps,
cairo_region_t *region);
cairo_warn cairo_span_renderer_t *
(*create_span_renderer) (cairo_operator_t op,
const cairo_pattern_t *pattern,
void *dst,
cairo_antialias_t antialias,
const cairo_composite_rectangles_t *rects);
const cairo_composite_rectangles_t *rects,
cairo_region_t *clip_region);
cairo_warn cairo_bool_t
(*check_span_renderer) (cairo_operator_t op,
@ -672,59 +686,15 @@ struct _cairo_surface_backend {
cairo_warn cairo_int_status_t
(*show_page) (void *surface);
/* Set given region as the clip region for the surface, replacing
* any previously set clip region. Passing in a NULL region will
* clear the surface clip region.
*
* The surface is expected to store the clip region and clip all
* following drawing operations against it until the clip region
* is cleared of replaced by another clip region.
*
* Cairo will call this function whenever a clip path can be
* represented as a device pixel aligned set of rectangles. When
* this is not possible, cairo will use mask surfaces for
* clipping.
*/
cairo_warn cairo_int_status_t
(*set_clip_region) (void *surface,
cairo_region_t *region);
/* Intersect the given path against the clip path currently set in
* the surface, using the given fill_rule and tolerance, and set
* the result as the new clipping path for the surface. Passing
* in a NULL path will clear the surface clipping path.
*
* The surface is expected to store the resulting clip path and
* clip all following drawing operations against it until the clip
* path cleared or intersected with a new path.
*
* If a surface implements this function, set_clip_region() will
* never be called and should not be implemented. If this
* function is not implemented cairo will use set_clip_region()
* (if available) and mask surfaces for clipping.
*/
cairo_warn cairo_int_status_t
(*intersect_clip_path) (void *dst,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias);
/* Get the extents of the current surface. For many surface types
* this will be as simple as { x=0, y=0, width=surface->width,
* height=surface->height}.
*
* This function need not take account of any clipping from
* set_clip_region since the generic version of set_clip_region
* saves those, and the generic get_clip_extents will only call
* into the specific surface->get_extents if there is no current
* clip.
*
* If this function is not implemented, or if it returns
* %CAIRO_INT_STATUS_UNSUPPORTED, the surface is considered to be
* boundless and inifnite bounds are used for it.
* FALSE the surface is considered to be
* boundless and infinite bounds are used for it.
*/
cairo_warn cairo_int_status_t
cairo_warn cairo_bool_t
(*get_extents) (void *surface,
cairo_rectangle_int_t *extents);
@ -745,7 +715,8 @@ struct _cairo_surface_backend {
unsigned int width,
unsigned int height,
cairo_glyph_t *glyphs,
int num_glyphs);
int num_glyphs,
cairo_region_t *clip_region);
void
(*get_font_options) (void *surface,
@ -775,14 +746,14 @@ struct _cairo_surface_backend {
(*paint) (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_rectangle_int_t *extents);
cairo_clip_t *clip);
cairo_warn cairo_int_status_t
(*mask) (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_rectangle_int_t *extents);
cairo_clip_t *clip);
cairo_warn cairo_int_status_t
(*stroke) (void *surface,
@ -794,7 +765,7 @@ struct _cairo_surface_backend {
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *extents);
cairo_clip_t *clip);
cairo_warn cairo_int_status_t
(*fill) (void *surface,
@ -804,7 +775,7 @@ struct _cairo_surface_backend {
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *extents);
cairo_clip_t *clip);
cairo_warn cairo_int_status_t
(*show_glyphs) (void *surface,
@ -813,8 +784,8 @@ struct _cairo_surface_backend {
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs,
cairo_rectangle_int_t *extents);
cairo_clip_t *clip,
int *remaining_glyphs);
cairo_surface_t *
(*snapshot) (void *surface);
@ -824,9 +795,6 @@ struct _cairo_surface_backend {
void *surface_b,
cairo_content_t content);
cairo_warn cairo_status_t
(*reset) (void *surface);
cairo_warn cairo_int_status_t
(*fill_stroke) (void *surface,
cairo_operator_t fill_op,
@ -842,7 +810,7 @@ struct _cairo_surface_backend {
cairo_matrix_t *stroke_ctm_inverse,
double stroke_tolerance,
cairo_antialias_t stroke_antialias,
cairo_rectangle_int_t *extents);
cairo_clip_t *clip);
cairo_surface_t *
(*create_solid_pattern_surface)
@ -869,7 +837,7 @@ struct _cairo_surface_backend {
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_scaled_font_t *scaled_font,
cairo_rectangle_int_t *extents);
cairo_clip_t *clip);
};
#include "cairo-surface-private.h"
@ -887,9 +855,9 @@ struct _cairo_image_surface {
int depth;
pixman_image_t *pixman_image;
cairo_region_t *clip_region;
unsigned owns_data : 1;
unsigned has_clip : 1;
unsigned transparency : 2;
};
@ -983,6 +951,8 @@ typedef struct _cairo_traps {
cairo_box_t extents;
unsigned int maybe_region : 1; /* hint: 0 implies that it cannot be */
int num_traps;
int traps_size;
cairo_trapezoid_t *traps;
@ -1245,12 +1215,16 @@ _cairo_gstate_in_stroke (cairo_gstate_t *gstate,
double y,
cairo_bool_t *inside_ret);
cairo_private void
cairo_private cairo_bool_t
_cairo_gstate_in_fill (cairo_gstate_t *gstate,
cairo_path_fixed_t *path,
double x,
double y,
cairo_bool_t *inside_ret);
double y);
cairo_private cairo_bool_t
_cairo_gstate_in_clip (cairo_gstate_t *gstate,
double x,
double y);
cairo_private cairo_status_t
_cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path);
@ -1258,12 +1232,12 @@ _cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path);
cairo_private cairo_status_t
_cairo_gstate_reset_clip (cairo_gstate_t *gstate);
cairo_private cairo_status_t
cairo_private cairo_bool_t
_cairo_gstate_clip_extents (cairo_gstate_t *gstate,
double *x1,
double *y1,
double *x2,
double *y2);
double *x2,
double *y2);
cairo_private cairo_rectangle_list_t*
_cairo_gstate_copy_clip_rectangle_list (cairo_gstate_t *gstate);
@ -1480,19 +1454,19 @@ cairo_private void
_cairo_intern_string_reset_static_data (void);
/* cairo-path-fixed.c */
cairo_private cairo_path_fixed_t *
_cairo_path_fixed_create (void);
cairo_private void
_cairo_path_fixed_init (cairo_path_fixed_t *path);
cairo_private cairo_status_t
_cairo_path_fixed_init_copy (cairo_path_fixed_t *path,
cairo_path_fixed_t *other);
const cairo_path_fixed_t *other);
cairo_private cairo_bool_t
_cairo_path_fixed_is_equal (cairo_path_fixed_t *path,
cairo_path_fixed_t *other);
cairo_private cairo_path_fixed_t *
_cairo_path_fixed_create (void);
_cairo_path_fixed_is_equal (const cairo_path_fixed_t *path,
const cairo_path_fixed_t *other);
cairo_private void
_cairo_path_fixed_fini (cairo_path_fixed_t *path);
@ -1578,64 +1552,69 @@ _cairo_path_fixed_interpret_flat (const cairo_path_fixed_t *path,
void *closure,
double tolerance);
cairo_private cairo_status_t
_cairo_path_fixed_append (cairo_path_fixed_t *path,
const cairo_path_fixed_t *other,
cairo_direction_t dir);
cairo_private void
_cairo_path_fixed_approximate_clip_extents (cairo_path_fixed_t *path,
_cairo_path_fixed_approximate_clip_extents (const cairo_path_fixed_t *path,
cairo_rectangle_int_t *extents);
cairo_private void
_cairo_path_fixed_approximate_fill_extents (cairo_path_fixed_t *path,
_cairo_path_fixed_approximate_fill_extents (const cairo_path_fixed_t *path,
cairo_rectangle_int_t *extents);
cairo_private void
_cairo_path_fixed_approximate_stroke_extents (cairo_path_fixed_t *path,
_cairo_path_fixed_fill_extents (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_rectangle_int_t *extents);
cairo_private void
_cairo_path_fixed_approximate_stroke_extents (const cairo_path_fixed_t *path,
cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
cairo_rectangle_int_t *extents);
cairo_private cairo_status_t
_cairo_path_fixed_stroke_extents (const cairo_path_fixed_t *path,
cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_rectangle_int_t *extents);
cairo_private void
_cairo_path_fixed_bounds (cairo_path_fixed_t *path,
_cairo_path_fixed_bounds (const cairo_path_fixed_t *path,
double *x1, double *y1,
double *x2, double *y2);
cairo_private void
_cairo_path_fixed_transform (cairo_path_fixed_t *path,
cairo_matrix_t *matrix);
const cairo_matrix_t *matrix);
cairo_private cairo_bool_t
_cairo_path_fixed_is_empty (cairo_path_fixed_t *path);
cairo_private cairo_bool_t
_cairo_path_fixed_is_box (cairo_path_fixed_t *path,
_cairo_path_fixed_is_box (const cairo_path_fixed_t *path,
cairo_box_t *box);
cairo_private cairo_bool_t
_cairo_path_fixed_is_rectangle (cairo_path_fixed_t *path,
_cairo_path_fixed_is_rectangle (const cairo_path_fixed_t *path,
cairo_box_t *box);
/* cairo-path-in-fill.c */
cairo_private void
_cairo_path_fixed_in_fill (cairo_path_fixed_t *path,
cairo_private cairo_bool_t
_cairo_path_fixed_in_fill (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
double x,
double y,
cairo_bool_t *is_inside);
double y);
/* cairo-path-fill.c */
cairo_private cairo_status_t
_cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path,
_cairo_path_fixed_fill_to_traps (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_traps_t *traps);
/* cairo-path-stroke.c */
cairo_private cairo_status_t
_cairo_path_fixed_stroke_to_traps (cairo_path_fixed_t *path,
_cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t *path,
cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
@ -1707,7 +1686,8 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
unsigned int width,
unsigned int height,
cairo_glyph_t *glyphs,
int num_glyphs);
int num_glyphs,
cairo_region_t *clip_region);
cairo_private cairo_status_t
_cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
@ -1789,11 +1769,12 @@ _cairo_surface_create_similar_scratch (cairo_surface_t *other,
int height);
cairo_private cairo_surface_t *
_cairo_surface_create_similar_solid (cairo_surface_t *other,
cairo_content_t content,
int width,
int height,
const cairo_color_t *color);
_cairo_surface_create_similar_solid (cairo_surface_t *other,
cairo_content_t content,
int width,
int height,
const cairo_color_t *color,
cairo_bool_t allow_fallback);
cairo_private cairo_surface_t *
_cairo_surface_create_solid_pattern_surface (cairo_surface_t *other,
@ -1813,22 +1794,20 @@ cairo_private void
_cairo_surface_set_font_options (cairo_surface_t *surface,
cairo_font_options_t *options);
cairo_private cairo_clip_mode_t
_cairo_surface_get_clip_mode (cairo_surface_t *surface);
cairo_private cairo_status_t
_cairo_surface_composite (cairo_operator_t op,
const cairo_pattern_t *src,
const cairo_pattern_t *mask,
cairo_surface_t *dst,
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height);
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height,
cairo_region_t *clip_region);
cairo_private cairo_status_t
_cairo_surface_fill_rectangle (cairo_surface_t *surface,
@ -1856,14 +1835,14 @@ cairo_private cairo_status_t
_cairo_surface_paint (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_rectangle_int_t *extents);
cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_surface_mask (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_rectangle_int_t *extents);
cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_surface_fill_stroke (cairo_surface_t *surface,
@ -1880,7 +1859,7 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface,
cairo_matrix_t *stroke_ctm_inverse,
double stroke_tolerance,
cairo_antialias_t stroke_antialias,
cairo_rectangle_int_t *extents);
cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_surface_stroke (cairo_surface_t *surface,
@ -1892,7 +1871,7 @@ _cairo_surface_stroke (cairo_surface_t *surface,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *extents);
cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_surface_fill (cairo_surface_t *surface,
@ -1902,7 +1881,7 @@ _cairo_surface_fill (cairo_surface_t *surface,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *extents);
cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_surface_show_text_glyphs (cairo_surface_t *surface,
@ -1916,7 +1895,7 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_scaled_font_t *scaled_font,
cairo_rectangle_int_t *extents);
cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_surface_composite_trapezoids (cairo_operator_t op,
@ -1930,23 +1909,23 @@ _cairo_surface_composite_trapezoids (cairo_operator_t op,
unsigned int width,
unsigned int height,
cairo_trapezoid_t *traps,
int ntraps);
int ntraps,
cairo_region_t *clip_region);
cairo_private cairo_span_renderer_t *
_cairo_surface_create_span_renderer (
cairo_operator_t op,
const cairo_pattern_t *pattern,
cairo_surface_t *dst,
cairo_antialias_t antialias,
const cairo_composite_rectangles_t *rects);
_cairo_surface_create_span_renderer (cairo_operator_t op,
const cairo_pattern_t *pattern,
cairo_surface_t *dst,
cairo_antialias_t antialias,
const cairo_composite_rectangles_t *rects,
cairo_region_t *clip_region);
cairo_private cairo_bool_t
_cairo_surface_check_span_renderer (
cairo_operator_t op,
const cairo_pattern_t *pattern,
cairo_surface_t *dst,
cairo_antialias_t antialias,
const cairo_composite_rectangles_t *rects);
_cairo_surface_check_span_renderer (cairo_operator_t op,
const cairo_pattern_t *pattern,
cairo_surface_t *dst,
cairo_antialias_t antialias,
const cairo_composite_rectangles_t *rects);
cairo_private cairo_status_t
_cairo_surface_acquire_source_image (cairo_surface_t *surface,
@ -2005,37 +1984,7 @@ _cairo_surface_is_similar (cairo_surface_t *surface_a,
cairo_surface_t *surface_b,
cairo_content_t content);
cairo_private cairo_status_t
_cairo_surface_reset (cairo_surface_t *surface);
cairo_private unsigned int
_cairo_surface_get_current_clip_serial (cairo_surface_t *surface);
cairo_private unsigned int
_cairo_surface_allocate_clip_serial (cairo_surface_t *surface);
cairo_private cairo_status_t
_cairo_surface_reset_clip (cairo_surface_t *surface);
cairo_private cairo_status_t
_cairo_surface_set_clip_region (cairo_surface_t *surface,
cairo_region_t *region,
unsigned int serial);
cairo_private cairo_int_status_t
_cairo_surface_intersect_clip_path (cairo_surface_t *surface,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias);
cairo_private cairo_clip_t *
_cairo_surface_get_clip (cairo_surface_t *surface);
cairo_private cairo_status_t
_cairo_surface_set_clip (cairo_surface_t *surface, cairo_clip_t *clip);
cairo_private cairo_int_status_t
cairo_private cairo_bool_t
_cairo_surface_get_extents (cairo_surface_t *surface,
cairo_rectangle_int_t *extents);
@ -2051,7 +2000,8 @@ _cairo_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font,
unsigned int width,
unsigned int height,
cairo_glyph_t *glyphs,
int num_glyphs);
int num_glyphs,
cairo_region_t *clip_region);
cairo_private cairo_status_t
_cairo_surface_composite_fixup_unbounded (cairo_surface_t *dst,
@ -2068,7 +2018,8 @@ _cairo_surface_composite_fixup_unbounded (cairo_surface_t *dst,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height);
unsigned int height,
cairo_region_t *clip_region);
cairo_private cairo_status_t
_cairo_surface_composite_shape_fixup_unbounded (cairo_surface_t *dst,
@ -2084,7 +2035,8 @@ _cairo_surface_composite_shape_fixup_unbounded (cairo_surface_t *dst,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height);
unsigned int height,
cairo_region_t *clip_region);
cairo_private cairo_bool_t
_cairo_surface_is_opaque (const cairo_surface_t *surface);
@ -2193,19 +2145,6 @@ _cairo_image_surface_create_for_data_with_content (unsigned char *data,
cairo_private void
_cairo_image_surface_assume_ownership_of_data (cairo_image_surface_t *surface);
/* XXX: It's a nasty kludge that this appears here. Backend functions
* like this should really be static. But we're doing this to work
* around some general defects in the backend clipping interfaces,
* (see some notes in test-paginated-surface.c).
*
* I want to fix the real defects, but it's "hard" as they touch many
* backends, so doing that will require synchronizing several backend
* maintainers.
*/
cairo_private cairo_int_status_t
_cairo_image_surface_set_clip_region (void *abstract_surface,
cairo_region_t *region);
cairo_private cairo_image_surface_t *
_cairo_image_surface_coerce (cairo_image_surface_t *surface,
cairo_format_t format);
@ -2439,8 +2378,8 @@ _cairo_traps_extents (const cairo_traps_t *traps,
cairo_box_t *extents);
cairo_private cairo_int_status_t
_cairo_traps_extract_region (const cairo_traps_t *tr,
cairo_region_t **region);
_cairo_traps_extract_region (cairo_traps_t *traps,
cairo_region_t **region);
cairo_private cairo_status_t
_cairo_traps_path (const cairo_traps_t *traps,
@ -2560,7 +2499,7 @@ _cairo_pattern_acquire_surfaces (const cairo_pattern_t *src,
cairo_surface_attributes_t *src_attributes,
cairo_surface_attributes_t *mask_attributes);
cairo_private cairo_status_t
cairo_private void
_cairo_pattern_get_extents (const cairo_pattern_t *pattern,
cairo_rectangle_int_t *extents);
@ -2577,23 +2516,8 @@ _cairo_pattern_equal (const cairo_pattern_t *a,
cairo_private void
_cairo_pattern_reset_static_data (void);
/* cairo-region.c */
struct _cairo_region {
cairo_status_t status;
pixman_region32_t rgn;
};
cairo_private void
_cairo_region_init (cairo_region_t *region);
cairo_private void
_cairo_region_init_rectangle (cairo_region_t *region,
const cairo_rectangle_int_t *rectangle);
cairo_private void
_cairo_region_fini (cairo_region_t *region);
_cairo_clip_reset_static_data (void);
/* cairo-unicode.c */
@ -2725,7 +2649,6 @@ slim_hidden_proto (cairo_status);
slim_hidden_proto (cairo_stroke);
slim_hidden_proto (cairo_stroke_preserve);
slim_hidden_proto (cairo_surface_copy_page);
slim_hidden_proto (cairo_surface_create_similar);
slim_hidden_proto (cairo_surface_destroy);
slim_hidden_proto (cairo_surface_finish);
slim_hidden_proto (cairo_surface_flush);
@ -2760,7 +2683,9 @@ slim_hidden_proto (cairo_region_create);
slim_hidden_proto (cairo_region_create_rectangle);
slim_hidden_proto (cairo_region_create_rectangles);
slim_hidden_proto (cairo_region_copy);
slim_hidden_proto (cairo_region_reference);
slim_hidden_proto (cairo_region_destroy);
slim_hidden_proto (cairo_region_equal);
slim_hidden_proto (cairo_region_status);
slim_hidden_proto (cairo_region_get_extents);
slim_hidden_proto (cairo_region_num_rectangles);

View file

@ -194,7 +194,7 @@ _test_fallback_surface_clone_similar (void *abstract_surface,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
static cairo_int_status_t
static cairo_bool_t
_test_fallback_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
@ -219,8 +219,6 @@ static const cairo_surface_backend_t test_fallback_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
NULL, /* set_clip_region */
NULL, /* intersect_clip_path */
_test_fallback_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */

View file

@ -193,7 +193,7 @@ _test_fallback16_surface_clone_similar (void *abstract_surface,
}
}
static cairo_int_status_t
static cairo_bool_t
_test_fallback16_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
@ -218,8 +218,6 @@ static const cairo_surface_backend_t test_fallback16_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
NULL, /* set_clip_region */
NULL, /* intersect_clip_path */
_test_fallback16_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */

View file

@ -50,26 +50,17 @@ _return_success (void)
/* These typedefs are just to silence the compiler... */
typedef cairo_int_status_t
(*_set_clip_region_func) (void *surface,
cairo_region_t *region);
typedef cairo_int_status_t
(*_intersect_clip_path_func) (void *dst,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias);
typedef cairo_int_status_t
(*_paint_func) (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_rectangle_int_t *extents);
cairo_clip_t *clip);
typedef cairo_int_status_t
(*_mask_func) (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_rectangle_int_t *extents);
cairo_clip_t *clip);
typedef cairo_int_status_t
(*_stroke_func) (void *surface,
@ -81,7 +72,7 @@ typedef cairo_int_status_t
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *extents);
cairo_clip_t *clip);
typedef cairo_int_status_t
(*_fill_func) (void *surface,
@ -91,7 +82,7 @@ typedef cairo_int_status_t
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *extents);
cairo_clip_t *clip);
typedef cairo_int_status_t
(*_show_glyphs_func) (void *surface,
@ -100,8 +91,8 @@ typedef cairo_int_status_t
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs,
cairo_rectangle_int_t *extents);
cairo_clip_t *clip,
int *remaining_glyphs);
typedef cairo_int_status_t
(*_show_text_glyphs_func) (void *surface,
@ -115,7 +106,7 @@ typedef cairo_int_status_t
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_scaled_font_t *scaled_font,
cairo_rectangle_int_t *extents);
cairo_clip_t *clip);
static cairo_surface_t *
_cairo_null_surface_create_similar (void *other,
@ -125,16 +116,11 @@ _cairo_null_surface_create_similar (void *other,
return _cairo_test_null_surface_create (content);
}
static cairo_int_status_t
static cairo_bool_t
_cairo_null_surface_get_extents (void *surface,
cairo_rectangle_int_t *extents)
{
extents->x = 0;
extents->y = 0;
extents->width = 0;
extents->height = 0;
return CAIRO_STATUS_SUCCESS;
return FALSE;
}
static cairo_bool_t
@ -160,8 +146,6 @@ static const cairo_surface_backend_t null_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
(_set_clip_region_func) _return_success, /* set_clip_region */
(_intersect_clip_path_func) _return_success, /* intersect_clip_path */
_cairo_null_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
@ -176,7 +160,6 @@ static const cairo_surface_backend_t null_surface_backend = {
(_show_glyphs_func) _return_success, /* show_glyphs */
NULL, /* snapshot */
NULL, /* is_similar */
NULL, /* reset */
NULL, /* fill_stroke */
NULL, /* create_solid_pattern_surface */
NULL, /* can_repaint_solid_pattern_surface */

View file

@ -61,37 +61,27 @@ static const cairo_surface_backend_t test_paginated_surface_backend;
static const cairo_paginated_surface_backend_t test_paginated_surface_paginated_backend;
cairo_surface_t *
_cairo_test_paginated_surface_create_for_data (unsigned char *data,
cairo_content_t content,
int width,
int height,
int stride)
_cairo_test_paginated_surface_create (cairo_surface_t *target)
{
cairo_status_t status;
cairo_surface_t *target;
cairo_surface_t *paginated;
test_paginated_surface_t *surface;
target = _cairo_image_surface_create_for_data_with_content (data, content,
width, height,
stride);
status = cairo_surface_status (target);
if (status)
return target;
if (unlikely (status))
return _cairo_surface_create_in_error (status);
surface = malloc (sizeof (test_paginated_surface_t));
if (unlikely (surface == NULL)) {
cairo_surface_destroy (target);
if (unlikely (surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
}
_cairo_surface_init (&surface->base, &test_paginated_surface_backend,
content);
target->content);
surface->target = target;
surface->target = cairo_surface_reference (target);
paginated = _cairo_paginated_surface_create (&surface->base,
content, width, height,
target->content,
&test_paginated_surface_paginated_backend);
status = paginated->status;
if (status == CAIRO_STATUS_SUCCESS) {
@ -115,49 +105,7 @@ _test_paginated_surface_finish (void *abstract_surface)
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_test_paginated_surface_set_clip_region (void *abstract_surface,
cairo_region_t *region)
{
test_paginated_surface_t *surface = abstract_surface;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return CAIRO_STATUS_SUCCESS;
/* XXX: The whole surface backend clipping interface is a giant
* disaster right now. In particular, its uncleanness shows up
* when trying to implement one surface that wraps another one (as
* we are doing here).
*
* Here are two of the problems that show up:
*
* 1. The most critical piece of information in all this stuff,
* the "clip" isn't getting passed to the backend
* functions. Instead the generic surface layer is caching that as
* surface->clip. This is a problem for surfaces like this one
* that do wrapping. Our base surface will have the clip set, but
* our target's surface will not.
*
* 2. We're here in our backend's set_clip_region function, and we
* want to call into our target surface's set_clip_region.
* Generally, we would do this by calling an equivalent
* _cairo_surface function, but _cairo_surface_set_clip_region
* does not have the same signature/semantics, (it has the
* clip_serial stuff as well).
*
* We kludge around each of these by manually copying the clip
* object from our base surface into the target's base surface
* (yuck!) and by reaching directly into the image surface's
* set_clip_region instead of calling into the generic
* _cairo_surface_set_clip_region (double yuck!).
*/
surface->target->clip = surface->base.clip;
return _cairo_image_surface_set_clip_region (surface->target, region);
}
static cairo_int_status_t
static cairo_bool_t
_test_paginated_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
@ -170,14 +118,14 @@ static cairo_int_status_t
_test_paginated_surface_paint (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
test_paginated_surface_t *surface = abstract_surface;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return CAIRO_STATUS_SUCCESS;
return _cairo_surface_paint (surface->target, op, source, extents);
return _cairo_surface_paint (surface->target, op, source, clip);
}
static cairo_int_status_t
@ -185,14 +133,15 @@ _test_paginated_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
test_paginated_surface_t *surface = abstract_surface;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return CAIRO_STATUS_SUCCESS;
return _cairo_surface_mask (surface->target, op, source, mask, extents);
return _cairo_surface_mask (surface->target,
op, source, mask, clip);
}
static cairo_int_status_t
@ -205,7 +154,7 @@ _test_paginated_surface_stroke (void *abstract_surface,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
test_paginated_surface_t *surface = abstract_surface;
@ -215,7 +164,8 @@ _test_paginated_surface_stroke (void *abstract_surface,
return _cairo_surface_stroke (surface->target, op, source,
path, style,
ctm, ctm_inverse,
tolerance, antialias, extents);
tolerance, antialias,
clip);
}
static cairo_int_status_t
@ -226,7 +176,7 @@ _test_paginated_surface_fill (void *abstract_surface,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
test_paginated_surface_t *surface = abstract_surface;
@ -235,7 +185,8 @@ _test_paginated_surface_fill (void *abstract_surface,
return _cairo_surface_fill (surface->target, op, source,
path, fill_rule,
tolerance, antialias, extents);
tolerance, antialias,
clip);
}
static cairo_bool_t
@ -258,7 +209,7 @@ _test_paginated_surface_show_text_glyphs (void *abstract_surface,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_scaled_font_t *scaled_font,
cairo_rectangle_int_t *extents)
cairo_clip_t *clip)
{
test_paginated_surface_t *surface = abstract_surface;
@ -268,8 +219,10 @@ _test_paginated_surface_show_text_glyphs (void *abstract_surface,
return _cairo_surface_show_text_glyphs (surface->target, op, source,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters, cluster_flags,
scaled_font, extents);
clusters, num_clusters,
cluster_flags,
scaled_font,
clip);
}
@ -302,8 +255,6 @@ static const cairo_surface_backend_t test_paginated_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
_test_paginated_surface_set_clip_region,
NULL, /* intersect_clip_path */
_test_paginated_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
@ -319,11 +270,10 @@ static const cairo_surface_backend_t test_paginated_surface_backend = {
_test_paginated_surface_mask,
_test_paginated_surface_stroke,
_test_paginated_surface_fill,
NULL, /* show_glyphs */
NULL, /* replaced by show_text_glyphs */
NULL, /* snapshot */
NULL, /* is_similar */
NULL, /* reset */
NULL, /* fill_stroke */
NULL, /* create_solid_pattern_surface */
NULL, /* can_repaint_solid_pattern_surface */

View file

@ -41,11 +41,7 @@
CAIRO_BEGIN_DECLS
cairo_surface_t *
_cairo_test_paginated_surface_create_for_data (unsigned char *data,
cairo_content_t content,
int width,
int height,
int stride);
_cairo_test_paginated_surface_create (cairo_surface_t *target);
CAIRO_END_DECLS

272
src/test-wrapping-surface.c Normal file
View file

@ -0,0 +1,272 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
* Copyright © Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Carl Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
/* Another mythical surface that exists to simply wrap another - do nothing
* itself but forward the calls onto a target surface.
*/
#include "cairoint.h"
#include "test-wrapping-surface.h"
#include "cairo-surface-wrapper-private.h"
typedef struct _test_wrapping_surface {
cairo_surface_t base;
cairo_surface_wrapper_t wrapper;
} test_wrapping_surface_t;
static const cairo_surface_backend_t test_wrapping_surface_backend;
slim_hidden_proto (_cairo_test_wrapping_surface_create);
cairo_surface_t *
_cairo_test_wrapping_surface_create (cairo_surface_t *target)
{
test_wrapping_surface_t *surface;
if (unlikely (target->status))
return _cairo_surface_create_in_error (target->status);
surface = malloc (sizeof (test_wrapping_surface_t));
if (unlikely (surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
_cairo_surface_init (&surface->base,
&test_wrapping_surface_backend,
target->content);
_cairo_surface_wrapper_init (&surface->wrapper, target);
return &surface->base;
}
slim_hidden_def (_cairo_test_wrapping_surface_create);
static cairo_surface_t *
_test_wrapping_surface_create_similar (void *abstract_surface,
cairo_content_t content,
int width,
int height)
{
test_wrapping_surface_t *surface = abstract_surface;
return _cairo_test_wrapping_surface_create (
_cairo_surface_wrapper_create_similar (&surface->wrapper,
content, width, height));
}
static cairo_status_t
_test_wrapping_surface_finish (void *abstract_surface)
{
test_wrapping_surface_t *surface = abstract_surface;
_cairo_surface_wrapper_fini (&surface->wrapper);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_test_wrapping_surface_acquire_source_image (void *abstract_surface,
cairo_image_surface_t **image_out,
void **image_extra)
{
test_wrapping_surface_t *surface = abstract_surface;
return _cairo_surface_wrapper_acquire_source_image (&surface->wrapper,
image_out, image_extra);
}
static void
_test_wrapping_surface_release_source_image (void *abstract_surface,
cairo_image_surface_t *image,
void *image_extra)
{
test_wrapping_surface_t *surface = abstract_surface;
_cairo_surface_wrapper_release_source_image (&surface->wrapper,
image, image_extra);
}
static cairo_bool_t
_test_wrapping_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
test_wrapping_surface_t *surface = abstract_surface;
return _cairo_surface_wrapper_get_extents (&surface->wrapper, rectangle);
}
static cairo_int_status_t
_test_wrapping_surface_paint (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_clip_t *clip)
{
test_wrapping_surface_t *surface = abstract_surface;
return _cairo_surface_wrapper_paint (&surface->wrapper, op, source, clip);
}
static cairo_int_status_t
_test_wrapping_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
cairo_clip_t *clip)
{
test_wrapping_surface_t *surface = abstract_surface;
return _cairo_surface_wrapper_mask (&surface->wrapper,
op, source, mask, clip);
}
static cairo_int_status_t
_test_wrapping_surface_stroke (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_stroke_style_t *style,
cairo_matrix_t *ctm,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
{
test_wrapping_surface_t *surface = abstract_surface;
return _cairo_surface_wrapper_stroke (&surface->wrapper,
op, source,
path, style,
ctm, ctm_inverse,
tolerance, antialias,
clip);
}
static cairo_int_status_t
_test_wrapping_surface_fill (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
{
test_wrapping_surface_t *surface = abstract_surface;
return _cairo_surface_wrapper_fill (&surface->wrapper,
op, source,
path, fill_rule,
tolerance, antialias,
clip);
}
static cairo_bool_t
_test_wrapping_surface_has_show_text_glyphs (void *abstract_surface)
{
test_wrapping_surface_t *surface = abstract_surface;
return _cairo_surface_wrapper_has_show_text_glyphs (&surface->wrapper);
}
static cairo_int_status_t
_test_wrapping_surface_show_text_glyphs (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const char *utf8,
int utf8_len,
cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_scaled_font_t *scaled_font,
cairo_clip_t *clip)
{
test_wrapping_surface_t *surface = abstract_surface;
return _cairo_surface_wrapper_show_text_glyphs (&surface->wrapper,
op, source,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters,
cluster_flags,
scaled_font,
clip);
}
static const cairo_surface_backend_t test_wrapping_surface_backend = {
CAIRO_INTERNAL_SURFACE_TYPE_TEST_WRAPPING,
_test_wrapping_surface_create_similar,
_test_wrapping_surface_finish,
_test_wrapping_surface_acquire_source_image,
_test_wrapping_surface_release_source_image,
NULL, NULL, /* dest_image */
NULL, /* clone_similar */
NULL, /* composite */
NULL, /* fill_rectangles */
NULL, /* composite_trapezoids */
NULL, /* create_span_renderer */
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
_test_wrapping_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
NULL, /* flush */
NULL, /* mark_dirty_rectangle */
NULL, /* scaled_font_fini */
NULL, /* scaled_glyph_fini */
_test_wrapping_surface_paint,
_test_wrapping_surface_mask,
_test_wrapping_surface_stroke,
_test_wrapping_surface_fill,
NULL, /* replaced by show_text_glyphs */
NULL, /* snapshot */
NULL, /* is_similar */
NULL, /* fill_stroke */
NULL, /* create_solid_pattern_surface */
NULL, /* can_repaint_solid_pattern_surface */
_test_wrapping_surface_has_show_text_glyphs,
_test_wrapping_surface_show_text_glyphs
/* XXX wrap fill-stroke and show_glyphs */
};

View file

@ -0,0 +1,51 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
* Copyright © 2009 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Carl Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#ifndef TEST_WRAPPING_SURFACE_H
#define TEST_WRAPPING_SURFACE_H
#include "cairo.h"
CAIRO_BEGIN_DECLS
cairo_surface_t *
_cairo_test_wrapping_surface_create (cairo_surface_t *target);
CAIRO_END_DECLS
#endif /* TEST_WRAPPING_SURFACE_H */

View file

@ -185,8 +185,8 @@ REFERENCE_IMAGES = \
clip-nesting.rgb24.ref.png \
clip-nesting.test-paginated.rgb24.ref.png \
clip-nesting.xlib.rgb24.ref.png \
clip-operator.pdf.argb32.xfail.png \
clip-operator.pdf.rgb24.xfail.png \
clip-operator.pdf.argb32.ref.png \
clip-operator.pdf.rgb24.ref.png \
clip-operator.ps2.rgb24.ref.png \
clip-operator.ps3.argb32.ref.png \
clip-operator.ps3.ref.png \
@ -198,15 +198,21 @@ REFERENCE_IMAGES = \
clip-operator.svg12.argb32.xfail.png \
clip-operator.svg12.rgb24.xfail.png \
clip-operator.test-paginated.argb32.ref.png \
clip-operator.xlib-fallback.rgb24.ref.png \
clip-operator.xlib-fallback.ref.png \
clip-operator.xlib.ref.png \
clip-operator.xlib.rgb24.ref.png \
clip-unbounded.ref.png \
clip-unbounded.rgb24.ref.png \
clip-unbounded.svg12.rgb24.xfail.png \
clipped-surface.ref.png \
clip-push-group.pdf.ref.png \
clip-push-group.ps2.argb32.ref.png \
clip-push-group.ps2.rgb24.ref.png \
clip-push-group.ps3.argb32.ref.png \
clip-push-group.ps3.rgb24.ref.png \
clip-push-group.quartz.ref.png \
clip-push-group.ref.png \
clip-push-group.xlib.ref.png \
clip-twice.pdf.argb32.ref.png \
clip-twice.ps2.argb32.ref.png \
clip-twice.ps2.rgb24.ref.png \
@ -220,8 +226,7 @@ REFERENCE_IMAGES = \
clip-twice.test-paginated.rgb24.ref.png \
clip-twice.xlib.ref.png \
clip-twice.xlib.rgb24.ref.png \
clipped-group.pdf.argb32.ref.png \
clipped-group.pdf.rgb24.ref.png \
clipped-group.pdf.ref.png \
clipped-group.ps2.ref.png \
clipped-group.ps3.ref.png \
clipped-group.ref.png \
@ -240,6 +245,8 @@ REFERENCE_IMAGES = \
composite-integer-translate-source.ps2.ref.png \
composite-integer-translate-source.ps3.ref.png \
composite-integer-translate-source.ref.png \
composite-integer-translate-source.svg12.argb32.xfail.png \
composite-integer-translate-source.svg12.rgb24.xfail.png \
copy-path.ps2.ref.png \
copy-path.ps3.ref.png \
copy-path.ref.png \
@ -299,7 +306,7 @@ REFERENCE_IMAGES = \
device-offset-fractional.gl.xfail.png \
device-offset-fractional.pdf.argb32.ref.png \
device-offset-fractional.pdf.ref.png \
device-offset-fractional.pdf.rgb24.ref.png \
device-offset-fractional.pdf.xfail.png \
device-offset-fractional.ps2.ref.png \
device-offset-fractional.ps3.ref.png \
device-offset-fractional.ref.png \
@ -311,8 +318,12 @@ REFERENCE_IMAGES = \
device-offset.rgb24.ref.png \
extended-blend.argb32.ref.png \
extended-blend.rgb24.ref.png \
extended-blend.svg12.argb32.xfail.png \
extended-blend.svg12.rgb24.xfail.png \
extended-blend-alpha.argb32.ref.png \
extended-blend-alpha.rgb24.ref.png \
extended-blend-alpha.svg12.argb32.xfail.png \
extended-blend-alpha.svg12.rgb24.xfail.png \
extend-pad-border.ps.ref.png \
extend-pad-border.ref.png \
extend-pad-border.svg.xfail.png \
@ -377,6 +388,9 @@ REFERENCE_IMAGES = \
fill-degenerate-sort-order.rgb24.ref.png \
fill-degenerate-sort-order.xlib.ref.png \
fill-degenerate-sort-order.xlib.rgb24.ref.png \
fill-empty.argb32.ref.png \
fill-empty.rgb24.ref.png \
fill-empty.svg12.rgb24.xfail.png \
fill-image.ps.ref.png \
fill-image.ref.png \
fill-image.xlib.ref.png \
@ -443,17 +457,13 @@ REFERENCE_IMAGES = \
ft-text-antialias-none.ps2.argb32.ref.png \
ft-text-antialias-none.ps3.argb32.ref.png \
ft-text-antialias-none.ref.png \
ft-text-vertical-layout-type1.pdf.argb32.ref.png \
ft-text-vertical-layout-type1.pdf.ref.png \
ft-text-vertical-layout-type1.pdf.rgb24.ref.png \
ft-text-vertical-layout-type1.ps2.ref.png \
ft-text-vertical-layout-type1.ps3.ref.png \
ft-text-vertical-layout-type1.ref.png \
ft-text-vertical-layout-type1.svg.ref.png \
ft-text-vertical-layout-type1.xlib.ref.png \
ft-text-vertical-layout-type3.pdf.argb32.ref.png \
ft-text-vertical-layout-type3.pdf.ref.png \
ft-text-vertical-layout-type3.pdf.rgb24.ref.png \
ft-text-vertical-layout-type3.ps2.ref.png \
ft-text-vertical-layout-type3.ps3.ref.png \
ft-text-vertical-layout-type3.ref.png \
@ -498,6 +508,8 @@ REFERENCE_IMAGES = \
image-surface-source.ps2.ref.png \
image-surface-source.ps3.ref.png \
image-surface-source.ref.png \
image-surface-source.svg12.argb32.xfail.png \
image-surface-source.svg12.rgb24.xfail.png \
infinite-join.ps2.ref.png \
infinite-join.ps3.ref.png \
infinite-join.ref.png \
@ -558,15 +570,14 @@ REFERENCE_IMAGES = \
mask-transformed-similar.pdf.ref.png \
mask-transformed-similar.ref.png \
mask-transformed-similar.svg.ref.png \
mask.pdf.argb32.xfail.png \
mask.pdf.rgb24.xfail.png \
mask.pdf.argb32.ref.png \
mask.pdf.rgb24.ref.png \
mask.quartz.ref.png \
mask.quartz.rgb24.ref.png \
mask.ref.png \
mask.rgb24.ref.png \
mask.svg.argb32.xfail.png \
mask.svg.rgb24.xfail.png \
mask.xlib-fallback.rgb24.ref.png \
mask.xlib.ref.png \
mask.xlib.rgb24.ref.png \
meta-surface-pattern.gl.argb32.ref.png \
@ -613,15 +624,16 @@ REFERENCE_IMAGES = \
operator-clear.rgb24.ref.png \
operator-clear.svg12.argb32.xfail.png \
operator-clear.svg12.rgb24.xfail.png \
operator-clear.xlib.ref.png \
operator-source.pdf.rgb24.xfail.png \
operator-clear.xlib.argb32.ref.png \
operator-clear.xlib.rgb24.ref.png \
operator-source.pdf.rgb24.ref.png \
operator-source.quartz.ref.png \
operator-source.quartz.rgb24.ref.png \
operator-source.ref.png \
operator-source.rgb24.ref.png \
operator-source.svg12.argb32.xfail.png \
operator-source.svg12.rgb24.xfail.png \
operator-source.xlib-fallback.rgb24.ref.png \
operator-source.xlib-fallback.ref.png \
operator-source.xlib.ref.png \
operator-source.xlib.rgb24.ref.png \
operator.ref.png \
@ -682,12 +694,15 @@ REFERENCE_IMAGES = \
path-append.xlib.ref.png \
pattern-getters.ref.png \
pdf-surface-source.ref.png \
pdf-surface-source.svg12.argb32.xfail.png \
pdf-surface-source.svg12.rgb24.xfail.png \
pixman-rotate.ref.png \
pixman-rotate.rgb24.ref.png \
ps-surface-source.ref.png \
ps-surface-source.svg12.argb32.xfail.png \
ps-surface-source.svg12.rgb24.xfail.png \
push-group.ref.png \
push-group.rgb24.ref.png \
push-group.xlib-fallback.rgb24.ref.png \
push-group.xlib.ref.png \
push-group.xlib.rgb24.ref.png \
quartz-surface-source.ps2.ref.png \
@ -727,19 +742,21 @@ REFERENCE_IMAGES = \
rotate-image-surface-paint.svg.ref.png \
scale-down-source-surface-paint.ref.png \
scale-offset-image.gl.ref.png \
scale-offset-image.pdf.argb32.ref.png \
scale-offset-image.pdf.rgb24.ref.png \
scale-offset-image.pdf.xfail.png \
scale-offset-image.ps.ref.png \
scale-offset-image.ref.png \
scale-offset-image.xfail.png \
scale-offset-image.meta.xfail.png \
scale-offset-image.xlib.xfail.png \
scale-offset-image.xlib-fallback.xfail.png \
scale-offset-similar.gl.ref.png \
scale-offset-similar.pdf.argb32.ref.png \
scale-offset-similar.pdf.rgb24.ref.png \
scale-offset-similar.pdf.xfail.png \
scale-offset-similar.ps.ref.png \
scale-offset-similar.ref.png \
scale-offset-similar.xfail.png \
scale-offset-similar.meta.xfail.png \
scale-offset-similar.xlib.xfail.png \
scale-offset-similar.xlib-fallback.xfail.png \
scale-source-surface-paint.ref.png \
scale-source-surface-paint.rgb24.ref.png \
scale-source-surface-paint.svg.argb32.xfail.png \
@ -773,7 +790,6 @@ REFERENCE_IMAGES = \
skew-extreme.ref.png \
smask-fill.ref.png \
smask-fill.svg.ref.png \
smask-fill.xlib-fallback.ref.png \
smask-fill.xlib.ref.png \
smask-image-mask.ref.png \
smask-mask.pdf.xfail.png \
@ -789,11 +805,13 @@ REFERENCE_IMAGES = \
smask-text.ps3.ref.png \
smask-text.ref.png \
smask-text.svg.ref.png \
smask-text.xlib.ref.png \
smask.pdf.xfail.png \
smask.ps2.ref.png \
smask.ps3.ref.png \
smask.ref.png \
smask.svg.ref.png \
smask.xlib.ref.png \
solid-pattern-cache-stress.ref.png \
source-clip-scale.gl.ref.png \
source-clip-scale.pdf.ref.png \
@ -821,6 +839,7 @@ REFERENCE_IMAGES = \
stroke-image.quartz.ref.png \
stroke-image.ref.png \
surface-pattern-big-scale-down.ref.png \
surface-pattern-big-scale-down.ps.xfail.png \
surface-pattern-scale-down.pdf.ref.png \
surface-pattern-scale-down.ps2.ref.png \
surface-pattern-scale-down.ps3.ref.png \
@ -835,8 +854,12 @@ REFERENCE_IMAGES = \
surface-pattern.ref.png \
surface-pattern.svg.xfail.png \
svg-surface-source.ref.png \
svg-surface-source.svg12.argb32.xfail.png \
svg-surface-source.svg12.rgb24.xfail.png \
test-fallback16-surface-source.ps.ref.png \
test-fallback16-surface-source.ref.png \
test-fallback16-surface-source.svg12.argb32.xfail.png \
test-fallback16-surface-source.svg12.rgb24.xfail.png \
text-antialias-gray.quartz.ref.png \
text-antialias-gray.ref.png \
text-antialias-none.quartz.ref.png \
@ -846,8 +869,8 @@ REFERENCE_IMAGES = \
text-glyph-range.ps2.ref.png \
text-glyph-range.ps3.ref.png \
text-glyph-range.ref.png \
text-pattern.pdf.argb32.xfail.png \
text-pattern.pdf.rgb24.xfail.png \
text-pattern.pdf.argb32.ref.png \
text-pattern.pdf.rgb24.ref.png \
text-pattern.ps3.argb32.ref.png \
text-pattern.ps3.rgb24.ref.png \
text-pattern.quartz.ref.png \
@ -924,6 +947,8 @@ REFERENCE_IMAGES = \
xlib-surface-source.ps2.ref.png \
xlib-surface-source.ps3.ref.png \
xlib-surface-source.ref.png \
xlib-surface-source.svg12.argb32.xfail.png \
xlib-surface-source.svg12.rgb24.xfail.png \
zero-alpha.ref.png
EXTRA_DIST += \
@ -1218,7 +1243,7 @@ run:
# Check tests under valgrind. Saves log to valgrind-log
check-valgrind:
$(MAKE) $(AM_MAKEFLAGS) check TESTS_ENVIRONMENT='$(TESTS_ENVIRONMENT) CAIRO_TEST_MODE="$(MODE),foreground" $(top_builddir)/libtool --mode=execute valgrind $(VALGRIND_FLAGS)' 2>&1 | tee valgrind-log
$(MAKE) $(AM_MAKEFLAGS) check TESTS_ENVIRONMENT='$(TESTS_ENVIRONMENT) CAIRO_TEST_MODE="$(MODE),foreground CAIRO_TEST_TIMEOUT=0" $(top_builddir)/libtool --mode=execute valgrind $(VALGRIND_FLAGS)' 2>&1 | tee valgrind-log
%.log: %.c cairo-test-suite
-./cairo-test-suite $(<:.c=)

View file

@ -21,6 +21,7 @@ test_sources = \
clip-operator.c \
clip-push-group.c \
clip-twice.c \
clip-unbounded.c \
clip-zero.c \
clipped-group.c \
clipped-surface.c \
@ -64,6 +65,7 @@ test_sources = \
fill-and-stroke-alpha.c \
fill-and-stroke-alpha-add.c \
fill-degenerate-sort-order.c \
fill-empty.c \
fill-image.c \
fill-missed-stop.c \
fill-rule.c \

View file

@ -70,13 +70,12 @@ buffer_diff_core (const unsigned char *_buf_a, int stride_a,
stride_a /= sizeof (uint32_t);
stride_b /= sizeof (uint32_t);
stride_diff /= sizeof (uint32_t);
for (y = 0; y < height; y++)
{
for (y = 0; y < height; y++) {
const uint32_t *row_a = buf_a + y * stride_a;
const uint32_t *row_b = buf_b + y * stride_b;
uint32_t *row = buf_diff + y * stride_diff;
for (x = 0; x < width; x++)
{
for (x = 0; x < width; x++) {
/* check if the pixels are the same */
if ((row_a[x] & mask) != (row_b[x] & mask)) {
int channel;
@ -99,6 +98,11 @@ buffer_diff_core (const unsigned char *_buf_a, int stride_a,
}
result.pixels_changed++;
if ((diff_pixel & 0x00ffffff) == 0) {
/* alpha only difference, convert to luminance */
uint8_t alpha = diff_pixel >> 24;
diff_pixel = alpha * 0x010101;
}
row[x] = diff_pixel;
} else {
row[x] = 0;

View file

@ -566,7 +566,7 @@ cairo_test_file_is_older (const char *filename,
while (num_ref_filenames--) {
struct stat ref;
char *ref_filename = ref_filenames++;
char *ref_filename = *ref_filenames++;
if (ref_filename == NULL)
continue;
@ -912,6 +912,11 @@ REPEAT:
goto UNWIND_SURFACE;
}
cairo_surface_set_user_data (surface,
&cairo_boilerplate_output_basename_key,
base_path,
NULL);
cairo_surface_set_device_offset (surface, dev_offset, dev_offset);
cr = cairo_create (surface);
@ -1080,13 +1085,17 @@ REPEAT:
ctx->test->width,
ctx->test->height);
diff_status = cairo_surface_write_to_png (test_image, out_png_path);
cairo_surface_destroy (test_image);
if (diff_status) {
if (cairo_surface_status (test_image) == CAIRO_STATUS_INVALID_STATUS)
ret = CAIRO_TEST_CRASHED;
else
ret = CAIRO_TEST_FAILURE;
cairo_test_log (ctx,
"Error: Failed to write output image: %s\n",
cairo_status_to_string (diff_status));
}
have_output = TRUE;
cairo_surface_destroy (test_image);
ret = CAIRO_TEST_XFAILURE;
goto UNWIND_CAIRO;
@ -1167,8 +1176,11 @@ REPEAT:
if (cairo_surface_status (test_image)) {
cairo_test_log (ctx, "Error: Failed to extract image: %s\n",
cairo_status_to_string (cairo_surface_status (test_image)));
if (cairo_surface_status (test_image) == CAIRO_STATUS_INVALID_STATUS)
ret = CAIRO_TEST_CRASHED;
else
ret = CAIRO_TEST_FAILURE;
cairo_surface_destroy (test_image);
ret = CAIRO_TEST_FAILURE;
goto UNWIND_CAIRO;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 199 B

After

Width:  |  Height:  |  Size: 164 B

Some files were not shown because too many files have changed in this diff Show more