Primitive "real" postscript output for stroke/fill/paint

This commit is contained in:
Keith Packard 2006-02-27 19:47:14 +01:00
parent 5a3c30eafe
commit cb3a445150
4 changed files with 467 additions and 262 deletions

View file

@ -38,11 +38,24 @@
#include "cairoint.h"
typedef enum {
CAIRO_PAGINATED_MODE_EVALUATE, /* evaluate page regions */
CAIRO_PAGINATED_MODE_RENDER /* render page contents */
} cairo_paginated_mode_t;
typedef void (*cairo_paginated_set_mode_t) (cairo_surface_t *target,
cairo_paginated_mode_t mode);
typedef struct {
cairo_paginated_set_mode_t set_mode;
} cairo_paginated_funcs_t;
cairo_private cairo_surface_t *
_cairo_paginated_surface_create (cairo_surface_t *target,
cairo_content_t content,
int width,
int height);
int height,
const cairo_paginated_funcs_t *funcs);
cairo_private cairo_surface_t *
_cairo_paginated_surface_get_target (cairo_surface_t *surface);

View file

@ -31,6 +31,7 @@
*
* Contributor(s):
* Carl Worth <cworth@cworth.org>
* Keith Packard <keithp@keithp.com>
*/
/* The paginated surface layer exists to provide as much code sharing
@ -85,6 +86,9 @@ typedef struct _cairo_paginated_surface {
/* The target surface to hold the final result. */
cairo_surface_t *target;
/* Paginated-surface specific functions for the target */
const cairo_paginated_funcs_t *funcs;
/* A cairo_meta_surface to record all operations. To be replayed
* against target, and also against image surface as necessary for
* fallbacks. */
@ -97,11 +101,27 @@ const cairo_private cairo_surface_backend_t cairo_paginated_surface_backend;
static cairo_int_status_t
_cairo_paginated_surface_show_page (void *abstract_surface);
typedef struct {
cairo_surface_t base;
int width;
int height;
cairo_surface_t *target;
cairo_bool_t fallback;
} cairo_evaluate_surface_t;
static cairo_evaluate_surface_t *
_cairo_evaluate_surface_create (cairo_surface_t *target,
int width,
int height);
cairo_surface_t *
_cairo_paginated_surface_create (cairo_surface_t *target,
cairo_content_t content,
int width,
int height)
int height,
const cairo_paginated_funcs_t *funcs)
{
cairo_paginated_surface_t *surface;
@ -116,6 +136,7 @@ _cairo_paginated_surface_create (cairo_surface_t *target,
surface->height = height;
surface->target = target;
surface->funcs = funcs;
surface->meta = _cairo_meta_surface_create (content, width, height);
if (cairo_surface_status (surface->meta))
@ -191,25 +212,49 @@ _cairo_paginated_surface_release_source_image (void *abstract_surface,
cairo_surface_destroy (&image->base);
}
static void
static cairo_int_status_t
_paint_page (cairo_paginated_surface_t *surface)
{
cairo_evaluate_surface_t *evaluate;
cairo_surface_t *image;
cairo_pattern_t *pattern;
cairo_status_t status;
image = _cairo_image_surface_create_with_content (surface->content,
surface->width,
surface->height);
evaluate = _cairo_evaluate_surface_create (surface->target,
surface->width, surface->height);
_cairo_meta_surface_replay (surface->meta, image);
surface->funcs->set_mode (surface->target, CAIRO_PAGINATED_MODE_EVALUATE);
_cairo_meta_surface_replay (surface->meta, &evaluate->base);
surface->funcs->set_mode (surface->target, CAIRO_PAGINATED_MODE_RENDER);
pattern = cairo_pattern_create_for_surface (image);
if (evaluate->base.status) {
status = evaluate->base.status;
cairo_surface_destroy (&evaluate->base);
return status;
}
if (evaluate->fallback)
{
image = _cairo_image_surface_create_with_content (surface->content,
surface->width,
surface->height);
_cairo_surface_paint (surface->target, CAIRO_OPERATOR_SOURCE, pattern);
_cairo_meta_surface_replay (surface->meta, image);
cairo_pattern_destroy (pattern);
pattern = cairo_pattern_create_for_surface (image);
cairo_surface_destroy (image);
_cairo_surface_paint (surface->target, CAIRO_OPERATOR_SOURCE, pattern);
cairo_pattern_destroy (pattern);
cairo_surface_destroy (image);
}
else
{
_cairo_meta_surface_replay (surface->meta, surface->target);
}
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
@ -409,3 +454,179 @@ const cairo_surface_backend_t cairo_paginated_surface_backend = {
_cairo_paginated_surface_show_glyphs,
_cairo_paginated_surface_snapshot
};
static cairo_int_status_t
_cairo_evaluate_surface_paint (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source)
{
cairo_evaluate_surface_t *surface = abstract_surface;
cairo_status_t status;
if (!surface->target->backend->paint)
status = CAIRO_INT_STATUS_UNSUPPORTED;
else
status = (*surface->target->backend->paint) (surface->target, op,
source);
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
surface->fallback = TRUE;
status = CAIRO_STATUS_SUCCESS;
}
return status;
}
static cairo_int_status_t
_cairo_evaluate_surface_mask (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source,
cairo_pattern_t *mask)
{
cairo_evaluate_surface_t *surface = abstract_surface;
cairo_status_t status;
if (!surface->target->backend->mask)
status = CAIRO_INT_STATUS_UNSUPPORTED;
else
status = (*surface->target->backend->mask) (surface->target, op,
source, mask);
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
surface->fallback = TRUE;
status = CAIRO_STATUS_SUCCESS;
}
return status;
}
static cairo_int_status_t
_cairo_evaluate_surface_stroke (void *abstract_surface,
cairo_operator_t op,
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_evaluate_surface_t *surface = abstract_surface;
cairo_status_t status;
if (!surface->target->backend->stroke)
status = CAIRO_INT_STATUS_UNSUPPORTED;
else
status = (*surface->target->backend->stroke) (surface->target, op,
source, path, style,
ctm, ctm_inverse,
tolerance, antialias);
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
surface->fallback = TRUE;
status = CAIRO_STATUS_SUCCESS;
}
return status;
}
static cairo_int_status_t
_cairo_evaluate_surface_fill (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias)
{
cairo_evaluate_surface_t *surface = abstract_surface;
cairo_status_t status;
if (!surface->target->backend->fill)
status = CAIRO_INT_STATUS_UNSUPPORTED;
else
status = (*surface->target->backend->fill) (surface->target, op,
source, path, fill_rule,
tolerance, antialias);
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
surface->fallback = TRUE;
status = CAIRO_STATUS_SUCCESS;
}
return status;
}
static cairo_int_status_t
_cairo_evaluate_surface_show_glyphs (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source,
const cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font)
{
cairo_evaluate_surface_t *surface = abstract_surface;
cairo_status_t status;
if (!surface->target->backend->show_glyphs)
status = CAIRO_INT_STATUS_UNSUPPORTED;
else
status = (*surface->target->backend->show_glyphs) (surface->target, op,
source,
glyphs, num_glyphs,
scaled_font);
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
surface->fallback = TRUE;
status = CAIRO_STATUS_SUCCESS;
}
return status;
}
static const cairo_surface_backend_t cairo_evaluate_surface_backend = {
NULL, /* create_similar */
NULL, /* finish_surface */
NULL, /* acquire_source_image */
NULL, /* release_source_image */
NULL, /* acquire_dest_image */
NULL, /* release_dest_image */
NULL, /* clone_similar */
NULL, /* composite */
NULL, /* fill_rectangles */
NULL, /* composite_trapezoids */
NULL, /* copy_page */
NULL, /* show_page */
NULL, /* set_clip_region */
NULL, /* clip_path */
NULL, /* get_extents */
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
NULL, /* flush */
NULL, /* mark_dirty_rectangle */
NULL, /* scaled_font_fini */
NULL, /* scaled_glyph_fini */
_cairo_evaluate_surface_paint,
_cairo_evaluate_surface_mask,
_cairo_evaluate_surface_stroke,
_cairo_evaluate_surface_fill,
_cairo_evaluate_surface_show_glyphs,
NULL, /* snapshot */
};
static cairo_evaluate_surface_t *
_cairo_evaluate_surface_create (cairo_surface_t *target,
int width,
int height)
{
cairo_evaluate_surface_t *surface;
surface = malloc (sizeof (cairo_evaluate_surface_t));
if (surface == NULL)
goto FAIL;
_cairo_surface_init (&surface->base, &cairo_evaluate_surface_backend);
surface->width = width;
surface->height = height;
surface->target = target;
surface->fallback = FALSE;
return surface;
FAIL:
_cairo_error (CAIRO_STATUS_NO_MEMORY);
return NULL;
}

