1 /* -*- Mode: C; c-basic-offset: 4 -*- */
2 /* Dia -- a diagram creation/manipulation program
3  * Copyright (C) 1998 Alexander Larsson
4  *
5  * vdx-export.c: Visio XML export filter for dia
6  * Copyright (C) 2006-2007 Ian Redfern
7  * based on the xfig filter code
8  * Copyright (C) 2001 Lars Clausen
9  * based on the dxf filter code
10  * Copyright (C) 2000 James Henstridge, Steffen Macke
11  *
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.
16  *
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.
21  *
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.
25  */
26 
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
30 
31 #include <stdio.h>
32 
33 #include <string.h>
34 #include <math.h>
35 #include <glib.h>
36 #include <stdlib.h>
37 #include <errno.h>
38 #include <locale.h>
39 #include <glib/gstdio.h>
40 
41 #include "intl.h"
42 #include "message.h"
43 #include "geometry.h"
44 #include "diarenderer.h"
45 #include "filter.h"
46 #include "object.h"
47 #include "properties.h"
48 #include "dia_image.h"
49 #include "group.h"
50 
51 #include "vdx.h"
52 #include "visio-types.h"
53 
54 /* Following code taken from xfig-export.c */
55 
56 #define VDX_TYPE_RENDERER           (vdx_renderer_get_type ())
57 #define VDX_RENDERER(obj)           (G_TYPE_CHECK_INSTANCE_CAST ((obj), VDX_TYPE_RENDERER, VDXRenderer))
58 #define VDX_RENDERER_CLASS(klass)   (G_TYPE_CHECK_CLASS_CAST ((klass), VDX_TYPE_RENDERER, VDXRendererClass))
59 #define VDX_IS_RENDERER(obj)        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VDX_TYPE_RENDERER))
60 #define VDX_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), VDX_TYPE_RENDERER, VDXRendererClass))
61 
62 GType vdx_renderer_get_type (void) G_GNUC_CONST;
63 
64 typedef struct _VDXRenderer VDXRenderer;
65 typedef struct _VDXRendererClass VDXRendererClass;
66 
67 struct _VDXRendererClass
68 {
69     DiaRendererClass parent_class;
70 };
71 
72 struct _VDXRenderer
73 {
74     DiaRenderer parent_instance;
75 
76     FILE *file;
77 
78     int depth;
79 
80     real linewidth;
81     LineCaps capsmode;
82     LineJoin joinmode;
83     LineStyle stylemode;
84     real dashlength;
85     FillStyle fillmode;
86     DiaFont *font;
87     real fontheight;
88 
89     /* Additions for VDX */
90 
91     gboolean first_pass;        /* When we make table of colours and fonts */
92     GArray *Colors;             /* Table of colours */
93     GArray *Fonts;              /* Table of fonts */
94     unsigned int shapeid;       /* Shape counter */
95     unsigned int version;       /* Visio version */
96     unsigned int xml_depth;     /* Pretty-printer */
97 };
98 
99 
100 static void begin_render(DiaRenderer *self);
101 static void end_render(DiaRenderer *renderer);
102 static void set_linewidth(DiaRenderer *self, real linewidth);
103 static void set_linecaps(DiaRenderer *self, LineCaps mode);
104 static void set_linejoin(DiaRenderer *self, LineJoin mode);
105 static void set_linestyle(DiaRenderer *self, LineStyle mode);
106 static void set_dashlength(DiaRenderer *self, real length);
107 static void set_fillstyle(DiaRenderer *self, FillStyle mode);
108 static void set_font(DiaRenderer *self, DiaFont *font, real height);
109 static void draw_line(DiaRenderer *self,
110 		      Point *start, Point *end,
111 		      Color *color);
112 static void draw_polyline(DiaRenderer *self,
113 			  Point *points, int num_points,
114 			  Color *color);
115 static void draw_polygon(DiaRenderer *self,
116 			 Point *points, int num_points,
117 			 Color *color);
118 static void fill_polygon(DiaRenderer *self,
119 			 Point *points, int num_points,
120 			 Color *color);
121 static void draw_rect(DiaRenderer *self,
122 		      Point *ul_corner, Point *lr_corner,
123 		      Color *color);
124 static void fill_rect(DiaRenderer *self,
125 		      Point *ul_corner, Point *lr_corner,
126 		      Color *color);
127 static void draw_arc(DiaRenderer *self,
128 		     Point *center,
129 		     real width, real height,
130 		     real angle1, real angle2,
131 		     Color *color);
132 static void fill_arc(DiaRenderer *self,
133 		     Point *center,
134 		     real width, real height,
135 		     real angle1, real angle2,
136 		     Color *color);
137 static void draw_ellipse(DiaRenderer *self,
138 			 Point *center,
139 			 real width, real height,
140 			 Color *color);
141 static void fill_ellipse(DiaRenderer *self,
142 			 Point *center,
143 			 real width, real height,
144 			 Color *color);
145 static void draw_string(DiaRenderer *self,
146 			const char *text,
147 			Point *pos, Alignment alignment,
148 			Color *color);
149 static void draw_image(DiaRenderer *self,
150 		       Point *point,
151 		       real width, real height,
152 		       DiaImage *image);
153 
154 static void vdx_renderer_class_init (VDXRendererClass *klass);
155 
156 static void
157 export_vdx(DiagramData *data, const gchar *filename,
158            const gchar *diafilename, void* user_data);
159 
160 static int
161 vdxCheckColor(VDXRenderer *renderer, Color *color);
162 
163 static gpointer parent_class = NULL;
164 
165 
166 /** Renderer type handler
167  * @returns renderer type
168  */
169 
170 GType
vdx_renderer_get_type(void)171 vdx_renderer_get_type (void)
172 {
173   static GType object_type = 0;
174 
175   if (!object_type)
176     {
177       static const GTypeInfo object_info =
178       {
179         sizeof (VDXRendererClass),
180         (GBaseInitFunc) NULL,
181         (GBaseFinalizeFunc) NULL,
182         (GClassInitFunc) vdx_renderer_class_init,
183         NULL,           /* class_finalize */
184         NULL,           /* class_data */
185         sizeof (VDXRenderer),
186         0,              /* n_preallocs */
187 	NULL            /* init */
188       };
189 
190       object_type = g_type_register_static (DIA_TYPE_RENDERER,
191                                             "VDXRenderer",
192                                             &object_info, 0);
193     }
194 
195   return object_type;
196 }
197 
198 /** Finalise a renderer
199  * @param object a renderer
200  */
201 
202 static void
vdx_renderer_finalize(GObject * object)203 vdx_renderer_finalize (GObject *object)
204 {
205   G_OBJECT_CLASS (parent_class)->finalize (object);
206 }
207 
208 /** Class constructor for renderer
209  * @param klass a renderer
210  */
211 
212 static void
vdx_renderer_class_init(VDXRendererClass * klass)213 vdx_renderer_class_init (VDXRendererClass *klass)
214 {
215   GObjectClass *object_class = G_OBJECT_CLASS (klass);
216   DiaRendererClass *renderer_class = DIA_RENDERER_CLASS (klass);
217 
218   parent_class = g_type_class_peek_parent (klass);
219 
220   object_class->finalize = vdx_renderer_finalize;
221 
222   renderer_class->begin_render = begin_render;
223   renderer_class->end_render = end_render;
224 
225   renderer_class->set_linewidth = set_linewidth;
226   renderer_class->set_linecaps = set_linecaps;
227   renderer_class->set_linejoin = set_linejoin;
228   renderer_class->set_linestyle = set_linestyle;
229   renderer_class->set_dashlength = set_dashlength;
230   renderer_class->set_fillstyle = set_fillstyle;
231   renderer_class->set_font = set_font;
232 
233   renderer_class->draw_line = draw_line;
234   renderer_class->draw_polyline = draw_polyline;
235 
236   renderer_class->draw_polygon = draw_polygon;
237   renderer_class->fill_polygon = fill_polygon;
238 
239   renderer_class->draw_rect = draw_rect;
240   renderer_class->fill_rect = fill_rect;
241 
242   renderer_class->draw_arc = draw_arc;
243   renderer_class->fill_arc = fill_arc;
244 
245   renderer_class->draw_ellipse = draw_ellipse;
246   renderer_class->fill_ellipse = fill_ellipse;
247 
248   /* Until we have NURBS, let Dia use lines */
249   /* renderer_class->draw_bezier = draw_bezier; */
250   /* renderer_class->fill_bezier = fill_bezier; */
251   /* renderer_class->draw_bezier_with_arrows = draw_bezier_with_arrows; */
252 
253   renderer_class->draw_string = draw_string;
254 
255   renderer_class->draw_image = draw_image;
256 
257   /* Believe these are never used or are unnecessary */
258   /* renderer_class->draw_line_with_arrows = draw_line_with_arrows; */
259   /* renderer_class->draw_polyline_with_arrows = draw_polyline_with_arrows; */
260   /* renderer_class->draw_arc_with_arrows = draw_arc_with_arrows; */
261   /* renderer_class->draw_object = draw_object; */
262 
263 }
264 
265 /** Initialises VDXrenderer
266  * @param self a renderer
267  */
268 
269 static void
begin_render(DiaRenderer * self)270 begin_render(DiaRenderer *self)
271 {
272     VDXRenderer *renderer = VDX_RENDERER(self);
273     Color c;
274 
275     renderer->depth = 0;
276 
277     renderer->linewidth = 0;
278     renderer->capsmode = 0;
279     renderer->joinmode = 0;
280     renderer->stylemode = 0;
281     renderer->dashlength = 0;
282     renderer->fillmode = 0;
283     renderer->font = NULL;
284     renderer->fontheight = 1;
285 
286     /* Specific to VDX */
287 
288     renderer->Colors = g_array_new(FALSE, TRUE, sizeof (Color));
289     renderer->Fonts = g_array_new(FALSE, TRUE, sizeof (char *));
290     renderer->shapeid = 0;
291     /* renderer->version = 0; */
292 
293     /* Black and white are 0 and 1 respectively */
294     c.red = 0.0; c.green = 0.0; c.blue = 0.0;
295     vdxCheckColor(renderer, &c);
296     c.red = 1.0; c.green = 1.0; c.blue = 1.0;
297     vdxCheckColor(renderer, &c);
298 }
299 
300 /** Destructor for renderer
301  * @param self a renderer
302  */
303 
304 static void
end_render(DiaRenderer * self)305 end_render(DiaRenderer *self)
306 {
307     VDXRenderer *renderer = VDX_RENDERER(self);
308 
309     /* Specific to VDX */
310     g_array_free(renderer->Colors, TRUE);
311     g_array_free(renderer->Fonts, TRUE);
312 }
313 
314 /** Convert a Dia point to a Visio one
315  * @param p a Dia-space point
316  * @returns a Visio-space point
317  */
318 
319 static Point
visio_point(Point p)320 visio_point(Point p)
321 {
322     Point q;
323     q.x = p.x/vdx_Point_Scale;
324     q.y = (p.y - vdx_Y_Offset)/vdx_Y_Flip/vdx_Point_Scale;
325     return q;
326 }
327 
328 /** Convert a Dia absolute length to a Visio one
329  * @param length a length
330  * @returns length in Visio space
331  */
332 
333 static double
visio_length(double length)334 visio_length(double length)
335 {
336     return length/vdx_Point_Scale;
337 }
338 
339 /** Set line width
340  * @param self a renderer
341  * @param linewidth new line width
342  */
343 
344 static void
set_linewidth(DiaRenderer * self,real linewidth)345 set_linewidth(DiaRenderer *self, real linewidth)
346 {
347   VDXRenderer *renderer = VDX_RENDERER(self);
348 
349   renderer->linewidth = linewidth;
350 }
351 
352 /** Set line caps
353  * @param self a renderer
354  * @param mode new line caps
355  */
356 
357 static void
set_linecaps(DiaRenderer * self,LineCaps mode)358 set_linecaps(DiaRenderer *self, LineCaps mode)
359 {
360   VDXRenderer *renderer = VDX_RENDERER(self);
361 
362   renderer->capsmode = mode;
363 }
364 
365 /** Set line join
366  * @param self a renderer
367  * @param mode new line join
368  */
369 
370 static void
set_linejoin(DiaRenderer * self,LineJoin mode)371 set_linejoin(DiaRenderer *self, LineJoin mode)
372 {
373   VDXRenderer *renderer = VDX_RENDERER(self);
374 
375   renderer->joinmode = mode;
376 }
377 
378 /** Set line style
379  * @param self a renderer
380  * @param mode new line style
381  */
382 
383 static void
set_linestyle(DiaRenderer * self,LineStyle mode)384 set_linestyle(DiaRenderer *self, LineStyle mode)
385 {
386   VDXRenderer *renderer = VDX_RENDERER(self);
387 
388   renderer->stylemode = mode;
389 }
390 
391 /** Set dash length
392  * @param self a renderer
393  * @param mode new dash length
394  */
395 
396 static void
set_dashlength(DiaRenderer * self,real length)397 set_dashlength(DiaRenderer *self, real length)
398 {
399   VDXRenderer *renderer = VDX_RENDERER(self);
400 
401   renderer->dashlength = length;
402 }
403 
404 /** Set fill style
405  * @param self a renderer
406  * @param mode new file style
407  */
408 
409 static void
set_fillstyle(DiaRenderer * self,FillStyle mode)410 set_fillstyle(DiaRenderer *self, FillStyle mode)
411 {
412   VDXRenderer *renderer = VDX_RENDERER(self);
413 
414   renderer->fillmode = mode;
415 }
416 
417 /** Set font
418  * @param self a renderer
419  * @param font new font
420  * @param height new font height
421  */
422 
423 static void
set_font(DiaRenderer * self,DiaFont * font,real height)424 set_font(DiaRenderer *self, DiaFont *font, real height)
425 {
426   VDXRenderer *renderer = VDX_RENDERER(self);
427 
428   renderer->font = font;
429   renderer->fontheight = height;
430 }
431 
432 /** Get colour number from colour table
433  * @param renderer a renderer
434  * @param color the colour
435  * @returns a colour index (black=0)
436  */
437 
438 static int
vdxCheckColor(VDXRenderer * renderer,Color * color)439 vdxCheckColor(VDXRenderer *renderer, Color *color)
440 {
441     int i;
442 
443     Color cmp_color;
444     for (i = 0; i < renderer->Colors->len; i++)
445     {
446         cmp_color = g_array_index(renderer->Colors, Color, i);
447         if (color_equals(color, &cmp_color)) return i;
448     }
449     /* Grow table */
450     g_array_append_val(renderer->Colors, *color);
451     return renderer->Colors->len;
452 }
453 
454 /** Get font number from font table
455  * @param renderer a renderer
456  * @returns a font index (from 0)
457  */
458 
459 static int
vdxCheckFont(VDXRenderer * renderer)460 vdxCheckFont(VDXRenderer *renderer)
461 {
462     int i;
463 
464     const char *cmp_font;
465     const char *font = dia_font_get_legacy_name(renderer->font);
466     for (i = 0; i < renderer->Fonts->len; i++)
467     {
468         cmp_font = g_array_index(renderer->Fonts, char *, i);
469         if (!strcmp(cmp_font, font)) return i;
470     }
471     /* Grow table */
472     g_array_append_val(renderer->Fonts, font);
473     return renderer->Fonts->len;
474 }
475 
476 /** Create a Visio line style object
477  * @param self a VDXRenderer
478  * @param color a colour
479  * @param Line a Line object
480  * @param start_arrow optional start arrow
481  * @param end_arrow optional end arrow
482  * @todo join, caps, dashlength
483  */
484 
485 static void
create_Line(VDXRenderer * renderer,Color * color,struct vdx_Line * Line,Arrow * start_arrow,Arrow * end_arrow)486 create_Line(VDXRenderer *renderer, Color *color, struct vdx_Line *Line,
487             Arrow *start_arrow, Arrow *end_arrow)
488 {
489     /* A Line (colour etc) */
490     memset(Line, 0, sizeof(*Line));
491     Line->type = vdx_types_Line;
492     switch (renderer->stylemode)
493     {
494     case LINESTYLE_DASHED:
495         Line->LinePattern = 2;
496         break;
497     case LINESTYLE_DOTTED:
498         Line->LinePattern = 3;
499         break;
500     case LINESTYLE_DASH_DOT:
501         Line->LinePattern = 4;
502         break;
503     case LINESTYLE_DASH_DOT_DOT:
504         Line->LinePattern = 5;
505         break;
506     default:
507     case LINESTYLE_SOLID:
508         Line->LinePattern = 1;
509         break;
510     }
511     Line->LineColor = *color;
512     Line->LineWeight = renderer->linewidth / vdx_Line_Scale;
513     if (start_arrow || end_arrow)
514     {
515         g_debug("create_Line (ARROWS)");
516     }
517 }
518 
519 
520 /** Create a Visio fill style object
521  * @param self a VDXRenderer
522  * @param color a colour
523  * @todo fillstyle
524  */
525 
526 static void
create_Fill(VDXRenderer * renderer,Color * color,struct vdx_Fill * Fill)527 create_Fill(VDXRenderer *renderer, Color *color, struct vdx_Fill *Fill)
528 {
529     /* A Fill (colour etc) */
530     memset(Fill, 0, sizeof(*Fill));
531     Fill->type = vdx_types_Fill;
532     Fill->FillForegnd = *color;
533     Fill->FillPattern = 1;      /* Solid fill */
534 }
535 
536 
537 /** Render a Dia line
538  * @param self a renderer
539  * @param start start of line
540  * @param end end of line
541  * @param color line colour
542  */
543 
544 static void
draw_line(DiaRenderer * self,Point * start,Point * end,Color * color)545 draw_line(DiaRenderer *self, Point *start, Point *end, Color *color)
546 {
547     VDXRenderer *renderer = VDX_RENDERER(self);
548     Point a, b;
549     struct vdx_Shape Shape;
550     struct vdx_XForm XForm;
551     struct vdx_XForm1D XForm1D;
552     struct vdx_Geom Geom;
553     struct vdx_MoveTo MoveTo;
554     struct vdx_LineTo LineTo;
555     struct vdx_Line Line;
556     char NameU[VDX_NAMEU_LEN];
557 
558     /* First time through, just construct the colour table */
559     if (renderer->first_pass)
560     {
561         vdxCheckColor(renderer, color);
562         return;
563     }
564 
565     g_debug("draw_line((%f,%f), (%f,%f))", start->x, start->y, end->x, end->y);
566 
567     /* Setup the standard shape object */
568     memset(&Shape, 0, sizeof(Shape));
569     Shape.type = vdx_types_Shape;
570     Shape.ID = renderer->shapeid++;
571     Shape.Type = "Shape";
572     sprintf(NameU, "Line.%d", Shape.ID);
573     Shape.NameU = NameU;
574     Shape.LineStyle_exists = 1;
575     Shape.FillStyle_exists = 1;
576     Shape.TextStyle_exists = 1;
577 
578     /* An XForm */
579     memset(&XForm, 0, sizeof(XForm));
580     XForm.type = vdx_types_XForm;
581     a = visio_point(*start);
582     b = visio_point(*end);
583     XForm.PinX = a.x;           /* Start */
584     XForm.PinY = a.y;
585     XForm.Width = fabs(b.x - a.x); /* Must be non-negative */
586     XForm.Height = fabs(b.y - a.y); /* Must be non-negative */
587     XForm.LocPinX = 0.0;
588     XForm.LocPinY = 0.0;
589     XForm.Angle = 0.0;
590 
591     /* Lines must have an XForm1D as well */
592     memset(&XForm1D, 0, sizeof(XForm1D));
593     XForm1D.type = vdx_types_XForm1D;
594     XForm1D.BeginX = a.x;
595     XForm1D.BeginY = a.y;
596     XForm1D.EndX = b.x;
597     XForm1D.EndY = b.y;
598 
599     /* Standard Geom object */
600     memset(&Geom, 0, sizeof(Geom));
601     Geom.NoFill = 1;
602     Geom.type = vdx_types_Geom;
603 
604     /* Two children - MoveTo(start) and LineTo(end) */
605     memset(&MoveTo, 0, sizeof(MoveTo));
606     MoveTo.type = vdx_types_MoveTo;
607     MoveTo.IX = 1;
608     MoveTo.X = 0;
609     MoveTo.Y = 0;
610 
611     memset(&LineTo, 0, sizeof(LineTo));
612     LineTo.type = vdx_types_LineTo;
613     LineTo.IX = 2;
614     LineTo.X = b.x-a.x;
615     LineTo.Y = b.y-a.y;
616 
617     /* A Line (colour etc) */
618     create_Line(renderer, color, &Line, 0, 0);
619 
620     /* Setup children */
621     Geom.children = g_slist_append(Geom.children, &MoveTo);
622     Geom.children = g_slist_append(Geom.children, &LineTo);
623 
624     Shape.children = g_slist_append(Shape.children, &XForm);
625     Shape.children = g_slist_append(Shape.children, &XForm1D);
626     Shape.children = g_slist_append(Shape.children, &Line);
627     Shape.children = g_slist_append(Shape.children, &Geom);
628 
629     /* Write out XML */
630     vdx_write_object(renderer->file, renderer->xml_depth, &Shape);
631 
632     /* Free up list entries */
633     g_slist_free(Geom.children);
634     g_slist_free(Shape.children);
635 }
636 
637 
638 /** Render a Dia polyline
639  * @param self a renderer
640  * @param points the points
641  * @param num_points how many points
642  * @param color line colour
643  */
644 
draw_polyline(DiaRenderer * self,Point * points,int num_points,Color * color)645 static void draw_polyline(DiaRenderer *self, Point *points, int num_points,
646 			  Color *color)
647 {
648     VDXRenderer *renderer = VDX_RENDERER(self);
649     Point a, b;
650     struct vdx_Shape Shape;
651     struct vdx_XForm XForm;
652     struct vdx_Geom Geom;
653     struct vdx_MoveTo MoveTo;
654     struct vdx_LineTo* LineTo;
655     struct vdx_Line Line;
656     char NameU[VDX_NAMEU_LEN];
657     unsigned int i;
658     double minX, minY, maxX, maxY;
659 
660     /* First time through, just construct the colour table */
661     if (renderer->first_pass)
662     {
663         vdxCheckColor(renderer, color);
664         return;
665     }
666 
667     g_debug("draw_polyline(%d)", num_points);
668 
669     /* Setup the standard shape object */
670     memset(&Shape, 0, sizeof(Shape));
671     Shape.type = vdx_types_Shape;
672     Shape.ID = renderer->shapeid++;
673     Shape.Type = "Shape";
674     sprintf(NameU, "PolyLine.%d", Shape.ID);
675     Shape.NameU = NameU;
676     Shape.LineStyle_exists = 1;
677     Shape.FillStyle_exists = 1;
678     Shape.TextStyle_exists = 1;
679 
680     /* An XForm */
681     memset(&XForm, 0, sizeof(XForm));
682     XForm.type = vdx_types_XForm;
683     a = visio_point(points[0]);
684 
685     /* Find width and height */
686     minX = points[0].x; minY = points[0].y;
687     maxX = points[0].x; maxY = points[0].y;
688     for (i=1; i<num_points; i++)
689     {
690         if (points[i].x < minX) minX = points[i].x;
691         if (points[i].x > maxX) maxX = points[i].x;
692         if (points[i].y < minY) minY = points[i].y;
693         if (points[i].y > maxY) maxY = points[i].y;
694     }
695     XForm.Width = visio_length(maxX - minX);
696     XForm.Height = visio_length(maxY - minY);
697 
698     XForm.PinX = a.x;           /* Start */
699     XForm.PinY = a.y;
700     XForm.LocPinX = 0.0;
701     XForm.LocPinY = 0.0;
702     XForm.Angle = 0.0;
703 
704     /* Standard Geom object */
705     memset(&Geom, 0, sizeof(Geom));
706     Geom.NoFill = 1;
707     Geom.type = vdx_types_Geom;
708 
709     /* Multiple children - MoveTo(start) and LineTo(others) */
710     memset(&MoveTo, 0, sizeof(MoveTo));
711     MoveTo.type = vdx_types_MoveTo;
712     MoveTo.IX = 1;
713     MoveTo.X = 0;
714     MoveTo.Y = 0;
715 
716     LineTo = g_new0(struct vdx_LineTo, num_points-1);
717     for (i=0; i<num_points-1; i++)
718     {
719         LineTo[i].type = vdx_types_LineTo;
720         LineTo[i].IX = i+2;
721         b = visio_point(points[i+1]);
722         LineTo[i].X = b.x-a.x;
723         LineTo[i].Y = b.y-a.y;
724     }
725 
726     /* A Line (colour etc) */
727     create_Line(renderer, color, &Line, 0, 0);
728 
729     /* Setup children */
730     Geom.children = g_slist_append(Geom.children, &MoveTo);
731     for (i=0; i<num_points-1; i++)
732     {
733         Geom.children = g_slist_append(Geom.children, &LineTo[i]);
734     }
735 
736     Shape.children = g_slist_append(Shape.children, &XForm);
737     Shape.children = g_slist_append(Shape.children, &Line);
738     Shape.children = g_slist_append(Shape.children, &Geom);
739 
740     /* Write out XML */
741     vdx_write_object(renderer->file, renderer->xml_depth, &Shape);
742 
743     /* Free up list entries */
744     g_slist_free(Geom.children);
745     g_slist_free(Shape.children);
746     g_free(LineTo);
747 }
748 
749 /** Render a Dia polygon
750  * @param self a renderer
751  * @param points corners of polygon
752  * @param num_points number of points
753  * @param color line colour
754  */
755 
draw_polygon(DiaRenderer * self,Point * points,int num_points,Color * color)756 static void draw_polygon(DiaRenderer *self,
757 			 Point *points, int num_points,
758 			 Color *color)
759 {
760     Point *more_points = g_new0(Point, num_points+1);
761     memcpy(more_points, points, num_points*sizeof(Point));
762     more_points[num_points] = more_points[0];
763     g_debug("draw_polygon -> draw_polyline");
764     draw_polyline(self, more_points, num_points+1, color);
765     g_free(more_points);
766 }
767 
768 /** Render a Dia filled polygon
769  * @param self a renderer
770  * @param points corners of polygon
771  * @param num_points number of points
772  * @param color line colour
773  */
774 
fill_polygon(DiaRenderer * self,Point * points,int num_points,Color * color)775 static void fill_polygon(DiaRenderer *self,
776 			 Point *points, int num_points,
777 			 Color *color)
778 {
779     VDXRenderer *renderer = VDX_RENDERER(self);
780     Point a, b;
781     struct vdx_Shape Shape;
782     struct vdx_XForm XForm;
783     struct vdx_Geom Geom;
784     struct vdx_MoveTo MoveTo;
785     struct vdx_LineTo* LineTo;
786     struct vdx_Fill Fill;
787     char NameU[VDX_NAMEU_LEN];
788     unsigned int i;
789     double minX, minY, maxX, maxY;
790 
791     /* First time through, just construct the colour table */
792     if (renderer->first_pass)
793     {
794         vdxCheckColor(renderer, color);
795         return;
796     }
797 
798     g_debug("fill_polygon(%d)", num_points);
799 
800     /* Setup the standard shape object */
801     memset(&Shape, 0, sizeof(Shape));
802     Shape.type = vdx_types_Shape;
803     Shape.ID = renderer->shapeid++;
804     Shape.Type = "Shape";
805     sprintf(NameU, "FillPolygon.%d", Shape.ID);
806     Shape.NameU = NameU;
807     Shape.LineStyle_exists = 1;
808     Shape.FillStyle_exists = 1;
809     Shape.TextStyle_exists = 1;
810 
811     /* An XForm */
812     memset(&XForm, 0, sizeof(XForm));
813     XForm.type = vdx_types_XForm;
814     a = visio_point(points[0]);
815 
816     /* Find width and height */
817     minX = points[0].x; minY = points[0].y;
818     maxX = points[0].x; maxY = points[0].y;
819     for (i=1; i<num_points; i++)
820     {
821         if (points[i].x < minX) minX = points[i].x;
822         if (points[i].x > maxX) maxX = points[i].x;
823         if (points[i].y < minY) minY = points[i].y;
824         if (points[i].y > maxY) maxY = points[i].y;
825     }
826     XForm.Width = visio_length(maxX - minX);
827     XForm.Height = visio_length(maxY - minY);
828 
829     XForm.PinX = a.x;           /* Start */
830     XForm.PinY = a.y;
831     XForm.LocPinX = 0.0;
832     XForm.LocPinY = 0.0;
833     XForm.Angle = 0.0;
834 
835     /* Standard Geom object */
836     memset(&Geom, 0, sizeof(Geom));
837     Geom.type = vdx_types_Geom;
838 
839     /* Multiple children - MoveTo(start) and LineTo(others) */
840     memset(&MoveTo, 0, sizeof(MoveTo));
841     MoveTo.type = vdx_types_MoveTo;
842     MoveTo.IX = 1;
843     MoveTo.X = 0;
844     MoveTo.Y = 0;
845 
846     LineTo = g_new0(struct vdx_LineTo, num_points);
847     for (i=0; i<num_points; i++)
848     {
849         LineTo[i].type = vdx_types_LineTo;
850         LineTo[i].IX = i+2;
851         /* Last point = first */
852         if (i == num_points-1) b = a;
853         else b = visio_point(points[i+1]);
854         LineTo[i].X = b.x-a.x;
855         LineTo[i].Y = b.y-a.y;
856     }
857 
858     /* A Line (colour etc) */
859     create_Fill(renderer, color, &Fill);
860 
861     /* Setup children */
862     Geom.children = g_slist_append(Geom.children, &MoveTo);
863     for (i=0; i<num_points; i++)
864     {
865         Geom.children = g_slist_append(Geom.children, &LineTo[i]);
866     }
867 
868     Shape.children = g_slist_append(Shape.children, &XForm);
869     Shape.children = g_slist_append(Shape.children, &Fill);
870     Shape.children = g_slist_append(Shape.children, &Geom);
871 
872     /* Write out XML */
873     vdx_write_object(renderer->file, renderer->xml_depth, &Shape);
874 
875     /* Free up list entries */
876     g_slist_free(Geom.children);
877     g_slist_free(Shape.children);
878     g_free(LineTo);
879 }
880 
881 /** Render a Dia rectangle
882  * @param self a renderer
883  * @param ul_corner Upper-left corner
884  * @param lr_corner Loower-right corner
885  * @param color line colour
886  */
887 
draw_rect(DiaRenderer * self,Point * ul_corner,Point * lr_corner,Color * color)888 static void draw_rect(DiaRenderer *self,
889 		      Point *ul_corner, Point *lr_corner,
890 		      Color *color)
891 {
892     Point points[5];            /* 5 so we close path */
893 
894     g_debug("draw_rect((%f,%f), (%f,%f)) -> draw_polyline",
895             ul_corner->x, ul_corner->y, lr_corner->x, lr_corner->y);
896     points[0].x = ul_corner->x; points[0].y = lr_corner->y;
897     points[1] = *lr_corner;
898     points[2].x = lr_corner->x; points[2].y = ul_corner->y;
899     points[3] = *ul_corner;
900     points[4] = points[0];
901 
902     draw_polygon(self, points, 5, color);
903 }
904 
905 /** Render a Dia filled rectangle
906  * @param self a renderer
907  * @param ul_corner Upper-left corner
908  * @param lr_corner Lower-right corner
909  * @param color line colour
910  */
911 
fill_rect(DiaRenderer * self,Point * ul_corner,Point * lr_corner,Color * color)912 static void fill_rect(DiaRenderer *self,
913 		      Point *ul_corner, Point *lr_corner,
914 		      Color *color)
915 {
916     Point points[5];            /* 5 so we close path */
917 
918     g_debug("fill_rect -> fill_polygon");
919     points[0].x = ul_corner->x; points[0].y = lr_corner->y;
920     points[1] = *lr_corner;
921     points[2].x = lr_corner->x; points[2].y = ul_corner->y;
922     points[3] = *ul_corner;
923     points[4] = points[0];
924 
925     fill_polygon(self, points, 5, color);
926 }
927 
928 /** Render a Dia arc
929  * @param self a renderer
930  * @param center centre of arc
931  * @param width width of ellipse
932  * @param height height of ellipse (= width for Dia circular arcs)
933  * @param angle1 start angle to x axis in degrees
934  * @param angle2 end angle to x axis in degrees
935  * @param color line colour
936  * @todo Not done yet
937  */
938 
draw_arc(DiaRenderer * self,Point * center,real width,real height,real angle1,real angle2,Color * color)939 static void draw_arc(DiaRenderer *self,
940 		     Point *center,
941 		     real width, real height,
942 		     real angle1, real angle2,
943 		     Color *color)
944 {
945     VDXRenderer *renderer = VDX_RENDERER(self);
946     Point a;
947     struct vdx_Shape Shape;
948     struct vdx_XForm XForm;
949     struct vdx_Geom Geom;
950     struct vdx_EllipticalArcTo EllipticalArcTo;
951     struct vdx_MoveTo MoveTo;
952     struct vdx_Line Line;
953     char NameU[VDX_NAMEU_LEN];
954     Point start, control, end;
955     float control_angle;
956 
957     /* First time through, just construct the colour table */
958     if (renderer->first_pass)
959     {
960         vdxCheckColor(renderer, color);
961         return;
962     }
963 
964     g_debug("draw_arc((%f,%f),%f,%f;%f,%f)", center->x, center->y,
965             width, height, angle1, angle2);
966 
967     /* Setup the standard shape object */
968     memset(&Shape, 0, sizeof(Shape));
969     Shape.type = vdx_types_Shape;
970     Shape.ID = renderer->shapeid++;
971     Shape.Type = "Shape";
972     sprintf(NameU, "Arc.%d", Shape.ID);
973     Shape.NameU = NameU;
974     Shape.LineStyle_exists = 1;
975     Shape.FillStyle_exists = 1;
976     Shape.TextStyle_exists = 1;
977 
978     /* An XForm */
979     memset(&XForm, 0, sizeof(XForm));
980     XForm.type = vdx_types_XForm;
981 
982     /* Find the start of the arc */
983     start = *center;
984     start.x += (width/2.0)*cos(angle1*DEG_TO_RAD);
985     start.y -= (height/2.0)*sin(angle1*DEG_TO_RAD);
986     g_debug("start(%f,%f)", start.x, start.y);
987     start = visio_point(start);
988 
989     /* Find a control point at the midpoint of the arc */
990     control = *center;
991     control_angle = (angle1 + angle2)/2.0;
992     if (angle1 > angle2)
993     {
994         /* Arc goes antclockwise - allow for this */
995         control_angle -= 180;
996     }
997     control.x += (width/2.0)*cos(control_angle*DEG_TO_RAD);
998     control.y -= (height/2.0)*sin(control_angle*DEG_TO_RAD);
999     g_debug("control(%f,%f @ %f)", control.x, control.y, control_angle);
1000     control = visio_point(control);
1001 
1002     /* And the endpoint */
1003     end = *center;
1004     end.x += (width/2.0)*cos(angle2*DEG_TO_RAD);
1005     end.y -= (height/2.0)*sin(angle2*DEG_TO_RAD);
1006     g_debug("end(%f,%f)", end.x, end.y);
1007     end = visio_point(end);
1008 
1009     a = start;
1010     XForm.PinX = a.x;           /* Start */
1011     XForm.PinY = a.y;
1012     XForm.Width = visio_length(width);
1013     XForm.Height = visio_length(height);
1014     XForm.LocPinX = 0;
1015     XForm.LocPinY = 0;
1016     XForm.Angle = 0.0;
1017 
1018     /* Standard Geom object */
1019     memset(&Geom, 0, sizeof(Geom));
1020     Geom.NoFill = 1;
1021     Geom.type = vdx_types_Geom;
1022 
1023     memset(&MoveTo, 0, sizeof(MoveTo));
1024     MoveTo.type = vdx_types_MoveTo;
1025     MoveTo.IX = 1;
1026     MoveTo.X = 0;
1027     MoveTo.Y = 0;
1028 
1029     /* Second child - EllipticalArcTo */
1030     memset(&EllipticalArcTo, 0, sizeof(EllipticalArcTo));
1031     EllipticalArcTo.type = vdx_types_EllipticalArcTo;
1032     EllipticalArcTo.IX = 2;
1033 
1034     /* X and Y are the end point
1035        A and B are a control point on the arc
1036        C is the angle of the major axis
1037        D is the ratio of the major to minor axes */
1038 
1039     /* Need to fix these */
1040     EllipticalArcTo.X = end.x - a.x;
1041     EllipticalArcTo.Y = end.y - a.y;
1042     EllipticalArcTo.A = control.x - a.x;
1043     EllipticalArcTo.B = control.y - a.y;
1044     EllipticalArcTo.C = 0.0;      /* Dia major axis always x axis  */
1045     if (fabs(height) > EPSILON)
1046         EllipticalArcTo.D = width/height; /* Always 1 for Dia */
1047     else
1048         EllipticalArcTo.D = 1/EPSILON;
1049 
1050     /* A Line (colour etc) */
1051     create_Line(renderer, color, &Line, 0, 0);
1052 
1053     /* Setup children */
1054     Geom.children = g_slist_append(Geom.children, &MoveTo);
1055     Geom.children = g_slist_append(Geom.children, &EllipticalArcTo);
1056 
1057     Shape.children = g_slist_append(Shape.children, &XForm);
1058     Shape.children = g_slist_append(Shape.children, &Line);
1059     Shape.children = g_slist_append(Shape.children, &Geom);
1060 
1061     /* Write out XML */
1062     vdx_write_object(renderer->file, renderer->xml_depth, &Shape);
1063 
1064     /* Free up list entries */
1065     g_slist_free(Geom.children);
1066     g_slist_free(Shape.children);
1067 }
1068 
1069 /** Render a Dia filled arc
1070  * @param self a renderer
1071  * @param center centre of arc
1072  * @param width width of bounding box
1073  * @param height height of bounding box
1074  * @param angle1 start angle
1075  * @param angle2 end angle
1076  * @param color line colour
1077  * @todo Not done yet - believe unused
1078  */
1079 
fill_arc(DiaRenderer * self,Point * center,real width,real height,real angle1,real angle2,Color * color)1080 static void fill_arc(DiaRenderer *self,
1081 		     Point *center,
1082 		     real width, real height,
1083 		     real angle1, real angle2,
1084 		     Color *color)
1085 {
1086     VDXRenderer *renderer = VDX_RENDERER(self);
1087 
1088     if (renderer->first_pass)
1089     {
1090         vdxCheckColor(renderer, color);
1091         return;
1092     }
1093     g_debug("fill_arc (TODO)");
1094 }
1095 
1096 /** Render a Dia ellipse (parallel to axes)
1097  * @param self a renderer
1098  * @param center centre of ellipse
1099  * @param width width of bounding box
1100  * @param height height of bounding box
1101  * @param color line colour
1102  */
1103 
draw_ellipse(DiaRenderer * self,Point * center,real width,real height,Color * color)1104 static void draw_ellipse(DiaRenderer *self,
1105 			 Point *center,
1106 			 real width, real height,
1107 			 Color *color)
1108 {
1109     VDXRenderer *renderer = VDX_RENDERER(self);
1110     Point a;
1111     struct vdx_Shape Shape;
1112     struct vdx_XForm XForm;
1113     struct vdx_Geom Geom;
1114     struct vdx_Ellipse Ellipse;
1115     struct vdx_Line Line;
1116     char NameU[VDX_NAMEU_LEN];
1117 
1118     /* First time through, just construct the colour table */
1119     if (renderer->first_pass)
1120     {
1121         vdxCheckColor(renderer, color);
1122         return;
1123     }
1124 
1125     g_debug("draw_ellipse");
1126 
1127     /* Setup the standard shape object */
1128     memset(&Shape, 0, sizeof(Shape));
1129     Shape.type = vdx_types_Shape;
1130     Shape.ID = renderer->shapeid++;
1131     Shape.Type = "Shape";
1132     sprintf(NameU, "Ellipse.%d", Shape.ID);
1133     Shape.NameU = NameU;
1134     Shape.LineStyle_exists = 1;
1135     Shape.FillStyle_exists = 1;
1136     Shape.TextStyle_exists = 1;
1137 
1138     /* An XForm */
1139     memset(&XForm, 0, sizeof(XForm));
1140     XForm.type = vdx_types_XForm;
1141     a = visio_point(*center);
1142     XForm.PinX = a.x;           /* Start */
1143     XForm.PinY = a.y;
1144     XForm.Width = visio_length(width);
1145     XForm.Height = visio_length(height);
1146     XForm.LocPinX = XForm.Width/2.0;
1147     XForm.LocPinY = XForm.Height/2.0;
1148     XForm.Angle = 0.0;
1149 
1150     /* Standard Geom object */
1151     memset(&Geom, 0, sizeof(Geom));
1152     Geom.NoFill = 1;
1153     Geom.type = vdx_types_Geom;
1154 
1155     /* One child - Ellipse */
1156     memset(&Ellipse, 0, sizeof(Ellipse));
1157     Ellipse.type = vdx_types_Ellipse;
1158     Ellipse.IX = 1;
1159     Ellipse.X = XForm.Width/2.0;
1160     Ellipse.Y = XForm.Height/2.0;
1161     Ellipse.A = XForm.Width;
1162     Ellipse.B = XForm.Height/2.0;
1163     Ellipse.C = XForm.Width/2.0;
1164     Ellipse.D = XForm.Height;
1165 
1166     /* A Line (colour etc) */
1167     create_Line(renderer, color, &Line, 0, 0);
1168 
1169     /* Setup children */
1170     Geom.children = g_slist_append(Geom.children, &Ellipse);
1171 
1172     Shape.children = g_slist_append(Shape.children, &XForm);
1173     Shape.children = g_slist_append(Shape.children, &Line);
1174     Shape.children = g_slist_append(Shape.children, &Geom);
1175 
1176     /* Write out XML */
1177     vdx_write_object(renderer->file, renderer->xml_depth, &Shape);
1178 
1179     /* Free up list entries */
1180     g_slist_free(Geom.children);
1181     g_slist_free(Shape.children);
1182 }
1183 
1184 /** Render a Dia filled ellipse (parallel to axes)
1185  * @param self a renderer
1186  * @param center centre of ellipse
1187  * @param width width of bounding box
1188  * @param height height of bounding box
1189  * @param color line colour
1190  */
1191 
fill_ellipse(DiaRenderer * self,Point * center,real width,real height,Color * color)1192 static void fill_ellipse(DiaRenderer *self,
1193 			 Point *center,
1194 			 real width, real height,
1195 			 Color *color)
1196 {
1197     VDXRenderer *renderer = VDX_RENDERER(self);
1198     Point a;
1199     struct vdx_Shape Shape;
1200     struct vdx_XForm XForm;
1201     struct vdx_Geom Geom;
1202     struct vdx_Ellipse Ellipse;
1203     struct vdx_Fill Fill;
1204     char NameU[VDX_NAMEU_LEN];
1205 
1206     /* First time through, just construct the colour table */
1207     if (renderer->first_pass)
1208     {
1209         vdxCheckColor(renderer, color);
1210         return;
1211     }
1212 
1213     g_debug("fill_ellipse");
1214 
1215     /* Setup the standard shape object */
1216     memset(&Shape, 0, sizeof(Shape));
1217     Shape.type = vdx_types_Shape;
1218     Shape.ID = renderer->shapeid++;
1219     Shape.Type = "Shape";
1220     sprintf(NameU, "FillEllipse.%d", Shape.ID);
1221     Shape.NameU = NameU;
1222     Shape.LineStyle_exists = 1;
1223     Shape.FillStyle_exists = 1;
1224     Shape.TextStyle_exists = 1;
1225 
1226     /* An XForm */
1227     memset(&XForm, 0, sizeof(XForm));
1228     XForm.type = vdx_types_XForm;
1229     a = visio_point(*center);
1230     XForm.PinX = a.x;           /* Start */
1231     XForm.PinY = a.y;
1232     XForm.Width = visio_length(width);
1233     XForm.Height = visio_length(height);
1234     XForm.LocPinX = XForm.Width/2.0;
1235     XForm.LocPinY = XForm.Height/2.0;
1236     XForm.Angle = 0.0;
1237 
1238     /* Standard Geom object */
1239     memset(&Geom, 0, sizeof(Geom));
1240     Geom.type = vdx_types_Geom;
1241 
1242     /* One child - Ellipse */
1243     memset(&Ellipse, 0, sizeof(Ellipse));
1244     Ellipse.type = vdx_types_Ellipse;
1245     Ellipse.IX = 1;
1246     Ellipse.X = XForm.Width/2.0;
1247     Ellipse.Y = XForm.Height/2.0;
1248     Ellipse.A = XForm.Width;
1249     Ellipse.B = XForm.Height/2.0;
1250     Ellipse.C = XForm.Width/2.0;
1251     Ellipse.D = XForm.Height;
1252 
1253     /* A Fill (colour etc) */
1254     create_Fill(renderer, color, &Fill);
1255 
1256     /* Setup children */
1257     Geom.children = g_slist_append(Geom.children, &Ellipse);
1258 
1259     Shape.children = g_slist_append(Shape.children, &XForm);
1260     Shape.children = g_slist_append(Shape.children, &Fill);
1261     Shape.children = g_slist_append(Shape.children, &Geom);
1262 
1263     /* Write out XML */
1264     vdx_write_object(renderer->file, renderer->xml_depth, &Shape);
1265 
1266     /* Free up list entries */
1267     g_slist_free(Geom.children);
1268     g_slist_free(Shape.children);
1269 }
1270 
1271 /** Render a Dia string
1272  * @param self a renderer
1273  * @param text the string
1274  * @param pos start (or centre etc.)
1275  * @param alignment alignment
1276  * @param color line colour
1277  * @todo Alignment, colour
1278  * @bug Bounding box incorrect
1279  */
1280 
draw_string(DiaRenderer * self,const char * text,Point * pos,Alignment alignment,Color * color)1281 static void draw_string(DiaRenderer *self,
1282 			const char *text,
1283 			Point *pos, Alignment alignment,
1284 			Color *color)
1285 {
1286     VDXRenderer *renderer = VDX_RENDERER(self);
1287     Point a;
1288     struct vdx_Shape Shape;
1289     struct vdx_XForm XForm;
1290     struct vdx_Char Char;
1291     struct vdx_Text Text;
1292     struct vdx_text my_text;
1293     char NameU[VDX_NAMEU_LEN];
1294 
1295     if (renderer->first_pass)
1296     {
1297         /* Add to colour and font tables */
1298         vdxCheckColor(renderer, color);
1299         vdxCheckFont(renderer);
1300         return;
1301     }
1302 
1303     g_debug("draw_string");
1304     /* Standard shape */
1305     memset(&Shape, 0, sizeof(Shape));
1306     Shape.type = vdx_types_Shape;
1307     Shape.ID = renderer->shapeid++;
1308     Shape.Type = "Shape";
1309     sprintf(NameU, "Text.%d", Shape.ID);
1310     Shape.NameU = NameU;
1311     Shape.LineStyle_exists = 1;
1312     Shape.FillStyle_exists = 1;
1313     Shape.TextStyle_exists = 1;
1314 
1315     /* XForm describes bounding box */
1316     memset(&XForm, 0, sizeof(XForm));
1317     XForm.type = vdx_types_XForm;
1318     a = visio_point(*pos);
1319     XForm.PinX = a.x;
1320     XForm.PinY = a.y;
1321     XForm.Angle = 0;
1322     /* Hack to give it an approximate bounding box */
1323     XForm.Height = renderer->fontheight/vdx_Font_Size_Conversion;
1324     XForm.Width = strlen(text)*renderer->fontheight/vdx_Font_Size_Conversion;
1325 
1326     /* Character properties */
1327     memset(&Char, 0, sizeof(Char));
1328     Char.type = vdx_types_Char;
1329     Char.Font = vdxCheckFont(renderer);
1330     Char.Color = *color;
1331     Char.FontScale = 1;
1332     Char.Size = renderer->fontheight/vdx_Font_Size_Conversion;
1333 
1334     /* Text object - no attributes */
1335     memset(&Text, 0, sizeof(Text));
1336     Text.type = vdx_types_Text;
1337 
1338     /* text object (XML pseudo-tag) - no attributes */
1339     memset(&my_text, 0, sizeof(my_text));
1340     my_text.type = vdx_types_text;
1341     my_text.text = (char *)text;
1342 
1343     /* Construct the children */
1344     Text.children = g_slist_append(Text.children, &my_text);
1345 
1346     Shape.children = g_slist_append(Shape.children, &XForm);
1347     Shape.children = g_slist_append(Shape.children, &Char);
1348     Shape.children = g_slist_append(Shape.children, &Text);
1349 
1350     vdx_write_object(renderer->file, renderer->xml_depth, &Shape);
1351 
1352     g_slist_free(Text.children);
1353     g_slist_free(Shape.children);
1354 }
1355 
1356 /** Reads binary file and converts to Base64 data
1357  * @param filename file to read
1358  * @returns Base64 encoded data (or NULL if problem)
1359  * @note glibc 2.12 offers g_base64_encode()
1360  */
1361 
1362 static char *
read_base64_file(const char * filename)1363 read_base64_file(const char *filename)
1364 {
1365     FILE *f;
1366     char *b64 = 0;
1367     char *s = 0;
1368     int c = 0;
1369     char map[64];
1370     unsigned int buf_len = 0;
1371     unsigned char buf[3];
1372     struct stat stat_buf;
1373 
1374     if (g_stat(filename, &stat_buf))
1375     {
1376         message_error(_("Couldn't read file %s"), filename);
1377         return 0;
1378     }
1379     b64 = g_new0(char, stat_buf.st_size*4/3+5);
1380     s = b64;
1381 
1382     f = g_fopen(filename, "r+b");
1383     if (!f)
1384     {
1385         message_error(_("Couldn't read file %s"), filename);
1386         return 0;
1387     }
1388 
1389     /* Construct Base64 mapping table */
1390     for(c=0; c<26; c++) map[c] = 'A' + c;
1391     for(c=0; c<26; c++) map[c+26] = 'a' + c;
1392     for(c=0; c<10; c++) map[c+52] = '0' + c;
1393     map[62] = '+';
1394     map[63] = '/';
1395 
1396     while((c = fgetc(f)) != EOF)
1397     {
1398         buf[buf_len++] = (unsigned char)c;
1399         if (buf_len == 3)
1400         {
1401             *s++ = map[buf[0] >> 2];
1402             *s++ = map[((buf[0] & 3) << 4) + (buf[1] >> 4)];
1403             *s++ = map[((buf[1] & 15) << 2) + (buf[2] >> 6)];
1404             *s++ = map[buf[2] & 63];
1405             buf_len = 0;
1406         }
1407     }
1408 
1409     if (buf_len == 1)
1410     {
1411         *s++ = map[buf[0] >> 2];
1412         *s++ = map[((buf[0] & 3) << 4)];
1413         *s++ = '=';
1414         *s++ = '=';
1415     }
1416     if (buf_len == 2)
1417     {
1418         *s++ = map[buf[0] >> 2];
1419         *s++ = map[((buf[0] & 3) << 4) + (buf[1] >> 4)];
1420         *s++ = map[((buf[1] & 15) << 2)];
1421         *s++ = '=';
1422     }
1423 
1424     fclose(f);
1425     *s = 0;
1426     return b64;
1427 
1428     /* Deal with any chunks left over */
1429     if (buf_len)
1430     {
1431         fputc(buf[0] << 2 | buf[1] >> 4, f);
1432         if (buf_len > 1)
1433         {
1434             fputc(buf[1] << 4 | buf[2] >> 2, f);
1435             if (buf_len > 2)
1436             {
1437                 /* This one can't happen */
1438                 fputc(buf[2] << 6 | buf[3], f);
1439             }
1440         }
1441     }
1442 
1443     fclose(f);
1444 }
1445 
1446 /** Render a Dia bitmap
1447  * @param self a renderer
1448  * @param point top left
1449  * @param width width
1450  * @param height height
1451  */
1452 
draw_image(DiaRenderer * self,Point * point,real width,real height,DiaImage * image)1453 static void draw_image(DiaRenderer *self,
1454 		       Point *point,
1455 		       real width, real height,
1456 		       DiaImage *image)
1457 {
1458     VDXRenderer *renderer = VDX_RENDERER(self);
1459     Point a, bottom_left;
1460     struct vdx_Shape Shape;
1461     struct vdx_XForm XForm;
1462     struct vdx_Geom Geom;
1463     struct vdx_Foreign Foreign;
1464     struct vdx_ForeignData ForeignData;
1465     struct vdx_text text;
1466     char NameU[VDX_NAMEU_LEN];
1467     const char *filename = NULL;
1468     const char *suffix = NULL;
1469 
1470     if (renderer->first_pass)
1471     {
1472         return;
1473     }
1474 
1475     g_debug("draw_image((%f,%f), %f, %f, %s", point->x, point->y,
1476             width, height, dia_image_filename(image));
1477     /* Setup the standard shape object */
1478     memset(&Shape, 0, sizeof(Shape));
1479     Shape.type = vdx_types_Shape;
1480     Shape.ID = renderer->shapeid++;
1481     Shape.Type = "Foreign";
1482     sprintf(NameU, "Foreign.%d", Shape.ID);
1483     Shape.NameU = NameU;
1484     Shape.LineStyle_exists = 1;
1485     Shape.FillStyle_exists = 1;
1486     Shape.TextStyle_exists = 1;
1487 
1488     /* An XForm */
1489     memset(&XForm, 0, sizeof(XForm));
1490     XForm.type = vdx_types_XForm;
1491     bottom_left.x = point->x;
1492     bottom_left.y = point->y + height;
1493     a = visio_point(bottom_left);
1494     XForm.PinX = a.x;           /* Start */
1495     XForm.PinY = a.y;
1496     XForm.Width = visio_length(width);
1497     XForm.Height = visio_length(height);
1498     XForm.LocPinX = 0;
1499     XForm.LocPinY = 0;
1500     XForm.Angle = 0.0;
1501 
1502     /* Standard Geom object */
1503     memset(&Geom, 0, sizeof(Geom));
1504     Geom.type = vdx_types_Geom;
1505     /* We don't use it, but our decoder needs it */
1506 
1507     /* And a Foreign */
1508     memset(&Foreign, 0, sizeof(Foreign));
1509     Foreign.type = vdx_types_Foreign;
1510     Foreign.ImgOffsetX = 0;
1511     Foreign.ImgOffsetY = 0;
1512     Foreign.ImgHeight = visio_length(height);
1513     Foreign.ImgWidth = visio_length(width);
1514 
1515     /* And a ForeignData */
1516     memset(&ForeignData, 0, sizeof(ForeignData));
1517     ForeignData.type = vdx_types_ForeignData;
1518     ForeignData.ForeignType = "Bitmap";
1519     ForeignData.CompressionType = "JPEG";
1520     ForeignData.CompressionLevel = 1.0;
1521     ForeignData.ObjectHeight = visio_length(height);
1522     ForeignData.ObjectWidth = visio_length(width);
1523 
1524     filename = dia_image_filename(image);
1525     if ((suffix = strrchr(filename, '.')))
1526     {
1527         suffix++;
1528         if (!g_ascii_strncasecmp(suffix, "png", 3)) { ForeignData.CompressionType = "PNG"; }
1529         if (!g_ascii_strncasecmp(suffix, "gif", 3)) { ForeignData.CompressionType = "GIF"; }
1530         if (!g_ascii_strncasecmp(suffix, "jpg", 3) || !g_ascii_strncasecmp(suffix, "jpeg", 4))
1531         { ForeignData.CompressionType = "JPEG"; }
1532         if (!g_ascii_strncasecmp(suffix, "tif", 3) || !g_ascii_strncasecmp(suffix, "tiff", 4))
1533         { ForeignData.CompressionType = "TIFF"; }
1534     }
1535 
1536     /* And the data itself */
1537     memset(&text, 0, sizeof(text));
1538     text.type = vdx_types_text;
1539     text.text = read_base64_file(filename);
1540     if (!text.text) return;     /* Problem reading file */
1541 
1542     /* Setup children */
1543     Shape.children = g_slist_append(Shape.children, &XForm);
1544     Shape.children = g_slist_append(Shape.children, &Geom);
1545     Shape.children = g_slist_append(Shape.children, &Foreign);
1546     Shape.children = g_slist_append(Shape.children, &ForeignData);
1547     ForeignData.children = g_slist_append(ForeignData.children, &text);
1548 
1549     /* Write out XML */
1550     vdx_write_object(renderer->file, renderer->xml_depth, &Shape);
1551 
1552     /* Free up list entries */
1553     g_slist_free(ForeignData.children);
1554     g_slist_free(Shape.children);
1555 
1556     /* And the Base64 data */
1557     g_free(text.text);
1558 }
1559 
1560 /** Convert Dia colour to hex string
1561  * @param c a colour
1562  * @returns string in form #000000
1563  * @note static buffer overwritten with next call; not thread-safe
1564  */
1565 
1566 const char *
vdx_string_color(Color c)1567 vdx_string_color(Color c)
1568 {
1569     static char buf[8];
1570     sprintf(buf, "#%.2X%.2X%.2X",
1571             (int)(c.red*255), (int)(c.green*255), (int)(c.blue*255));
1572     return buf;
1573 }
1574 
1575 /** Return string XML-encoded
1576  * @param s a string
1577  * @returns encoded string
1578  * @note uses static buffer so can be used as inline filter in printf
1579  */
1580 
1581 const char *
vdx_convert_xml_string(const char * s)1582 vdx_convert_xml_string(const char *s)
1583 {
1584     static char *out = 0;
1585     char *c;
1586 
1587     /* If (as almost always) no change required, return intact */
1588     if (strcspn(s, "&<>\"'") == strlen(s)) return s;
1589 
1590     /* Ensure we have enough space, even if all the string is quotes */
1591     out = realloc(out, 6*strlen(s)+1);
1592     c = out;
1593 
1594     while(*s)
1595     {
1596         switch(*s)
1597         {
1598         case '&':
1599             strcpy(c, "&amp;"); c += 5;
1600             break;
1601         case '<':
1602             strcpy(c, "&lt;"); c += 4;
1603             break;
1604         case '>':
1605             strcpy(c, "&gt;"); c += 4;
1606             break;
1607         case '\"':
1608         case '\'':
1609             strcpy(c, "&quot;"); c += 6;
1610             break;
1611         default:
1612             *c++ = *s;
1613         }
1614         s++;
1615     }
1616     *c = 0;
1617     return out;
1618 }
1619 
1620 /** Write VDX file header
1621  * @param data diagram data
1622  * @param renderer a renderer
1623  * @note Must know if 2002 or 2003 before start
1624  * @todo paper size, orientation, metadata, 2003 font attributes
1625  */
1626 
1627 static void
write_header(DiagramData * data,VDXRenderer * renderer)1628 write_header(DiagramData *data, VDXRenderer *renderer)
1629 {
1630     FILE *file = renderer->file;
1631     Color c;
1632     const char *f;
1633     unsigned int i;
1634     struct vdx_StyleSheet StyleSheet;
1635     struct vdx_StyleProp StyleProp;
1636     struct vdx_Line Line;
1637     struct vdx_Fill Fill;
1638     struct vdx_TextBlock TextBlock;
1639     struct vdx_Char Char;
1640     struct vdx_Para Para;
1641     struct vdx_Tabs Tabs;
1642     static Color color_black = {0,0,0};
1643 
1644     g_debug("write_header");
1645 
1646     /* Basic XML identifying info */
1647 
1648     fprintf(file, "<?xml version='1.0' encoding='utf-8'?>\n");
1649     fprintf(file, "<!-- Created by Dia -->\n");
1650     if (renderer->version == 2002)
1651     {
1652         fprintf(file,
1653                 "<VisioDocument "
1654                 "xmlns='urn:schemas-microsoft-com:office:visio'>\n");
1655     }
1656     if (renderer->version == 2003)
1657     {
1658         fprintf(file, "<VisioDocument "
1659                 "xmlns='http://schemas.microsoft.com/visio/2003/core' "
1660                 "start='190' metric='0' "
1661                 "DocLangID='1033' version='11.0' xml:space='preserve'>\n");
1662     }
1663 
1664     /* Skipping DocumentProperties, DocumentSettings - observed unnecessary */
1665 
1666     /*  Other fields that may be useful:
1667         fprintf(file, (data->paper.is_portrait?"Portrait\n":"Landscape\n"));
1668         fprintf(file, "%s\n", data->paper.name);
1669         fprintf(file, "%f\n", data->paper.scaling*100.0);
1670     */
1671 
1672     /* Colour table */
1673 
1674     fprintf(file, "  <Colors>\n");
1675     for (i = 0; i < renderer->Colors->len; i++)
1676     {
1677         c = g_array_index(renderer->Colors, Color, i);
1678         fprintf(file, "    <ColorEntry IX='%d' RGB='%s'/>\n",
1679                 i, vdx_string_color(c));
1680     }
1681     fprintf(file, "  </Colors>\n");
1682 
1683     /* Font table - different between the two versions (alas) */
1684 
1685     if (renderer->version == 2002)
1686     {
1687         fprintf(file, "  <Fonts>\n");
1688         for (i = 0; i < renderer->Fonts->len; i++)
1689         {
1690             struct vdx_FontEntry Font;
1691             memset(&Font, 0, sizeof(Font));
1692             Font.type = vdx_types_FontEntry;
1693             f = g_array_index(renderer->Fonts, char *, i);
1694 
1695             /* Assume want stndard fonts names converted */
1696             if (!strcmp(f, "Helvetica")) f = "Arial";
1697             if (!strcmp(f, "Times")) f = "Times New Roman";
1698 
1699             Font.Name = (char *)f;
1700             /* Sensible defaults */
1701             Font.CharSet = 0;
1702             Font.CharSet_exists = 1;
1703             Font.PitchAndFamily = 18;
1704             Font.PitchAndFamily_exists = 1;
1705             Font.Attributes = 23040;
1706             Font.Attributes_exists = 1;
1707             Font.Weight = 0;
1708             Font.Unicode = 0;
1709 
1710             /* Some observed values */
1711             if (!strcmp(f, "Arial")) Font.PitchAndFamily = 32;
1712             if (!strcmp(f, "Wingdings") || !strcmp(f, "Monotype Sorts") ||
1713                 !strcmp(f, "Symbol")) Font.CharSet = 2;
1714             if (!strcmp(f, "Monotype Sorts")) Font.Attributes = 4096;
1715             if (!strcmp(f, "Wingdings") || !strcmp(f, "Monotype Sorts"))
1716                 Font.PitchAndFamily = 2;
1717             vdx_write_object(renderer->file, 2, &Font);
1718         }
1719         fprintf(file, "  </Fonts>\n");
1720     }
1721     if (renderer->version == 2003)
1722     {
1723         fprintf(file, "  <FaceNames>\n");
1724         for (i = 0; i < renderer->Fonts->len; i++)
1725         {
1726             f = g_array_index(renderer->Fonts, char *, i);
1727 
1728             /* Assume want stndard fonts names converted */
1729             if (!strcmp(f, "Helvetica")) f = "Arial";
1730             if (!strcmp(f, "Times")) f = "Times New Roman";
1731 
1732             /* Missing attrs UnicodeRanges="31367 -2147483648 8 0"
1733                CharSets="1073742335 -65536"
1734                Panos="2 11 6 4 2 2 2 2 2 4" Flags="325" */
1735             fprintf(file, "    <FaceName ID='%d' Name='%s'/>\n",
1736                     i, f);
1737         }
1738         fprintf(file, "  </FaceNames>\n");
1739     }
1740 
1741     /* An initial stylesheet (mandatory) */
1742     memset(&StyleSheet, 0, sizeof(StyleSheet));
1743     StyleSheet.type = vdx_types_StyleSheet;
1744     StyleSheet.NameU = "No Style";
1745 
1746     /* All these values observed */
1747     memset(&StyleProp, 0, sizeof(StyleProp));
1748     StyleProp.type = vdx_types_StyleProp;
1749     StyleProp.EnableLineProps = 1;
1750     StyleProp.EnableFillProps = 1;
1751     StyleProp.EnableTextProps = 1;
1752 
1753     memset(&Line, 0, sizeof(Line));
1754     Line.type = vdx_types_Line;
1755     Line.LineWeight = 0.01;
1756     Line.LinePattern = 1;
1757 
1758     memset(&Fill, 0, sizeof(Fill));
1759     Fill.type = vdx_types_Fill;
1760     Fill.FillForegnd = color_black;
1761     Fill.FillPattern = 1;
1762 
1763     memset(&TextBlock, 0, sizeof(TextBlock));
1764     TextBlock.type = vdx_types_TextBlock;
1765     TextBlock.VerticalAlign = 1;
1766     TextBlock.DefaultTabStop = 0.59055118110236;
1767 
1768     memset(&Char, 0, sizeof(Char));
1769     Char.type = vdx_types_Char;
1770     Char.FontScale = 1;
1771     Char.Size = 0.16666666666667;
1772 
1773     memset(&Para, 0, sizeof(Para));
1774     Para.type = vdx_types_Para;
1775     Para.SpLine = -1.2;
1776     Para.HorzAlign = 1;
1777     Para.BulletStr = "&#xe000;";
1778     Para.BulletFontSize = "-1";
1779 
1780     memset(&Tabs, 0, sizeof(Tabs));
1781     Tabs.type = vdx_types_Tabs;
1782 
1783     /* Setup children */
1784     StyleSheet.children = g_slist_append(StyleSheet.children, &StyleProp);
1785     StyleSheet.children = g_slist_append(StyleSheet.children, &Line);
1786     StyleSheet.children = g_slist_append(StyleSheet.children, &Fill);
1787     StyleSheet.children = g_slist_append(StyleSheet.children, &TextBlock);
1788     StyleSheet.children = g_slist_append(StyleSheet.children, &Char);
1789     StyleSheet.children = g_slist_append(StyleSheet.children, &Para);
1790     StyleSheet.children = g_slist_append(StyleSheet.children, &Tabs);
1791 
1792     fprintf(file, "  <StyleSheets>\n");
1793     vdx_write_object(renderer->file, 2, &StyleSheet);
1794     fprintf(file, "  </StyleSheets>\n");
1795 
1796     g_slist_free(StyleSheet.children);
1797 
1798     /*  Following attributes observed */
1799     fprintf(file, "  <Pages>\n");
1800     fprintf(file, "    <Page ID='0' NameU='Page-1' ViewScale='-1' "
1801             "ViewCenterX='5.8425196850394' ViewCenterY='3.7244094488189'>\n");
1802     fprintf(file, "      <Shapes>\n");
1803     renderer->xml_depth = 4;
1804     renderer->shapeid = 1;
1805 
1806     /* Exit nested <VisioDocument><Pages><Page><Shapes> */
1807 }
1808 
1809 /** Write VDX file trailer
1810  * @param data diagram data
1811  * @param renderer a renderer
1812  */
1813 
1814 static void
write_trailer(DiagramData * data,VDXRenderer * renderer)1815 write_trailer(DiagramData *data, VDXRenderer *renderer)
1816 {
1817     FILE *file = renderer->file;
1818 
1819     g_debug("write_trailer");
1820 
1821     /* Enter nested <VisioDocument><Pages><Page><Shapes> */
1822 
1823     fprintf(file, "      </Shapes>\n");
1824     fprintf(file, "    </Page>\n");
1825     fprintf(file, "  </Pages>\n");
1826     fprintf(file, "</VisioDocument>\n");
1827 }
1828 
1829 /** Write VDX file
1830  * @param data diagram data
1831  * @param filename output file (should check suffix)
1832  * @param diafilename input filename (unused)
1833  * @param user_data user data (unused)
1834  * @note Must know if 2002 or 2003 before start
1835  */
1836 
1837 static void
export_vdx(DiagramData * data,const gchar * filename,const gchar * diafilename,void * user_data)1838 export_vdx(DiagramData *data, const gchar *filename,
1839            const gchar *diafilename, void* user_data)
1840 {
1841     FILE *file;
1842     VDXRenderer *renderer;
1843     int i;
1844     Layer *layer;
1845     char* old_locale;
1846 
1847     file = g_fopen(filename, "w");
1848 
1849     if (file == NULL) {
1850         message_error(_("Can't open output file %s: %s\n"),
1851                       dia_message_filename(filename), strerror(errno));
1852         return;
1853     }
1854 
1855     /* ugly, but still better than creatin corrupt files */
1856     old_locale = setlocale(LC_NUMERIC, "C");
1857 
1858     /* Create and initialise our renderer */
1859     renderer = g_object_new(VDX_TYPE_RENDERER, NULL);
1860 
1861     renderer->file = file;
1862 
1863     renderer->first_pass = TRUE;
1864 
1865     renderer->version = 2002;   /* For now */
1866 
1867     DIA_RENDERER_GET_CLASS(renderer)->begin_render(DIA_RENDERER(renderer));
1868 
1869     /* First run through without drawing to setup tables */
1870     for (i=0; i<data->layers->len; i++)
1871     {
1872         layer = (Layer *) g_ptr_array_index(data->layers, i);
1873         layer_render(layer, DIA_RENDERER(renderer), NULL, NULL, data, 0);
1874         renderer->depth++;
1875     }
1876 
1877     write_header(data, renderer);
1878 
1879     DIA_RENDERER_GET_CLASS(renderer)->end_render(DIA_RENDERER(renderer));
1880 
1881     renderer->first_pass = FALSE;
1882 
1883     DIA_RENDERER_GET_CLASS(renderer)->begin_render(DIA_RENDERER(renderer));
1884 
1885     /* Now render */
1886 
1887     for (i=0; i<data->layers->len; i++)
1888     {
1889         layer = (Layer *) g_ptr_array_index(data->layers, i);
1890         layer_render(layer, DIA_RENDERER(renderer), NULL, NULL, data, 0);
1891         renderer->depth++;
1892     }
1893 
1894     DIA_RENDERER_GET_CLASS(renderer)->end_render(DIA_RENDERER(renderer));
1895 
1896     /* Done */
1897 
1898     write_trailer(data, renderer);
1899 
1900     g_object_unref(renderer);
1901 
1902     /* dont screw Dia's global state */
1903     setlocale(LC_NUMERIC, old_locale);
1904 
1905     fclose(file);
1906 }
1907 
1908 /* interface from filter.h */
1909 
1910 static const gchar *extensions[] = { "vdx", NULL };
1911 DiaExportFilter vdx_export_filter = {
1912   N_("Visio XML format"),
1913   extensions,
1914   export_vdx
1915 };
1916 
1917 #if 0
1918 
1919 /* The following are not provided by vdx-export.c so we use the defaults.
1920    If they become necessary after testing, we can reinstate them */
1921 
1922 /** Render a Dia line with arrows
1923  * @param self a renderer
1924  * @param start start of line
1925  * @param end end of line
1926  * @param line_width width of line
1927  * @param color line colour
1928  * @param start_arrow start arrow
1929  * @param end_arrow end arrow
1930  */
1931 
1932 static void draw_line_with_arrows(DiaRenderer *self,
1933 				  Point *start, Point *end,
1934 				  real line_width,
1935 				  Color *color,
1936 				  Arrow *start_arrow,
1937 				  Arrow *end_arrow)
1938 {
1939     VDXRenderer *renderer = VDX_RENDERER(self);
1940     Point a, b;
1941     struct vdx_Shape Shape;
1942     struct vdx_XForm XForm;
1943     struct vdx_XForm1D XForm1D;
1944     struct vdx_Geom Geom;
1945     struct vdx_MoveTo MoveTo;
1946     struct vdx_LineTo LineTo;
1947     struct vdx_Line Line;
1948     char NameU[VDX_NAMEU_LEN];
1949 
1950     /* Exactly as draw_line for now */
1951 
1952     if (renderer->first_pass)
1953     {
1954         vdxCheckColor(renderer, color);
1955         return;
1956     }
1957 
1958     g_debug("draw_line_with_arrows");
1959     memset(&Shape, 0, sizeof(Shape));
1960     Shape.type = vdx_types_Shape;
1961     Shape.ID = renderer->shapeid++;
1962     Shape.Type = "Shape";
1963     sprintf(NameU, "ArrowLine.%d", Shape.ID);
1964     Shape.NameU = NameU;
1965     Shape.LineStyle_exists = 1;
1966     Shape.FillStyle_exists = 1;
1967     Shape.TextStyle_exists = 1;
1968 
1969     memset(&XForm, 0, sizeof(XForm));
1970     XForm.type = vdx_types_XForm;
1971     a = visio_point(*start);
1972     b = visio_point(*end);
1973     XForm.PinX = a.x;
1974     XForm.PinY = a.y;
1975     XForm.Width = fabs(b.x - a.x);
1976     XForm.Height = fabs(b.y - a.y);
1977     XForm.LocPinX = 0.0;
1978     XForm.LocPinY = 0.0;
1979     XForm.Angle = 0.0;
1980 
1981     memset(&XForm1D, 0, sizeof(XForm1D));
1982     XForm1D.type = vdx_types_XForm1D;
1983     XForm1D.BeginX = a.x;
1984     XForm1D.BeginY = a.y;
1985     XForm1D.EndX = b.x;
1986     XForm1D.EndY = b.y;
1987 
1988     memset(&Geom, 0, sizeof(Geom));
1989     Geom.NoFill = 1;
1990     Geom.type = vdx_types_Geom;
1991 
1992     memset(&MoveTo, 0, sizeof(MoveTo));
1993     MoveTo.type = vdx_types_MoveTo;
1994     MoveTo.IX = 1;
1995     MoveTo.X = 0;
1996     MoveTo.Y = 0;
1997 
1998     memset(&LineTo, 0, sizeof(LineTo));
1999     LineTo.type = vdx_types_LineTo;
2000     LineTo.IX = 2;
2001     LineTo.X = b.x-a.x;
2002     LineTo.Y = b.y-a.y;
2003 
2004     create_Line(renderer, color, &Line, start_arrow, end_arrow);
2005 
2006     Geom.children = g_slist_append(Geom.children, &MoveTo);
2007     Geom.children = g_slist_append(Geom.children, &LineTo);
2008 
2009     Shape.children = g_slist_append(Shape.children, &XForm);
2010     Shape.children = g_slist_append(Shape.children, &XForm1D);
2011     Shape.children = g_slist_append(Shape.children, &Line);
2012     Shape.children = g_slist_append(Shape.children, &Geom);
2013 
2014     vdx_write_object(renderer->file, renderer->xml_depth, &Shape);
2015 
2016     g_slist_free(Geom.children);
2017     g_slist_free(Shape.children);
2018 }
2019 
2020 /** Render a Dia polyline with arrows
2021  * @param self a renderer
2022  * @param points points on line
2023  * @param num_points number of points
2024  * @param line_width width of line
2025  * @param color line colour
2026  * @param start_arrow start arrow
2027  * @param end_arrow end arrow
2028  * @todo Not done yet
2029  */
2030 
2031 static void draw_polyline_with_arrows(DiaRenderer *self,
2032 				      Point *points, int num_points,
2033 				      real line_width,
2034 				      Color *color,
2035 				      Arrow *start_arrow,
2036 				      Arrow *end_arrow)
2037 {
2038     VDXRenderer *renderer = VDX_RENDERER(self);
2039 
2040     if (renderer->first_pass)
2041     {
2042         vdxCheckColor(renderer, color);
2043         return;
2044     }
2045     g_debug("draw_polyline_with_arrows (UNUSED)");
2046 }
2047 
2048 /** Render a Dia arc with arrows
2049  * @param self a renderer
2050  * @param startpoint start of arc
2051  * @param endpoint end of arc
2052  * @param midpoint middle of arc
2053  * @param line_width line width
2054  * @param color line colour
2055  * @param start_arrow start arrow
2056  * @param end_arrow end arrow
2057  * @todo Not done yet - believe unused
2058  */
2059 
2060 static void draw_arc_with_arrows(DiaRenderer *self,
2061 				 Point *startpoint,
2062 				 Point *endpoint,
2063 				 Point *midpoint,
2064 				 real line_width,
2065 				 Color *color,
2066 				 Arrow *start_arrow,
2067 				 Arrow *end_arrow)
2068 {
2069     VDXRenderer *renderer = VDX_RENDERER(self);
2070 
2071     if (renderer->first_pass)
2072     {
2073         vdxCheckColor(renderer, color);
2074         return;
2075     }
2076     g_debug("draw_arc_with_arrows (TODO)");
2077 }
2078 
2079 /** Render a Dia Bezier
2080  * @param self a renderer
2081  * @param points list of Bezier points
2082  * @param numpoints number of points
2083  * @param color line colour
2084  * @todo Not done yet - either convert to arcs or NURBS (Visio 2003)
2085  */
2086 
2087 static void draw_bezier(DiaRenderer *self,
2088 			BezPoint *points,
2089 			int numpoints,
2090 			Color *color)
2091 {
2092     VDXRenderer *renderer = VDX_RENDERER(self);
2093 
2094     if (renderer->first_pass)
2095     {
2096         vdxCheckColor(renderer, color);
2097         return;
2098     }
2099     g_debug("draw_bezier (TODO)");
2100 }
2101 
2102 /** Render a Dia Bezier with arrows
2103  * @param self a renderer
2104  * @param points list of Bezier points
2105  * @param numpoints number of points
2106  * @param line_width line width
2107  * @param color line colour
2108  * @param start_arrow start arrow
2109  * @param end_arrow end arrow
2110  * @todo Not done yet - either convert to arcs or NURBS (Visio 2003)
2111  */
2112 
2113 static void draw_bezier_with_arrows(DiaRenderer *self,
2114 				    BezPoint *points,
2115 				    int numpoints,
2116 				    real line_width,
2117 				    Color *color,
2118 				    Arrow *start_arrow,
2119 				    Arrow *end_arrow)
2120 {
2121     VDXRenderer *renderer = VDX_RENDERER(self);
2122 
2123     if (renderer->first_pass)
2124     {
2125         vdxCheckColor(renderer, color);
2126         return;
2127     }
2128     g_debug("draw_bezier_with_arrows (TODO)");
2129 }
2130 
2131 /** Render a Dia filled Bezier
2132  * @param self a renderer
2133  * @param points list of Bezier points (last = first)
2134  * @param numpoints number of points
2135  * @param color line colour
2136  * @todo Not done yet - either convert to arcs or NURBS (Visio 2003)
2137  */
2138 
2139 static void fill_bezier(DiaRenderer *self,
2140 			BezPoint *points,
2141 			int numpoints,
2142 			Color *color)
2143 {
2144     VDXRenderer *renderer = VDX_RENDERER(self);
2145 
2146     if (renderer->first_pass)
2147     {
2148         vdxCheckColor(renderer, color);
2149         return;
2150     }
2151 
2152     g_debug("fill_bezier (TODO)");
2153 }
2154 
2155 /** Render a Dia object
2156  * @param self a renderer
2157  * @param object an object
2158  * @note No work done here - perhaps should push/pop renderer state
2159  */
2160 
2161 static void draw_object(DiaRenderer *self,
2162 			DiaObject *object)
2163 {
2164     VDXRenderer *renderer = VDX_RENDERER(self);
2165 
2166     g_debug("draw_object -> renderer");
2167     /* Get the object to draw itself */
2168     object->ops->draw(object, DIA_RENDERER(renderer));
2169 }
2170 
2171 
2172 #endif
2173