~ubuntu-branches/ubuntu/trusty/xcircuit/trusty

« back to all changes in this revision

Viewing changes to .pc/05_fix_string_format.patch/svg.c

  • Committer: Package Import Robot
  • Author(s): Roland Stigge
  • Date: 2012-04-06 14:39:32 UTC
  • mfrom: (0.9.1) (1.1.8) (3.1.8 sid)
  • Revision ID: package-import@ubuntu.com-20120406143932-c41e1tscchjvoxth
Tags: 3.7.39.dfsg-1
New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*----------------------------------------------------------------------*/
 
2
/* svg.c                                                                */
 
3
/* Copyright (c) 2009  Tim Edwards, Open Circuit Design                 */
 
4
/*----------------------------------------------------------------------*/
 
5
 
 
6
#include <stdio.h>
 
7
#include <stdlib.h>
 
8
#include <string.h>
 
9
#ifndef XC_WIN32
 
10
#include <unistd.h>
 
11
#endif
 
12
#include <math.h>
 
13
#include <limits.h>
 
14
#include <sys/stat.h>
 
15
#ifndef XC_WIN32
 
16
#include <sys/wait.h>
 
17
#else
 
18
#include <process.h>
 
19
#endif
 
20
 
 
21
#ifndef _MSC_VER
 
22
#include <X11/Intrinsic.h>
 
23
#include <X11/StringDefs.h>
 
24
#endif
 
25
 
 
26
/*----------------------------------------------------------------------*/
 
27
/* Local includes                                                       */
 
28
/*----------------------------------------------------------------------*/
 
29
 
 
30
#ifdef TCL_WRAPPER 
 
31
#include <tk.h>
 
32
#endif
 
33
 
 
34
#include "colordefs.h"
 
35
#include "xcircuit.h"
 
36
 
 
37
/*----------------------------------------------------------------------*/
 
38
/* Function prototype declarations                                      */
 
39
/*----------------------------------------------------------------------*/
 
40
#include "prototypes.h"
 
41
 
 
42
void SVGDrawString(labelptr, int, objinstptr);
 
43
 
 
44
/*----------------------------------------------------------------------*/
 
45
/* External Variable definitions                                        */
 
46
/*----------------------------------------------------------------------*/
 
47
 
 
48
extern Display *dpy;
 
49
extern Pixmap STIPPLE[8];
 
50
extern XCWindowData *areawin;
 
51
extern Globaldata xobjs;
 
52
extern int *appcolors;
 
53
extern colorindex *colorlist;
 
54
extern int number_colors;
 
55
extern fontinfo *fonts;
 
56
extern short fontcount;
 
57
 
 
58
/*----------------------------------------------------------------------*/
 
59
/* The output file is a global variable used by all routines.           */
 
60
/*----------------------------------------------------------------------*/
 
61
 
 
62
FILE *svgf;
 
63
 
 
64
/*----------------------------------------------------------------------*/
 
65
/*----------------------------------------------------------------------*/
 
66
 
 
67
void svg_printcolor(int passcolor, char *prefix)
 
68
{
 
69
   int i;
 
70
   if (passcolor != DEFAULTCOLOR) {
 
71
      for (i = 0; i < number_colors; i++) {
 
72
         if (colorlist[i].color.pixel == passcolor) break;
 
73
      }
 
74
      if (i < number_colors) {
 
75
         fprintf(svgf, "%s\"#%02x%02x%02x\" ",
 
76
                prefix,
 
77
                (colorlist[i].color.red >> 8),
 
78
                (colorlist[i].color.green >> 8),
 
79
                (colorlist[i].color.blue >> 8));
 
80
      }
 
81
   }
 
82
}
 
83
 
 
84
/*----------------------------------------------------------------------*/
 
85
/* Since we can't do stipples in SVG, and since the whole stipple thing */
 
86
/* was only put in because we can't (easily) do transparency effects    */
 
87
/* in X11, we convert stipples to transparency when the stipple is a    */
 
88
/* mask, and do a color blend with white when the stipple is opaque.    */
 
89
/*                                                                      */
 
90
/* Blend amount is 1 (almost original color) to 7 (almost white)        */
 
91
/*----------------------------------------------------------------------*/
 
92
 
 
93
void svg_blendcolor(int passcolor, char *prefix, int amount)
 
94
{
 
95
   int i, bred, bgreen, bblue;
 
96
 
 
97
   if (passcolor != DEFAULTCOLOR) {
 
98
      for (i = 0; i < number_colors; i++) {
 
99
         if (colorlist[i].color.pixel == passcolor) break;
 
100
      }
 
101
      if (i < number_colors) {
 
102
         bred = colorlist[i].color.red >> 8;
 
103
         bgreen = colorlist[i].color.green >> 8;
 
104
         bblue = colorlist[i].color.blue >> 8;
 
105
      }
 
106
   }
 
107
   else {
 
108
         bred = bgreen = bblue = 0;
 
109
   }
 
110
   bred = ((bred * amount) + (255 * (8 - amount))) >> 3;
 
111
   bgreen = ((bgreen * amount) + (255 * (8 - amount))) >> 3;
 
112
   bblue = ((bblue * amount) + (255 * (8 - amount))) >> 3;
 
113
 
 
114
   fprintf(svgf, "%s\"#%02x%02x%02x\" ", prefix, bred, bgreen, bblue);
 
115
}
 
116
 
 
117
/*----------------------------------------------------------------------*/
 
118
/* Fill and/or draw a border around an element                          */
 
119
/*----------------------------------------------------------------------*/
 
120
 
 
121
void svg_stroke(int passcolor, short style, float width)
 
