Add mask support and switch to SVG 1.2 for compositing operators.

return xml node instead of cairo status. (emit_composite_svg_pattern): ditto. (emit_composite_pattern): ditto. (emit_operator): use SVG 1.2 operators, since feComposite filter always composite resulting surface to current canvas. (_cairo_svg_surface_composite): removed. (_cairo_svg_surface_fill_rectangles): removed. (intersect): removed. (_cairo_svg_surface_composite_trapezoids): removed. (emit_paint): new. (_cairo_svg_surface_paint): new. (_cairo_svg_surface_mask): new. (_cairo_svg_surface_stroke): emit operator.
This commit is contained in:
Emmanuel Pacaud 2006-02-13 12:41:10 +00:00
parent 8ff1866724
commit 921dcc16f9
2 changed files with 105 additions and 208 deletions

View file

@ -1,3 +1,22 @@
2006-02-13 Emmanuel Pacaud <emmanuel.pacaud@free.fr>
Add mask support and switch to SVG 1.2 for compositing operators.
* src/cairo-svg-surface.c (emit_composite_image_pattern): return xml
node instead of cairo status.
(emit_composite_svg_pattern): ditto.
(emit_composite_pattern): ditto.
(emit_operator): use SVG 1.2 operators, since feComposite filter
always composite resulting surface to current canvas.
(_cairo_svg_surface_composite): removed.
(_cairo_svg_surface_fill_rectangles): removed.
(intersect): removed.
(_cairo_svg_surface_composite_trapezoids): removed.
(emit_paint): new.
(_cairo_svg_surface_paint): new.
(_cairo_svg_surface_mask): new.
(_cairo_svg_surface_stroke): emit operator.
2006-02-11 Christian Biesinger <cbiesinger@web.de>
* doc/public/cairo-docs.xml:

View file

