More honesty about bug 144394, it's not quite fixed yet.
[dia.git] / lib / diasvgrenderer.c
blobb210620f0c03f1870f8c51ac50a7ca71a86e48f0
1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1998 Alexander Larsson
4 * render_svg.c - an SVG renderer for dia, based on render_eps.c
5 * Copyright (C) 1999, 2000 James Henstridge
7 * diasvgrenderer.c - refactoring of the above to serve as the
8 * base class for plug-ins/svg/render_svg.c and
9 * plug-ins/shape/shape-export.c
10 * Copyright (C) 2002, Hans Breuer
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 #include <config.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <time.h>
32 #include <math.h>
33 #include <glib.h>
34 #ifdef HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
38 #include <libxml/entities.h>
39 #include <libxml/tree.h>
40 #include <libxml/xmlmemory.h>
42 #include "geometry.h"
43 #include "intl.h"
44 #include "message.h"
45 #include "dia_xml_libxml.h"
46 #include "dia_image.h"
48 #include "diasvgrenderer.h"
49 #include "textline.h"
51 #define DTOSTR_BUF_SIZE G_ASCII_DTOSTR_BUF_SIZE
52 #define dia_svg_dtostr(buf,d) \
53 g_ascii_formatd(buf,sizeof(buf),"%g",d)
55 /* DiaSvgRenderer methods */
56 static void
57 begin_render(DiaRenderer *self)
59 DiaSvgRenderer *renderer = DIA_SVG_RENDERER (self);
61 renderer->linewidth = 0;
62 renderer->linecap = "butt";
63 renderer->linejoin = "miter";
64 renderer->linestyle = NULL;
67 static void
68 end_render(DiaRenderer *self)
70 DiaSvgRenderer *renderer = DIA_SVG_RENDERER (self);
71 g_free(renderer->linestyle);
73 xmlSetDocCompressMode(renderer->doc, 0);
74 xmlDiaSaveFile(renderer->filename, renderer->doc);
75 g_free(renderer->filename);
76 xmlFreeDoc(renderer->doc);
79 static void
80 set_linewidth(DiaRenderer *self, real linewidth)
81 { /* 0 == hairline **/
82 DiaSvgRenderer *renderer = DIA_SVG_RENDERER (self);
84 if (linewidth == 0)
85 renderer->linewidth = 0.001;
86 else
87 renderer->linewidth = linewidth;
90 static void
91 set_linecaps(DiaRenderer *self, LineCaps mode)
93 DiaSvgRenderer *renderer = DIA_SVG_RENDERER (self);
95 switch(mode) {
96 case LINECAPS_BUTT:
97 renderer->linecap = "butt";
98 break;
99 case LINECAPS_ROUND:
100 renderer->linecap = "round";
101 break;
102 case LINECAPS_PROJECTING:
103 renderer->linecap = "square";
104 break;
105 default:
106 renderer->linecap = "butt";
110 static void
111 set_linejoin(DiaRenderer *self, LineJoin mode)
113 DiaSvgRenderer *renderer = DIA_SVG_RENDERER (self);
115 switch(mode) {
116 case LINEJOIN_MITER:
117 renderer->linejoin = "miter";
118 break;
119 case LINEJOIN_ROUND:
120 renderer->linejoin = "round";
121 break;
122 case LINEJOIN_BEVEL:
123 renderer->linejoin = "bevel";
124 break;
125 default:
126 renderer->linejoin = "miter";
130 static void
131 set_linestyle(DiaRenderer *self, LineStyle mode)
133 DiaSvgRenderer *renderer = DIA_SVG_RENDERER (self);
134 real hole_width;
135 gchar dash_length_buf[DTOSTR_BUF_SIZE];
136 gchar dot_length_buf[DTOSTR_BUF_SIZE];
137 gchar hole_width_buf[DTOSTR_BUF_SIZE];
139 renderer->saved_line_style = mode;
141 g_free(renderer->linestyle);
142 switch(mode) {
143 case LINESTYLE_SOLID:
144 renderer->linestyle = NULL;
145 break;
146 case LINESTYLE_DASHED:
147 dia_svg_dtostr(dash_length_buf, renderer->dash_length);
148 renderer->linestyle = g_strdup_printf("%s", dash_length_buf);
149 break;
150 case LINESTYLE_DASH_DOT:
151 hole_width = (renderer->dash_length - renderer->dot_length) / 2.0;
153 dia_svg_dtostr(dash_length_buf, renderer->dash_length);
154 dia_svg_dtostr(dot_length_buf, renderer->dot_length);
155 dia_svg_dtostr(hole_width_buf, hole_width);
157 renderer->linestyle = g_strdup_printf("%s %s %s %s",
158 dash_length_buf,
159 hole_width_buf,
160 dot_length_buf,
161 hole_width_buf );
162 break;
163 case LINESTYLE_DASH_DOT_DOT:
164 hole_width = (renderer->dash_length - 2.0*renderer->dot_length) / 3.0;
166 dia_svg_dtostr(dash_length_buf, renderer->dash_length);
167 dia_svg_dtostr(dot_length_buf, renderer->dot_length);
168 dia_svg_dtostr(hole_width_buf, hole_width);
170 renderer->linestyle = g_strdup_printf("%s %s %s %s %s %s",
171 dash_length_buf,
172 hole_width_buf,
173 dot_length_buf,
174 hole_width_buf,
175 dot_length_buf,
176 hole_width_buf );
177 break;
178 case LINESTYLE_DOTTED:
180 dia_svg_dtostr(dot_length_buf, renderer->dot_length);
182 renderer->linestyle = g_strdup_printf("%s", dot_length_buf);
183 break;
184 default:
185 renderer->linestyle = NULL;
189 static void
190 set_dashlength(DiaRenderer *self, real length)
191 { /* dot = 20% of len */
192 DiaSvgRenderer *renderer = DIA_SVG_RENDERER (self);
194 if (length<0.001)
195 length = 0.001;
197 renderer->dash_length = length;
198 renderer->dot_length = length*0.2;
200 set_linestyle(self, renderer->saved_line_style);
203 static void
204 set_fillstyle(DiaRenderer *self, FillStyle mode)
206 switch(mode) {
207 case FILLSTYLE_SOLID:
208 break;
209 default:
210 message_error("svg_renderer: Unsupported fill mode specified!\n");
214 /* the return value of this function should not be saved anywhere */
215 static const gchar *
216 get_draw_style(DiaSvgRenderer *renderer,
217 Color *colour)
219 static GString *str = NULL;
220 gchar linewidth_buf[DTOSTR_BUF_SIZE];
222 if (!str) str = g_string_new(NULL);
223 g_string_truncate(str, 0);
225 /* TODO(CHECK): the shape-export didn't have 'fill: none' here */
226 g_string_sprintf(str, "fill: none; fill-opacity:0; stroke-width: %s", dia_svg_dtostr(linewidth_buf, renderer->linewidth) );
227 if (strcmp(renderer->linecap, "butt"))
228 g_string_sprintfa(str, "; stroke-linecap: %s", renderer->linecap);
229 if (strcmp(renderer->linejoin, "miter"))
230 g_string_sprintfa(str, "; stroke-linejoin: %s", renderer->linejoin);
231 if (renderer->linestyle)
232 g_string_sprintfa(str, "; stroke-dasharray: %s", renderer->linestyle);
234 if (colour)
235 g_string_sprintfa(str, "; stroke: #%02x%02x%02x",
236 (int)ceil(255*colour->red), (int)ceil(255*colour->green),
237 (int)ceil(255*colour->blue));
239 return str->str;
242 /* the return value of this function should not be saved anywhere */
243 static const gchar *
244 get_fill_style(DiaSvgRenderer *renderer,
245 Color *colour)
247 static GString *str = NULL;
249 if (!str) str = g_string_new(NULL);
251 g_string_sprintf(str, "fill: #%02x%02x%02x",
252 (int)ceil(255*colour->red), (int)ceil(255*colour->green),
253 (int)ceil(255*colour->blue));
255 return str->str;
258 static void
259 draw_line(DiaRenderer *self,
260 Point *start, Point *end,
261 Color *line_colour)
263 DiaSvgRenderer *renderer = DIA_SVG_RENDERER (self);
264 xmlNodePtr node;
265 gchar d_buf[DTOSTR_BUF_SIZE];
267 node = xmlNewChild(renderer->root, renderer->svg_name_space, "line", NULL);
269 xmlSetProp(node, "style", get_draw_style(renderer, line_colour));
271 dia_svg_dtostr(d_buf, start->x);
272 xmlSetProp(node, "x1", d_buf);
273 dia_svg_dtostr(d_buf, start->y);
274 xmlSetProp(node, "y1", d_buf);
275 dia_svg_dtostr(d_buf, end->x);
276 xmlSetProp(node, "x2", d_buf);
277 dia_svg_dtostr(d_buf, end->y);
278 xmlSetProp(node, "y2", d_buf);
281 static void
282 draw_polyline(DiaRenderer *self,
283 Point *points, int num_points,
284 Color *line_colour)
286 DiaSvgRenderer *renderer = DIA_SVG_RENDERER (self);
287 int i;
288 xmlNodePtr node;
289 GString *str;
290 gchar px_buf[DTOSTR_BUF_SIZE];
291 gchar py_buf[DTOSTR_BUF_SIZE];
293 node = xmlNewChild(renderer->root, renderer->svg_name_space, "polyline", NULL);
295 xmlSetProp(node, "style", get_draw_style(renderer, line_colour));
297 str = g_string_new(NULL);
298 for (i = 0; i < num_points; i++)
299 g_string_sprintfa(str, "%s,%s ",
300 dia_svg_dtostr(px_buf, points[i].x),
301 dia_svg_dtostr(py_buf, points[i].y) );
302 xmlSetProp(node, "points", str->str);
303 g_string_free(str, TRUE);
306 static void
307 draw_polygon(DiaRenderer *self,
308 Point *points, int num_points,
309 Color *line_colour)
311 DiaSvgRenderer *renderer = DIA_SVG_RENDERER (self);
312 int i;
313 xmlNodePtr node;
314 GString *str;
315 gchar px_buf[DTOSTR_BUF_SIZE];
316 gchar py_buf[DTOSTR_BUF_SIZE];
318 node = xmlNewChild(renderer->root, renderer->svg_name_space, "polygon", NULL);
320 xmlSetProp(node, "style", get_draw_style(renderer, line_colour));
322 str = g_string_new(NULL);
323 for (i = 0; i < num_points; i++)
324 g_string_sprintfa(str, "%s,%s ",
325 dia_svg_dtostr(px_buf, points[i].x),
326 dia_svg_dtostr(py_buf, points[i].y) );
327 xmlSetProp(node, "points", str->str);
328 g_string_free(str, TRUE);
331 static void
332 fill_polygon(DiaRenderer *self,
333 Point *points, int num_points,
334 Color *colour)
336 DiaSvgRenderer *renderer = DIA_SVG_RENDERER (self);
337 int i;
338 xmlNodePtr node;
339 GString *str;
340 gchar px_buf[DTOSTR_BUF_SIZE];
341 gchar py_buf[DTOSTR_BUF_SIZE];
343 node = xmlNewChild(renderer->root, renderer->svg_name_space, "polygon", NULL);
345 xmlSetProp(node, "style", get_fill_style(renderer, colour));
347 str = g_string_new(NULL);
348 for (i = 0; i < num_points; i++)
349 g_string_sprintfa(str, "%s,%s ",
350 dia_svg_dtostr(px_buf, points[i].x),
351 dia_svg_dtostr(py_buf, points[i].y) );
352 xmlSetProp(node, "points", str->str);
353 g_string_free(str, TRUE);
356 static void
357 draw_rect(DiaRenderer *self,
358 Point *ul_corner, Point *lr_corner,
359 Color *colour)
361 DiaSvgRenderer *renderer = DIA_SVG_RENDERER (self);
362 xmlNodePtr node;
363 gchar d_buf[DTOSTR_BUF_SIZE];
365 node = xmlNewChild(renderer->root, NULL, "rect", NULL);
367 xmlSetProp(node, "style", get_draw_style(renderer, colour));
369 dia_svg_dtostr(d_buf, ul_corner->x);
370 xmlSetProp(node, "x", d_buf);
371 dia_svg_dtostr(d_buf, ul_corner->y);
372 xmlSetProp(node, "y", d_buf);
373 dia_svg_dtostr(d_buf, lr_corner->x - ul_corner->x);
374 xmlSetProp(node, "width", d_buf);
375 dia_svg_dtostr(d_buf, lr_corner->y - ul_corner->y);
376 xmlSetProp(node, "height", d_buf);
379 static void
380 fill_rect(DiaRenderer *self,
381 Point *ul_corner, Point *lr_corner,
382 Color *colour)
384 DiaSvgRenderer *renderer = DIA_SVG_RENDERER (self);
385 xmlNodePtr node;
386 gchar d_buf[DTOSTR_BUF_SIZE];
388 node = xmlNewChild(renderer->root, renderer->svg_name_space, "rect", NULL);
390 xmlSetProp(node, "style", get_fill_style(renderer, colour));
392 dia_svg_dtostr(d_buf, ul_corner->x);
393 xmlSetProp(node, "x", d_buf);
394 dia_svg_dtostr(d_buf, ul_corner->y);
395 xmlSetProp(node, "y", d_buf);
396 dia_svg_dtostr(d_buf, lr_corner->x - ul_corner->x);
397 xmlSetProp(node, "width", d_buf);
398 dia_svg_dtostr(d_buf, lr_corner->y - ul_corner->y);
399 xmlSetProp(node, "height", d_buf);
402 static void
403 draw_arc(DiaRenderer *self,
404 Point *center,
405 real width, real height,
406 real angle1, real angle2,
407 Color *colour)
409 DiaSvgRenderer *renderer = DIA_SVG_RENDERER (self);
410 xmlNodePtr node;
411 char buf[512];
412 real rx = width / 2, ry = height / 2;
413 real sx=center->x + rx*cos(angle1*G_PI/180);
414 real sy=center->y - ry*sin(angle1*G_PI/180);
415 real ex=center->x + rx*cos(angle2*G_PI/180);
416 real ey=center->y - ry*sin(angle2*G_PI/180);
417 int swp = 0; /* always drawin negative direction */
418 int large_arc = (angle2 - angle1 >= 180);
419 gchar sx_buf[DTOSTR_BUF_SIZE];
420 gchar sy_buf[DTOSTR_BUF_SIZE];
421 gchar rx_buf[DTOSTR_BUF_SIZE];
422 gchar ry_buf[DTOSTR_BUF_SIZE];
423 gchar ex_buf[DTOSTR_BUF_SIZE];
424 gchar ey_buf[DTOSTR_BUF_SIZE];
426 node = xmlNewChild(renderer->root, renderer->svg_name_space, "path", NULL);
428 xmlSetProp(node, "style", get_draw_style(renderer, colour));
430 g_snprintf(buf, sizeof(buf), "M %s,%s A %s,%s 0 %d %d %s,%s",
431 dia_svg_dtostr(sx_buf, sx), dia_svg_dtostr(sy_buf, sy),
432 dia_svg_dtostr(rx_buf, rx), dia_svg_dtostr(ry_buf, ry),
433 large_arc, swp,
434 dia_svg_dtostr(ex_buf, ex), dia_svg_dtostr(ey_buf, ey) );
436 xmlSetProp(node, "d", buf);
439 static void
440 fill_arc(DiaRenderer *self,
441 Point *center,
442 real width, real height,
443 real angle1, real angle2,
444 Color *colour)
446 DiaSvgRenderer *renderer = DIA_SVG_RENDERER (self);
447 xmlNodePtr node;
448 char buf[512];
449 real rx = width / 2, ry = height / 2;
450 real sx=center->x + rx*cos(angle1*G_PI/180);
451 real sy=center->y - ry*sin(angle1*G_PI/180);
452 real ex=center->x + rx*cos(angle2*G_PI/180);
453 real ey=center->y - ry*sin(angle2*G_PI/180);
454 int swp = 0; /* always drawin negative direction */
455 int large_arc = (angle2 - angle1 >= 180);
456 gchar sx_buf[DTOSTR_BUF_SIZE];
457 gchar sy_buf[DTOSTR_BUF_SIZE];
458 gchar rx_buf[DTOSTR_BUF_SIZE];
459 gchar ry_buf[DTOSTR_BUF_SIZE];
460 gchar ex_buf[DTOSTR_BUF_SIZE];
461 gchar ey_buf[DTOSTR_BUF_SIZE];
462 gchar cx_buf[DTOSTR_BUF_SIZE];
463 gchar cy_buf[DTOSTR_BUF_SIZE];
465 node = xmlNewChild(renderer->root, NULL, "path", NULL);
467 xmlSetProp(node, "style", get_fill_style(renderer, colour));
469 g_snprintf(buf, sizeof(buf), "M %s,%s A %s,%s 0 %d %d %s,%s L %s,%s z",
470 dia_svg_dtostr(sx_buf, sx), dia_svg_dtostr(sy_buf, sy),
471 dia_svg_dtostr(rx_buf, rx), dia_svg_dtostr(ry_buf, ry),
472 large_arc, swp,
473 dia_svg_dtostr(ex_buf, ex), dia_svg_dtostr(ey_buf, ey),
474 dia_svg_dtostr(cx_buf, center->x),
475 dia_svg_dtostr(cy_buf, center->y) );
477 xmlSetProp(node, "d", buf);
480 static void
481 draw_ellipse(DiaRenderer *self,
482 Point *center,
483 real width, real height,
484 Color *colour)
486 DiaSvgRenderer *renderer = DIA_SVG_RENDERER (self);
487 xmlNodePtr node;
488 gchar d_buf[DTOSTR_BUF_SIZE];
490 node = xmlNewChild(renderer->root, renderer->svg_name_space, "ellipse", NULL);
492 xmlSetProp(node, "style", get_draw_style(renderer, colour));
494 dia_svg_dtostr(d_buf, center->x);
495 xmlSetProp(node, "cx", d_buf);
496 dia_svg_dtostr(d_buf, center->y);
497 xmlSetProp(node, "cy", d_buf);
498 dia_svg_dtostr(d_buf, width / 2);
499 xmlSetProp(node, "rx", d_buf);
500 dia_svg_dtostr(d_buf, height / 2);
501 xmlSetProp(node, "ry", d_buf);
504 static void
505 fill_ellipse(DiaRenderer *self,
506 Point *center,
507 real width, real height,
508 Color *colour)
510 DiaSvgRenderer *renderer = DIA_SVG_RENDERER (self);
511 xmlNodePtr node;
512 gchar d_buf[DTOSTR_BUF_SIZE];
514 node = xmlNewChild(renderer->root, renderer->svg_name_space, "ellipse", NULL);
516 xmlSetProp(node, "style", get_fill_style(renderer, colour));
518 dia_svg_dtostr(d_buf, center->x);
519 xmlSetProp(node, "cx", d_buf);
520 dia_svg_dtostr(d_buf, center->y);
521 xmlSetProp(node, "cy", d_buf);
522 dia_svg_dtostr(d_buf, width / 2);
523 xmlSetProp(node, "rx", d_buf);
524 dia_svg_dtostr(d_buf, height / 2);
525 xmlSetProp(node, "ry", d_buf);
528 static void
529 draw_bezier(DiaRenderer *self,
530 BezPoint *points,
531 int numpoints,
532 Color *colour)
534 DiaSvgRenderer *renderer = DIA_SVG_RENDERER (self);
535 int i;
536 xmlNodePtr node;
537 GString *str;
538 gchar p1x_buf[DTOSTR_BUF_SIZE];
539 gchar p1y_buf[DTOSTR_BUF_SIZE];
540 gchar p2x_buf[DTOSTR_BUF_SIZE];
541 gchar p2y_buf[DTOSTR_BUF_SIZE];
542 gchar p3x_buf[DTOSTR_BUF_SIZE];
543 gchar p3y_buf[DTOSTR_BUF_SIZE];
545 node = xmlNewChild(renderer->root, renderer->svg_name_space, "path", NULL);
547 xmlSetProp(node, "style", get_draw_style(renderer, colour));
549 str = g_string_new(NULL);
551 if (points[0].type != BEZ_MOVE_TO)
552 g_warning("first BezPoint must be a BEZ_MOVE_TO");
554 g_string_sprintf(str, "M %s %s",
555 dia_svg_dtostr(p1x_buf, (gdouble) points[0].p1.x),
556 dia_svg_dtostr(p1y_buf, (gdouble) points[0].p1.y) );
558 for (i = 1; i < numpoints; i++)
559 switch (points[i].type) {
560 case BEZ_MOVE_TO:
561 g_warning("only first BezPoint can be a BEZ_MOVE_TO");
562 break;
563 case BEZ_LINE_TO:
564 g_string_sprintfa(str, " L %s,%s",
565 dia_svg_dtostr(p1x_buf, (gdouble) points[i].p1.x),
566 dia_svg_dtostr(p1y_buf, (gdouble) points[i].p1.y) );
567 break;
568 case BEZ_CURVE_TO:
569 g_string_sprintfa(str, " C %s,%s %s,%s %s,%s",
570 dia_svg_dtostr(p1x_buf, (gdouble) points[i].p1.x),
571 dia_svg_dtostr(p1y_buf, (gdouble) points[i].p1.y),
572 dia_svg_dtostr(p2x_buf, (gdouble) points[i].p2.x),
573 dia_svg_dtostr(p2y_buf, (gdouble) points[i].p2.y),
574 dia_svg_dtostr(p3x_buf, (gdouble) points[i].p3.x),
575 dia_svg_dtostr(p3y_buf, (gdouble) points[i].p3.y) );
576 break;
578 xmlSetProp(node, "d", str->str);
579 g_string_free(str, TRUE);
582 static void
583 fill_bezier(DiaRenderer *self,
584 BezPoint *points, /* Last point must be same as first point */
585 int numpoints,
586 Color *colour)
588 DiaSvgRenderer *renderer = DIA_SVG_RENDERER (self);
589 int i;
590 xmlNodePtr node;
591 GString *str;
592 gchar p1x_buf[DTOSTR_BUF_SIZE];
593 gchar p1y_buf[DTOSTR_BUF_SIZE];
594 gchar p2x_buf[DTOSTR_BUF_SIZE];
595 gchar p2y_buf[DTOSTR_BUF_SIZE];
596 gchar p3x_buf[DTOSTR_BUF_SIZE];
597 gchar p3y_buf[DTOSTR_BUF_SIZE];
599 node = xmlNewChild(renderer->root, renderer->svg_name_space, "path", NULL);
601 xmlSetProp(node, "style", get_fill_style(renderer, colour));
603 str = g_string_new(NULL);
605 if (points[0].type != BEZ_MOVE_TO)
606 g_warning("first BezPoint must be a BEZ_MOVE_TO");
608 g_string_sprintf(str, "M %s %s",
609 dia_svg_dtostr(p1x_buf, (gdouble) points[0].p1.x),
610 dia_svg_dtostr(p1y_buf, (gdouble) points[0].p1.y) );
612 for (i = 1; i < numpoints; i++)
613 switch (points[i].type) {
614 case BEZ_MOVE_TO:
615 g_warning("only first BezPoint can be a BEZ_MOVE_TO");
616 break;
617 case BEZ_LINE_TO:
618 g_string_sprintfa(str, " L %s,%s",
619 dia_svg_dtostr(p1x_buf, (gdouble) points[i].p1.x),
620 dia_svg_dtostr(p1y_buf, (gdouble) points[i].p1.y) );
621 break;
622 case BEZ_CURVE_TO:
623 g_string_sprintfa(str, " C %s,%s %s,%s %s,%s",
624 dia_svg_dtostr(p1x_buf, (gdouble) points[i].p1.x),
625 dia_svg_dtostr(p1y_buf, (gdouble) points[i].p1.y),
626 dia_svg_dtostr(p2x_buf, (gdouble) points[i].p2.x),
627 dia_svg_dtostr(p2y_buf, (gdouble) points[i].p2.y),
628 dia_svg_dtostr(p3x_buf, (gdouble) points[i].p3.x),
629 dia_svg_dtostr(p3y_buf, (gdouble) points[i].p3.y) );
630 break;
632 g_string_append(str, "z");
633 xmlSetProp(node, "d", str->str);
634 g_string_free(str, TRUE);
637 static void
638 draw_string(DiaRenderer *self,
639 const char *text,
640 Point *pos, Alignment alignment,
641 Color *colour)
643 DiaSvgRenderer *renderer = DIA_SVG_RENDERER (self);
644 xmlNodePtr node;
645 char *style, *tmp;
646 real saved_width;
647 gchar d_buf[DTOSTR_BUF_SIZE];
649 node = xmlNewChild(renderer->root, renderer->svg_name_space, "text", text);
651 saved_width = renderer->linewidth;
652 renderer->linewidth = 0.001;
653 style = (char*)get_fill_style(renderer, colour);
654 /* return value must not be freed */
655 renderer->linewidth = saved_width;
656 /* This is going to break for non-LTR texts, as SVG thinks 'start' is
657 * 'right' for those.
659 switch (alignment) {
660 case ALIGN_LEFT:
661 style = g_strconcat(style, "; text-anchor:start", NULL);
662 break;
663 case ALIGN_CENTER:
664 style = g_strconcat(style, "; text-anchor:middle", NULL);
665 break;
666 case ALIGN_RIGHT:
667 style = g_strconcat(style, "; text-anchor:end", NULL);
668 break;
670 tmp = g_strdup_printf("%s; font-size: %s", style,
671 dia_svg_dtostr(d_buf, self->font_height) );
672 g_free (style);
673 style = tmp;
675 if (self->font) {
676 tmp = g_strdup_printf("%s; font-family: %s; font-style: %s; "
677 "font-weight: %s",style,
678 dia_font_get_family(self->font),
679 dia_font_get_slant_string(self->font),
680 dia_font_get_weight_string(self->font));
681 g_free(style);
682 style = tmp;
685 /* have to do something about fonts here ... */
687 xmlSetProp(node, "style", style);
688 g_free(style);
690 dia_svg_dtostr(d_buf, pos->x);
691 xmlSetProp(node, "x", d_buf);
692 dia_svg_dtostr(d_buf, pos->y);
693 xmlSetProp(node, "y", d_buf);
697 static void
698 draw_text_line(DiaRenderer *self, TextLine *text_line,
699 Point *pos, Color *colour)
701 DiaSvgRenderer *renderer = DIA_SVG_RENDERER (self);
702 xmlNodePtr node;
703 char *style, *tmp;
704 real saved_width;
705 gchar d_buf[DTOSTR_BUF_SIZE];
706 DiaFont *font;
708 node = xmlNewChild(renderer->root, renderer->svg_name_space, "text",
709 text_line_get_string(text_line));
711 saved_width = renderer->linewidth;
712 renderer->linewidth = 0.001;
713 style = (char*)get_fill_style(renderer, colour);
714 /* return value must not be freed */
715 renderer->linewidth = saved_width;
716 tmp = g_strdup_printf("%s; font-size: %s", style,
717 dia_svg_dtostr(d_buf, text_line_get_height(text_line)));
718 g_free (style);
719 style = tmp;
721 tmp = g_strdup_printf("%s; length: %s", style,
722 dia_svg_dtostr(d_buf, text_line_get_width(text_line)));
723 g_free (style);
724 style = tmp;
726 font = text_line_get_font(text_line);
727 tmp = g_strdup_printf("%s; font-family: %s; font-style: %s; "
728 "font-weight: %s",style,
729 dia_font_get_family(font),
730 dia_font_get_slant_string(font),
731 dia_font_get_weight_string(font));
732 g_free(style);
733 style = tmp;
735 /* have to do something about fonts here ... */
737 xmlSetProp(node, "style", style);
738 g_free(style);
740 dia_svg_dtostr(d_buf, pos->x);
741 xmlSetProp(node, "x", d_buf);
742 dia_svg_dtostr(d_buf, pos->y);
743 xmlSetProp(node, "y", d_buf);
746 static void
747 draw_image(DiaRenderer *self,
748 Point *point,
749 real width, real height,
750 DiaImage image)
752 DiaSvgRenderer *renderer = DIA_SVG_RENDERER (self);
753 xmlNodePtr node;
754 gchar d_buf[DTOSTR_BUF_SIZE];
756 node = xmlNewChild(renderer->root, NULL, "image", NULL);
758 dia_svg_dtostr(d_buf, point->x);
759 xmlSetProp(node, "x", d_buf);
760 dia_svg_dtostr(d_buf, point->y);
761 xmlSetProp(node, "y", d_buf);
762 dia_svg_dtostr(d_buf, width);
763 xmlSetProp(node, "width", d_buf);
764 dia_svg_dtostr(d_buf, height);
765 xmlSetProp(node, "height", d_buf);
766 xmlSetProp(node, "xlink:href", dia_image_filename(image));
769 /* constructor */
770 static void
771 dia_svg_renderer_init (GTypeInstance *instance, gpointer g_class)
775 static gpointer parent_class = NULL;
777 /* destructor */
778 static void
779 dia_svg_renderer_finalize (GObject *object)
781 G_OBJECT_CLASS (parent_class)->finalize (object);
784 /* gobject boiler plate, vtable initialization */
785 static void dia_svg_renderer_class_init (DiaSvgRendererClass *klass);
787 GType
788 dia_svg_renderer_get_type (void)
790 static GType object_type = 0;
792 if (!object_type)
794 static const GTypeInfo object_info =
796 sizeof (DiaSvgRendererClass),
797 (GBaseInitFunc) NULL,
798 (GBaseFinalizeFunc) NULL,
799 (GClassInitFunc) dia_svg_renderer_class_init,
800 NULL, /* class_finalize */
801 NULL, /* class_data */
802 sizeof (DiaSvgRenderer),
803 0, /* n_preallocs */
804 dia_svg_renderer_init /* init */
807 object_type = g_type_register_static (DIA_TYPE_RENDERER,
808 "DiaSvgRenderer",
809 &object_info, 0);
812 return object_type;
815 static void
816 dia_svg_renderer_class_init (DiaSvgRendererClass *klass)
818 GObjectClass *object_class = G_OBJECT_CLASS (klass);
819 DiaRendererClass *renderer_class = DIA_RENDERER_CLASS (klass);
820 DiaSvgRendererClass *svg_renderer_class = DIA_SVG_RENDERER_CLASS (klass);
822 parent_class = g_type_class_peek_parent (klass);
824 object_class->finalize = dia_svg_renderer_finalize;
826 /* renderer members */
827 renderer_class->begin_render = begin_render;
828 renderer_class->end_render = end_render;
830 renderer_class->set_linewidth = set_linewidth;
831 renderer_class->set_linecaps = set_linecaps;
832 renderer_class->set_linejoin = set_linejoin;
833 renderer_class->set_linestyle = set_linestyle;
834 renderer_class->set_dashlength = set_dashlength;
835 renderer_class->set_fillstyle = set_fillstyle;
837 renderer_class->draw_line = draw_line;
838 renderer_class->fill_polygon = fill_polygon;
839 renderer_class->draw_rect = draw_rect;
840 renderer_class->fill_rect = fill_rect;
841 renderer_class->draw_arc = draw_arc;
842 renderer_class->fill_arc = fill_arc;
843 renderer_class->draw_ellipse = draw_ellipse;
844 renderer_class->fill_ellipse = fill_ellipse;
846 renderer_class->draw_string = draw_string;
847 renderer_class->draw_image = draw_image;
849 /* medium level functions */
850 renderer_class->draw_rect = draw_rect;
851 renderer_class->draw_polyline = draw_polyline;
852 renderer_class->draw_polygon = draw_polygon;
854 renderer_class->draw_bezier = draw_bezier;
855 renderer_class->fill_bezier = fill_bezier;
856 /* renderer_class->draw_text_line = draw_text_line;*/
858 /* svg specific */
859 svg_renderer_class->get_draw_style = get_draw_style;
860 svg_renderer_class->get_fill_style = get_fill_style;