122
{
 
123
   float        tmpwidth;
 
124
   short        minwidth, solidpart, shade;
 
125
 
 
126
   tmpwidth = UTopTransScale(xobjs.pagelist[areawin->page]->wirewidth * width);
 
127
   minwidth = max(1, (short)tmpwidth);
 
128
 
 
129
   if (style & FILLED || (!(style & FILLED) && style & OPAQUE)) {
 
130
      if ((style & FILLSOLID) == FILLSOLID) {
 
131
         svg_printcolor(passcolor, "fill=");
 
132
      }
 
133
      else if (!(style & FILLED)) {
 
134
         fprintf(svgf, "fill=\"white\" ");
 
135
      }
 
136
      else {
 
137
         shade = 1 + ((style & FILLSOLID) >> 5);
 
138
         if (style & OPAQUE) {
 
139
            svg_blendcolor(passcolor, "fill=", shade);
 
140
         }
 
141
         else {
 
142
            svg_printcolor(passcolor, "fill=");
 
143
            fprintf(svgf, "fill-opacity=\"%g\" ", (float)shade / 8);
 
144
         }
 
145
      }
 
146
   }
 
147
   else
 
148
      fprintf(svgf, "fill=\"none\" ");
 
149
 
 
150
   if (!(style & NOBORDER)) {
 
151
      /* set up dots or dashes */
 
152
      if (style & DASHED) solidpart = 4 * minwidth;
 
153
      else if (style & DOTTED) solidpart = minwidth;
 
154
      if (style & (DASHED | DOTTED)) {
 
155
         fprintf(svgf, "style=\"stroke-dasharray:%d,%d\" ", solidpart, 4 * minwidth);
 
156
 
 
157
         fprintf(svgf, "stroke-width=\"%g\" ", tmpwidth);
 
158
         fprintf(svgf, "stroke-linecap=\"butt\" ");
 
159
         if (style & SQUARECAP)
 
160
            fprintf(svgf, "stroke-linejoin=\"miter\" ");
 
161
         else
 
162
            fprintf(svgf, "stroke-linejoin=\"bevel\" ");
 
163
      }
 
164
      else {
 
165
         fprintf(svgf, "stroke-width=\"%g\" ", tmpwidth);
 
166
         if (style & SQUARECAP) {
 
167
            fprintf(svgf, "stroke-linejoin=\"miter\" ");
 
168
            fprintf(svgf, "stroke-linecap=\"projecting\" ");
 
169
         }
 
170
         else {
 
171
            fprintf(svgf, "stroke-linejoin=\"bevel\" ");
 
172
            fprintf(svgf, "stroke-linecap=\"round\" ");
 
173
         }
 
174
      }
 
175
      svg_printcolor(passcolor, "stroke=");
 
176
   }
 
177
   else
 
178
      fprintf(svgf, "stroke=\"none\" ");
 
179
   fprintf(svgf, "/>\n");
 
180
}
 
181
 
 
182
/*----------------------------------------------------------------------*/
 
183
/* Finish a path and fill and/or stroke                                 */
 
184
/*----------------------------------------------------------------------*/
 
185
 
 
186
void svg_strokepath(int passcolor, short style, float width)
 
187
{
 
188
   /* Finish the path, closing if necessary */
 
189
   if (!(style & UNCLOSED))
 
190
      fprintf(svgf, "z\" ");
 
191
   else
 
192
      fprintf(svgf, "\" ");
 
193
 
 
194
   svg_stroke(passcolor, style, width);
 
195
}
 
196
 
 
197
/*-------------------------------------------------------------------------*/
 
198
 
 
199
void SVGCreateImages(int page)
 
200
{
 
201
    Imagedata *img;
 
202
    int i, x, y;
 
203
    short *glist;
 
204
    FILE *ppf;
 
205
    union {
 
206
       u_char b[4];
 
207
       u_long i;
 
208
    } pixel;
 
209
    char *fname, outname[128], *pptr;
 
210
#ifndef XC_WIN32
 
211
    pid_t pid;
 
212
#endif
 
213
 
 
214
    /* Check which images are used on this page */
 
215
    glist = (short *)malloc(xobjs.images * sizeof(short));
 
216
    for (i = 0; i < xobjs.images; i++) glist[i] = 0;
 
217
    count_graphics(xobjs.pagelist[page]->pageinst->thisobject, glist);
 
218
 
 
219
    for (i = 0; i < xobjs.images; i++) {
 
220
       if (glist[i] == 0) continue;
 
221
       img = xobjs.imagelist + i;
 
222
 
 
223
       /* Generate a PPM file, then convert it to PNG */
 
224
 
 
225
       fname = tmpnam(NULL);
 
226
       ppf = fopen(fname, "w");
 
227
       if (ppf != NULL) {
 
228
          fprintf(ppf, "P6 %d %d 255\n", img->image->width, img->image->height);
 
229
          for (y = 0; y < img->image->height; y++) {
 
230
             for (x = 0; x < img->image->width; x++) {
 
231
                pixel.i = XGetPixel(img->image, x, y);
 
232
                fwrite(&pixel.b[2], 1, 1, ppf);
 
233
                fwrite(&pixel.b[1], 1, 1, ppf);
 
234
                fwrite(&pixel.b[0], 1, 1, ppf);
 
235
             }
 
236
          }
 
237
       }
 
238
       fclose(ppf);
 
239
 
 
240
       /* Run "convert" to make this into a png file */
 
241
 
 
242
       strcpy(outname, img->filename);
 
243
       if ((pptr = strrchr(outname, '.')) != NULL)
 
244
          strcpy(pptr, ".png");
 
245
       else
 
246
          strcat(outname, ".png");
 
247
 
 
248
#ifndef XC_WIN32
 
249
       if ((pid = vfork()) == 0) {
 
250
          execlp("convert", "convert", fname, outname, NULL);
 
251
          exit(0);      /* not reached */
 
252
       }
 
253
       waitpid(pid, NULL, 0);
 
254
       unlink(fname);
 
255
#else
 
256
       _spawnl(_P_WAIT, GM_EXEC, GM_EXEC, "convert", fname, outname, NULL);
 
257
       _unlink(fname);
 
258
#endif
 
259
 
 
260
       Fprintf(stdout, "Generated standalone PNG image file %s\n", outname);
 
261
    }
 
262
    free(glist);
 
263
}
 
264
 
 
265
/*-------------------------------------------------------------------------*/
 
266
 
 
267
void SVGDrawGraphic(graphicptr gp)
 
268
{
 
269
    XPoint ppt, corner;
 
270
    Imagedata *img;
 
271
    int i;
 
272
    char outname[128], *pptr;
 
273
    float tscale;
 
274
    int rotation;
 
275
 
 
276
    for (i = 0; i < xobjs.images; i++) {
 
277
       img = xobjs.imagelist + i;
 
278
       if (img->image == gp->source)
 
279
          break;
 
280
    }
 
281
    if (i == xobjs.images) return;
 
282
 
 
283
    strcpy(outname, img->filename);
 
284
    if ((pptr = strrchr(outname, '.')) != NULL)
 
285
       strcpy(pptr, ".png");
 
286
    else
 
287
       strcat(outname, ".png");
 
288
 
 
289
    UPushCTM();
 
290
    UPreMultCTM(DCTM, gp->position, gp->scale, gp->rotation);
 
291
    corner.x = -(gp->source->width >> 1);
 
292
    corner.y = (gp->source->height >> 1);
 
293
    UTransformbyCTM(DCTM, &corner, &ppt, 1);
 
294
    UPopCTM();
 
295
 
 
296
    tscale = gp->scale * UTopScale();
 
297
    rotation = gp->rotation + UTopRotation();
 
298
    if (rotation >= 360) rotation -= 360;
 
299
    else if (rotation < 0) rotation += 360;
 
300
    
 
301
    fprintf(svgf, "<image transform=\"translate(%d,%d) scale(%g) rotate(%d)\"\n",
 
302
                        ppt.x, ppt.y, tscale, rotation);
 
303
    fprintf(svgf, "  width=\"%dpx\" height=\"%dpx\"",
 
304
                        gp->source->width, gp->source->height);
 
305
    fprintf(svgf, " xlink:href=\"%s\">\n", outname);
 
306
    fprintf(svgf, "</image>\n");
 
307
}
 