@ -74,6 +74,7 @@ struct cairo_svg_document {
unsigned int pattern_id;
unsigned int filter_id;
unsigned int clip_id;
unsigned int mask_id;
};
struct cairo_svg_surface {
@ -392,7 +393,7 @@ _cairo_surface_base64_encode (cairo_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
static xmlNodePtr
emit_composite_image_pattern (xmlNodePtr node,
cairo_surface_pattern_t *pattern,
double *width,
@ -410,11 +411,11 @@ emit_composite_image_pattern (xmlNodePtr node,
status = _cairo_surface_acquire_source_image (surface, &image, &image_extra);
if (status)
return status;
return NULL;
status = _cairo_surface_base64_encode (surface, &image_buffer);
if (status)
return status;
return NULL;
child = xmlNewChild (node, NULL, CC2XML ("image"), NULL);
_cairo_dtostr (buffer, sizeof buffer, image->width);
@ -438,10 +439,10 @@ emit_composite_image_pattern (xmlNodePtr node,
_cairo_surface_release_source_image (pattern->surface, image, image_extra);
return status;
return child;
}
static cairo_int_status_t
static xmlNodePtr
emit_composite_svg_pattern (xmlNodePtr node,
cairo_surface_pattern_t *pattern,
double *width,
@ -455,7 +456,7 @@ emit_composite_svg_pattern (xmlNodePtr node,
/* FIXME: self copy is not supported yet */
if (surface->id == 0)
return CAIRO_STATUS_SUCCESS;
return NULL;
child = xmlNewChild (node, NULL, CC2XML("use"), NULL);
snprintf (buffer, sizeof buffer, "#surface%d", surface->id);
@ -472,10 +473,10 @@ emit_composite_svg_pattern (xmlNodePtr node,
if (height != NULL)
*height = surface->height;
return CAIRO_STATUS_SUCCESS;
return child;
}
static cairo_int_status_t
static xmlNodePtr
emit_composite_pattern (xmlNodePtr node,
cairo_surface_pattern_t *pattern,
double *width,
@ -488,69 +489,27 @@ emit_composite_pattern (xmlNodePtr node,
return emit_composite_image_pattern (node, pattern, width, height, is_pattern);
}
static cairo_int_status_t
_cairo_svg_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_svg_surface_t *dst = abstract_dst;
cairo_surface_pattern_t *src = (cairo_surface_pattern_t *) src_pattern;
if (mask_pattern)
return CAIRO_STATUS_SUCCESS;
if (src_pattern->type != CAIRO_PATTERN_SURFACE)
return CAIRO_STATUS_SUCCESS;
return emit_composite_pattern (dst->xml_node, src, NULL, NULL, FALSE);
}
/* FIXME: Here we use a SVG 1.2 feature. We should probably have
* an API to limit output SVG version, and fallback to image when
* necessary. */
static void
emit_operator (cairo_operator_t op, cairo_svg_surface_t *surface,
xmlBufferPtr style)
emit_operator (xmlNodePtr node, cairo_operator_t op)
{
char const *op_str[] = {
NULL,
NULL, NULL, "in", "out", "atop",
NULL, NULL, NULL, NULL, NULL,
"xor", NULL, NULL };
cairo_svg_document_t *document = surface->document;
xmlNodePtr child, primitive;
xmlBufferPtr id;
char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
"clear",
"src", "src-over", "src-in",
"src-out", "src-atop",
"dst", "dst-over", "dst-in",
"dst-out", "dst-atop",
"xor", "plus",
"color-dodge" /* FIXME: saturate ? */
};
if (op_str[op] == NULL)
return;
child = xmlNewChild (document->xml_node_defs, NULL, CC2XML ("filter"), NULL);
primitive = xmlNewChild (child, NULL, CC2XML ("feComposite"), NULL);
xmlSetProp (primitive, CC2XML ("operator"), CC2XML (op_str[op]));
xmlSetProp (primitive, CC2XML ("in"), CC2XML ("SourceGraphic"));
xmlSetProp (primitive, CC2XML ("in2"), CC2XML ("BackgroundImage"));
id = xmlBufferCreate ();
xmlBufferCat (id, CC2XML ("filter"));
snprintf (buffer, sizeof buffer, "%d", document->filter_id);
xmlBufferCat (id, C2XML (buffer));
xmlSetProp (child, CC2XML ("id"), C2XML (xmlBufferContent (id)));
xmlBufferCat (style, CC2XML ("filter: url(#"));
xmlBufferCat (style, xmlBufferContent (id));
xmlBufferCat (style, CC2XML (");"));
xmlBufferFree (id);
document->filter_id++;
xmlSetProp (node, CC2XML ("comp-op"), C2XML (op_str[op]));
}
static void
@ -828,7 +787,7 @@ typedef struct
xmlBufferPtr path;
} svg_path_info_t;
static cairo_status_t
static cairo_status_t
_cairo_svg_path_move_to (void *closure, cairo_point_t *point)
{
svg_path_info_t *info = closure;
@ -917,42 +876,6 @@ _cairo_svg_path_close_path (void *closure)
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_svg_surface_fill_rectangles (void *abstract_surface,
cairo_operator_t op,
const cairo_color_t *color,
cairo_rectangle_t *rects,
int num_rects)
{
cairo_svg_surface_t *surface = abstract_surface;
xmlNodePtr child;
xmlBufferPtr style;
char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
int i;
style = xmlBufferCreate ();
emit_color (color, style, "fill", "opacity");
xmlBufferCat (style, " stroke: none;");
emit_operator (op, surface, style);
for (i = 0; i < num_rects; i++) {
child = xmlNewChild (surface->xml_node, NULL, CC2XML ("rect"), NULL);
_cairo_dtostr (buffer, sizeof buffer, rects[i].x);
xmlSetProp (child, CC2XML ("x"), C2XML (buffer));
_cairo_dtostr (buffer, sizeof buffer, rects[i].y);
xmlSetProp (child, CC2XML ("y"), C2XML (buffer));
_cairo_dtostr (buffer, sizeof buffer, rects[i].width);
xmlSetProp (child, CC2XML ("width"), C2XML (buffer));
_cairo_dtostr (buffer, sizeof buffer, rects[i].height);
xmlSetProp (child, CC2XML ("height"), C2XML (buffer));
xmlSetProp (child, CC2XML ("style"), xmlBufferContent (style));
}
xmlBufferFree (style);
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_svg_surface_fill (void *abstract_surface,
cairo_operator_t op,
@ -978,7 +901,6 @@ _cairo_svg_surface_fill (void *abstract_surface,
xmlBufferCat (style, " stroke: none;");
xmlBufferCat (style, " fill-rule: ");
xmlBufferCat (style, fill_rule == CAIRO_FILL_RULE_EVEN_ODD ? "evenodd;" : "nonzero;");
emit_operator (op, surface, style);
status = _cairo_path_fixed_interpret (path,
CAIRO_DIRECTION_FORWARD,
@ -991,6 +913,7 @@ _cairo_svg_surface_fill (void *abstract_surface,
child = xmlNewChild (surface->xml_node, NULL, CC2XML ("path"), NULL);
xmlSetProp (child, CC2XML ("d"), xmlBufferContent (info.path));
xmlSetProp (child, CC2XML ("style"), xmlBufferContent (style));
emit_operator (child, op);
xmlBufferFree (info.path);
xmlBufferFree (style);
@ -998,91 +921,6 @@ _cairo_svg_surface_fill (void *abstract_surface,
return status;
}
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_svg_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_svg_surface_t *surface = abstract_dst;
xmlBufferPtr style, path;
xmlNodePtr child;
double left_x1, left_x2, right_x1, right_x2;
char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
int i;
style = xmlBufferCreate ();
emit_pattern (surface, pattern, style, 0);
xmlBufferCat (style, "stroke: none;");
path = xmlBufferCreate ();
for (i = 0; i < num_traps; i++) {
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);
xmlBufferCat (path, CC2XML ("M "));
_cairo_dtostr (buffer, sizeof buffer, left_x1);
xmlBufferCat (path, CC2XML (buffer));
xmlBufferCat (path, CC2XML (" "));
_cairo_dtostr (buffer, sizeof buffer,
_cairo_fixed_to_double (traps[i].top));
xmlBufferCat (path, CC2XML (buffer));
xmlBufferCat (path, CC2XML (" L "));
_cairo_dtostr (buffer, sizeof buffer, left_x2);
xmlBufferCat (path, CC2XML (buffer));
xmlBufferCat (path, CC2XML (" "));
_cairo_dtostr (buffer, sizeof buffer,
_cairo_fixed_to_double (traps[i].bottom));
xmlBufferCat (path, CC2XML (buffer));
xmlBufferCat (path, CC2XML (" L "));
_cairo_dtostr (buffer, sizeof buffer, right_x2);
xmlBufferCat (path, CC2XML (buffer));
xmlBufferCat (path, CC2XML (" "));
_cairo_dtostr (buffer, sizeof buffer,
_cairo_fixed_to_double (traps[i].bottom));
xmlBufferCat (path, CC2XML (buffer));
xmlBufferCat (path, CC2XML (" L "));
_cairo_dtostr (buffer, sizeof buffer, right_x1);
xmlBufferCat (path, CC2XML (buffer));
xmlBufferCat (path, CC2XML (" "));
_cairo_dtostr (buffer, sizeof buffer,
_cairo_fixed_to_double (traps[i].top));
xmlBufferCat (path, CC2XML (buffer));
xmlBufferCat (path, CC2XML (" Z"));
}
child = xmlNewChild (surface->xml_node, NULL, CC2XML ("path"), NULL);
xmlSetProp (child, CC2XML ("d"), xmlBufferContent (path));
xmlSetProp (child, CC2XML ("style"), xmlBufferContent (style));
xmlBufferFree (path);
xmlBufferFree (style);
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_svg_surface_get_extents (void *abstract_surface,
cairo_rectangle_t *rectangle)
@ -1102,26 +940,26 @@ _cairo_svg_surface_get_extents (void *abstract_surface,
return CAIRO_STATUS_SUCCESS;
}
/* First attempt of paint implementation, but obviously I didn't
* understand how it's supposed to work */
#if 0
static cairo_int_status_t
_cairo_svg_surface_paint (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source)
static xmlNodePtr
emit_paint (xmlNodePtr node,
cairo_svg_surface_t *surface,
cairo_operator_t op,
cairo_pattern_t *source)
{
cairo_svg_surface_t *surface = abstract_surface;
xmlNodePtr child;
xmlBufferPtr style;
char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
if (source->type == CAIRO_PATTERN_SURFACE)
return emit_composite_pattern (node,
(cairo_surface_pattern_t *) source,
NULL, NULL, FALSE);
style = xmlBufferCreate ();
emit_pattern (surface, source, style, 0);
xmlBufferCat (style, " stroke: none;");
emit_operator (op, surface, style);
child = xmlNewChild (surface->xml_node, NULL, CC2XML ("rect"), NULL);
child = xmlNewChild (node, NULL, CC2XML ("rect"), NULL);
xmlSetProp (child, CC2XML ("x"), CC2XML ("0"));
xmlSetProp (child, CC2XML ("y"), CC2XML ("0"));
_cairo_dtostr (buffer, sizeof buffer, surface->width);
@ -1129,12 +967,51 @@ _cairo_svg_surface_paint (void *abstract_surface,
_cairo_dtostr (buffer, sizeof buffer, surface->height);
xmlSetProp (child, CC2XML ("height"), C2XML (buffer));
xmlSetProp (child, CC2XML ("style"), xmlBufferContent (style));
emit_operator (child, op);
xmlBufferFree (style);
return child;
}
static cairo_int_status_t
_cairo_svg_surface_paint (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source)
{
cairo_svg_surface_t *surface = abstract_surface;
emit_paint (surface->xml_node, surface, op, source);
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_svg_surface_mask (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source,
cairo_pattern_t *mask)
{
cairo_svg_surface_t *surface = abstract_surface;
cairo_svg_document_t *document = surface->document;
xmlNodePtr child, mask_node;
char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
mask_node = xmlNewChild (document->xml_node_defs, NULL, CC2XML ("mask"), NULL);
snprintf (buffer, sizeof buffer, "mask%d", document->mask_id);
xmlSetProp (mask_node, CC2XML ("id"), C2XML (buffer));
emit_paint (mask_node, surface, op, mask);
child = emit_paint (surface->xml_node, surface, op, source);
if (child) {
snprintf (buffer, sizeof buffer, "url(#mask%d)", document->mask_id);
xmlSetProp (child, CC2XML ("mask"), C2XML (buffer));
}
document->mask_id++;
return CAIRO_STATUS_SUCCESS;
}
#endif
static cairo_int_status_t
_cairo_svg_surface_stroke (void *abstract_dst,
@ -1231,9 +1108,9 @@ _cairo_svg_surface_stroke (void *abstract_dst,
&info);
child = xmlNewChild (surface->xml_node, NULL, CC2XML ("path"), NULL);
xmlSetProp (child, CC2XML ("d"), xmlBufferContent (info.path));
xmlSetProp (child, CC2XML ("style"), xmlBufferContent (style));
emit_operator (child, op);
xmlBufferFree (info.path);
xmlBufferFree (style);
@ -1357,9 +1234,9 @@ static const cairo_surface_backend_t cairo_svg_surface_backend = {
NULL, /* acquire_dest_image */
NULL, /* release_dest_image */
NULL, /* clone_similar */
_cairo_svg_surface_composite,
_cairo_svg_surface_fill_rectangles,
_cairo_svg_surface_composite_trapezoids,
NULL, /* _cairo_svg_surface_composite, */
NULL, /* _cairo_svg_surface_fill_rectangles, */
NULL, /* _cairo_svg_surface_composite_trapezoids,*/
NULL, /* copy_page */
NULL, /* show_page */
NULL, /* set_clip_region */
@ -1371,8 +1248,8 @@ static const cairo_surface_backend_t cairo_svg_surface_backend = {
NULL, /* mark dirty rectangle */
NULL, /* scaled font fini */
NULL, /* scaled glyph fini */
NULL, /*_cairo_svg_surface_paint,*/
NULL, /* mask */
_cairo_svg_surface_paint,
_cairo_svg_surface_mask,
_cairo_svg_surface_stroke,
_cairo_svg_surface_fill,
NULL /* show_glyphs */
@ -1407,6 +1284,7 @@ _cairo_svg_document_create (cairo_output_stream_t *output_stream,
document->pattern_id = 0;
document->filter_id = 0;
document->clip_id = 0;
document->mask_id = 0;
doc = xmlNewDoc (CC2XML ("1.0"));
node = xmlNewNode (NULL, CC2XML ("svg"));
@ -1423,7 +1301,7 @@ _cairo_svg_document_create (cairo_output_stream_t *output_stream,
xmlSetProp (node, CC2XML ("height"), CC2XML (buffer));
xmlSetProp (node, CC2XML ("xmlns"), CC2XML ("http://www.w3.org/2000/svg"));
xmlSetProp (node, CC2XML ("xmlns:xlink"), CC2XML ("http://www.w3.org/1999/xlink"));
xmlSetProp (node, CC2XML ("version"), CC2XML ("1.1"));
xmlSetProp (node, CC2XML ("version"), CC2XML ("1.2"));
return document;
}