Use PDF 're' operator for rectangle paths

Modify cairo-pdf-operators.c to emit to 're' path operator when the
path contains only a rectangle. This can only be done when the path is
logically equivilent to the the path drawn by the 're'
operator. Otherwise dashed strokes may start on the wrong line.

ie the path must be equivalent to:

  cairo_move_to (cr, x, y);
  cairo_rel_line_to (cr, width, 0);
  cairo_rel_line_to (cr, 0, height);
  cairo_rel_line_to (cr, -width, 0);
  cairo_close_path (cr);

which is also equivilent to cairo_rectangle().
This commit is contained in:
Adrian Johnson 2008-02-26 23:17:04 +10:30
parent 7acfee38b1
commit 40f4750f5e
4 changed files with 59 additions and 7 deletions

View file

@ -802,3 +802,27 @@ _cairo_path_fixed_is_box (cairo_path_fixed_t *path,
return FALSE;
}
/**
* Check whether the given path contains a single rectangle
* that is logically equivalent to:
* cairo_move_to (cr, x, y);
* cairo_rel_line_to (cr, width, 0);
* cairo_rel_line_to (cr, 0, height);
* cairo_rel_line_to (cr, -width, 0);
* cairo_close_path (cr);
*/
cairo_bool_t
_cairo_path_fixed_is_rectangle (cairo_path_fixed_t *path,
cairo_box_t *box)
{
cairo_path_buf_t *buf = &path->buf_head.base;
if (!_cairo_path_fixed_is_box (path, box))
return FALSE;
if (buf->points[0].y == buf->points[1].y)
return TRUE;
return FALSE;
}

View file

@ -328,6 +328,23 @@ _cairo_pdf_path_close_path (void *closure)
return _cairo_output_stream_get_status (info->output);
}
static cairo_status_t
_cairo_pdf_path_rectangle (pdf_path_info_t *info, cairo_box_t *box)
{
double x1 = _cairo_fixed_to_double (box->p1.x);
double y1 = _cairo_fixed_to_double (box->p1.y);
double x2 = _cairo_fixed_to_double (box->p2.x);
double y2 = _cairo_fixed_to_double (box->p2.y);
cairo_matrix_transform_point (info->path_transform, &x1, &y1);
cairo_matrix_transform_point (info->path_transform, &x2, &y2);
_cairo_output_stream_printf (info->output,
"%f %f %f %f re ",
x1, y1, x2 - x1, y2 - y1);
return _cairo_output_stream_get_status (info->output);
}
/* The line cap value is needed to workaround the fact that PostScript
* and PDF semantics for stroking degenerate sub-paths do not match
* cairo semantics. (PostScript draws something for any line cap
@ -346,6 +363,7 @@ _cairo_pdf_operators_emit_path (cairo_pdf_operators_t *pdf_operators,
cairo_output_stream_t *word_wrap;
cairo_status_t status, status2;
pdf_path_info_t info;
cairo_box_t box;
word_wrap = _word_wrap_stream_create (pdf_operators->stream, 79);
status = _cairo_output_stream_get_status (word_wrap);
@ -355,13 +373,17 @@ _cairo_pdf_operators_emit_path (cairo_pdf_operators_t *pdf_operators,
info.output = word_wrap;
info.path_transform = path_transform;
info.line_cap = line_cap;
status = _cairo_path_fixed_interpret (path,
CAIRO_DIRECTION_FORWARD,
_cairo_pdf_path_move_to,
_cairo_pdf_path_line_to,
_cairo_pdf_path_curve_to,
_cairo_pdf_path_close_path,
&info);
if (_cairo_path_fixed_is_rectangle (path, &box)) {
status = _cairo_pdf_path_rectangle (&info, &box);
} else {
status = _cairo_path_fixed_interpret (path,
CAIRO_DIRECTION_FORWARD,
_cairo_pdf_path_move_to,
_cairo_pdf_path_line_to,
_cairo_pdf_path_curve_to,
_cairo_pdf_path_close_path,
&info);
}
status2 = _cairo_output_stream_destroy (word_wrap);
if (status == CAIRO_STATUS_SUCCESS)

View file

@ -169,6 +169,8 @@ _cairo_ps_surface_emit_header (cairo_ps_surface_t *surface)
"/l { lineto } bind def\n"
"/c { curveto } bind def\n"
"/h { closepath } bind def\n"
"/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto\n"
" 0 exch rlineto 0 rlineto closepath } bind def\n"
"/S { stroke } bind def\n"
"/f { fill } bind def\n"
"/f* { eofill } bind def\n"

View file

@ -1399,6 +1399,10 @@ cairo_private cairo_bool_t
_cairo_path_fixed_is_box (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_box_t *box);
/* cairo_path_fill.c */
cairo_private cairo_status_t
_cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path,