308
 
 
309
/*-------------------------------------------------------------------------*/
 
310
 
 
311
void SVGDrawSpline(splineptr thespline, int passcolor)
 
312
{
 
313
   XPoint       tmppoints[4];
 
314
 
 
315
   UTransformbyCTM(DCTM, thespline->ctrl, tmppoints, 4);
 
316
 
 
317
   fprintf(svgf, "<path d=\"M%d,%d C%d,%d %d,%d %d,%d ",
 
318
                tmppoints[0].x, tmppoints[0].y,
 
319
                tmppoints[1].x, tmppoints[1].y,
 
320
                tmppoints[2].x, tmppoints[2].y,
 
321
                tmppoints[3].x, tmppoints[3].y);
 
322
   svg_strokepath(passcolor, thespline->style, thespline->width);
 
323
}
 
324
 
 
325
/*-------------------------------------------------------------------------*/
 
326
 
 
327
void SVGDrawPolygon(polyptr thepoly, int passcolor)
 
328
{
 
329
   int i;
 
330
   XPoint *tmppoints = (pointlist) malloc(thepoly->number * sizeof(XPoint));
 
331
 
 
332
   UTransformbyCTM(DCTM, thepoly->points, tmppoints, thepoly->number);
 
333
   
 
334
   fprintf(svgf, "<path ");
 
335
   if (thepoly->style & BBOX) fprintf(svgf, "visibility=\"hidden\" ");
 
336
   fprintf(svgf, "d=\"M%d,%d L", tmppoints[0].x, tmppoints[0].y);
 
337
   for (i = 1; i < thepoly->number; i++) {
 
338
      fprintf(svgf, "%d,%d ", tmppoints[i].x, tmppoints[i].y);
 
339
   }
 
340
 
 
341
   svg_strokepath(passcolor, thepoly->style, thepoly->width);
 
342
   free(tmppoints);
 
343
}
 
344
 
 
345
/*-------------------------------------------------------------------------*/
 
346
 
 
347
void SVGDrawArc(arcptr thearc, int passcolor)
 
348
{
 
349
   XPoint  endpoints[2];
 
350
   int     radius[2];
 
351
   int     tarc;
 
352
 
 
353
   radius[0] = UTopTransScale(thearc->radius);
 
354
   radius[1] = UTopTransScale(thearc->yaxis);
 
355
 
 
356
   tarc = (thearc->angle2 - thearc->angle1);
 
357
   if (tarc == 360) {
 
358
      UTransformbyCTM(DCTM, &(thearc->position), endpoints, 1);
 
359
      fprintf(svgf, "<ellipse cx=\"%d\" cy=\"%d\" rx=\"%d\" ry=\"%d\" ",
 
360
                endpoints[0].x, endpoints[0].y, radius[0], radius[1]);
 
361
      svg_stroke(passcolor, thearc->style, thearc->width);
 
362
   }
 
363
   else {
 
364
      UfTransformbyCTM(DCTM, thearc->points, endpoints, 1);
 
365
      UfTransformbyCTM(DCTM, thearc->points + thearc->number - 1, endpoints + 1, 1);
 
366
 
 
367
      /* When any arc is flipped, the direction of travel reverses. */
 
368
      fprintf(svgf, "<path d=\"M%d,%d A%d,%d 0 %d,%d %d,%d ",
 
369
                endpoints[0].x, endpoints[0].y,
 
370
                radius[0], radius[1],
 
371
                ((tarc > 180) ? 1 : 0),
 
372
                (((DCTM->a * DCTM->e) >= 0) ? 1 : 0),
 
373
                endpoints[1].x, endpoints[1].y);
 
374
      svg_strokepath(passcolor, thearc->style, thearc->width);
 
375
   }
 
376
}
 
377
 
 
378
/*-------------------------------------------------------------------------*/
 
379
 
 
380
void SVGDrawPath(pathptr thepath, int passcolor)
 
381
{
 
382
   XPoint       *tmppoints = (pointlist) malloc(sizeof(XPoint));
 
383
   genericptr   *genpath;
 
384
   polyptr      thepoly;
 
385
   splineptr    thespline;
 
386
   int          i, firstpt = 1;
 
387
   
 
388
   fprintf(svgf, "<path d=\"");
 
389
 
 
390
   for (genpath = thepath->plist; genpath < thepath->plist + thepath->parts;
 
391
          genpath++) {
 
392
      switch(ELEMENTTYPE(*genpath)) {
 
393
         case POLYGON:
 
394
            thepoly = TOPOLY(genpath);
 
395
            tmppoints = (pointlist) realloc(tmppoints, thepoly->number * sizeof(XPoint));
 
396
            UTransformbyCTM(DCTM, thepoly->points, tmppoints, thepoly->number);
 
397
            if (firstpt) {
 
398
               fprintf(svgf, "M%d,%d ", tmppoints[0].x, tmppoints[0].y);
 
399
               firstpt = 0;
 
400
            }
 
401
            fprintf(svgf, "L");
 
402
            for (i = 1; i < thepoly->number; i++) {
 
403
               fprintf(svgf, "%d,%d ", tmppoints[i].x, tmppoints[i].y);
 
404
            }
 
405
            break;
 
406
         case SPLINE:
 
407
            thespline = TOSPLINE(genpath);
 
408
            tmppoints = (pointlist) realloc(tmppoints, 4 * sizeof(XPoint));
 
409
            UTransformbyCTM(DCTM, thespline->ctrl, tmppoints, 4);
 
410
            if (firstpt) {
 
411
               fprintf(svgf, "M%d,%d ", tmppoints[0].x, tmppoints[0].y);
 
412
               firstpt = 0;
 
413
            }
 
414
            fprintf(svgf, "C%d,%d %d,%d %d,%d ",
 
415
                tmppoints[1].x, tmppoints[1].y,
 
416
                tmppoints[2].x, tmppoints[2].y,
 
417
                tmppoints[3].x, tmppoints[3].y);
 
418
            break;
 
419
      }
 
420
   } 
 
421
   svg_strokepath(passcolor, thepath->style, thepath->width);
 
422
   free(tmppoints);
 
423
}
 
424
 
 
425
/*----------------------------------------------------------------------*/
 
