diff options
-rw-r--r-- | ChangeLog | 9 | ||||
-rw-r--r-- | rsvg-filter.c | 216 | ||||
-rw-r--r-- | rsvg-filter.h | 5 | ||||
-rw-r--r-- | rsvg-image.c | 3 | ||||
-rw-r--r-- | rsvg-marker.c | 24 | ||||
-rw-r--r-- | rsvg-paint-server.c | 12 | ||||
-rw-r--r-- | rsvg-shapes.c | 680 | ||||
-rw-r--r-- | rsvg-shapes.h | 15 | ||||
-rw-r--r-- | rsvg-structure.c | 13 | ||||
-rw-r--r-- | rsvg.c | 128 |
10 files changed, 633 insertions, 472 deletions
@@ -1,10 +1,15 @@ +2005-05-30 Caleb Moore <c.moore@student.unsw.edu.au> + + * rsvg-shapes.c: converted all shapes to be manipulatable + * rsvg-filter.c: made transfer functions more similar to everything else + 2005-05-20 Caleb Moore <c.moore@student.unsw.edu.au> - * rsvg_paint_server.c, rsvg_art_paint_server.c, rsvg.c: converted to use the new create->manipulate->use system. + * rsvg-paint-server.c, rsvg-art-paint-server.c, rsvg.c: converted to use the new create->manipulate->use system. 2005-05-17 Caleb Moore <c.moore@student.unsw.edu.au> - * rsvg_structure.c: Fixed a problem with <use> not working. + * rsvg-structure.c: Fixed a problem with <use> not working. 2005-05-17 Caleb Moore <c.moore@student.unsw.edu.au> diff --git a/rsvg-filter.c b/rsvg-filter.c index 4cdf4d46..8a4cbe7a 100644 --- a/rsvg-filter.c +++ b/rsvg-filter.c @@ -2212,11 +2212,22 @@ rsvg_new_filter_primitive_colour_matrix (void) /*************************************************************/ /*************************************************************/ -struct ComponentTransferData +typedef struct _RsvgNodeComponentTransferFunc RsvgNodeComponentTransferFunc; + +typedef gdouble (*ComponentTransferFunc) (gdouble C, + RsvgNodeComponentTransferFunc* + user_data); + +typedef struct _RsvgFilterPrimitiveComponentTransfer +RsvgFilterPrimitiveComponentTransfer; + +struct _RsvgNodeComponentTransferFunc { + RsvgNode super; + ComponentTransferFunc function; + gchar channel; gdouble *tableValues; guint nbTableValues; - gdouble slope; gdouble intercept; gdouble amplitude; @@ -2224,30 +2235,13 @@ struct ComponentTransferData gdouble offset; }; -typedef gdouble (*ComponentTransferFunc) (gdouble C, - struct ComponentTransferData * - user_data); - -typedef struct _RsvgFilterPrimitiveComponentTransfer -RsvgFilterPrimitiveComponentTransfer; - - struct _RsvgFilterPrimitiveComponentTransfer { RsvgFilterPrimitive super; - ComponentTransferFunc Rfunction; - struct ComponentTransferData Rdata; - ComponentTransferFunc Gfunction; - struct ComponentTransferData Gdata; - ComponentTransferFunc Bfunction; - struct ComponentTransferData Bdata; - ComponentTransferFunc Afunction; - struct ComponentTransferData Adata; }; static gint -get_component_transfer_table_value (gdouble C, - struct ComponentTransferData *user_data) +get_component_transfer_table_value (gdouble C, RsvgNodeComponentTransferFunc *user_data) { gdouble N; gint k; @@ -2261,15 +2255,13 @@ get_component_transfer_table_value (gdouble C, } static gdouble -identity_component_transfer_func (gdouble C, - struct ComponentTransferData *user_data) +identity_component_transfer_func (gdouble C, RsvgNodeComponentTransferFunc *user_data) { return C; } static gdouble -table_component_transfer_func (gdouble C, - struct ComponentTransferData *user_data) +table_component_transfer_func (gdouble C, RsvgNodeComponentTransferFunc *user_data) { guint k; gdouble vk, vk1; @@ -2292,8 +2284,7 @@ table_component_transfer_func (gdouble C, } static gdouble -discrete_component_transfer_func (gdouble C, - struct ComponentTransferData *user_data) +discrete_component_transfer_func (gdouble C, RsvgNodeComponentTransferFunc *user_data) { gint k; @@ -2306,15 +2297,13 @@ discrete_component_transfer_func (gdouble C, } static gdouble -linear_component_transfer_func (gdouble C, - struct ComponentTransferData *user_data) +linear_component_transfer_func (gdouble C, RsvgNodeComponentTransferFunc *user_data) { return (user_data->slope * C) + user_data->intercept; } static gdouble -gamma_component_transfer_func (gdouble C, - struct ComponentTransferData *user_data) +gamma_component_transfer_func (gdouble C, RsvgNodeComponentTransferFunc *user_data) { return user_data->amplitude * pow (C, user_data->exponent) + user_data->offset; @@ -2325,10 +2314,13 @@ rsvg_filter_primitive_component_transfer_render (RsvgFilterPrimitive * self, RsvgFilterContext * ctx) { - gint x, y; + gint x, y, c; + guint i; gint temp; gint rowstride, height, width; FPBox boundarys; + RsvgNodeComponentTransferFunc * channels[4]; + ComponentTransferFunc functions[4]; guchar *in_pixels; guchar *output_pixels; @@ -2340,6 +2332,26 @@ rsvg_filter_primitive_component_transfer_render (RsvgFilterPrimitive * cself = (RsvgFilterPrimitiveComponentTransfer *) self; boundarys = rsvg_filter_primitive_get_bounds (self, ctx); + for (c = 0; c < 4; c++) + { + char channel = "rgba"[c]; + for (i = 0; i < self->super.children->len; i++) + { + RsvgNodeComponentTransferFunc * temp; + temp = (RsvgNodeComponentTransferFunc *) + g_ptr_array_index(self->super.children, i); + if (temp->channel == channel) + { + functions[c] = temp->function; + channels[c] = temp; + break; + } + } + if (i == self->super.children->len) + functions[c] = identity_component_transfer_func; + + } + in = rsvg_filter_get_in (self->in, ctx); in_pixels = gdk_pixbuf_get_pixels (in); @@ -2354,59 +2366,21 @@ rsvg_filter_primitive_component_transfer_render (RsvgFilterPrimitive * for (y = boundarys.y1; y < boundarys.y2; y++) for (x = boundarys.x1; x < boundarys.x2; x++) - { - temp = cself->Rfunction((double)in_pixels[y * rowstride + x * 4] / 255.0, &cself->Rdata) * 255.0; - if (temp > 255) - temp = 255; - else if (temp < 0) - temp = 0; - output_pixels[y * rowstride + x * 4] = temp; - - temp = cself->Gfunction((double)in_pixels[y * rowstride + x * 4 + 1] / 255.0, &cself->Gdata) * 255.0; - if (temp > 255) - temp = 255; - else if (temp < 0) - temp = 0; - output_pixels[y * rowstride + x * 4 + 1] = temp; - - temp = cself->Bfunction((double)in_pixels[y * rowstride + x * 4 + 2] / 255.0, &cself->Bdata) * 255.0; - if (temp > 255) - temp = 255; - else if (temp < 0) - temp = 0; - output_pixels[y * rowstride + x * 4 + 2] = temp; - - temp = cself->Afunction((double)in_pixels[y * rowstride + x * 4 + 3] / 255.0, &cself->Adata) * 255.0; - if (temp > 255) - temp = 255; - else if (temp < 0) - temp = 0; - output_pixels[y * rowstride + x * 4 + 3] = temp; - } + for (c = 0; c < 4; c++) + { + temp = functions[c]((double)in_pixels[y * rowstride + x * 4 + c] / 255.0, channels[c]) * 255.0; + if (temp > 255) + temp = 255; + else if (temp < 0) + temp = 0; + output_pixels[y * rowstride + x * 4 + c] = temp; + } rsvg_filter_store_result (self->result, output, ctx); g_object_unref (G_OBJECT (in)); g_object_unref (G_OBJECT (output)); } -static void -rsvg_filter_primitive_component_transfer_free (RsvgNode * self) -{ - RsvgFilterPrimitiveComponentTransfer *cself; - - cself = (RsvgFilterPrimitiveComponentTransfer *) self; - g_string_free (cself->super.result, TRUE); - if (cself->Rdata.nbTableValues) - g_free (cself->Rdata.tableValues); - if (cself->Gdata.nbTableValues) - g_free (cself->Gdata.tableValues); - if (cself->Bdata.nbTableValues) - g_free (cself->Bdata.tableValues); - if (cself->Adata.nbTableValues) - g_free (cself->Adata.tableValues); - g_free (cself); -} - static void rsvg_filter_primitive_component_transfer_set_atts (RsvgNode * self, RsvgHandle * ctx, RsvgPropertyBag * atts) { @@ -2473,72 +2447,37 @@ rsvg_new_filter_primitive_component_transfer (void) filter->super.result = g_string_new ("none"); filter->super.in = g_string_new ("none"); filter->super.sizedefaults = 1; - filter->Rfunction = identity_component_transfer_func; - filter->Gfunction = identity_component_transfer_func; - filter->Bfunction = identity_component_transfer_func; - filter->Afunction = identity_component_transfer_func; - filter->Rdata.nbTableValues = 0; - filter->Gdata.nbTableValues = 0; - filter->Bdata.nbTableValues = 0; - filter->Adata.nbTableValues = 0; filter->super.render = &rsvg_filter_primitive_component_transfer_render; - filter->super.super.free = &rsvg_filter_primitive_component_transfer_free; + filter->super.super.free = &rsvg_filter_free; filter->super.super.type = RSVG_NODE_FILTER_PRIMITIVE; filter->super.super.set_atts = rsvg_filter_primitive_component_transfer_set_atts; + + filter->super.super.children = g_ptr_array_new (); return (RsvgNode *)filter; } -void -rsvg_start_filter_primitive_component_transfer_function (RsvgHandle * ctx, - RsvgPropertyBag * atts, char channel) +static void +rsvg_node_component_transfer_function_set_atts (RsvgNode * self, + RsvgHandle * ctx, + RsvgPropertyBag * atts) { const char *value; - - ComponentTransferFunc * function; - struct ComponentTransferData * data; - - function = NULL; - data = NULL; - - if (channel == 'r') - { - function = &((RsvgFilterPrimitiveComponentTransfer *)(ctx->currentnode))->Rfunction; - data = &((RsvgFilterPrimitiveComponentTransfer *)(ctx->currentnode))->Rdata; - } - else if (channel == 'g') - { - function = &((RsvgFilterPrimitiveComponentTransfer *)(ctx->currentnode))->Gfunction; - data = &((RsvgFilterPrimitiveComponentTransfer *)(ctx->currentnode))->Gdata; - } - else if (channel == 'b') - { - function = &((RsvgFilterPrimitiveComponentTransfer *)(ctx->currentnode))->Bfunction; - data = &((RsvgFilterPrimitiveComponentTransfer *)(ctx->currentnode))->Bdata; - } - else if (channel == 'a') - { - function = &((RsvgFilterPrimitiveComponentTransfer *)(ctx->currentnode))->Afunction; - data = &((RsvgFilterPrimitiveComponentTransfer *)(ctx->currentnode))->Adata; - } - else - { - g_assert_not_reached(); - } + RsvgNodeComponentTransferFunc * data = (RsvgNodeComponentTransferFunc *)self; if (rsvg_property_bag_size (atts)) { if ((value = rsvg_property_bag_lookup (atts, "type"))) { if (!strcmp (value, "identity")) - *function = identity_component_transfer_func; + data->function = identity_component_transfer_func; else if (!strcmp (value, "table")) - *function = table_component_transfer_func; + data->function = table_component_transfer_func; else if (!strcmp (value, "discrete")) - *function = discrete_component_transfer_func; + data->function = discrete_component_transfer_func; else if (!strcmp (value, "linear")) - *function = linear_component_transfer_func; + data->function = linear_component_transfer_func; else if (!strcmp (value, "gamma")) - *function = gamma_component_transfer_func; + data->function = gamma_component_transfer_func; } if ((value = rsvg_property_bag_lookup (atts, "tableValues"))) { @@ -2569,6 +2508,30 @@ rsvg_start_filter_primitive_component_transfer_function (RsvgHandle * ctx, } } +static void +rsvg_component_transfer_function_free(RsvgNode * self) + +{ + RsvgNodeComponentTransferFunc *filter = (RsvgNodeComponentTransferFunc *)self; + if (filter->nbTableValues) + g_free(filter->tableValues); + g_free(self); +} + +RsvgNode * +rsvg_new_node_component_transfer_function (char channel) +{ + RsvgNodeComponentTransferFunc *filter; + + filter = g_new (RsvgNodeComponentTransferFunc, 1); + filter->super.free = rsvg_component_transfer_function_free; + filter->super.type = RSVG_NODE_FILTER_PRIMITIVE; + filter->super.set_atts = rsvg_node_component_transfer_function_set_atts; + filter->channel = channel; + filter->function = identity_component_transfer_func; + filter->nbTableValues = 0; + return (RsvgNode *)filter; +} /*************************************************************/ /*************************************************************/ @@ -4457,6 +4420,7 @@ rsvg_new_filter_primitive_light_source(char type) data->super.free = rsvg_filter_primitive_light_source_free; data->super.set_atts = rsvg_filter_primitive_light_source_set_atts; data->specularExponent = 1; + data->super.type = RSVG_NODE_FILTER_PRIMITIVE_MERGE_NODE; if (type == 's') data->type = SPOTLIGHT; else if (type == 'd') diff --git a/rsvg-filter.h b/rsvg-filter.h index 86035460..e6c03d5f 100644 --- a/rsvg-filter.h +++ b/rsvg-filter.h @@ -74,9 +74,8 @@ rsvg_new_filter_primitive_colour_matrix (void); RsvgNode * rsvg_new_filter_primitive_component_transfer (void); -void -rsvg_start_filter_primitive_component_transfer_function (RsvgHandle * ctx, - RsvgPropertyBag * atts, char channel); +RsvgNode * +rsvg_new_node_component_transfer_function (char channel); RsvgNode * rsvg_new_filter_primitive_erode (void); diff --git a/rsvg-image.c b/rsvg-image.c index 6b090a72..0b9f9a37 100644 --- a/rsvg-image.c +++ b/rsvg-image.c @@ -451,7 +451,8 @@ rsvg_preserve_aspect_ratio(unsigned int aspect_ratio, double width, { neww = *w; newh = *h; - if ((height * *w > width * *h) != (aspect_ratio & RSVG_ASPECT_RATIO_SLICE)) + if ((height * *w > width * *h) == + ((aspect_ratio & RSVG_ASPECT_RATIO_SLICE) == 0)) { neww = width * *h / height; diff --git a/rsvg-marker.c b/rsvg-marker.c index fd23f79f..980a9623 100644 --- a/rsvg-marker.c +++ b/rsvg-marker.c @@ -81,13 +81,14 @@ rsvg_node_marker_set_atts (RsvgNode * self, RsvgHandle *ctx, RsvgPropertyBag *at if ((value = rsvg_property_bag_lookup (atts, "markerUnits"))) { if (!strcmp (value, "userSpaceOnUse")) marker->bbox = FALSE; - else - marker->bbox = TRUE; - } + if (!strcmp (value, "objectBoundingBox")) + marker->bbox = TRUE; + } if ((value = rsvg_property_bag_lookup (atts, "preserveAspectRatio"))) marker->preserve_aspect_ratio = rsvg_css_parse_aspect_ratio (value); if ((value = rsvg_property_bag_lookup (atts, "overflow"))) marker->overflow = rsvg_css_parse_overflow(value); + rsvg_parse_style_attrs (ctx, self->state, "marker", klazz, id, atts); } } @@ -116,23 +117,6 @@ rsvg_new_marker (void) return &marker->super; } - -static void -rsvg_state_reassemble(RsvgNode * self, RsvgState * state) -{ - RsvgState store; - if (self == NULL) - { - return; - } - rsvg_state_reassemble(self->parent, state); - - rsvg_state_clone (&store, self->state); - rsvg_state_reinherit(&store, state); - rsvg_state_finalize(state); - *state = store; -} - void rsvg_marker_render (RsvgMarker *self, gdouble x, gdouble y, gdouble orient, gdouble linewidth, RsvgDrawingCtx *ctx) { diff --git a/rsvg-paint-server.c b/rsvg-paint-server.c index 74c97bfc..62853219 100644 --- a/rsvg-paint-server.c +++ b/rsvg-paint-server.c @@ -311,7 +311,7 @@ rsvg_linear_gradient_set_atts (RsvgNode * self, RsvgHandle *ctx, RsvgPropertyBag if ((value = rsvg_property_bag_lookup (atts, "gradientUnits"))) { if (!strcmp (value, "userSpaceOnUse")) grad->obj_bbox = FALSE; - else + else if (!strcmp (value, "objectBoundingBox")) grad->obj_bbox = TRUE; grad->hasbbox = TRUE; } @@ -356,10 +356,14 @@ rsvg_radial_gradient_set_atts (RsvgNode * self, RsvgHandle *ctx, RsvgPropertyBag if ((value = rsvg_property_bag_lookup (atts, "cx"))){ grad->cx = rsvg_css_parse_normalized_length (value, ctx->dpi_x, 1, font_size); grad->hascx = TRUE; + if (!grad->hasfx) + grad->fx = grad->cx; } if ((value = rsvg_property_bag_lookup (atts, "cy"))){ grad->cy = rsvg_css_parse_normalized_length (value, ctx->dpi_y, 1, font_size); grad->hascy = TRUE; + if (!grad->hasfy) + grad->fy = grad->cy; } if ((value = rsvg_property_bag_lookup (atts, "r"))){ grad->r = rsvg_css_parse_normalized_length (value, rsvg_dpi_percentage (ctx), 1, font_size); @@ -394,7 +398,7 @@ rsvg_radial_gradient_set_atts (RsvgNode * self, RsvgHandle *ctx, RsvgPropertyBag if ((value = rsvg_property_bag_lookup (atts, "gradientUnits"))) { if (!strcmp (value, "userSpaceOnUse")) grad->obj_bbox = FALSE; - else + else if (!strcmp (value, "objectBoundingBox")) grad->obj_bbox = TRUE; grad->hasbbox = TRUE; } @@ -469,14 +473,14 @@ rsvg_pattern_set_atts (RsvgNode * self, RsvgHandle *ctx, RsvgPropertyBag *atts) if ((value = rsvg_property_bag_lookup (atts, "patternUnits"))) { if (!strcmp (value, "userSpaceOnUse")) pattern->obj_bbox = FALSE; - else + else if (!strcmp (value, "objectBoundingBox")) pattern->obj_bbox = TRUE; pattern->hasbbox = TRUE; } if ((value = rsvg_property_bag_lookup (atts, "patternContentUnits"))) { if (!strcmp (value, "userSpaceOnUse")) pattern->obj_cbbox = FALSE; - else + else if (!strcmp (value, "objectBoundingBox")) pattern->obj_cbbox = TRUE; pattern->hascbox = TRUE; } diff --git a/rsvg-shapes.c b/rsvg-shapes.c index f7ce819c..098a23b9 100644 --- a/rsvg-shapes.c +++ b/rsvg-shapes.c @@ -39,70 +39,70 @@ #define RSVG_ARC_MAGIC ((double) 0.5522847498) static void -rsvg_node_ath_free (RsvgNode *self) +rsvg_node_path_free (RsvgNode *self) { RsvgNodePath *z = (RsvgNodePath *)self; rsvg_state_finalize (z->super.state); g_free(z->super.state); - g_free (z->d); + if (z->d) + g_free (z->d); g_free (z); } static void -rsvg_node_ath_draw (RsvgNode * self, RsvgDrawingCtx *ctx, - int dominate) +rsvg_node_path_draw (RsvgNode * self, RsvgDrawingCtx *ctx, + int dominate) { RsvgNodePath *path = (RsvgNodePath*)self; + if (!path->d) + return; rsvg_state_reinherit_top(ctx, self->state, dominate); rsvg_render_path (ctx, path->d); } -void -rsvg_handle_path (RsvgHandle *ctx, const char * d, const char * id, RsvgState state) -{ - RsvgNodePath *path; - - path = g_new (RsvgNodePath, 1); - path->d = g_strdup(d); - path->super.state = g_new(RsvgState, 1); - *path->super.state = state; - path->super.type = RSVG_NODE_PATH; - path->super.free = rsvg_node_ath_free; - path->super.draw = rsvg_node_ath_draw; - rsvg_defs_set (ctx->defs, id, &path->super); - - path->super.parent = (RsvgNode *)ctx->currentnode; - if (path->super.parent != NULL) - rsvg_node_group_pack(path->super.parent, - &path->super); -} - -void -rsvg_start_path (RsvgHandle *ctx, RsvgPropertyBag *atts) +static void +rsvg_node_path_set_atts (RsvgNode * self, RsvgHandle *ctx, RsvgPropertyBag *atts) { - const char * klazz = NULL, * id = NULL, *value, *d = NULL; - RsvgState state; - rsvg_state_init(&state); + const char * klazz = NULL, * id = NULL, *value; + RsvgNodePath * path = (RsvgNodePath *)self; - if (rsvg_property_bag_size (atts)) { if ((value = rsvg_property_bag_lookup (atts, "d"))) - d = value; + { + if (path->d) + g_free(path->d); + path->d = g_strdup(value); + } if ((value = rsvg_property_bag_lookup (atts, "class"))) klazz = value; if ((value = rsvg_property_bag_lookup (atts, "id"))) - id = value; + { + id = value; + rsvg_defs_register_name (ctx->defs, value, self); + } - rsvg_parse_style_attrs (ctx, &state, "path", klazz, id, atts); + rsvg_parse_style_attrs (ctx, self->state, "path", klazz, id, atts); } +} + +RsvgNode * +rsvg_new_path (void) +{ + RsvgNodePath *path; + path = g_new (RsvgNodePath, 1); + path->d = NULL; + path->super.state = g_new(RsvgState, 1); + rsvg_state_init(path->super.state); + path->super.children = NULL; + path->super.type = RSVG_NODE_PATH; + path->super.free = rsvg_node_path_free; + path->super.draw = rsvg_node_path_draw; + path->super.set_atts = rsvg_node_path_set_atts; - if (d == NULL) - return; - - rsvg_handle_path (ctx, d, id, state); + return &path->super; } static GString * @@ -130,191 +130,299 @@ rsvg_make_poly_point_list(const char * points) return str; } +struct _RsvgNodePoly +{ + RsvgNode super; + double * pointlist; + gboolean is_polyline; + guint pointlist_len; +}; + +typedef struct _RsvgNodePoly RsvgNodePoly; + static void -rsvg_start_any_poly(RsvgHandle *ctx, RsvgPropertyBag *atts, gboolean is_polyline) +_rsvg_node_poly_set_atts(RsvgNode * self, RsvgHandle *ctx, + RsvgPropertyBag *atts) { - /* the only difference between polygon and polyline is - that a polyline closes the path */ - - const char * verts = (const char *)NULL; - GString * g = NULL; - gchar ** pointlist = NULL; + RsvgNodePoly * poly = (RsvgNodePoly *)self; const char * klazz = NULL, * id = NULL, *value; - gsize pointlist_len = 0; - RsvgState state; - rsvg_state_init(&state); if (rsvg_property_bag_size (atts)) { /* support for svg < 1.0 which used verts */ if ((value = rsvg_property_bag_lookup (atts, "verts")) || (value = rsvg_property_bag_lookup (atts, "points"))) - verts = value; + { + guint i; + GString * g = NULL; + gsize pointlist_len = 0; + gchar ** pointlist = NULL; + + if (poly->pointlist) + g_free(poly->pointlist); + + g = rsvg_make_poly_point_list (value); + pointlist = g_strsplit (g->str, " ", -1); + g_string_free (g, TRUE); + + if (pointlist) + { + while(pointlist[pointlist_len] != NULL) + pointlist_len++; + } + if (pointlist_len > 0) + pointlist_len--; + + poly->pointlist = g_new(double, pointlist_len); + poly->pointlist_len = pointlist_len; + + for (i = 0; i < pointlist_len; i++) + poly->pointlist[i] = atof(pointlist[i]); + + if (pointlist) + g_strfreev(pointlist); + } if ((value = rsvg_property_bag_lookup (atts, "class"))) klazz = value; if ((value = rsvg_property_bag_lookup (atts, "id"))) - id = value; + { + id = value; + rsvg_defs_register_name (ctx->defs, value, self); + } - rsvg_parse_style_attrs (ctx, &state, (is_polyline ? "polyline" : "polygon"), klazz, id, atts); + rsvg_parse_style_attrs (ctx, self->state, (poly->is_polyline ? "polyline" : "polygon"), klazz, id, atts); } - if (!verts) - return; - - /* todo: make the following more memory and CPU friendly */ - g = rsvg_make_poly_point_list (verts); - pointlist = g_strsplit (g->str, " ", -1); - g_string_free (g, TRUE); - - if (pointlist) - { - while(pointlist[pointlist_len] != NULL) - pointlist_len++; - } +} +static void +_rsvg_node_poly_draw(RsvgNode * self, RsvgDrawingCtx *ctx, + int dominate) +{ + RsvgNodePoly * poly = (RsvgNodePoly *)self; /* represent as a "moveto, lineto*, close" path */ - if (pointlist_len >= 2) - { - gsize i; - GString * d = g_string_sized_new (strlen(verts)); - g_string_append_printf (d, "M %s %s ", pointlist[0], pointlist[1] ); - - for (i = 2; pointlist[i] != NULL && pointlist[i][0] != '\0'; i += 2) - g_string_append_printf (d, "L %s %s ", pointlist[i], pointlist[i+1]); - - if (!is_polyline) - g_string_append (d, "Z"); - - rsvg_handle_path (ctx, d->str, id, state); - g_string_free (d, TRUE); - } + if (poly->pointlist_len < 2) + return; + + gsize i; + GString * d = g_string_new (""); + g_string_append_printf (d, "M %f %f ", poly->pointlist[0], poly->pointlist[1] ); + + for (i = 2; i < poly->pointlist_len; i += 2) + g_string_append_printf (d, "L %f %f ", poly->pointlist[i], poly->pointlist[i+1]); - if (pointlist) - g_strfreev(pointlist); + if (!poly->is_polyline) + g_string_append (d, "Z"); + + rsvg_state_reinherit_top(ctx, self->state, dominate); + rsvg_render_path (ctx, d->str); + + g_string_free (d, TRUE); } -void -rsvg_start_polygon (RsvgHandle *ctx, RsvgPropertyBag *atts) +static void +_rsvg_node_poly_free (RsvgNode *self) { - rsvg_start_any_poly (ctx, atts, FALSE); + RsvgNodePoly *z = (RsvgNodePoly *)self; + rsvg_state_finalize (z->super.state); + g_free(z->super.state); + if (z->pointlist) + g_free (z->pointlist); + g_free (z); } -void -rsvg_start_polyline (RsvgHandle *ctx, RsvgPropertyBag *atts) + +static RsvgNode * +rsvg_new_any_poly(gboolean is_polyline) { - rsvg_start_any_poly (ctx, atts, TRUE); + RsvgNodePoly *poly; + poly = g_new (RsvgNodePoly, 1); + poly->super.children = NULL; + poly->super.state = g_new(RsvgState, 1); + rsvg_state_init(poly->super.state); + poly->super.type = RSVG_NODE_PATH; + poly->super.free = _rsvg_node_poly_free; + poly->super.draw = _rsvg_node_poly_draw; + poly->super.set_atts = _rsvg_node_poly_set_atts; + poly->pointlist = NULL; + poly->is_polyline = is_polyline; + poly->pointlist_len = 0; + return &poly->super; } -void -rsvg_start_line (RsvgHandle *ctx, RsvgPropertyBag *atts) +RsvgNode * +rsvg_new_polygon (void) { - double x1 = 0, y1 = 0, x2 = 0, y2 = 0; - GString * d = NULL; - const char * klazz = NULL, * id = NULL, *value; - char buf [G_ASCII_DTOSTR_BUF_SIZE]; + return rsvg_new_any_poly (FALSE); +} + +RsvgNode * +rsvg_new_polyline (void) +{ + return rsvg_new_any_poly (TRUE); +} + + +struct _RsvgNodeLine +{ + RsvgNode super; + double x1, x2, y1, y2; +}; + +typedef struct _RsvgNodeLine RsvgNodeLine; + +static void +_rsvg_node_line_set_atts (RsvgNode * self, RsvgHandle *ctx, RsvgPropertyBag *atts) +{ + const char * klazz = NULL, *id = NULL, *value; double font_size; - RsvgState state; - rsvg_state_init(&state); + RsvgNodeLine * line = (RsvgNodeLine *) self; font_size = rsvg_state_current_font_size (ctx); + if (rsvg_property_bag_size (atts)) { if ((value = rsvg_property_bag_lookup (atts, "x1"))) - x1 = rsvg_css_parse_normalized_length (value, ctx->dpi_x, (gdouble)ctx->width, font_size); + line->x1 = rsvg_css_parse_normalized_length (value, ctx->dpi_x, (gdouble)ctx->width, font_size); if ((value = rsvg_property_bag_lookup (atts, "y1"))) - y1 = rsvg_css_parse_normalized_length (value, ctx->dpi_y, (gdouble)ctx->height, font_size); + line->y1 = rsvg_css_parse_normalized_length (value, ctx->dpi_y, (gdouble)ctx->height, font_size); if ((value = rsvg_property_bag_lookup (atts, "x2"))) - x2 = rsvg_css_parse_normalized_length (value, ctx->dpi_x, (gdouble)ctx->width, font_size); + line->x2 = rsvg_css_parse_normalized_length (value, ctx->dpi_x, (gdouble)ctx->width, font_size); if ((value = rsvg_property_bag_lookup (atts, "y2"))) - y2 = rsvg_css_parse_normalized_length (value, ctx->dpi_y, (gdouble)ctx->height, font_size); + line->y2 = rsvg_css_parse_normalized_length (value, ctx->dpi_y, (gdouble)ctx->height, font_size); if ((value = rsvg_property_bag_lookup (atts, "class"))) klazz = value; if ((value = rsvg_property_bag_lookup (atts, "id"))) - id = value; - - rsvg_parse_style_attrs (ctx, &state, "line", klazz, id, atts); + { + id = value; + rsvg_defs_register_name (ctx->defs, value, self); + } + + rsvg_parse_style_attrs (ctx, self->state, "line", klazz, id, atts); } - +} + +static void +_rsvg_node_line_draw(RsvgNode * overself, RsvgDrawingCtx *ctx, + int dominate) +{ + GString * d; + char buf [G_ASCII_DTOSTR_BUF_SIZE]; + RsvgNodeLine * self = (RsvgNodeLine *)overself; + /* emulate a line using a path */ /* ("M %f %f L %f %f", x1, y1, x2, y2) */ d = g_string_new ("M "); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), x1)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), self->x1)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), y1)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), self->y1)); g_string_append (d, " L "); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), x2)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), self->x2)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), y2)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), self->y2)); - rsvg_handle_path (ctx, d->str, id, state); - g_string_free (d, TRUE); + rsvg_state_reinherit_top(ctx, overself->state, dominate); + rsvg_render_path (ctx, d->str); + + g_string_free (d, TRUE); } -void -rsvg_start_rect (RsvgHandle *ctx, RsvgPropertyBag *atts) +RsvgNode * +rsvg_new_line (void) +{ + RsvgNodeLine *line; + line = g_new (RsvgNodeLine, 1); + line->super.children = NULL; + line->super.state = g_new(RsvgState, 1); + rsvg_state_init(line->super.state); + line->super.type = RSVG_NODE_PATH; + line->super.free = rsvg_node_free; + line->super.draw = _rsvg_node_line_draw; + line->super.set_atts = _rsvg_node_line_set_atts; + line->x1 = line->x2 = line->y1 = line->y2 = 0; + return &line->super; +} + +struct _RsvgNodeRect +{ + RsvgNode super; + double x, y, w, h, rx, ry; + gboolean got_rx, got_ry; +}; + +typedef struct _RsvgNodeRect RsvgNodeRect; + +static void +_rsvg_node_rect_set_atts (RsvgNode * self, RsvgHandle *ctx, RsvgPropertyBag *atts) { - double x = 0., y = 0., w = 0, h = 0, rx = 0., ry = 0.; - GString * d = NULL; const char * klazz = NULL, * id = NULL, *value; - char buf [G_ASCII_DTOSTR_BUF_SIZE]; - gboolean got_rx = FALSE, got_ry = FALSE; double font_size; - RsvgState state; - rsvg_state_init(&state); + RsvgNodeRect * rect = (RsvgNodeRect *)self; font_size = rsvg_state_current_font_size (ctx); if (rsvg_property_bag_size (atts)) { if ((value = rsvg_property_bag_lookup (atts, "x"))) - x = rsvg_css_parse_normalized_length (value, ctx->dpi_x, (gdouble)ctx->width, font_size); + rect->x = rsvg_css_parse_normalized_length (value, ctx->dpi_x, (gdouble)ctx->width, font_size); if ((value = rsvg_property_bag_lookup (atts, "y"))) - y = rsvg_css_parse_normalized_length (value, ctx->dpi_y, (gdouble)ctx->height, font_size); + rect->y = rsvg_css_parse_normalized_length (value, ctx->dpi_y, (gdouble)ctx->height, font_size) + 0.01; if ((value = rsvg_property_bag_lookup (atts, "width"))) - w = rsvg_css_parse_normalized_length (value, ctx->dpi_x, (gdouble)ctx->width, font_size); + rect->w = rsvg_css_parse_normalized_length (value, ctx->dpi_x, (gdouble)ctx->width, font_size); if ((value = rsvg_property_bag_lookup (atts, "height"))) - h = rsvg_css_parse_normalized_length (value, ctx->dpi_y, (gdouble)ctx->height, font_size); + rect->h = rsvg_css_parse_normalized_length (value, ctx->dpi_y, (gdouble)ctx->height, font_size); if ((value = rsvg_property_bag_lookup (atts, "rx"))) { - rx = rsvg_css_parse_normalized_length (value, ctx->dpi_x, (gdouble)ctx->width, font_size); - got_rx = TRUE; + rect->rx = rsvg_css_parse_normalized_length (value, ctx->dpi_x, (gdouble)ctx->width, font_size); + rect->got_rx = TRUE; } if ((value = rsvg_property_bag_lookup (atts, "ry"))) { - ry = rsvg_css_parse_normalized_length (value, ctx->dpi_y, (gdouble)ctx->height, font_size); - got_ry = TRUE; + rect->ry = rsvg_css_parse_normalized_length (value, ctx->dpi_y, (gdouble)ctx->height, font_size); + rect->got_ry = TRUE; } if ((value = rsvg_property_bag_lookup (atts, "class"))) klazz = value; if ((value = rsvg_property_bag_lookup (atts, "id"))) - id = value; + { + id = value; + rsvg_defs_register_name (ctx->defs, value, self); + } - rsvg_parse_style_attrs (ctx, &state, "rect", klazz, id, atts); + rsvg_parse_style_attrs (ctx, self->state, "rect", klazz, id, atts); } +} + +static void +_rsvg_node_rect_draw(RsvgNode * self, RsvgDrawingCtx *ctx, + int dominate) +{ + double rx, ry; + GString * d = NULL; + RsvgNodeRect * rect = (RsvgNodeRect *)self; + char buf [G_ASCII_DTOSTR_BUF_SIZE]; - if (got_rx && !got_ry) - ry = rx; - else if (got_ry && !got_rx) - rx = ry; + if (rect->got_rx) + rx = rect->rx; + else + rx = rect->ry; + if (rect->got_ry) + ry = rect->ry; + else + ry = rect->rx; - if (w == 0. || h == 0. || rx < 0. || ry < 0.) - return; + if (rx > fabs(rect->w / 2.)) + rx = fabs(rect->w / 2.); + if (ry > fabs(rect->h / 2.)) + ry = fabs(rect->h / 2.); - if (rx > fabs(w / 2.)) - rx = fabs(w / 2.); - if (ry > fabs(h / 2.)) - ry = fabs(h / 2.); - - /* incrementing y by 1 properly draws borders. this is a HACK */ - y += .01; - /* emulate a rect using a path */ d = g_string_new ("M "); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), x + rx)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), rect->x + rx)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), y)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), rect->y)); g_string_append (d, " H "); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), x + w - rx)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), rect->x + rect->w - rx)); g_string_append (d, " A"); g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), rx)); @@ -327,12 +435,12 @@ rsvg_start_rect (RsvgHandle *ctx, RsvgPropertyBag *atts) g_string_append_c (d, ' '); g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), 1.)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), x+w)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), rect->x+rect->w)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), y+ry)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), rect->y+ry)); g_string_append (d, " V "); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), y+h-ry)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), rect->y+rect->h-ry)); g_string_append (d, " A"); g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), rx)); @@ -345,12 +453,12 @@ rsvg_start_rect (RsvgHandle *ctx, RsvgPropertyBag *atts) g_string_append_c (d, ' '); g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), 1.)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), x + w - rx)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), rect->x + rect->w - rx)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), y + h)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), rect->y + rect->h)); g_string_append (d, " H "); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), x + rx)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), rect->x + rx)); g_string_append (d, " A"); g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), rx)); @@ -363,12 +471,12 @@ rsvg_start_rect (RsvgHandle *ctx, RsvgPropertyBag *atts) g_string_append_c (d, ' '); g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), 1.)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), x)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), rect->x)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), y + h - ry)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), rect->y +rect-> h - ry)); g_string_append (d, " V "); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), y+ry)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), rect->y+ry)); g_string_append (d, " A"); g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), rx)); @@ -381,210 +489,294 @@ rsvg_start_rect (RsvgHandle *ctx, RsvgPropertyBag *atts) g_string_append_c (d, ' '); g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), 1.)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), x+rx)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), rect->x+rx)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), y)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), rect->y)); g_string_append (d, " Z"); - rsvg_handle_path (ctx, d->str, id, state); + rsvg_state_reinherit_top(ctx, self->state, dominate); + rsvg_render_path (ctx, d->str); g_string_free (d, TRUE); } -void -rsvg_start_circle (RsvgHandle *ctx, RsvgPropertyBag *atts) +RsvgNode * +rsvg_new_rect (void) +{ + RsvgNodeRect *rect; + rect = g_new (RsvgNodeRect, 1); + rect->super.children = NULL; + rect->super.state = g_new(RsvgState, 1); + rsvg_state_init(rect->super.state); + rect->super.type = RSVG_NODE_PATH; + rect->super.free = rsvg_node_free; + rect->super.draw = _rsvg_node_rect_draw; + rect->super.set_atts = _rsvg_node_rect_set_atts; + rect->x = rect->y = rect->w = rect->h = rect->rx = rect->ry = 0; + rect->got_rx = rect->got_ry = FALSE; + return &rect->super; +} + +struct _RsvgNodeCircle +{ + RsvgNode super; + double cx, cy, r; +}; + +typedef struct _RsvgNodeCircle RsvgNodeCircle; + +static void +_rsvg_node_circle_set_atts (RsvgNode * self, RsvgHandle *ctx, RsvgPropertyBag *atts) { - double cx = 0, cy = 0, r = 0; - GString * d = NULL; const char * klazz = NULL, * id = NULL, *value; - char buf [G_ASCII_DTOSTR_BUF_SIZE]; double font_size; - RsvgState state; - rsvg_state_init(&state); + RsvgNodeCircle * circle = (RsvgNodeCircle *)self; font_size = rsvg_state_current_font_size (ctx); if (rsvg_property_bag_size (atts)) { if ((value = rsvg_property_bag_lookup (atts, "cx"))) - cx = rsvg_css_parse_normalized_length (value, ctx->dpi_x, (gdouble)ctx->width, font_size); + circle->cx = rsvg_css_parse_normalized_length (value, ctx->dpi_x, (gdouble)ctx->width, font_size); if ((value = rsvg_property_bag_lookup (atts, "cy"))) - cy = rsvg_css_parse_normalized_length (value, ctx->dpi_y, (gdouble)ctx->height, font_size); + circle->cy = rsvg_css_parse_normalized_length (value, ctx->dpi_y, (gdouble)ctx->height, font_size); if ((value = rsvg_property_bag_lookup (atts, "r"))) - r = rsvg_css_parse_normalized_length (value, rsvg_dpi_percentage (ctx), - rsvg_viewport_percentage((gdouble)ctx->width, (gdouble)ctx->height), - font_size); + circle->r = rsvg_css_parse_normalized_length (value, rsvg_dpi_percentage (ctx), + rsvg_viewport_percentage((gdouble)ctx->width, (gdouble)ctx->height), + font_size); if ((value = rsvg_property_bag_lookup (atts, "class"))) klazz = value; if ((value = rsvg_property_bag_lookup (atts, "id"))) - id = value; + { + id = value; + rsvg_defs_register_name (ctx->defs, value, self); + } - rsvg_parse_style_attrs (ctx, &state, "circle", klazz, id, atts); + rsvg_parse_style_attrs (ctx, self->state, "circle", klazz, id, atts); } - - if (r <= 0.) - return; +} + +static void +_rsvg_node_circle_draw(RsvgNode * self, RsvgDrawingCtx *ctx, + int dominate) +{ + GString * d = NULL; + RsvgNodeCircle * circle = (RsvgNodeCircle *)self; + char buf [G_ASCII_DTOSTR_BUF_SIZE]; + + if (circle->r <= 0) + return; /* approximate a circle using 4 bezier curves */ d = g_string_new ("M "); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cx+r)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), circle->cx+circle->r)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cy)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), circle->cy)); g_string_append (d, " C "); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cx+r)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), circle->cx+circle->r)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cy + r * RSVG_ARC_MAGIC)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), circle->cy + circle->r * RSVG_ARC_MAGIC)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cx + r * RSVG_ARC_MAGIC)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), circle->cx + circle->r * RSVG_ARC_MAGIC)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cy + r)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), circle->cy + circle->r)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cx)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), circle->cx)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cy + r)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), circle->cy + circle->r)); g_string_append (d, " C "); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cx - r * RSVG_ARC_MAGIC)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), circle->cx - circle->r * RSVG_ARC_MAGIC)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cy + r)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), circle->cy + circle->r)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cx - r)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), circle->cx - circle->r)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cy + r * RSVG_ARC_MAGIC)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), circle->cy + circle->r * RSVG_ARC_MAGIC)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cx - r)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), circle->cx - circle->r)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cy)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), circle->cy)); g_string_append (d, " C "); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cx - r)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), circle-> cx - circle->r)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cy - r * RSVG_ARC_MAGIC)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), circle->cy - circle->r * RSVG_ARC_MAGIC)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cx - r * RSVG_ARC_MAGIC)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), circle->cx - circle->r * RSVG_ARC_MAGIC)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cy - r)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), circle->cy - circle->r)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cx)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), circle->cx)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cy - r)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), circle->cy - circle->r)); g_string_append (d, " C "); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cx + r * RSVG_ARC_MAGIC)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), circle->cx + circle->r * RSVG_ARC_MAGIC)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cy - r)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), circle->cy - circle->r)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cx + r)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), circle->cx + circle->r)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cy - r * RSVG_ARC_MAGIC)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), circle->cy - circle->r * RSVG_ARC_MAGIC)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cx + r)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), circle->cx + circle->r)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cy)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), circle->cy)); g_string_append (d, " Z"); - rsvg_handle_path (ctx, d->str, id, state); + rsvg_state_reinherit_top(ctx, self->state, dominate); + rsvg_render_path (ctx, d->str); + g_string_free (d, TRUE); } -void -rsvg_start_ellipse (RsvgHandle *ctx, RsvgPropertyBag *atts) +RsvgNode * +rsvg_new_circle (void) +{ + RsvgNodeCircle *circle; + circle = g_new (RsvgNodeCircle, 1); + circle->super.children = NULL; + circle->super.state = g_new(RsvgState, 1); + rsvg_state_init(circle->super.state); + circle->super.type = RSVG_NODE_PATH; + circle->super.free = rsvg_node_free; + circle->super.draw = _rsvg_node_circle_draw; + circle->super.set_atts = _rsvg_node_circle_set_atts; + circle->cx = circle->cy = circle->r = 0; + return &circle->super; +} + +struct _RsvgNodeEllipse +{ + RsvgNode super; + double cx, cy, rx, ry; +}; + +typedef struct _RsvgNodeEllipse RsvgNodeEllipse; + +static void +_rsvg_node_ellipse_set_atts (RsvgNode * self, RsvgHandle *ctx, RsvgPropertyBag *atts) { - double cx = 0, cy = 0, rx = 0, ry = 0; - GString * d = NULL; const char * klazz = NULL, * id = NULL, *value; - char buf [G_ASCII_DTOSTR_BUF_SIZE]; double font_size; - RsvgState state; - rsvg_state_init(&state); + RsvgNodeEllipse * ellipse = (RsvgNodeEllipse *)self; font_size = rsvg_state_current_font_size (ctx); if (rsvg_property_bag_size (atts)) { if ((value = rsvg_property_bag_lookup (atts, "cx"))) - cx = rsvg_css_parse_normalized_length (value, ctx->dpi_x, (gdouble)ctx->width, font_size); + ellipse->cx = rsvg_css_parse_normalized_length (value, ctx->dpi_x, (gdouble)ctx->width, font_size); if ((value = rsvg_property_bag_lookup (atts, "cy"))) - cy = rsvg_css_parse_normalized_length (value, ctx->dpi_y, (gdouble)ctx->height, font_size); + ellipse->cy = rsvg_css_parse_normalized_length (value, ctx->dpi_y, (gdouble)ctx->height, font_size); if ((value = rsvg_property_bag_lookup (atts, "rx"))) - rx = rsvg_css_parse_normalized_length (value, ctx->dpi_x, (gdouble)ctx->width, font_size); + ellipse->rx = rsvg_css_parse_normalized_length (value, ctx->dpi_x, (gdouble)ctx->width, font_size); if ((value = rsvg_property_bag_lookup (atts, "ry"))) - ry = rsvg_css_parse_normalized_length (value, ctx->dpi_y, (gdouble)ctx->height, font_size); + ellipse->ry = rsvg_css_parse_normalized_length (value, ctx->dpi_y, (gdouble)ctx->height, font_size); if ((value = rsvg_property_bag_lookup (atts, "class"))) klazz = value; if ((value = rsvg_property_bag_lookup (atts, "id"))) - id = value; + { + id = value; + rsvg_defs_register_name (ctx->defs, value, self); + } - rsvg_parse_style_attrs (ctx, &state, "ellipse", klazz, id, atts); - } - - if (rx <= 0. || ry <= 0.) - return; + rsvg_parse_style_attrs (ctx, self->state, "ellipse", klazz, id, atts); + } +} + +static void +_rsvg_node_ellipse_draw(RsvgNode * self, RsvgDrawingCtx *ctx, + int dominate) +{ + RsvgNodeEllipse * ellipse = (RsvgNodeEllipse *)self; + GString * d = NULL; + char buf [G_ASCII_DTOSTR_BUF_SIZE]; + if (ellipse->rx <= 0 || ellipse->ry <= 0) + return; /* approximate an ellipse using 4 bezier curves */ d = g_string_new ("M "); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cx + rx)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), ellipse->cx + ellipse->rx)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cy)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), ellipse->cy)); g_string_append (d, " C "); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cx + rx)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), ellipse->cx + ellipse->rx)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cy - RSVG_ARC_MAGIC * ry)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), ellipse->cy - RSVG_ARC_MAGIC * ellipse->ry)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cx + RSVG_ARC_MAGIC * rx)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), ellipse->cx + RSVG_ARC_MAGIC * ellipse->rx)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cy - ry)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), ellipse->cy - ellipse->ry)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cx)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), ellipse->cx)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cy - ry)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), ellipse->cy - ellipse->ry)); g_string_append (d, " C "); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cx - RSVG_ARC_MAGIC * rx)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), ellipse->cx - RSVG_ARC_MAGIC * ellipse->rx)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cy - ry)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), ellipse->cy - ellipse->ry)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cx - rx)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), ellipse->cx - ellipse->rx)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cy - RSVG_ARC_MAGIC * ry)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), ellipse->cy - RSVG_ARC_MAGIC * ellipse->ry)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cx - rx)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), ellipse->cx - ellipse->rx)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cy)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), ellipse->cy)); g_string_append (d, " C "); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cx - rx)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), ellipse->cx - ellipse->rx)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cy + RSVG_ARC_MAGIC * ry)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), ellipse->cy + RSVG_ARC_MAGIC * ellipse->ry)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cx - RSVG_ARC_MAGIC * rx)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), ellipse->cx - RSVG_ARC_MAGIC * ellipse->rx)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cy + ry)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), ellipse->cy + ellipse->ry)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cx)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), ellipse->cx)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cy + ry)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), ellipse->cy + ellipse->ry)); g_string_append (d, " C "); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cx + RSVG_ARC_MAGIC * rx)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), ellipse->cx + RSVG_ARC_MAGIC * ellipse->rx)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cy + ry)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), ellipse->cy + ellipse->ry)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cx + rx)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), ellipse->cx + ellipse->rx)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cy + RSVG_ARC_MAGIC * ry)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), ellipse->cy + RSVG_ARC_MAGIC * ellipse->ry)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cx + rx)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), ellipse->cx + ellipse->rx)); g_string_append_c (d, ' '); - g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), cy)); + g_string_append (d, g_ascii_dtostr (buf, sizeof (buf), ellipse->cy)); g_string_append (d, " Z"); - - rsvg_handle_path (ctx, d->str, id, state); + + rsvg_state_reinherit_top(ctx, self->state, dominate); + rsvg_render_path (ctx, d->str); g_string_free (d, TRUE); } + +RsvgNode * +rsvg_new_ellipse (void) +{ + RsvgNodeEllipse *ellipse; + ellipse = g_new (RsvgNodeEllipse, 1); + ellipse->super.children = NULL; + ellipse->super.state = g_new(RsvgState, 1); + rsvg_state_init(ellipse->super.state); + ellipse->super.type = RSVG_NODE_PATH; + ellipse->super.free = rsvg_node_free; + ellipse->super.draw = _rsvg_node_ellipse_draw; + ellipse->super.set_atts = _rsvg_node_ellipse_set_atts; + ellipse->cx = ellipse->cy = ellipse->rx = ellipse->ry = 0; + return &ellipse->super; +} diff --git a/rsvg-shapes.h b/rsvg-shapes.h index 94cc5a7b..0f323899 100644 --- a/rsvg-shapes.h +++ b/rsvg-shapes.h @@ -33,14 +33,13 @@ G_BEGIN_DECLS -void rsvg_handle_path (RsvgHandle *ctx, const char * d, const char * id, RsvgState); -void rsvg_start_path (RsvgHandle *ctx, RsvgPropertyBag *atts); -void rsvg_start_polygon (RsvgHandle *ctx, RsvgPropertyBag *atts); -void rsvg_start_polyline (RsvgHandle *ctx, RsvgPropertyBag *atts); -void rsvg_start_line (RsvgHandle *ctx, RsvgPropertyBag *atts); -void rsvg_start_rect (RsvgHandle *ctx, RsvgPropertyBag *atts); -void rsvg_start_circle (RsvgHandle *ctx, RsvgPropertyBag *atts); -void rsvg_start_ellipse (RsvgHandle *ctx, RsvgPropertyBag *atts); +RsvgNode * rsvg_new_path (void); +RsvgNode * rsvg_new_polygon (void); +RsvgNode * rsvg_new_polyline (void); +RsvgNode * rsvg_new_line (void); +RsvgNode * rsvg_new_rect (void); +RsvgNode * rsvg_new_circle (void); +RsvgNode * rsvg_new_ellipse (void); typedef struct _RsvgNodePath RsvgNodePath; diff --git a/rsvg-structure.c b/rsvg-structure.c index 1d24fa08..16e45e1d 100644 --- a/rsvg-structure.c +++ b/rsvg-structure.c @@ -80,8 +80,10 @@ void rsvg_node_free (RsvgNode *self) { rsvg_state_finalize (self->state); - g_free(self->state); - g_ptr_array_free(self->children, TRUE); + if (self->state != NULL) + g_free(self->state); + if (self->children != NULL) + g_ptr_array_free(self->children, TRUE); g_free (self); } @@ -442,14 +444,17 @@ rsvg_node_symbol_set_atts(RsvgNode *self, RsvgHandle *ctx, RsvgPropertyBag *atts { RsvgNodeSymbol *symbol = (RsvgNodeSymbol *)self; - const char * klazz = NULL, *id = NULL, *value; + const char * klazz = NULL, *value, *id = NULL; if (rsvg_property_bag_size(atts)) { if ((value = rsvg_property_bag_lookup (atts, "class"))) klazz = value; if ((value = rsvg_property_bag_lookup (atts, "id"))) - id = value; + { + id = value; + rsvg_defs_register_name (ctx->defs, value, &symbol->super); + } if ((value = rsvg_property_bag_lookup (atts, "viewBox"))) { symbol->has_vbox = rsvg_css_parse_vbox (value, @@ -164,8 +164,56 @@ static void rsvg_filter_handler_start (RsvgHandle *ctx, const xmlChar *name, RsvgPropertyBag *atts) { + + /*replace this stuff with a hash for fast reading!*/ RsvgNode * newnode = NULL; - if (!strcmp ((char *)name, "filter")) + if (!strcmp ((char *)name, "g")) + newnode = rsvg_new_group (); + else if (!strcmp ((char *)name, "a")) /*treat anchors as groups for now*/ + newnode = rsvg_new_group (); + else if (!strcmp ((char *)name, "switch")) + newnode = rsvg_new_switch (); + else if (!strcmp ((char *)name, "defs")) + newnode = rsvg_new_defs (); + else if (!strcmp ((char *)name, "use")) + newnode = rsvg_new_use (); + else if (!strcmp ((char *)name, "path")) + newnode = rsvg_new_path (); + else if (!strcmp ((char *)name, "line")) + newnode = rsvg_new_line (); + else if (!strcmp ((char *)name, "rect")) + newnode = rsvg_new_rect (); + else if (!strcmp ((char *)name, "ellipse")) + newnode = rsvg_new_ellipse (); + else if (!strcmp ((char *)name, "circle")) + newnode = rsvg_new_circle (); + else if (!strcmp ((char *)name, "polygon")) + newnode = rsvg_new_polygon (); + else if (!strcmp ((char *)name, "polyline")) + newnode = rsvg_new_polyline (); + else if (!strcmp ((char *)name, "symbol")) + newnode = rsvg_new_symbol (); + else if (!strcmp ((char *)name, "svg")) + newnode = rsvg_new_svg (); + else if (!strcmp ((char *)name, "mask")) + newnode = rsvg_new_mask(); + else if (!strcmp ((char *)name, "clipPath")) + newnode = rsvg_new_clip_path(); + else if (!strcmp ((char *)name, "image")) + newnode = rsvg_new_image (); + else if (!strcmp ((char *)name, "marker")) + newnode = rsvg_new_marker (); + else if (!strcmp ((char *)name, "stop")) + newnode = rsvg_new_stop (); + else if (!strcmp ((char *)name, "pattern")) + newnode = rsvg_new_pattern (); + else if (!strcmp ((char *)name, "linearGradient")) + newnode = rsvg_new_linear_gradient (); + else if (!strcmp ((char *)name, "radialGradient")) + newnode = rsvg_new_radial_gradient (); + else if (!strcmp ((char *)name, "conicalGradient")) + newnode = rsvg_new_radial_gradient (); + else if (!strcmp ((char *)name, "filter")) newnode = rsvg_new_filter(); else if (!strcmp ((char *)name, "feBlend")) newnode = rsvg_new_filter_primitive_blend (); @@ -201,44 +249,20 @@ rsvg_filter_handler_start (RsvgHandle *ctx, const xmlChar *name, newnode = rsvg_new_filter_primitive_turbulence(); else if (!strcmp ((char *)name, "feMergeNode")) newnode = rsvg_new_filter_primitive_merge_node(); - else if (!strcmp ((char *)name, "g")) - newnode = rsvg_new_group (); - else if (!strcmp ((char *)name, "a")) /*treat anchors as groups for now*/ - newnode = rsvg_new_group (); - else if (!strcmp ((char *)name, "switch")) - newnode = rsvg_new_switch (); - else if (!strcmp ((char *)name, "defs")) - newnode = rsvg_new_defs (); - else if (!strcmp ((char *)name, "use")) - newnode = rsvg_new_use (); - else if (!strcmp ((char *)name, "symbol")) - newnode = rsvg_new_symbol (); - else if (!strcmp ((char *)name, "svg")) - newnode = rsvg_new_svg (); - else if (!strcmp ((char *)name, "mask")) - newnode = rsvg_new_mask(); - else if (!strcmp ((char *)name, "clipPath")) - newnode = rsvg_new_clip_path(); - else if (!strcmp ((char *)name, "image")) - newnode = rsvg_new_image (); - else if (!strcmp ((char *)name, "marker")) - newnode = rsvg_new_marker (); + else if (!strcmp ((char *)name, "feFuncR")) + newnode = rsvg_new_node_component_transfer_function('r'); + else if (!strcmp ((char *)name, "feFuncG")) + newnode = rsvg_new_node_component_transfer_function('g'); + else if (!strcmp ((char *)name, "feFuncB")) + newnode = rsvg_new_node_component_transfer_function('b'); + else if (!strcmp ((char *)name, "feFuncA")) + newnode = rsvg_new_node_component_transfer_function('a'); else if (!strcmp ((char *)name, "feDistantLight")) newnode = rsvg_new_filter_primitive_light_source('d'); else if (!strcmp ((char *)name, "feSpotLight")) newnode = rsvg_new_filter_primitive_light_source('s'); else if (!strcmp ((char *)name, "fePointLight")) newnode = rsvg_new_filter_primitive_light_source('p'); - else if (!strcmp ((char *)name, "stop")) - newnode = rsvg_new_stop (); - else if (!strcmp ((char *)name, "pattern")) - newnode = rsvg_new_pattern (); - else if (!strcmp ((char *)name, "linearGradient")) - newnode = rsvg_new_linear_gradient (); - else if (!strcmp ((char *)name, "radialGradient")) - newnode = rsvg_new_radial_gradient (); - else if (!strcmp ((char *)name, "conicalGradient")) - newnode = rsvg_new_radial_gradient (); if (newnode) { rsvg_node_set_atts(newnode, ctx, atts); @@ -515,21 +539,7 @@ rsvg_start_element (void *data, const xmlChar *name, } else { - if (!strcmp ((char *)name, "path")) - rsvg_start_path (ctx, bag); - else if (!strcmp ((char *)name, "line")) - rsvg_start_line (ctx, bag); - else if (!strcmp ((char *)name, "rect")) - rsvg_start_rect (ctx, bag); - else if (!strcmp ((char *)name, "circle")) - rsvg_start_circle (ctx, bag); - else if (!strcmp ((char *)name, "ellipse")) - rsvg_start_ellipse (ctx, bag); - else if (!strcmp ((char *)name, "polygon")) - rsvg_start_polygon (ctx, bag); - else if (!strcmp ((char *)name, "polyline")) - rsvg_start_polyline (ctx, bag); - else if (!strcmp ((char *)name, "text")) + if (!strcmp ((char *)name, "text")) rsvg_start_text (ctx, bag); else if (!strcmp ((char *)name, "style")) rsvg_start_style (ctx, bag); @@ -539,14 +549,6 @@ rsvg_start_element (void *data, const xmlChar *name, rsvg_start_desc (ctx, bag); else if (!strcmp ((char *)name, "metadata")) rsvg_start_metadata (ctx, bag); - else if (!strcmp ((char *)name, "feFuncR")) - rsvg_start_filter_primitive_component_transfer_function(ctx, bag, 'r'); - else if (!strcmp ((char *)name, "feFuncG")) - rsvg_start_filter_primitive_component_transfer_function(ctx, bag, 'g'); - else if (!strcmp ((char *)name, "feFuncB")) - rsvg_start_filter_primitive_component_transfer_function(ctx, bag, 'b'); - else if (!strcmp ((char *)name, "feFuncA")) - rsvg_start_filter_primitive_component_transfer_function(ctx, bag, 'a'); rsvg_filter_handler_start (ctx, name, bag); } @@ -590,18 +592,24 @@ rsvg_end_element (void *data, const xmlChar *name) !strcmp ((char *)name, "symbol") || !strcmp ((char *)name, "svg") || !strcmp ((char *)name, "a") || + !strcmp ((char *)name, "line") || + !strcmp ((char *)name, "rect") || + !strcmp ((char *)name, "circle") || + !strcmp ((char *)name, "ellipse") || + !strcmp ((char *)name, "polyline") || + !strcmp ((char *)name, "polygon") || + !strcmp ((char *)name, "path") || !strcmp ((char *)name, "g") || !strcmp ((char *)name, "pattern") || !strcmp ((char *)name, "linearGradient") || !strcmp ((char *)name, "radialGradient") || !strcmp ((char *)name, "conicalGradient") || - !strcmp ((char *)name, "stop")) + !strcmp ((char *)name, "stop") || + !strncmp ((char *)name, "fe", 2)) { + /*when type enums are working right we should test if the end is the same as the current node*/ rsvg_pop_def_group(ctx); } - else if (!strncmp ((char *)name, "fe", 2) && - strncmp ((char *)name, "feFunc", 6)) - rsvg_pop_def_group(ctx); } } |