Add a new fill_stroke surface backend method.

This method is for use in vector backends, where fill immediatly followed by
stroke command with the same path can be emited in the same backend command.
This commit also factorize the detection of such cases in the meta surface
backend and automatically call the fill_stroke method on replay.
This commit is contained in:
Emmanuel Pacaud 2007-08-25 20:49:50 +02:00
parent 43d35e0110
commit ac51fff0db
4 changed files with 169 additions and 7 deletions

View file

@ -735,14 +735,54 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface,
break;
}
case CAIRO_COMMAND_FILL:
status = _cairo_surface_fill (target,
command->fill.op,
&command->fill.source.base,
dev_path,
command->fill.fill_rule,
command->fill.tolerance,
command->fill.antialias);
{
cairo_command_t *stroke_command;
stroke_command = (i < num_elements - 1) ? elements[i + 1] : 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;
cairo_matrix_t tmp;
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);
tmp = surface->device_transform;
status = cairo_matrix_invert (&tmp);
assert (status == CAIRO_STATUS_SUCCESS);
cairo_matrix_multiply (&dev_ctm_inverse, &tmp, &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);
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);
break;
}
case CAIRO_COMMAND_SHOW_GLYPHS:
{
cairo_glyph_t *glyphs = command->show_glyphs.glyphs;

View file

@ -550,3 +550,30 @@ _cairo_path_fixed_device_transform (cairo_path_fixed_t *path,
_cairo_fixed_from_double (device_transform->xx),
_cairo_fixed_from_double (device_transform->yy));
}
cairo_bool_t
_cairo_path_fixed_is_equal (cairo_path_fixed_t *path,
cairo_path_fixed_t *other)
{
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->last_move_point.x != other->last_move_point.x ||
path->last_move_point.y != other->last_move_point.y)
return FALSE;
other_buf = other->buf_head;
for (path_buf = path->buf_head; path_buf != NULL; path_buf = path_buf->next) {
if (other_buf == NULL ||
path_buf->num_ops != other_buf->num_ops ||
path_buf->num_points != other_buf->num_points ||
memcmp (path_buf->op, other_buf->op, path_buf->num_ops) != 0 ||
memcmp (path_buf->points, other_buf->points, path_buf->num_points != 0))
return FALSE;
other_buf = other_buf->next;
}
return TRUE;
}

View file

@ -1386,6 +1386,65 @@ _cairo_surface_mask (cairo_surface_t *surface,
return status;
}
cairo_status_t
_cairo_surface_fill_stroke (cairo_surface_t *surface,
cairo_operator_t fill_op,
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,
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_status_t status;
if (surface->backend->fill_stroke) {
cairo_pattern_union_t dev_stroke_source;
cairo_pattern_union_t dev_fill_source;
cairo_matrix_t dev_ctm = *stroke_ctm;
cairo_matrix_t dev_ctm_inverse = *stroke_ctm_inverse;
status = _cairo_surface_copy_pattern_for_destination (stroke_source, surface, &dev_stroke_source.base);
if (status)
return status;
status = _cairo_surface_copy_pattern_for_destination (fill_source, surface, &dev_fill_source.base);
if (status) {
_cairo_pattern_fini (&dev_stroke_source.base);
return status;
}
status = surface->backend->fill_stroke (surface, fill_op, &dev_fill_source.base,
fill_rule, fill_tolerance, fill_antialias,
path, stroke_op, &dev_stroke_source.base, stroke_style,
&dev_ctm, &dev_ctm_inverse, stroke_tolerance,
stroke_antialias);
_cairo_pattern_fini (&dev_stroke_source.base);
_cairo_pattern_fini (&dev_fill_source.base);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
}
status = _cairo_surface_fill (surface, fill_op, fill_source, path,
fill_rule, fill_tolerance, fill_antialias);
if (status)
return status;
status = _cairo_surface_stroke (surface, stroke_op, stroke_source, path,
stroke_style, stroke_ctm, stroke_ctm_inverse,
stroke_tolerance, stroke_antialias);
return status;
}
cairo_status_t
_cairo_surface_stroke (cairo_surface_t *surface,
cairo_operator_t op,

View file

@ -874,6 +874,22 @@ struct _cairo_surface_backend {
cairo_warn cairo_status_t
(*reset) (void *surface);
cairo_warn cairo_int_status_t
(*fill_stroke) (void *surface,
cairo_operator_t fill_op,
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,
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);
};
typedef struct _cairo_format_masks {
@ -1469,6 +1485,10 @@ cairo_private cairo_status_t
_cairo_path_fixed_init_copy (cairo_path_fixed_t *path,
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);
@ -1750,6 +1770,22 @@ _cairo_surface_mask (cairo_surface_t *surface,
cairo_pattern_t *source,
cairo_pattern_t *mask);
cairo_private cairo_status_t
_cairo_surface_fill_stroke (cairo_surface_t *surface,
cairo_operator_t fill_op,
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,
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_private cairo_status_t
_cairo_surface_stroke (cairo_surface_t *surface,
cairo_operator_t op,