426
/* Main recursive object instance drawing routine.                      */
 
427
/*    context is the instance information passed down from above        */
 
428
/*    theinstance is the object instance to be drawn                    */
 
429
/*    level is the level of recursion                                   */
 
430
/*    passcolor is the inherited color value passed to object           */
 
431
/*----------------------------------------------------------------------*/
 
432
 
 
433
void SVGDrawObject(objinstptr theinstance, short level, int passcolor, pushlistptr *stack)
 
434
{
 
435
   genericptr   *areagen;
 
436
   float        tmpwidth;
 
437
   int          defaultcolor = passcolor;
 
438
   int          curcolor = passcolor;
 
439
   int          thispart;
 
440
   objectptr    theobject = theinstance->thisobject;
 
441
 
 
442
   /* All parts are given in the coordinate system of the object, unless */
 
443
   /* this is the top-level object, in which they will be interpreted as */
 
444
   /* relative to the screen.                                            */
 
445
 
 
446
   UPushCTM();
 
447
 
 
448
   if (stack) push_stack(stack, theinstance, NULL);
 
449
   if (level != 0)
 
450
       UPreMultCTM(DCTM, theinstance->position, theinstance->scale,
 
451
                        theinstance->rotation);
 
452
 
 
453
   /* make parameter substitutions */
 
454
   psubstitute(theinstance);
 
455
 
 
456
   /* draw all of the elements */
 
457
   
 
458
   tmpwidth = UTopTransScale(xobjs.pagelist[areawin->page]->wirewidth);
 
459
 
 
460
   /* Here---set a default style using "g" like PostScript "gsave"      */
 
461
   /* stroke-width = tmpwidth, stroke = passcolor                       */
 
462
 
 
463
   /* guard against plist being regenerated during a redraw by the      */
 
464
   /* expression parameter mechanism (should that be prohibited?)       */
 
465
 
 
466
   for (thispart = 0; thispart < theobject->parts; thispart++) {
 
467
      areagen = theobject->plist + thispart;
 
468
      if ((*areagen)->type & DRAW_HIDE) continue;
 
469
 
 
470
      if (defaultcolor != DOFORALL) {
 
471
         if ((*areagen)->color != curcolor) {
 
472
            if ((*areagen)->color == DEFAULTCOLOR)
 
473
               curcolor = defaultcolor;
 
474
            else
 
475
               curcolor = (*areagen)->color;
 
476
         }
 
477
      }
 
478
 
 
479
      switch(ELEMENTTYPE(*areagen)) {
 
480
         case(POLYGON):
 
481
            if (level == 0 || !((TOPOLY(areagen))->style & BBOX))
 
482
               SVGDrawPolygon(TOPOLY(areagen), curcolor);
 
483
            break;
 
484
   
 
485
         case(SPLINE):
 
486
            SVGDrawSpline(TOSPLINE(areagen), curcolor);
 
487
            break;
 
488
   
 
489
         case(ARC):
 
490
            SVGDrawArc(TOARC(areagen), curcolor);
 
491
            break;
 
492
 
 
493
         case(PATH):
 
494
            SVGDrawPath(TOPATH(areagen), curcolor);
 
495
            break;
 
496
 
 
497
         case(GRAPHIC):
 
498
            SVGDrawGraphic(TOGRAPHIC(areagen));
 
499
            break;
 
500
   
 
501
         case(OBJINST):
 
502
            if (areawin->editinplace && stack && (TOOBJINST(areagen)
 
503
                        == areawin->topinstance)) {
 
504
               /* If stack matches areawin->stack, then don't   */
 
505
               /* draw because it would be redundant.            */
 
506
               pushlistptr alist = *stack, blist = areawin->stack;
 
507
               while (alist && blist) {
 
508
                  if (alist->thisinst != blist->thisinst) break;
 
509
                  alist = alist->next;
 
510
                  blist = blist->next;
 
511
               }
 
512
               if ((!alist) || (!blist)) break;
 
513
            }
 
514
            SVGDrawObject(TOOBJINST(areagen), level + 1, curcolor, stack);
 
515
            break;
 
516
   
 
517
          case(LABEL): 
 
518
            if (level == 0 || TOLABEL(areagen)->pin == False ||
 
519
                        (TOLABEL(areagen)->justify & PINVISIBLE))
 
520
            SVGDrawString(TOLABEL(areagen), curcolor, theinstance);
 
521
            break;
 
522
      }
 
523
   }
 
524
 
 
525
   UPopCTM();
 
526
   if (stack) pop_stack(stack);
 
527
}
 
528
 
 
529
/*----------------------------------------------------------------------*/
 
530
 
 
531
#define addlinepoint(pointlist, numvals, xval, yval) \
 
532
{  if (!numvals) pointlist = (XPoint *)malloc(sizeof(XPoint)); \
 
533
   else pointlist = (XPoint *)realloc(pointlist, (numvals + 1) * sizeof(XPoint)); \
 
534
   pointlist[numvals].x = xval; \
 
535
   pointlist[numvals++].y = -yval; \
 
536
}
 
537
 
 
538
/*----------------------------------------------------------------------*/
 
539
/* Draw an entire string, including parameter substitutions             */
 
540
/*----------------------------------------------------------------------*/
 
541
 
 
542
void SVGDrawString(labelptr drawlabel, int passcolor, objinstptr localinst)
 