View file

@ -306,7 +306,8 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *stream,
return _cairo_paginated_surface_create (target,
CAIRO_CONTENT_COLOR_ALPHA,
width, height);
width, height,
NULL); /* XXX */
}
/**

View file

@ -56,6 +56,7 @@
*/
static const cairo_surface_backend_t cairo_ps_surface_backend;
static const cairo_paginated_funcs_t cairo_ps_paginated_funcs;
typedef struct cairo_ps_surface {
cairo_surface_t base;
@ -71,6 +72,8 @@ typedef struct cairo_ps_surface {
cairo_bool_t need_start_page;
int num_pages;
cairo_paginated_mode_t mode;
#if DONE_ADDING_FONTS_SUPPORT_BACK_AFTER_SWITCHING_TO_PAGINATED
cairo_array_t fonts;
#endif
@ -141,6 +144,7 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
surface->height = height;
surface->x_dpi = PS_SURFACE_DPI_DEFAULT;
surface->y_dpi = PS_SURFACE_DPI_DEFAULT;
surface->mode = CAIRO_PAGINATED_MODE_EVALUATE;
#if DONE_ADDING_DEVICE_SCALE_SUPPORT_AFTER_SWITCHING_TO_PAGINATED
surface->base.device_x_scale = surface->x_dpi / 72.0;
surface->base.device_y_scale = surface->y_dpi / 72.0;
@ -157,7 +161,8 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
return _cairo_paginated_surface_create (&surface->base,
CAIRO_CONTENT_COLOR_ALPHA,
width, height);
width, height,
&cairo_ps_paginated_funcs);
}
/**
@ -472,17 +477,6 @@ _cairo_ps_surface_write_font_subsets (cairo_ps_surface_t *surface)
}
#endif
/* XXX: This function wil go away in favor of the new "analysis mode"
* of cairo_paginated_surface_t */
static cairo_int_status_t
_cairo_ps_surface_add_fallback_area (cairo_ps_surface_t *surface,
int x, int y,
unsigned int width,
unsigned int height)
{
return CAIRO_STATUS_SUCCESS;
}
static cairo_bool_t
color_is_gray (cairo_color_t *color)
{
@ -493,66 +487,66 @@ color_is_gray (cairo_color_t *color)
}
static cairo_bool_t
color_is_translucent (const cairo_color_t *color)
color_is_opaque (const cairo_color_t *color)
{
return color->alpha < 0.999;
return color->alpha >= 0.999;
}
static cairo_bool_t
format_is_translucent (cairo_format_t format)
format_is_opaque (cairo_format_t format)
{
switch (format) {
case CAIRO_FORMAT_ARGB32:
return TRUE;
case CAIRO_FORMAT_RGB24:
return FALSE;
case CAIRO_FORMAT_A8:
case CAIRO_FORMAT_RGB24:
return TRUE;
case CAIRO_FORMAT_A8:
return FALSE;
case CAIRO_FORMAT_A1:
return TRUE;
}
return TRUE;
return FALSE;
}
static cairo_bool_t
surface_is_translucent (const cairo_surface_t *surface)
surface_is_opaque (const cairo_surface_t *surface)
{
if (_cairo_surface_is_image (surface)) {
const cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
return format_is_translucent (image_surface->format);
return format_is_opaque (image_surface->format);
}
return TRUE;
}
static cairo_bool_t
gradient_is_translucent (const cairo_gradient_pattern_t *gradient)
gradient_is_opaque (const cairo_gradient_pattern_t *gradient)
{
return TRUE; /* XXX no gradient support */
return FALSE; /* XXX no gradient support */
#if 0
int i;
for (i = 0; i < gradient->n_stops; i++)
if (color_is_translucent (&gradient->stops[i].color))
return TRUE;
return FALSE;
if (!color_is_opaque (&gradient->stops[i].color))
return FALSE;
return TRUE;
#endif
}
static cairo_bool_t
pattern_is_translucent (const cairo_pattern_t *abstract_pattern)
pattern_is_opaque (const cairo_pattern_t *abstract_pattern)
{
const cairo_pattern_union_t *pattern;
pattern = (cairo_pattern_union_t *) abstract_pattern;
switch (pattern->base.type) {
case CAIRO_PATTERN_TYPE_SOLID:
return color_is_translucent (&pattern->solid.color);
return color_is_opaque (&pattern->solid.color);
case CAIRO_PATTERN_TYPE_SURFACE:
return surface_is_translucent (pattern->surface.surface);
return surface_is_opaque (pattern->surface.surface);
case CAIRO_PATTERN_TYPE_LINEAR:
case CAIRO_PATTERN_TYPE_RADIAL:
return gradient_is_translucent (&pattern->gradient.base);
return gradient_is_opaque (&pattern->gradient.base);
}
ASSERT_NOT_REACHED;
@ -624,35 +618,35 @@ operator_always_translucent (cairo_operator_t op)
}
static cairo_bool_t
color_operation_needs_fallback (cairo_operator_t op,
const cairo_color_t *color)
pattern_surface_supported (const cairo_surface_pattern_t *pattern)
{
if (operator_always_opaque (op))
if (pattern->surface->backend->acquire_source_image == NULL)
return FALSE;
if (operator_always_translucent (op))
return TRUE;
return color_is_translucent (color);
return TRUE;
}
static cairo_bool_t
pattern_type_supported (const cairo_pattern_t *pattern)
pattern_supported (const cairo_pattern_t *pattern)
{
if (pattern->type == CAIRO_PATTERN_TYPE_SOLID)
return TRUE;
if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE)
return pattern_surface_supported ((const cairo_surface_pattern_t *) pattern);
return FALSE;
}
static cairo_bool_t
pattern_operation_needs_fallback (cairo_operator_t op,
pattern_operation_supported (cairo_operator_t op,
const cairo_pattern_t *pattern)
{
if (! pattern_type_supported (pattern))
return TRUE;
if (operator_always_opaque (op))
if (! pattern_supported (pattern))
return FALSE;
if (operator_always_translucent (op))
if (operator_always_opaque (op))
return TRUE;
return pattern_is_translucent (pattern);
if (operator_always_translucent (op))
return FALSE;
return pattern_is_opaque (pattern);
}
/* PS Output - this section handles output of the parts of the meta
@ -812,7 +806,15 @@ static void
emit_surface_pattern (cairo_ps_surface_t *surface,
cairo_surface_pattern_t *pattern)
{
/* XXX: NYI */
cairo_image_surface_t *image;
cairo_status_t status;
void *image_extra;
status = _cairo_surface_acquire_source_image (pattern->surface,
&image,
&image_extra);
assert (status == CAIRO_STATUS_SUCCESS);
emit_image (surface, image, &pattern->base.matrix);
}
static void
@ -855,200 +857,6 @@ emit_pattern (cairo_ps_surface_t *surface, cairo_pattern_t *pattern)
}
}
static cairo_int_status_t
_cairo_ps_surface_composite (cairo_operator_t op,
cairo_pattern_t *src_pattern,
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)
{
cairo_ps_surface_t *surface = abstract_dst;
cairo_output_stream_t *stream = surface->stream;
cairo_surface_pattern_t *surface_pattern;
cairo_status_t status;
cairo_image_surface_t *image;
void *image_extra;
if (surface->need_start_page)
_cairo_ps_surface_start_page (surface);
if (mask_pattern) {
/* FIXME: Investigate how this can be done... we'll probably
* need pixmap fallbacks for this, though. */
_cairo_output_stream_printf (stream,
"%% _cairo_ps_surface_composite: with mask\n");
goto bail;
}
status = CAIRO_STATUS_SUCCESS;
switch (src_pattern->type) {
case CAIRO_PATTERN_TYPE_SOLID:
_cairo_output_stream_printf (stream,
"%% _cairo_ps_surface_composite: solid\n");
goto bail;
case CAIRO_PATTERN_TYPE_SURFACE:
surface_pattern = (cairo_surface_pattern_t *) src_pattern;
if (src_pattern->extend != CAIRO_EXTEND_NONE) {
_cairo_output_stream_printf (stream,
"%% _cairo_ps_surface_composite: repeating image\n");
goto bail;
}
status = _cairo_surface_acquire_source_image (surface_pattern->surface,
&image,
&image_extra);
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
_cairo_output_stream_printf (stream,
"%% _cairo_ps_surface_composite: src_pattern not available as image\n");
goto bail;
} else if (status) {
break;
}
status = emit_image (surface, image, &src_pattern->matrix);
_cairo_surface_release_source_image (surface_pattern->surface,
image, image_extra);
break;
case CAIRO_PATTERN_TYPE_LINEAR:
case CAIRO_PATTERN_TYPE_RADIAL:
_cairo_output_stream_printf (stream,
"%% _cairo_ps_surface_composite: gradient\n");
goto bail;
}
return status;
bail:
return _cairo_ps_surface_add_fallback_area (surface, dst_x, dst_y, width, height);
}
static cairo_int_status_t
_cairo_ps_surface_fill_rectangles (void *abstract_surface,
cairo_operator_t op,
const cairo_color_t *color,
cairo_rectangle_t *rects,
int num_rects)
{
cairo_ps_surface_t *surface = abstract_surface;
cairo_output_stream_t *stream = surface->stream;
cairo_solid_pattern_t solid;
int i;
if (!num_rects)
return CAIRO_STATUS_SUCCESS;
if (surface->need_start_page)
_cairo_ps_surface_start_page (surface);
if (color_operation_needs_fallback (op, color)) {
int min_x = rects[0].x;
int min_y = rects[0].y;
int max_x = rects[0].x + rects[0].width;
int max_y = rects[0].y + rects[0].height;
for (i = 1; i < num_rects; i++) {
if (rects[i].x < min_x) min_x = rects[i].x;
if (rects[i].y < min_y) min_y = rects[i].y;
if (rects[i].x + rects[i].width > max_x) max_x = rects[i].x + rects[i].width;
if (rects[i].y + rects[i].height > max_y) max_y = rects[i].y + rects[i].height;
}
return _cairo_ps_surface_add_fallback_area (surface, min_x, min_y, max_x - min_x, max_y - min_y);
}
_cairo_output_stream_printf (stream,
"%% _cairo_ps_surface_fill_rectangles\n");
_cairo_pattern_init_solid (&solid, color);
emit_pattern (surface, &solid.base);
_cairo_pattern_fini (&solid.base);
_cairo_output_stream_printf (stream, "[");
for (i = 0; i < num_rects; i++) {
_cairo_output_stream_printf (stream,
" %d %d %d %d",
rects[i].x, rects[i].y,
rects[i].width, rects[i].height);
}
_cairo_output_stream_printf (stream, " ] rectfill\n");
return CAIRO_STATUS_SUCCESS;
}
static double
intersect (cairo_line_t *line, cairo_fixed_t y)
{
return _cairo_fixed_to_double (line->p1.x) +
_cairo_fixed_to_double (line->p2.x - line->p1.x) *
_cairo_fixed_to_double (y - line->p1.y) /
_cairo_fixed_to_double (line->p2.y - line->p1.y);
}
static cairo_int_status_t
_cairo_ps_surface_composite_trapezoids (cairo_operator_t op,
cairo_pattern_t *pattern,
void *abstract_dst,
cairo_antialias_t antialias,
int x_src,
int y_src,
int x_dst,
int y_dst,
unsigned int width,
unsigned int height,
cairo_trapezoid_t *traps,
int num_traps)
{
cairo_ps_surface_t *surface = abstract_dst;
cairo_output_stream_t *stream = surface->stream;
int i;
if (pattern_operation_needs_fallback (op, pattern))
return _cairo_ps_surface_add_fallback_area (surface, x_dst, y_dst, width, height);
if (surface->need_start_page)
_cairo_ps_surface_start_page (surface);
_cairo_output_stream_printf (stream,
"%% _cairo_ps_surface_composite_trapezoids\n");
emit_pattern (surface, pattern);
for (i = 0; i < num_traps; i++) {
double left_x1, left_x2, right_x1, right_x2, top, bottom;
left_x1 = intersect (&traps[i].left, traps[i].top);
left_x2 = intersect (&traps[i].left, traps[i].bottom);
right_x1 = intersect (&traps[i].right, traps[i].top);
right_x2 = intersect (&traps[i].right, traps[i].bottom);
top = _cairo_fixed_to_double (traps[i].top);
bottom = _cairo_fixed_to_double (traps[i].bottom);
_cairo_output_stream_printf
(stream,
"%f %f moveto %f %f lineto %f %f lineto %f %f lineto "
"closepath\n",
left_x1, top,
left_x2, bottom,
right_x2, bottom,
right_x1, top);
}
_cairo_output_stream_printf (stream,
"fill\n");
return CAIRO_STATUS_SUCCESS;
}
typedef struct
{
cairo_output_stream_t *output_stream;
@ -1135,6 +943,9 @@ _cairo_ps_surface_intersect_clip_path (void *abstract_surface,
cairo_ps_surface_path_info_t info;
const char *ps_operator;
if (surface->mode == CAIRO_PAGINATED_MODE_EVALUATE)
return CAIRO_STATUS_SUCCESS;
_cairo_output_stream_printf (stream,
"%% _cairo_ps_surface_intersect_clip_path\n");
@ -1265,7 +1076,153 @@ _cairo_ps_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font,
#endif
static cairo_int_status_t
_cairo_ps_surface_fill (void *abstract_surface,
_cairo_ps_surface_paint (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source)
{
cairo_ps_surface_t *surface = abstract_surface;
cairo_output_stream_t *stream = surface->stream;
cairo_ps_surface_path_info_t info;
if (surface->mode == CAIRO_PAGINATED_MODE_EVALUATE) {
if (!pattern_operation_supported (op, source))
return CAIRO_INT_STATUS_UNSUPPORTED;
return CAIRO_STATUS_SUCCESS;
}
if (surface->need_start_page)
_cairo_ps_surface_start_page (surface);
_cairo_output_stream_printf (stream,
"%% _cairo_ps_surface_paint\n");
emit_pattern (surface, source);
info.output_stream = stream;
info.has_current_point = FALSE;
_cairo_output_stream_printf (stream, "0 0 moveto\n");
_cairo_output_stream_printf (stream, "%f 0 lineto\n", surface->width);
_cairo_output_stream_printf (stream, "%f %f lineto\n",
surface->width, surface->height);
_cairo_output_stream_printf (stream, "0 %f lineto\n", surface->height);
_cairo_output_stream_printf (stream, "closepath fill\n");
return CAIRO_STATUS_SUCCESS;
}
static int
_cairo_ps_line_cap (cairo_line_cap_t cap)
{
switch (cap) {
case CAIRO_LINE_CAP_BUTT:
return 0;
case CAIRO_LINE_CAP_ROUND:
return 1;
case CAIRO_LINE_CAP_SQUARE:
return 2;
default:
ASSERT_NOT_REACHED;
return 0;
}
}
static int
_cairo_ps_line_join (cairo_line_join_t join)
{
switch (join) {
case CAIRO_LINE_JOIN_MITER:
return 0;
case CAIRO_LINE_JOIN_ROUND:
return 1;
case CAIRO_LINE_JOIN_BEVEL:
return 2;
default:
ASSERT_NOT_REACHED;
return 0;
}
}
static cairo_int_status_t
_cairo_ps_surface_stroke (void *abstract_surface,
cairo_operator_t op,
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_ps_surface_t *surface = abstract_surface;
cairo_output_stream_t *stream = surface->stream;
cairo_int_status_t status;
cairo_ps_surface_path_info_t info;
if (surface->mode == CAIRO_PAGINATED_MODE_EVALUATE) {
if (!pattern_operation_supported (op, source))
return CAIRO_INT_STATUS_UNSUPPORTED;
return CAIRO_STATUS_SUCCESS;
}
if (surface->need_start_page)
_cairo_ps_surface_start_page (surface);
_cairo_output_stream_printf (stream,
"%% _cairo_ps_surface_stroke\n");
emit_pattern (surface, source);
info.output_stream = stream;
info.has_current_point = FALSE;
status = _cairo_path_fixed_interpret (path,
CAIRO_DIRECTION_FORWARD,
_cairo_ps_surface_path_move_to,
_cairo_ps_surface_path_line_to,
_cairo_ps_surface_path_curve_to,
_cairo_ps_surface_path_close_path,
&info);
/*
* Switch to user space to set line parameters
*/
_cairo_output_stream_printf (stream,
"gsave\n");
_cairo_output_stream_printf (stream,
"[%f %f %f %f 0 0] concat\n",
ctm->xx, ctm->yx, ctm->xy, ctm->yy);
/* line width */
_cairo_output_stream_printf (stream, "%f setlinewidth\n",
style->line_width);
/* line cap */
_cairo_output_stream_printf (stream, "%d setlinecap\n",
_cairo_ps_line_cap (style->line_cap));
/* line join */
_cairo_output_stream_printf (stream, "%d setlinejoin\n",
_cairo_ps_line_join (style->line_join));
/* dashes */
if (style->num_dashes) {
int d;
_cairo_output_stream_printf (stream, "[");
for (d = 0; d < style->num_dashes; d++)
_cairo_output_stream_printf (stream, " %f", style->dash[d]);
_cairo_output_stream_printf (stream, "] %f setdash\n",
style->dash_offset);
}
/* miter limit */
_cairo_output_stream_printf (stream, "%f setmiterlimit\n",
style->miter_limit);
_cairo_output_stream_printf (stream,
"stroke\n");
_cairo_output_stream_printf (stream,
"grestore\n");
return status;
}
static cairo_int_status_t
_cairo_ps_surface_fill (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source,
cairo_path_fixed_t *path,
@ -1279,12 +1236,12 @@ _cairo_ps_surface_fill (void *abstract_surface,
cairo_ps_surface_path_info_t info;
const char *ps_operator;
if (pattern_operation_needs_fallback (op, source))
return _cairo_ps_surface_add_fallback_area (surface,
0, 0,
surface->width,
surface->height);
if (surface->mode == CAIRO_PAGINATED_MODE_EVALUATE) {
if (!pattern_operation_supported (op, source))
return CAIRO_INT_STATUS_UNSUPPORTED;
return CAIRO_STATUS_SUCCESS;
}
if (surface->need_start_page)
_cairo_ps_surface_start_page (surface);
@ -1329,9 +1286,9 @@ static const cairo_surface_backend_t cairo_ps_surface_backend = {
NULL, /* acquire_dest_image */
NULL, /* release_dest_image */
NULL, /* clone_similar */
_cairo_ps_surface_composite,
_cairo_ps_surface_fill_rectangles,
_cairo_ps_surface_composite_trapezoids,
NULL, /* composite */
NULL, /* fill_rectangles */
NULL, /* composite_trapezoids */
_cairo_ps_surface_copy_page,
_cairo_ps_surface_show_page,
NULL, /* set_clip_region */
@ -1350,9 +1307,22 @@ static const cairo_surface_backend_t cairo_ps_surface_backend = {
/* Here are the drawing functions */
NULL, /* paint */
_cairo_ps_surface_paint, /* paint */
NULL, /* mask */
NULL, /* stroke */
_cairo_ps_surface_stroke,
_cairo_ps_surface_fill,
NULL /* show_glyphs */
};
static void
_cairo_ps_paginated_set_mode (cairo_surface_t *target,
cairo_paginated_mode_t mode)
{
cairo_ps_surface_t *surface = (cairo_ps_surface_t *) target;
surface->mode = mode;
}
static const cairo_paginated_funcs_t cairo_ps_paginated_funcs = {
_cairo_ps_paginated_set_mode,
};