543
{
 
544
   stringpart *strptr;
 
545
   char *textptr;
 
546
   short  fstyle, ffont, tmpjust, baseline, deltay;
 
547
   int    pos, defaultcolor, curcolor, scolor;
 
548
   short  oldx, oldfont, oldstyle;
 
549
   int olinerise = 4;
 
550
   float  tmpscale = 1.0, natscale = 1.0;
 
551
   XPoint newpoint;
 
552
   TextExtents tmpext;
 
553
   short *tabstops = NULL;
 
554
   short tabno, numtabs = 0, group = 0;
 
555
   int open_text, open_span, open_decor;
 
556
   XPoint *decorations = NULL;
 
557
   short nvals = 0;
 
558
 
 
559
   char *symbol_html_encoding[] = {
 
560
        " ", "!", "&#8704;", "#", "&#8707;", "%", "&", "?", "(", ")",
 
561
        "*", "+", ",", "&#8722;", ".", "/", "0", "1", "2", "3", "4",
 
562
        "5", "6", "7", "8", "9", ":", ";", "<", "=", ">", "?", "&#8773;",
 
563
        "&#913;", "&#914;", "&#935;", "&#916;", "&#917;", "&#934;",
 
564
        "&#915;", "&#919;", "&#921;", "&#977;", "&#922;", "&#923;",
 
565
        "&#924;", "&#925;", "&#927;", "&#928;", "&#920;", "&#929;",
 
566
        "&#931;", "&#932;", "&#933;", "&#963;", "&#937;", "&#926;",
 
567
        "&#936;", "&#918;", "[", "&#8756;", "]", "&#8869;", "_",
 
568
        "&#8254;", "&#945;", "&#946;", "&#967;", "&#948;", "&#949;",
 
569
        "&#966;", "&#947;", "&#951;", "&#953;", "&#966;", "&#954;",
 
570
        "&#955;", "&#956;", "&#957;", "&#959;", "&#960;", "&#952;",
 
571
        "&#961;", "&#963;", "&#964;", "&#965;", "&#969;", "&#969;",
 
572
        "&#958;", "&#968;", "&#950;", "{", "|", "}", "~", "", "", "",
 
573
        "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
 
574
        "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
 
575
        "&#978;", "&#8242;", "&#8804;", "&#8260;", "&#8734;", "&#402;",
 
576
        "&#9827;", "&#9830;", "&#9829;", "&#9824;", "&#8596;",
 
577
        "&#8592;", "&#8593;", "&#8594;", "&#8595;", "&#176;", "&#177;",
 
578
        "&#8243;", "&#8805;", "&#215;", "&#8733;", "&#8706;", "&#8226;",
 
579
        "&#247;", "&#8800;", "&#8801;", "&#8773;", "&#8230;"
 
580
   };
 
581
 
 
582
   /* Standard encoding vector, in HTML, from character 161 to 255 */
 
583
   u_int standard_html_encoding[] = {
 
584
        161, 162, 163, 8725, 165, 131, 167, 164, 146, 147, 171, 8249,
 
585
        8250, 64256, 64258, 0, 8211, 8224, 8225, 183, 0, 182, 8226,
 
586
        8218, 8222, 8221, 187, 8230, 8240, 0, 191, 0, 96, 180, 710,
 
587
        126, 713, 728, 729, 168, 0, 730, 184, 0, 733, 731, 711, 8212,
 
588
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 508, 0,
 
589
        170, 0, 0, 0, 0, 321, 216, 338, 186, 0, 0, 0, 0, 0, 230, 0,
 
590
        0, 0, 185, 0, 0, 322, 248, 339, 223};
 
591
 
 
592
   if (fontcount == 0) return;
 
593
 
 
594
   /* Don't draw temporary labels from schematic capture system */
 
595
   if (drawlabel->string->type != FONT_NAME) return;
 
596
 
 
597
   if (passcolor == DOSUBSTRING)
 
598
      defaultcolor = curcolor = drawlabel->color;
 
599
   else
 
600
      defaultcolor = curcolor = passcolor;
 
601
 
 
602
   if (defaultcolor != DOFORALL) {
 
603
      if (drawlabel->color != DEFAULTCOLOR)
 
604
         curcolor = drawlabel->color;
 
605
      else
 
606
         curcolor = defaultcolor;
 
607
   }
 
608
 
 
609
   /* calculate the transformation matrix for this object */
 
610
   /* in natural units of the alphabet vectors            */
 
611
   /* (conversion to window units)                        */
 
612
 
 
613
   /* Labels don't rotate in Firefox, so use <g> record for transform */
 
614
 
 
615
   UPushCTM();
 
616
   UPreMultCTM(DCTM, drawlabel->position, drawlabel->scale, drawlabel->rotation);
 
617
 
 
618
   /* check for flip invariance; recompute CTM and justification if necessary */
 
619
   tmpjust = flipadjust(drawlabel->justify);
 
620
 
 
621
   /* Note that the Y-scale is inverted or text comes out upside-down.  But we  */
 
622
   /* need to adjust to the Y baseline.                                         */
 
623
 
 
624
   fprintf(svgf, "<g transform=\"matrix(%4g %4g %4g %4g %3g %3g)\" ",
 
625
        DCTM->a, DCTM->d, -(DCTM->b), -(DCTM->e), DCTM->c, DCTM->f);
 
626
 
 
627
   svg_printcolor(passcolor, "fill=");
 
628
   fprintf(svgf, ">\n");
 
629
 
 
630
   /* "natural" (unscaled) length */
 
631
   tmpext = ULength(drawlabel, localinst, 0, NULL);
 
632
 
 
633
   newpoint.x = (tmpjust & NOTLEFT ?
 
634
       (tmpjust & RIGHT ? -tmpext.width : -tmpext.width >> 1) : 0);
 
635
   newpoint.y = (tmpjust & NOTBOTTOM ?
 
636
       (tmpjust & TOP ? -tmpext.ascent : -(tmpext.ascent + tmpext.base) >> 1)
 
637
                : -tmpext.base);
 
638
 
 
639
   /* Pinlabels have an additional offset spacing to pad */
 
640
   /* them from the circuit point to which they attach.  */
 
641
 
 
642
   if (drawlabel->pin) {
 
643
      pinadjust(tmpjust, &(newpoint.x), &(newpoint.y), 1);
 
644
   }
 
645
 
 
646
   oldx = newpoint.x;
 
647
   baseline = newpoint.y;
 
648
 
 
649
   open_text = -1;
 
650
   open_span = 0;
 
651
   open_decor = 0;
 
652
   pos = 0;
 
653
   for (strptr = drawlabel->string; strptr != NULL;
 
654
                strptr = nextstringpart(strptr, localinst)) {
 
655
 
 
656
      /* All segments other than text cancel any        */
 
657
      /* existing overline/underline in effect.         */
 
658
 
 
659
      if (strptr->type != TEXT_STRING)
 
660
         fstyle &= 0xfc7;
 
661
 
 
662
      switch(strptr->type) {
 
663
         case RETURN:
 
664
            while (open_span > 0) {
 
665
               fprintf(svgf, "</tspan>");
 
666
               open_span--;
 
667
            }
 
668
            while (open_text > 0) {
 
669
               fprintf(svgf, "</text>");
 
670
               open_text--;
 
671
            }
 
672
            if (open_decor) {
 
673
               addlinepoint(decorations, nvals, newpoint.x, group);
 
674
               open_decor--;
 
675
            }
 
676
            break;
 
677
 
 
678
         case FONT_SCALE:
 
679
         case FONT_NAME:
 
680
            while (open_span > 0) {
 
681
               fprintf(svgf, "</tspan>");
 
682
               open_span--;
 
683
            }
 
684
            while (open_text > 0) {
 
685
               fprintf(svgf, "</text>");
 
686
               open_text--;
 
687
            }
 
688
            if (open_decor) {
 
689
               addlinepoint(decorations, nvals, newpoint.x, group);
 
690
               open_decor--;
 
691
            }
 
692
            break;
 
693
 
 
694
         case KERN:
 
695
         case TABFORWARD:
 
696
         case TABBACKWARD:
 
697
         case TABSTOP:
 
698
         case HALFSPACE:
 
699
         case QTRSPACE:
 
700
         case NOLINE:
 
701
         case UNDERLINE:
 
702
         case OVERLINE:
 
703
         case SUBSCRIPT:
 
704
         case SUPERSCRIPT:
 
705
         case NORMALSCRIPT:
 
706
            while (open_span > 1) {
 
707
               fprintf(svgf, "</tspan>");
 
708
               open_span--;
 
709
            }
 
710
            if (open_decor) {
 
711
               addlinepoint(decorations, nvals, newpoint.x, group);
 
712
               open_decor--;
 
713
            }
 
714
            break;
 
715
 
 
716
         /* These do not need to be handled */
 
717
         case TEXT_STRING:
 
718
         case PARAM_START:
 
719
         case PARAM_END:
 
720
            break;
 
721
 
 
722
         /* These are not handled yet, but should be */
 
723
         case FONT_COLOR:
 
724
            break;
 
725
 
 
726
         default:
 
727
            break;
 
728
      }
 
729
 
 
730
      /* deal with each text segment type */
 
731
 
 
732
      switch(strptr->type) {
 
733
         case FONT_SCALE:
 
734
         case FONT_NAME:
 
735
            if (strptr->data.font < fontcount) {
 
736
               ffont = strptr->data.font;
 
737
               fstyle = 0;                 /* style reset by font change */
 
738
               if (baseline == newpoint.y) {  /* set top-level font and style */
 
739
                  oldfont = ffont;
 
740
                  oldstyle = fstyle;
 
741
               }
 
742
            }
 
743
            fprintf(svgf, "<text stroke=\"none\" ");
 
744
            fprintf(svgf, "font-family=");
 
745
            if (issymbolfont(ffont))
 
746
                fprintf(svgf, "\"Times\" ");
 
747
            else if (!strncmp(fonts[ffont].family, "Times", 5))
 
748
                fprintf(svgf, "\"Times\" ");
 
749
            else
 
750
               fprintf(svgf, "\"%s\" ", fonts[ffont].family);
 
751
 
 
752
            if (fonts[ffont].flags & 0x1)
 
753
               fprintf(svgf, " font-weight=\"bold\" ");
 
754
            if (fonts[ffont].flags & 0x2) {
 
755
               if (issansfont(ffont))
 
756
                  fprintf(svgf, " font-style=\"oblique\" ");
 
757
               else
 
758
                  fprintf(svgf, " font-style=\"italic\" ");
 
759
            }
 
760
            olinerise = (issansfont(ffont)) ? 7 : 4;
 
761
                      
 
762
            if (strptr->type == FONT_SCALE) {
 
763
               tmpscale = natscale * strptr->data.scale;
 
764
               if (baseline == newpoint.y) /* reset top-level scale */
 
765
                  natscale = tmpscale;
 
766
            }
 
767
            else
 
768
               tmpscale = 1;
 
769
 
 
770
            /* Actual scale taken care of by transformation matrix */
 
771
            fprintf(svgf, "font-size=\"%g\" >", tmpscale * 40);
 
772
            fprintf(svgf, "<tspan x=\"%d\" y=\"%d\">", newpoint.x, -newpoint.y);
 
773
            open_text++;
 
774
            open_span++;
 
775
            break;
 
776
 
 
777
         case KERN:
 
778
            newpoint.x += strptr->data.kern[0];
 
779
            newpoint.y += strptr->data.kern[1];
 
780
            fprintf(svgf, "<text dx=\"%d\" dy=\"%d\">",
 
781
                        strptr->data.kern[0], strptr->data.kern[1]);
 
782
            open_text++;
 
783
            break;
 
784
                
 
785
         case FONT_COLOR:
 
786
            if (defaultcolor != DOFORALL) {
 
787
               if (strptr->data.color != DEFAULTCOLOR)
 
788
                  curcolor = colorlist[strptr->data.color].color.pixel;
 
789
               else {
 
790
                  curcolor = DEFAULTCOLOR;
 
791
               }
 
792
            }
 
793
            break;
 
794
 
 
795
         case TABBACKWARD:      /* find first tab value with x < xtotal */
 
796
            for (tabno = numtabs - 1; tabno >= 0; tabno--) {
 
797
               if (tabstops[tabno] < newpoint.x) {
 
798
                  newpoint.x = tabstops[tabno];
 
799
                  break;
 
800
               }
 
801
            }
 
802
            fprintf(svgf, "<tspan x=\"%d\">", newpoint.x);
 
803
            open_span++;
 
804
            break;
 
805
 
 
806
         case TABFORWARD:       /* find first tab value with x > xtotal */
 
807
            for (tabno = 0; tabno < numtabs; tabno++) {
 
808
               if (tabstops[tabno] > newpoint.x) {
 
809
                  newpoint.x = tabstops[tabno];
 
810
                  break;
 
811
               }
 
812
            }
 
813
            fprintf(svgf, "<tspan x=\"%d\">", newpoint.x);
 
814
            open_span++;
 
815
            break;
 
816
 
 
817
         case TABSTOP:
 
818
            numtabs++;
 
819
            if (tabstops == NULL) tabstops = (short *)malloc(sizeof(short));
 
820
            else tabstops = (short *)realloc(tabstops, numtabs * sizeof(short));
 
821
            tabstops[numtabs - 1] = newpoint.x;
 
822
            /* Force a tab at this point so that the output aligns      */
 
823
            /* to our computation of the position, not its own. */
 
824
            fprintf(svgf, "<tspan x=\"%d\">", newpoint.x);
 
825
            open_span++;
 
826
            break;
 
827
 
 
828
         case RETURN:
 
829
            tmpscale = natscale = 1.0;
 
830
            baseline -= BASELINE;
 
831
            newpoint.y = baseline;
 
832
            newpoint.x = oldx;
 
833
            fprintf(svgf, "<tspan x=\"%d\" y=\"%d\">", newpoint.x, -newpoint.y);
 
834
            open_span++;
 
835
            break;
 
836
        
 
837
         case SUBSCRIPT:
 
838
            natscale *= SUBSCALE; 
 
839
            tmpscale = natscale;
 
840
            deltay = (short)((TEXTHEIGHT >> 1) * natscale);
 
841
            newpoint.y -= deltay;
 
842
            fprintf(svgf, "<tspan dy=\"%d\" font-size=\"%g\">", deltay,
 
843
                        40 * natscale);
 
844
            open_span++;
 
845
            break;
 
846
 
 
847
         case SUPERSCRIPT:
 
848
            natscale *= SUBSCALE;
 
849
            tmpscale = natscale;
 
850
            deltay = (short)(TEXTHEIGHT * natscale);
 
851
            newpoint.y += deltay;
 
852
            fprintf(svgf, "<tspan dy=\"%d\" font-size=\"%g\">", -deltay,
 
853
                        40 * natscale);
 
854
            open_span++;
 
855
            break;
 
856
 
 
857
         case NORMALSCRIPT:
 
858
            tmpscale = natscale = 1.0;
 
859
            ffont = oldfont;    /* revert to top-level font and style */
 
860
            fstyle = oldstyle;
 
861
            newpoint.y = baseline;
 
862
            fprintf(svgf, "<tspan y=\"%d\">", baseline); 
 
863
            open_span++;
 
864
            break;
 
865
 
 
866
         case UNDERLINE:
 
867
            fstyle |= 8;
 
868
            group = newpoint.y - 6;
 
869
            addlinepoint(decorations, nvals, newpoint.x, group);
 
870
            open_decor++;
 
871
            break;
 
872
 
 
873
         case OVERLINE:
 
874
            if (strptr->nextpart != NULL && strptr->nextpart->type == TEXT_STRING) {
 
875
               objectptr charptr;
 
876
               int tmpheight;
 
877
 
 
878
               group = 0;
 
879
               for (textptr = strptr->nextpart->data.string;
 
880
                                textptr && *textptr != '\0'; textptr++) {
 
881
                  charptr = fonts[ffont].encoding[*(u_char *)textptr];
 
882
                  tmpheight = (int)((float)charptr->bbox.height
 
883
                                * fonts[ffont].scale);
 
884
                  if (group < tmpheight) group = (short)tmpheight;
 
885
               }
 
886
               fstyle |= 16;
 
887
               group += olinerise + newpoint.y;
 
888
               addlinepoint(decorations, nvals, newpoint.x, group);
 
889
            }
 
890
            open_decor++;
 
891
            break;
 
892
 
 
893
         case NOLINE:
 
894
            break;
 
895
 
 
896
         case HALFSPACE: case QTRSPACE: {
 
897
            short addx;
 
898
            objectptr drawchar = fonts[ffont].encoding[(u_char)32];
 
899
            addx = (drawchar->bbox.lowerleft.x + drawchar->bbox.width) *
 
900
                        fonts[ffont].scale;
 
901
            addx >>= ((strptr->type == HALFSPACE) ? 1 : 2);
 
902
            newpoint.x += addx;
 
903
            fprintf(svgf, "<tspan dx=\"%d\">", addx);
 
904
            open_span++;
 
905
 
 
906
            } break;
 
907
            
 
908
         case TEXT_STRING:
 
909
            textptr = strptr->data.string;
 
910
 
 
911
            if (issymbolfont(ffont)) {
 
912
               for (; *textptr != '\0'; textptr++)
 
913
                  if (((u_char)(*textptr) >= 32) && ((u_char)(*textptr) < 158))
 
914
                     fprintf(svgf, "%s", symbol_html_encoding[(*textptr) - 32]);
 
915
            }
 
916
            else {
 
917
               /* Handle "&" and non-ASCII characters in the text */
 
918
               if (isisolatin1(ffont)) {
 
919
                  for (; *textptr != '\0'; textptr++) {
 
920
                     if (*textptr == '&')
 
921
                        fprintf(svgf, "&amp;");
 
922
                     else if ((u_char)(*textptr) >= 128)
 
923
                        fprintf(svgf, "&#%d;", (int)((u_char)*textptr));
 
924
                     else if ((u_char)(*textptr) >= 32)
 
925
                        fprintf(svgf, "%c", *textptr);
 
926
                  }
 
927
               }
 
928
               else {
 
929
                  for (; *textptr != '\0'; textptr++) {
 
930
                     if (*textptr == '&')
 
931
                        fprintf(svgf, "&amp;");
 
932
                     else if ((u_char)(*textptr) >= 161)
 
933
                        fprintf(svgf, "&#%d;",
 
934
                                standard_html_encoding[(u_char)(*textptr)
 
935
                                - 161]);
 
936
                     else if ((u_char)(*textptr) >= 32 && (u_char)(*textptr) < 161)
 
937
                        fprintf(svgf, "%c", *textptr);
 
938
                  }
 
939
               }
 
940
            }
 
941
            pos--;
 
942
 
 
943
            /* Compute the new X position */
 
944
 
 
945
            for (textptr = strptr->data.string; *textptr != '\0'; textptr++) {
 
946
               objectptr drawchar = fonts[ffont].encoding[(u_char)(*textptr)];
 
947
               short addx = (drawchar->bbox.lowerleft.x + drawchar->bbox.width) *
 
948
                        fonts[ffont].scale;
 
949
               newpoint.x += addx;
 
950
            }
 
951
            break;
 
952
      }
 
953
      pos++;
 
954
   }
 
955
   while (open_span > 0) {
 
956
      fprintf(svgf, "</tspan>");
 
957
      open_span--;
 
958
   }
 
959
   while (open_text > 0) {
 
960
      fprintf(svgf, "</text>");
 
961
      open_text--;
 
962
   }
 
963
   fprintf(svgf, "\n</text>");
 
964
 
 
965
   UPopCTM();
 
966
 
 
967
   if (tabstops != NULL) free(tabstops);
 
968
 
 
969
   /* If there were decorations (underlines, overlines), generate them */
 
970
 
 
971
   if (decorations != NULL) {
 
972
      int i;
 
973
      if (open_decor) {
 
974
         addlinepoint(decorations, nvals, newpoint.x, group);
 
975
      }
 
976
      for (i = 0; i < nvals; i += 2) {
 
977
         fprintf(svgf, "\n<line stroke-width=\"2\" stroke-linecap=\"square\" "
 
978
                "x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%d\" />",
 
979
                decorations[i].x, decorations[i].y, decorations[i + 1].x,
 
980
                decorations[i + 1].y);
 
981
      }
 
982
      free(decorations);
 
983
   }
 
984
   fprintf(svgf, "</g>\n");
 
985
}
 
986
 
 
987
/*----------------------------------------------------------------------*/
 
988
/* Write the SVG file output                                            */
 
989
/*----------------------------------------------------------------------*/
 
990
 
 
991
#define PMARGIN 6               /* Pixel margin around drawing */
 
992
 
 
993
void
 
994
OutputSVG(char *filename, Boolean fullscale)
 
995
{
 
996
   short        savesel;
 
997
   objinstptr   pinst;
 
998
   int cstyle;
 
999
   float outwidth, outheight, cscale;
 
1000
 
 
1001
   svgf = fopen(filename, "w");
 
1002
   if (svgf == NULL) {
 
1003
      Fprintf(stderr, "Cannot open file %s for writing.\n", filename);
 
1004
      return;
 
1005
   }
 
1006
 
 
1007
   /* Generate external image files, if necessary */
 
1008
   SVGCreateImages(areawin->page);
 
1009
 
 
1010
   /* Save the number of selections and set it to zero while we do the  */
 
1011
   /* object drawing.                                                   */
 
1012
 
 
1013
   savesel = areawin->selects;
 
1014
   areawin->selects = 0;
 
1015
   pinst = xobjs.pagelist[areawin->page]->pageinst;
 
1016
 
 
1017
   UPushCTM();  /* Save the top-level graphics state */
 
1018
 
 
1019
   /* This is like UMakeWCTM()---it inverts the whole picture so that   */
 
1020
   /* The origin is at the top left, and all data points fit in a box   */
 
1021
   /* at (0, 0) to the object (width, height)                           */
 
1022
 
 
1023
   DCTM->a = 1.0;
 
1024
   DCTM->b = 0.0;
 
1025
   DCTM->c = -pinst->bbox.lowerleft.x;
 
1026
   DCTM->d = 0.0;
 
1027
   DCTM->e = -1.0;
 
1028
   DCTM->f = pinst->bbox.lowerleft.y + pinst->bbox.height;
 
1029
 
 
1030
   fprintf(svgf, "<svg xmlns=\"http://www.w3.org/2000/svg\"\n");
 
1031
   fprintf(svgf, "   xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n");
 
1032
   fprintf(svgf, "   version=\"1.1\"\n");
 
1033
   fprintf(svgf, "   id=\"%s\" ", pinst->thisobject->name);
 
1034
 
 
1035
   if (fullscale) {
 
1036
      fprintf(svgf, "width=\"100%%\" height=\"100%%\" ");
 
1037
   }
 
1038
   else {
 
1039
      cscale = getpsscale(xobjs.pagelist[areawin->page]->outscale, areawin->page);
 
1040
      cstyle = xobjs.pagelist[areawin->page]->coordstyle;
 
1041
 
 
1042
      outwidth = toplevelwidth(pinst, NULL) * cscale;
 
1043
      outwidth /= (cstyle == CM) ?  IN_CM_CONVERT : 72.0;
 
1044
      outheight = toplevelheight(pinst, NULL) * cscale;
 
1045
      outheight /= (cstyle == CM) ?  IN_CM_CONVERT : 72.0;
 
1046
 
 
1047
      /* Set display height to that specified in the output properties (in inches) */
 
1048
      fprintf(svgf, "width=\"%.3g%s\" height=\"%.3g%s\" ",
 
1049
                outwidth, (cstyle == CM) ? "cm" : "in",
 
1050
                outheight, (cstyle == CM) ? "cm" : "in");
 
1051
   }
 
1052
   fprintf(svgf, " viewBox=\"%d %d %d %d\">\n",
 
1053
                -PMARGIN, -PMARGIN, pinst->bbox.width + PMARGIN,
 
1054
                pinst->bbox.height + PMARGIN);
 
1055
 
 
1056
   fprintf(svgf, "<desc>\n");
 
1057
   fprintf(svgf, "XCircuit Version %2.1f\n", PROG_VERSION);
 
1058
   fprintf(svgf, "File \"%s\" Page %d\n", xobjs.pagelist[areawin->page]->filename,
 
1059
                areawin->page + 1); 
 
1060
   fprintf(svgf, "</desc>\n");
 
1061
 
 
1062
   /* Set default color to black */
 
1063
   fprintf(svgf, "<g stroke=\"black\">\n");
 
1064
 
 
1065
   if (areawin->hierstack) free_stack(&areawin->hierstack);
 
1066
   SVGDrawObject(areawin->topinstance, TOPLEVEL, FOREGROUND, &areawin->hierstack);
 
1067
   if (areawin->hierstack) free_stack(&areawin->hierstack);
 
1068
 
 
1069
   /* restore the selection list (if any) */
 
1070
   areawin->selects = savesel;
 
1071
 
 
1072
   fprintf(svgf, "</g>\n</svg>\n");
 
1073
   fclose(svgf);
 
1074
 
 
1075
   UPopCTM();   /* Restore the top-level graphics state */
 
1076
}
 
1077
 
 
1078
#ifdef TCL_WRAPPER 
 
1079
 
 
1080
/*----------------------------------------------------------------------*/
 
1081
/* The TCL command-line for the SVG file write routine.                 */
 
1082
/*----------------------------------------------------------------------*/
 
1083
 
 
1084
int xctcl_svg(ClientData clientData, Tcl_Interp *interp,
 
1085
        int objc, Tcl_Obj *CONST objv[])
 
1086
{
 
1087
   char filename[128], *pptr;
 
1088
   Boolean fullscale = 0;
 
1089
   int locobjc = objc;
 
1090
   char *lastarg;
 
1091
 
 
1092
   /* Argument "-full" forces full scale (not scaled per page output settings) */
 
1093
   if (objc > 1) {
 
1094
      lastarg = Tcl_GetString(objv[objc - 1]);
 
1095
      if (lastarg[0] == '-') {
 
1096
         if (!strncmp(lastarg + 1, "full", 4))
 
1097
            fullscale = 1;
 
1098
         else {
 
1099
            Tcl_SetResult(interp, "Unknown option.\n", NULL);
 
1100
            return TCL_ERROR;
 
1101
         }
 
1102
         locobjc--;
 
1103
      }
 
1104
   }
 
1105
 
 
1106
 
 
1107
   if (locobjc >= 2) {
 
1108
      /* If there is a non-option argument, use it for the output filename */
 
1109
      sprintf(filename, Tcl_GetString(objv[1]));
 
1110
   }
 
1111
   else if (xobjs.pagelist[areawin->page]->pageinst->thisobject->name == NULL)
 
1112
      sprintf(filename, xobjs.pagelist[areawin->page]->filename);
 
1113
   else
 
1114
      sprintf(filename, xobjs.pagelist[areawin->page]->pageinst->thisobject->name);
 
1115
 
 
1116
   pptr = strrchr(filename, '.');
 
1117
   if (pptr != NULL)
 
1118
      sprintf(pptr + 1, "svg");
 
1119
   else if (strcmp(filename + strlen(filename) - 3, "svg"))
 
1120
      strcat(filename, ".svg");
 
1121
 
 
1122
   OutputSVG(filename, fullscale);
 
1123
   Fprintf(stdout, "Saved page as SVG format file \"%s\"\n", filename);
 
1124
   return XcTagCallback(interp, objc, objv);
 
1125
}
 
1126
 
 
1127
#endif /* TCL_WRAPPER */
 
1128
 
 
1129
/*-------------------------------------------------------------------------*/