PLplot  5.15.0
svg.c
Go to the documentation of this file.
1 // November 8, 2006
2 //
3 // PLplot driver for SVG 1.1 (http://www.w3.org/Graphics/SVG/)
4 //
5 // Copyright (C) 2006 Hazen Babcock
6 //
7 // This file is part of PLplot.
8 //
9 // PLplot is free software; you can redistribute it and/or modify
10 // it under the terms of the GNU Library General Public License as published
11 // by the Free Software Foundation; either version 2 of the License, or
12 // (at your option) any later version.
13 //
14 // PLplot is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU Library General Public License for more details.
18 //
19 // You should have received a copy of the GNU Library General Public License
20 // along with PLplot; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 //
23 //
24 
25 //---------------------------------------------
26 // Header files, defines and local variables
27 // ---------------------------------------------
28 
29 #include <stdarg.h>
30 #include <math.h>
31 
32 // PLplot header files
33 
34 #include "plplotP.h"
35 #include "drivers.h"
36 
37 // constants
38 
39 #define SVG_Default_X 720
40 #define SVG_Default_Y 540
41 
42 #define POINTS_PER_INCH 72
43 
44 #define MAX_STRING_LEN 1000
45 
46 // This has been generated empirically by looking carefully at results from
47 // examples 1 and 2.
48 
49 #define FONT_SIZE_RATIO 1.34
50 #define FONT_SHIFT_RATIO 0.705
51 #define FONT_SHIFT_OFFSET 0.5
52 
53 // local variables
54 
55 PLDLLIMPEXP_DRIVER const char* plD_DEVICE_INFO_svg = "svg:Scalable Vector Graphics (SVG 1.1):1:svg:57:svg\n";
56 
57 static int already_warned = 0;
58 
59 static int text_clipping = 1;
60 static DrvOpt svg_options[] = { { "text_clipping", DRV_INT, &text_clipping, "Use text clipping (text_clipping=0|1)" } };
61 
62 typedef struct
63 {
64  short textClipping;
69  int svgIndent;
70  FILE *svgFile;
72  // char curColor[7];
73 } SVG;
74 
75 // font stuff
76 
77 // Debugging extras
78 
79 //-----------------------------------------------
80 // function declarations
81 // -----------------------------------------------
82 
83 // Functions for writing XML SVG tags to a file
84 
85 static void svg_open( SVG *, const char * );
86 static void svg_open_end( SVG * );
87 static void svg_attr_value( SVG *, const char *, const char * );
88 static void svg_attr_values( SVG *, const char *, const char *, ... );
89 static void svg_close( SVG *, const char * );
90 static void svg_general( SVG *, const char * );
91 static void svg_indent( SVG * );
92 static void svg_stroke_width( PLStream * );
93 static void svg_stroke_color( PLStream * );
94 static void svg_fill_color( PLStream * );
95 static void svg_fill_background_color( PLStream * );
96 static int svg_family_check( PLStream * );
97 
98 
99 // General
100 
101 static void poly_line( PLStream *, short *, short *, PLINT, short );
102 static void gradient( PLStream *, short *, short *, PLINT );
103 static void write_hex( FILE *, unsigned char );
104 static void write_unicode( FILE *, PLUNICODE );
105 static void specify_font( FILE *, PLUNICODE );
106 
107 // String processing
108 
109 static void proc_str( PLStream *, EscText * );
110 
111 // PLplot interface functions
112 
114 void plD_init_svg( PLStream * );
115 void plD_line_svg( PLStream *, short, short, short, short );
116 void plD_polyline_svg( PLStream *, short *, short *, PLINT );
117 void plD_eop_svg( PLStream * );
118 void plD_bop_svg( PLStream * );
119 void plD_tidy_svg( PLStream * );
120 void plD_state_svg( PLStream *, PLINT );
121 void plD_esc_svg( PLStream *, PLINT, void * );
122 
123 //--------------------------------------------------------------------------
124 // dispatch_init_init()
125 //
126 // Initialize device dispatch table
127 //--------------------------------------------------------------------------
128 
130 {
131 #ifndef ENABLE_DYNDRIVERS
132  pdt->pl_MenuStr = "Scalable Vector Graphics (SVG 1.1)";
133  pdt->pl_DevName = "svg";
134 #endif
136  pdt->pl_seq = 57;
140  pdt->pl_eop = (plD_eop_fp) plD_eop_svg;
141  pdt->pl_bop = (plD_bop_fp) plD_bop_svg;
144  pdt->pl_esc = (plD_esc_fp) plD_esc_svg;
145 }
146 
147 //--------------------------------------------------------------------------
148 // svg_init()
149 //
150 // Initialize device
151 //--------------------------------------------------------------------------
152 
154 {
155  SVG *aStream;
156 
157  pls->termin = 0; // not an interactive device
158  pls->color = 1; // supports color
159  pls->width = 1;
160  pls->verbose = 1;
161  pls->bytecnt = 0;
162  //pls->debug = 1;
163  pls->dev_text = 1; // handles text
164  pls->dev_unicode = 1; // wants text as unicode
165  pls->page = 0;
166  pls->dev_fill0 = 1; // driver generates solid fills
167  pls->dev_fill1 = 0; // Use PLplot core fallback for pattern fills
168  pls->dev_gradient = 1; // driver renders gradient
169 
170  pls->graphx = GRAPHICS_MODE;
171 
172  if ( !pls->colorset )
173  pls->color = 1;
174 
175  // Initialize family file info
176  plFamInit( pls );
177 
178  // Prompt for a file name if not already set
179  plOpenFile( pls );
180 // Allocate and initialize device-specific data
181 
182  if ( pls->dev != NULL )
183  free( (void *) pls->dev );
184 
185  pls->dev = calloc( 1, (size_t) sizeof ( SVG ) );
186  if ( pls->dev == NULL )
187  plexit( "plD_init_svg: Out of memory." );
188 
189  aStream = (SVG *) pls->dev;
190 
191  // Set the bounds for plotting in points (unit of 1/72 of an inch). Default is SVG_Default_X points x SVG_Default_Y points unless otherwise specified by plspage or -geometry option.
192 
193  if ( pls->xlength <= 0 || pls->ylength <= 0 )
194  {
195  aStream->canvasXSize = SVG_Default_X;
196  aStream->canvasYSize = SVG_Default_Y;
197  }
198  else
199  {
200  aStream->canvasXSize = pls->xlength;
201  aStream->canvasYSize = pls->ylength;
202  }
203  // Calculate ratio of (larger) internal PLplot coordinates to external
204  // coordinates used for svg file.
205  if ( aStream->canvasXSize > aStream->canvasYSize )
206  aStream->scale = (PLFLT) ( PIXELS_X - 1 ) / (PLFLT) aStream->canvasXSize;
207  else
208  aStream->scale = (PLFLT) PIXELS_Y / (PLFLT) aStream->canvasYSize;
209  plP_setphy( (PLINT) 0, (PLINT) ( aStream->scale * aStream->canvasXSize ), (PLINT) 0, (PLINT) ( aStream->scale * aStream->canvasYSize ) ); // Scaled points.
210 
211  plP_setpxl( aStream->scale * POINTS_PER_INCH / 25.4, aStream->scale * POINTS_PER_INCH / 25.4 ); // Scaled points/mm.
212 
213  aStream->svgFile = pls->OutFile;
214 
215  // Handle the text clipping option
216  plParseDrvOpts( svg_options );
217 
218  // Turn on text clipping if the user desires this
219  if ( text_clipping )
220  {
221  aStream->textClipping = 1;
222  }
223  aStream->textClipping = (short) text_clipping;
224 
225  aStream->svgIndent = 0;
226  aStream->gradient_index = 0;
227  svg_general( aStream, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" );
228  svg_general( aStream, "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n" );
229  svg_general( aStream, " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n" );
230 }
231 
232 //--------------------------------------------------------------------------
233 // svg_bop()
234 //
235 // Set up for the next page.
236 //--------------------------------------------------------------------------
237 
239 {
240  SVG *aStream;
241 
242  // Plot familying stuff. Not really understood, just copying gd.c
243  plGetFam( pls );
244 // n.b. pls->dev can change because of an indirect call to plD_init_svg
245 // from plGetFam if familying is enabled. Thus, wait to define aStream until
246 // now.
247  aStream = pls->dev;
248 
249  pls->famadv = 1;
250  pls->page++;
251  if ( svg_family_check( pls ) )
252  {
253  return;
254  }
255 
256  // write opening svg tag for the new page
257 
258  svg_open( aStream, "svg" );
259  svg_attr_value( aStream, "xmlns", "http://www.w3.org/2000/svg" );
260  svg_attr_value( aStream, "xmlns:xlink", "http://www.w3.org/1999/xlink" );
261  svg_attr_value( aStream, "version", "1.1" );
262  // svg_attr_values("width", "%dcm", (int)((double)canvasXSize/POINTS_PER_INCH * 2.54));
263  // svg_attr_values("height", "%dcm", (int)((double)canvasYSize/POINTS_PER_INCH * 2.54));
264  svg_attr_values( aStream, "width", "%dpt", aStream->canvasXSize );
265  svg_attr_values( aStream, "height", "%dpt", aStream->canvasYSize );
266  svg_attr_values( aStream, "viewBox", "%d %d %d %d", 0, 0, aStream->canvasXSize, aStream->canvasYSize );
267  svg_general( aStream, ">\n" );
268 
269  // set the background by drawing a rectangle that is the size of
270  // of the canvas and filling it with the background color.
271 
272  svg_open( aStream, "rect" );
273  svg_attr_values( aStream, "x", "%d", 0 );
274  svg_attr_values( aStream, "y", "%d", 0 );
275  svg_attr_values( aStream, "width", "%d", aStream->canvasXSize );
276  svg_attr_values( aStream, "height", "%d", aStream->canvasYSize );
277  svg_attr_value( aStream, "stroke", "none" );
279  svg_open_end( aStream );
280 
281  // invert the coordinate system so that PLplot graphs appear right side up
282 
283  svg_open( aStream, "g" );
284  svg_attr_values( aStream, "transform", "matrix(1 0 0 -1 0 %d)", aStream->canvasYSize );
285  svg_general( aStream, ">\n" );
286 }
287 
288 //--------------------------------------------------------------------------
289 // svg_line()
290 //
291 // Draw a line in the current color from (x1,y1) to (x2,y2).
292 //--------------------------------------------------------------------------
293 
294 void plD_line_svg( PLStream *pls, short x1a, short y1a, short x2a, short y2a )
295 {
296  SVG *aStream;
297 
298  aStream = pls->dev;
299 
300  if ( svg_family_check( pls ) )
301  {
302  return;
303  }
304  svg_open( aStream, "polyline" );
305  svg_stroke_width( pls );
306  svg_stroke_color( pls );
307  svg_attr_value( aStream, "fill", "none" );
308  // svg_attr_value(aStream, "shape-rendering", "crispEdges");
309  svg_attr_values( aStream, "points", "%r,%r %r,%r", (double) x1a / aStream->scale, (double) y1a / aStream->scale, (double) x2a / aStream->scale, (double) y2a / aStream->scale );
310  svg_open_end( aStream );
311 }
312 
313 //--------------------------------------------------------------------------
314 // svg_polyline()
315 //
316 // Draw a polyline in the current color.
317 //--------------------------------------------------------------------------
318 
319 void plD_polyline_svg( PLStream *pls, short *xa, short *ya, PLINT npts )
320 {
321  if ( svg_family_check( pls ) )
322  {
323  return;
324  }
325  poly_line( pls, xa, ya, npts, 0 );
326 }
327 
328 //--------------------------------------------------------------------------
329 // svg_eop()
330 //
331 // End of page
332 //--------------------------------------------------------------------------
333 
335 {
336  SVG *aStream;
337 
338  aStream = pls->dev;
339 
340  if ( svg_family_check( pls ) )
341  {
342  return;
343  }
344  // write the closing svg tag
345 
346  svg_close( aStream, "g" );
347  svg_close( aStream, "svg" );
348 }
349 
350 //--------------------------------------------------------------------------
351 // svg_tidy()
352 //
353 // Close graphics file or otherwise clean up.
354 //--------------------------------------------------------------------------
355 
357 {
358  if ( svg_family_check( pls ) )
359  {
360  return;
361  }
362  plCloseFile( pls );
363 }
364 
365 //--------------------------------------------------------------------------
366 // plD_state_svg()
367 //
368 // Handle change in PLStream state (color, pen width, fill attribute, etc).
369 //
370 // Nothing is done here because these attributes are aquired from
371 // PLStream for each element that is drawn.
372 //--------------------------------------------------------------------------
373 
375 {
376 }
377 
378 //--------------------------------------------------------------------------
379 // svg_esc()
380 //
381 // Escape function.
382 //--------------------------------------------------------------------------
383 
384 void plD_esc_svg( PLStream *pls, PLINT op, void *ptr )
385 {
386  if ( svg_family_check( pls ) )
387  {
388  return;
389  }
390  switch ( op )
391  {
392  case PLESC_FILL: // fill polygon
393  poly_line( pls, pls->dev_x, pls->dev_y, pls->dev_npts, 1 );
394  break;
395  case PLESC_GRADIENT: // render gradient inside polygon
396  gradient( pls, pls->dev_x, pls->dev_y, pls->dev_npts );
397  break;
398  case PLESC_HAS_TEXT: // render text
399  proc_str( pls, (EscText *) ptr );
400  break;
401  }
402 }
403 
404 //--------------------------------------------------------------------------
405 // poly_line()
406 //
407 // Handles drawing filled and unfilled polygons
408 //--------------------------------------------------------------------------
409 
410 void poly_line( PLStream *pls, short *xa, short *ya, PLINT npts, short fill )
411 {
412  int i;
413  SVG *aStream;
414 
415  aStream = pls->dev;
416 
417  svg_open( aStream, "polyline" );
418  if ( fill )
419  {
420  // Two adjacent regions will put non-zero width boundary strokes on top
421  // of each other on their common boundary. Thus, a stroke on the boundary
422  // of a filled region is generally a bad idea when the fill is partially
423  // opaque because the partial opacity of the two boundary strokes which
424  // are on top of each other will mutually interfere and produce a
425  // bad-looking result. On the other hand, for completely opaque fills
426  // a boundary stroke is a good idea since if it is of sufficient width
427  // it will keep the background from leaking through at the anti-aliased
428  // edges of filled regions that have a common boundary with other
429  // filled regions.
430  if ( pls->curcolor.a < 0.99 )
431  {
432  svg_attr_value( aStream, "stroke", "none" );
433  }
434  else
435  {
436  svg_stroke_width( pls );
437  svg_stroke_color( pls );
438  }
439  svg_fill_color( pls );
440  if ( pls->dev_eofill )
441  svg_attr_value( aStream, "fill-rule", "evenodd" );
442  else
443  svg_attr_value( aStream, "fill-rule", "nonzero" );
444  }
445  else
446  {
447  svg_stroke_width( pls );
448  svg_stroke_color( pls );
449  svg_attr_value( aStream, "fill", "none" );
450  }
451  //svg_attr_value(aStream, "shape-rendering", "crispEdges");
452  svg_indent( aStream );
453  fprintf( aStream->svgFile, "points=\"" );
454  for ( i = 0; i < npts; i++ )
455  {
456  fprintf( aStream->svgFile, "%.2f,%.2f ", (double) xa[i] / aStream->scale, (double) ya[i] / aStream->scale );
457  if ( ( ( i + 1 ) % 10 ) == 0 )
458  {
459  fprintf( aStream->svgFile, "\n" );
460  svg_indent( aStream );
461  }
462  }
463  fprintf( aStream->svgFile, "\"/>\n" );
464  aStream->svgIndent -= 2;
465 }
466 
467 //--------------------------------------------------------------------------
468 // gradient()
469 //
470 // Draws gradient
471 //--------------------------------------------------------------------------
472 
473 void gradient( PLStream *pls, short *xa, short *ya, PLINT npts )
474 {
475  int i;
476  // 27 should be the maximum needed below, but be generous.
477  char buffer[50];
478  SVG *aStream;
479 
480  aStream = pls->dev;
481 
482  svg_open( aStream, "g>" );
483  svg_open( aStream, "defs>" );
484  svg_open( aStream, "linearGradient" );
485  // Allows ~2^31 unique gradient id's, gradient_index incremented below.
486  sprintf( buffer, "MyGradient%010d", aStream->gradient_index );
487  svg_attr_value( aStream, "id", buffer );
488  svg_attr_value( aStream, "gradientUnits", "userSpaceOnUse" );
489  sprintf( buffer, "%.2f", pls->xgradient[0] / aStream->scale );
490  svg_attr_value( aStream, "x1", buffer );
491  sprintf( buffer, "%.2f", pls->ygradient[0] / aStream->scale );
492  svg_attr_value( aStream, "y1", buffer );
493  sprintf( buffer, "%.2f", pls->xgradient[1] / aStream->scale );
494  svg_attr_value( aStream, "x2", buffer );
495  sprintf( buffer, "%.2f", pls->ygradient[1] / aStream->scale );
496  svg_attr_value( aStream, "y2", buffer );
497  svg_general( aStream, ">\n" );
498 
499  for ( i = 0; i < pls->ncol1; i++ )
500  {
501  svg_indent( aStream );
502  fprintf( aStream->svgFile, "<stop offset=\"%.3f\" ",
503  (double) i / (double) ( pls->ncol1 - 1 ) );
504  fprintf( aStream->svgFile, "stop-color=\"#" );
505  write_hex( aStream->svgFile, pls->cmap1[i].r );
506  write_hex( aStream->svgFile, pls->cmap1[i].g );
507  write_hex( aStream->svgFile, pls->cmap1[i].b );
508  fprintf( aStream->svgFile, "\" " );
509  fprintf( aStream->svgFile, "stop-opacity=\"%.3f\"/>\n", pls->cmap1[i].a );
510  }
511 
512  svg_close( aStream, "linearGradient" );
513  svg_close( aStream, "defs" );
514  svg_open( aStream, "polyline" );
515  sprintf( buffer, "url(#MyGradient%010d)", aStream->gradient_index++ );
516  svg_attr_value( aStream, "fill", buffer );
517  svg_indent( aStream );
518  fprintf( aStream->svgFile, "points=\"" );
519  for ( i = 0; i < npts; i++ )
520  {
521  fprintf( aStream->svgFile, "%.2f,%.2f ", (double) xa[i] / aStream->scale, (double) ya[i] / aStream->scale );
522  if ( ( ( i + 1 ) % 10 ) == 0 )
523  {
524  fprintf( aStream->svgFile, "\n" );
525  svg_indent( aStream );
526  }
527  }
528  fprintf( aStream->svgFile, "\"/>\n" );
529  aStream->svgIndent -= 2;
530  svg_close( aStream, "g" );
531 }
532 
533 //--------------------------------------------------------------------------
534 // proc_str()
535 //
536 // Processes strings for display.
537 //
538 // NOTE:
539 //
540 // (1) This was tested on Firefox and Camino where it seemed to display
541 // text properly. However, it isn't obvious to me that these browsers
542 // conform to the specification. Basically the issue is that some of
543 // the text properties (i.e. dy) that you specify inside a tspan element
544 // remain in force until the end of the text element. It would seem to
545 // me that they should only apply inside the tspan tag. To get around
546 // this, and because it was easier anyway, I used what is essentially
547 // a list of tspan tags rather than a tree of tspan tags. Perhaps
548 // better described as a tree with one branch?
549 //
550 // (2) To deal with the some whitespace annoyances, the entire text
551 // element must be written on a single line. If there are lots of
552 // format characters then this line might end up being too long
553 // for some SVG implementations.
554 //
555 // (3) Text placement is not ideal. Vertical offset seems to be
556 // particularly troublesome.
557 //
558 // (4) See additional notes in specify_font re. to sans / serif
559 //
560 //--------------------------------------------------------------------------
561 
562 void proc_str( PLStream *pls, EscText *args )
563 {
564  char plplot_esc;
565  short i;
566  short totalTags = 1;
567  short ucs4Len = (short) args->unicode_array_len;
568  double ftHt, scaled_offset, scaled_ftHt;
569  PLUNICODE fci;
570  PLINT rcx[4], rcy[4];
571  static PLINT prev_rcx[4], prev_rcy[4];
572  PLFLT rotation, shear, stride, cos_rot, sin_rot, sin_shear, cos_shear;
573  PLFLT t[4];
574  int glyph_size, sum_glyph_size;
575  short if_write;
576  // PLFLT *t = args->xform;
577  PLUNICODE *ucs4 = args->unicode_array;
578  SVG *aStream;
579  PLFLT old_sscale, sscale, old_soffset, soffset, old_dup, ddup;
580  PLINT level;
581  PLINT same_clip;
582 
583  // check that we got unicode
584  if ( ucs4Len == 0 )
585  {
586  printf( "Non unicode string passed to SVG driver, ignoring\n" );
587  return;
588  }
589 
590  // get plplot escape character and the current font
591  plgesc( &plplot_esc );
592  plgfci( &fci );
593 
594  // determine the font height in points.
595  ftHt = FONT_SIZE_RATIO * pls->chrht * POINTS_PER_INCH / 25.4;
596 
597  // Setup & apply text clipping area if desired
598  aStream = (SVG *) pls->dev;
599  if ( aStream->textClipping )
600  {
601  // Use PLplot core routine difilt_clip to appropriately
602  // transform the coordinates of the clipping rectangle
603  difilt_clip( rcx, rcy );
604  same_clip = TRUE;
605  if ( aStream->which_clip == 0 )
606  {
607  same_clip = FALSE;
608  }
609  else
610  {
611  for ( i = 0; i < 4; i++ )
612  {
613  if ( rcx[i] != prev_rcx[i] ||
614  rcy[i] != prev_rcy[i] )
615  same_clip = FALSE;
616  }
617  }
618  if ( !same_clip )
619  {
620  svg_open( aStream, "clipPath" );
621  svg_attr_values( aStream, "id", "text-clipping%d", aStream->which_clip );
622  svg_general( aStream, ">\n" );
623 
624  // Output a polygon to represent the clipping region.
625  svg_open( aStream, "polygon" );
626  svg_attr_values( aStream,
627  "points",
628  "%f,%f %f,%f %f,%f %f,%f",
629  ( (PLFLT) rcx[0] ) / aStream->scale,
630  ( (PLFLT) rcy[0] ) / aStream->scale,
631  ( (PLFLT) rcx[1] ) / aStream->scale,
632  ( (PLFLT) rcy[1] ) / aStream->scale,
633  ( (PLFLT) rcx[2] ) / aStream->scale,
634  ( (PLFLT) rcy[2] ) / aStream->scale,
635  ( (PLFLT) rcx[3] ) / aStream->scale,
636  ( (PLFLT) rcy[3] ) / aStream->scale );
637  svg_open_end( aStream );
638 
639  svg_close( aStream, "clipPath" );
640  for ( i = 0; i < 4; i++ )
641  {
642  prev_rcx[i] = rcx[i];
643  prev_rcy[i] = rcy[i];
644  }
645  aStream->which_clip++;
646  }
647  svg_open( aStream, "g" );
648  svg_attr_values( aStream, "clip-path",
649  "url(#text-clipping%d)", aStream->which_clip - 1 );
650  svg_general( aStream, ">\n" );
651  }
652 
653  // This draws the clipping region on the screen which can
654  // be very helpful for debugging.
655 
656  //
657  // svg_open(aStream, "polygon");
658  // svg_attr_values(aStream,
659  // "points",
660  // "%f,%f %f,%f %f,%f %f,%f",
661  // ((PLFLT)rcx[0])/aStream->scale,
662  // ((PLFLT)rcy[0])/aStream->scale,
663  // ((PLFLT)rcx[1])/aStream->scale,
664  // ((PLFLT)rcy[1])/aStream->scale,
665  // ((PLFLT)rcx[2])/aStream->scale,
666  // ((PLFLT)rcy[2])/aStream->scale,
667  // ((PLFLT)rcx[3])/aStream->scale,
668  // ((PLFLT)rcy[3])/aStream->scale);
669  // svg_stroke_width(pls);
670  // svg_stroke_color(pls);
671  // svg_attr_value(aStream, "fill", "none");
672  // svg_open_end(aStream);
673  //
674 
675  // Calculate the tranformation matrix for SVG based on the
676  // transformation matrix provided by PLplot.
677  plRotationShear( args->xform, &rotation, &shear, &stride );
678  // N.B. Experimentally, I (AWI) have found the svg rotation angle is
679  // the negative of the libcairo rotation angle, and the svg shear angle
680  // is pi minus the libcairo shear angle.
681  rotation -= pls->diorot * PI / 2.0;
682  cos_rot = cos( rotation );
683  sin_rot = -sin( rotation );
684  sin_shear = sin( shear );
685  cos_shear = -cos( shear );
686  t[0] = cos_rot * stride;
687  t[1] = -sin_rot * stride;
688  t[2] = cos_rot * sin_shear + sin_rot * cos_shear;
689  t[3] = -sin_rot * sin_shear + cos_rot * cos_shear;
690 
691  //--------------
692  // open text tag
693  // --------------
694 
695  svg_open( aStream, "text" );
696 
697  svg_attr_value( aStream, "dominant-baseline", "no-change" );
698 
699  // set font color
700  svg_fill_color( pls );
701 
702  // white space preserving mode
703  svg_attr_value( aStream, "xml:space", "preserve" );
704 
705  // set the font size
706  svg_attr_values( aStream, "font-size", "%d", (int) ftHt );
707 
708  // Apply coordinate transform for text display.
709  // The transformation also defines the location of the text in x and y.
710  svg_attr_values( aStream, "transform", "matrix(%f %f %f %f %f %f)",
711  t[0], t[1], t[2], t[3],
712  (double) ( args->x / aStream->scale ),
713  (double) ( args->y / aStream->scale ) );
714 
715 
716  //----------------------------------------------------------
717  // Write the text with formatting
718  // We just keep stacking up tspan tags, then close them all
719  // after we have written out all of the text.
720  // ----------------------------------------------------------
721 
722  // For if_write = 0, we write nothing and instead accumulate the
723  // sum_glyph_size from the fontsize of the individual glyphs which
724  // is then used to figure out the initial x position from text-anchor and
725  // args->just that is used to write out the SVG xml for if_write = 1.
726 
727  glyph_size = (int) ftHt;
728  sum_glyph_size = 0;
729  if_write = 0;
730  while ( if_write < 2 )
731  {
732  if ( if_write == 1 )
733  {
734  //printf("number of characters = %f\n", sum_glyph_size/ftHt);
735  // The above coordinate transform defines the _raw_ x position of the
736  // text without justification so this attribute value depends on
737  // text-anchor and args->just*sum_glyph_size
738  // N.B. sum_glyph_size calculation only correct for monospaced fonts
739  // so generally sum_glyph_size will be overestimated by various amounts
740  // depending on what glyphs are to be rendered, the font, etc. However,
741  // this correction is differential respect to the end points or the
742  // middle so you should be okay so long as you don't deviate too far
743  // from those anchor points.
744  if ( args->just < 0.33 )
745  {
746  svg_attr_value( aStream, "text-anchor", "start" ); // left justification
747  svg_attr_values( aStream, "x", "%f", (double) ( -args->just * sum_glyph_size ) );
748  }
749  else if ( args->just > 0.66 )
750  {
751  svg_attr_value( aStream, "text-anchor", "end" ); // right justification
752  svg_attr_values( aStream, "x", "%f", (double) ( ( 1. - args->just ) * sum_glyph_size ) );
753  }
754  else
755  {
756  svg_attr_value( aStream, "text-anchor", "middle" ); // center
757  svg_attr_values( aStream, "x", "%f", (double) ( ( 0.5 - args->just ) * sum_glyph_size ) );
758  }
759 
760  // The text goes at zero in y since the above
761  // coordinate transform defines the y position of the text
762  svg_attr_values( aStream, "y", "%f",
763  FONT_SHIFT_RATIO * 0.5 * ftHt +
765 
766  fprintf( aStream->svgFile, ">" );
767 
768  // specify the initial font
769  specify_font( aStream->svgFile, fci );
770  }
771  i = 0;
772  scaled_ftHt = ftHt;
773  level = 0;
774  ddup = 0.;
775  while ( i < ucs4Len )
776  {
777  if ( ucs4[i] < PL_FCI_MARK ) // not a font change
778  {
779  if ( ucs4[i] != (PLUNICODE) plplot_esc ) // a character to display
780  {
781  if ( if_write )
782  {
783  write_unicode( aStream->svgFile, ucs4[i] );
784  }
785  else
786  {
787  sum_glyph_size += glyph_size;
788  }
789  i++;
790  continue;
791  }
792  i++;
793  if ( ucs4[i] == (PLUNICODE) plplot_esc ) // a escape character to display
794  {
795  if ( if_write )
796  {
797  write_unicode( aStream->svgFile, ucs4[i] );
798  }
799  else
800  {
801  sum_glyph_size += glyph_size;
802  }
803  i++;
804  continue;
805  }
806  else
807  {
808  // super/subscript logic follows that in plstr routine (plsym.c)
809  // for Hershey fonts. Factor of FONT_SHIFT_RATIO*0.80 is empirical
810  // adjustment.
811  if ( ucs4[i] == (PLUNICODE) 'u' ) // Superscript
812  {
813  plP_script_scale( TRUE, &level,
814  &old_sscale, &sscale, &old_soffset, &soffset );
815  // The correction for the difference in magnitude
816  // between the baseline and middle coordinate systems
817  // for superscripts should be
818  // 0.5*(base font size - superscript/subscript font size).
819  old_dup = ddup;
820  ddup = 0.5 * ( 1.0 - sscale );
821  if ( level <= 0 )
822  {
823  scaled_offset = FONT_SHIFT_RATIO * ftHt * ( 0.80 * ( soffset - old_soffset ) - ( ddup - old_dup ) );
824  }
825  else
826  {
827  scaled_offset = -FONT_SHIFT_RATIO * ftHt * ( 0.80 * ( soffset - old_soffset ) + ( ddup - old_dup ) );
828  }
829  scaled_ftHt = sscale * ftHt;
830  if ( if_write )
831  {
832  totalTags++;
833  fprintf( aStream->svgFile, "<tspan dy=\"%f\" font-size=\"%d\">", scaled_offset, (int) scaled_ftHt );
834  }
835  else
836  {
837  glyph_size = (int) scaled_ftHt;
838  }
839  }
840  if ( ucs4[i] == (PLUNICODE) 'd' ) // Subscript
841  {
842  plP_script_scale( FALSE, &level,
843  &old_sscale, &sscale, &old_soffset, &soffset );
844  // The correction for the difference in magnitude
845  // between the baseline and middle coordinate systems
846  // for superscripts should be
847  // 0.5*(base font size - superscript/subscript font size).
848  old_dup = ddup;
849  ddup = 0.5 * ( 1.0 - sscale );
850  if ( level < 0 )
851  {
852  scaled_offset = FONT_SHIFT_RATIO * ftHt * ( 0.80 * ( soffset - old_soffset ) - ( ddup - old_dup ) );
853  }
854  else
855  {
856  scaled_offset = -FONT_SHIFT_RATIO * ftHt * ( 0.80 * ( soffset - old_soffset ) + ( ddup - old_dup ) );
857  }
858  scaled_ftHt = sscale * ftHt;
859  if ( if_write )
860  {
861  totalTags++;
862  fprintf( aStream->svgFile, "<tspan dy=\"%f\" font-size=\"%d\">", scaled_offset, (int) scaled_ftHt );
863  }
864  else
865  {
866  glyph_size = (int) scaled_ftHt;
867  }
868  }
869  i++;
870  }
871  }
872  else // a font change
873  {
874  if ( if_write )
875  {
876  specify_font( aStream->svgFile, ucs4[i] );
877  totalTags++;
878  }
879  i++;
880  }
881  }
882  if_write++;
883  }
884 
885  //----------------------------------------------
886  // close out all the tspan tags and the text tag
887  // ----------------------------------------------
888 
889  for ( i = 0; i < totalTags; i++ )
890  {
891  fprintf( aStream->svgFile, "</tspan>" );
892  }
893  // The following commented out (by AWI) because it is a bad idea to
894  // put line ends in the middle of a text tag. This was the key to
895  // all the text rendering issues we had.
896  //fprintf(svgFile,"\n");
897  // For the same reason use fprintf and svgIndent -= 2;
898  // to close the text tag rather than svg_close("text"); since
899  // we don't want indentation spaces entering the text.
900  // svg_close("text");
901  fprintf( aStream->svgFile, "</text>\n" );
902  aStream->svgIndent -= 2;
903  if ( aStream->textClipping )
904  {
905  svg_close( aStream, "g" );
906  }
907 }
908 
909 //--------------------------------------------------------------------------
910 // svg_open ()
911 //
912 // Used to open a new XML expression, sets the indent level appropriately
913 //--------------------------------------------------------------------------
914 
915 void svg_open( SVG *aStream, const char *tag )
916 {
917  svg_indent( aStream );
918  fprintf( aStream->svgFile, "<%s\n", tag );
919  aStream->svgIndent += 2;
920 }
921 
922 //--------------------------------------------------------------------------
923 // svg_open_end ()
924 //
925 // Used to end the opening of a new XML expression i.e. add
926 // the final ">".
927 //--------------------------------------------------------------------------
928 
929 void svg_open_end( SVG *aStream )
930 {
931  svg_indent( aStream );
932  fprintf( aStream->svgFile, "/>\n" );
933  aStream->svgIndent -= 2;
934 }
935 
936 //--------------------------------------------------------------------------
937 // svg_attr_value ()
938 //
939 // Prints two strings to svgFile as a XML attribute value pair
940 // i.e. foo="bar"
941 //--------------------------------------------------------------------------
942 
943 void svg_attr_value( SVG *aStream, const char *attribute, const char *value )
944 {
945  svg_indent( aStream );
946  fprintf( aStream->svgFile, "%s=\"%s\"\n", attribute, value );
947 }
948 
949 //--------------------------------------------------------------------------
950 // svg_attr_values ()
951 //
952 // Prints a string and a bunch of numbers / strings as a XML attribute
953 // value pair i.e. foo="0 10 1.0 5.3 bar"
954 //
955 // This function is derived from an example in
956 // "The C Programming Language" by Kernighan and Ritchie.
957 //
958 //--------------------------------------------------------------------------
959 
960 void svg_attr_values( SVG *aStream, const char *attribute, const char *format, ... )
961 {
962  va_list ap;
963  const char *p, *sval;
964  int ival;
965  double dval;
966 
967  svg_indent( aStream );
968  fprintf( aStream->svgFile, "%s=\"", attribute );
969  va_start( ap, format );
970  for ( p = format; *p; p++ )
971  {
972  if ( *p != '%' )
973  {
974  fprintf( aStream->svgFile, "%c", *p );
975  continue;
976  }
977  switch ( *++p )
978  {
979  case 'd':
980  ival = va_arg( ap, int );
981  fprintf( aStream->svgFile, "%d", ival );
982  break;
983  case 'f':
984  dval = va_arg( ap, double );
985  fprintf( aStream->svgFile, "%f", dval );
986  break;
987  case 'r':
988  // r is non-standard, but use it here to format rounded value
989  dval = va_arg( ap, double );
990  fprintf( aStream->svgFile, "%.2f", dval );
991  break;
992  case 's':
993  sval = va_arg( ap, char * );
994  fprintf( aStream->svgFile, "%s", sval );
995  break;
996  default:
997  fprintf( aStream->svgFile, "%c", *p );
998  break;
999  }
1000  }
1001  fprintf( aStream->svgFile, "\"\n" );
1002  va_end( ap );
1003 }
1004 
1005 //--------------------------------------------------------------------------
1006 // svg_close ()
1007 //
1008 // Used to close a XML expression, sets the indent level appropriately
1009 //--------------------------------------------------------------------------
1010 
1011 void svg_close( SVG *aStream, const char *tag )
1012 {
1013  aStream->svgIndent -= 2;
1014  svg_indent( aStream );
1015  if ( strlen( tag ) > 0 )
1016  {
1017  fprintf( aStream->svgFile, "</%s>\n", tag );
1018  }
1019  else
1020  {
1021  fprintf( aStream->svgFile, "/>\n" );
1022  }
1023 }
1024 
1025 //--------------------------------------------------------------------------
1026 // svg_general ()
1027 //
1028 // Used to print any text into the svgFile
1029 //--------------------------------------------------------------------------
1030 
1031 void svg_general( SVG *aStream, const char *text )
1032 {
1033  svg_indent( aStream );
1034  fprintf( aStream->svgFile, "%s", text );
1035 }
1036 
1037 //--------------------------------------------------------------------------
1038 // svg_indent ()
1039 //
1040 // Indents properly based on the current indent level
1041 //--------------------------------------------------------------------------
1042 
1043 void svg_indent( SVG *aStream )
1044 {
1045  short i;
1046  for ( i = 0; i < aStream->svgIndent; i++ )
1047  {
1048  fprintf( aStream->svgFile, " " );
1049  }
1050 }
1051 
1052 //--------------------------------------------------------------------------
1053 // svg_stroke_width ()
1054 //
1055 // sets the stroke width based on the current width
1056 //--------------------------------------------------------------------------
1057 
1059 {
1060  SVG *aStream;
1061 
1062  aStream = pls->dev;
1063  svg_indent( aStream );
1064  fprintf( aStream->svgFile, "stroke-width=\"%e\"\n", pls->width );
1065 }
1066 
1067 //--------------------------------------------------------------------------
1068 // svg_stroke_color ()
1069 //
1070 // sets the stroke color based on the current color
1071 //--------------------------------------------------------------------------
1072 
1074 {
1075  SVG *aStream;
1076 
1077  aStream = pls->dev;
1078  svg_indent( aStream );
1079  fprintf( aStream->svgFile, "stroke=\"#" );
1080  write_hex( aStream->svgFile, pls->curcolor.r );
1081  write_hex( aStream->svgFile, pls->curcolor.g );
1082  write_hex( aStream->svgFile, pls->curcolor.b );
1083  fprintf( aStream->svgFile, "\"\n" );
1084  svg_indent( aStream );
1085  fprintf( aStream->svgFile, "stroke-opacity=\"%f\"\n", pls->curcolor.a );
1086 }
1087 
1088 //--------------------------------------------------------------------------
1089 // svg_fill_color ()
1090 //
1091 // sets the fill color based on the current color
1092 //--------------------------------------------------------------------------
1093 
1095 {
1096  SVG *aStream;
1097 
1098  aStream = pls->dev;
1099  svg_indent( aStream );
1100  fprintf( aStream->svgFile, "fill=\"#" );
1101  write_hex( aStream->svgFile, pls->curcolor.r );
1102  write_hex( aStream->svgFile, pls->curcolor.g );
1103  write_hex( aStream->svgFile, pls->curcolor.b );
1104  fprintf( aStream->svgFile, "\"\n" );
1105  svg_indent( aStream );
1106  fprintf( aStream->svgFile, "fill-opacity=\"%f\"\n", pls->curcolor.a );
1107 }
1108 
1109 //--------------------------------------------------------------------------
1110 // svg_fill_background_color ()
1111 //
1112 // sets the background fill color based on the current background color
1113 //--------------------------------------------------------------------------
1114 
1116 {
1117  SVG *aStream;
1118 
1119  aStream = pls->dev;
1120  svg_indent( aStream );
1121  fprintf( aStream->svgFile, "fill=\"#" );
1122  write_hex( aStream->svgFile, pls->cmap0[0].r );
1123  write_hex( aStream->svgFile, pls->cmap0[0].g );
1124  write_hex( aStream->svgFile, pls->cmap0[0].b );
1125  fprintf( aStream->svgFile, "\"\n" );
1126  svg_indent( aStream );
1127  fprintf( aStream->svgFile, "fill-opacity=\"%f\"\n", pls->cmap0[0].a );
1128 }
1129 
1130 //--------------------------------------------------------------------------
1131 // svg_family_check ()
1132 //
1133 // support function to help supress more than one page if family file
1134 // output not specified by the user (e.g., with the -fam command-line option).
1135 //--------------------------------------------------------------------------
1136 
1138 {
1139  if ( pls->family || pls->page == 1 )
1140  {
1141  return 0;
1142  }
1143  else
1144  {
1145  if ( !already_warned )
1146  {
1147  already_warned = 1;
1148  plwarn( "All pages after the first skipped because family file output not specified.\n" );
1149  }
1150  return 1;
1151  }
1152 }
1153 
1154 //--------------------------------------------------------------------------
1155 // write_hex ()
1156 //
1157 // writes a unsigned char as an appropriately formatted hex value
1158 //--------------------------------------------------------------------------
1159 
1160 void write_hex( FILE *svgFile, unsigned char val )
1161 {
1162  if ( val < 16 )
1163  {
1164  fprintf( svgFile, "0%X", val );
1165  }
1166  else
1167  {
1168  fprintf( svgFile, "%X", val );
1169  }
1170 }
1171 
1172 //--------------------------------------------------------------------------
1173 // write_unicode ()
1174 //
1175 // writes a unicode character, appropriately formatted (i.e. &#xNNN)
1176 // with invalid xml characters replaced by ' '.
1177 //--------------------------------------------------------------------------
1178 
1179 void write_unicode( FILE *svgFile, PLUNICODE ucs4_char )
1180 {
1181  if ( ucs4_char >= ' ' || ucs4_char == '\t' || ucs4_char == '\n' || ucs4_char == '\r' )
1182  fprintf( svgFile, "&#x%x;", ucs4_char );
1183  else
1184  fprintf( svgFile, "&#x%x;", ' ' );
1185 }
1186 
1187 //--------------------------------------------------------------------------
1188 // specify_font ()
1189 //
1190 // Note:
1191 // We don't actually specify a font, just the fonts properties.
1192 // The hope is that this will give the display program the freedom
1193 // to choose the font with the glyphs that it needs to display
1194 // the text.
1195 //
1196 // Known Issues:
1197 // (1) On OS-X 10.4 with Firefox and Camino the "serif" font-family
1198 // looks more like the "italic" font-style.
1199 //
1200 //--------------------------------------------------------------------------
1201 
1202 void specify_font( FILE *svgFile, PLUNICODE ucs4_char )
1203 {
1204  fprintf( svgFile, "<tspan " );
1205 
1206  // sans, serif, mono, script, symbol
1207 
1208  if ( ( ucs4_char & 0x00F ) == 0x000 )
1209  {
1210  fprintf( svgFile, "font-family=\"sans-serif\" " );
1211  }
1212  else if ( ( ucs4_char & 0x00F ) == 0x001 )
1213  {
1214  fprintf( svgFile, "font-family=\"serif\" " );
1215  }
1216  else if ( ( ucs4_char & 0x00F ) == 0x002 )
1217  {
1218  fprintf( svgFile, "font-family=\"mono-space\" " );
1219  }
1220  else if ( ( ucs4_char & 0x00F ) == 0x003 )
1221  {
1222  fprintf( svgFile, "font-family=\"cursive\" " );
1223  }
1224  else if ( ( ucs4_char & 0x00F ) == 0x004 )
1225  {
1226  // this should be symbol, but that doesn't seem to be available
1227  fprintf( svgFile, "font-family=\"sans-serif\" " );
1228  }
1229 
1230  // normal, italic, oblique
1231 
1232  if ( ( ucs4_char & 0x0F0 ) == 0x000 )
1233  {
1234  fprintf( svgFile, "font-style=\"normal\" " );
1235  }
1236  else if ( ( ucs4_char & 0x0F0 ) == 0x010 )
1237  {
1238  fprintf( svgFile, "font-style=\"italic\" " );
1239  }
1240  else if ( ( ucs4_char & 0x0F0 ) == 0x020 )
1241  {
1242  fprintf( svgFile, "font-style=\"oblique\" " );
1243  }
1244 
1245  // normal, bold
1246 
1247  if ( ( ucs4_char & 0xF00 ) == 0x000 )
1248  {
1249  fprintf( svgFile, "font-weight=\"normal\">" );
1250  }
1251  else if ( ( ucs4_char & 0xF00 ) == 0x100 )
1252  {
1253  fprintf( svgFile, "font-weight=\"bold\">" );
1254  }
1255 }
int plParseDrvOpts(DrvOpt *acc_opt)
Definition: plargs.c:1461
void plP_script_scale(PLBOOL ifupper, PLINT *level, PLFLT *old_scale, PLFLT *scale, PLFLT *old_offset, PLFLT *offset)
Definition: plsym.c:1302
static void svg_fill_background_color(PLStream *)
Definition: svg.c:1115
static void write_hex(FILE *, unsigned char)
Definition: svg.c:1160
void plgesc(char *p_esc)
Definition: plcore.c:3914
void plexit(PLCHAR_VECTOR errormsg)
Definition: plctrl.c:1958
int which_clip
Definition: svg.c:65
PLFLT just
Definition: plplotP.h:708
int canvasYSize
Definition: svg.c:67
unsigned char b
Definition: plplot.h:550
PLINT dev_fill1
Definition: plstrm.h:571
PLINT * ygradient
Definition: plstrm.h:775
void plD_line_svg(PLStream *, short, short, short, short)
Definition: svg.c:294
Definition: svg.c:62
FILE * OutFile
Definition: plstrm.h:575
#define PLESC_FILL
Definition: plplot.h:279
static int svg_family_check(PLStream *)
Definition: svg.c:1137
plD_esc_fp pl_esc
Definition: disptab.h:90
static void svg_general(SVG *, const char *)
Definition: svg.c:1031
#define SVG_Default_Y
Definition: svg.c:40
PLUINT PLUNICODE
Definition: plplot.h:201
void plOpenFile(PLStream *pls)
Definition: plctrl.c:2571
void plCloseFile(PLStream *pls)
Definition: plctrl.c:2635
void plGetFam(PLStream *pls)
Definition: plctrl.c:2780
void(* plD_tidy_fp)(struct PLStream_struct *)
Definition: disptab.h:72
static void proc_str(PLStream *, EscText *)
Definition: svg.c:562
PLINT dev_text
Definition: plstrm.h:572
PLINT dev_npts
Definition: plstrm.h:581
const char * pl_MenuStr
Definition: disptab.h:79
void plD_tidy_svg(PLStream *)
Definition: svg.c:356
PLINT color
Definition: plstrm.h:569
PLINT dev_unicode
Definition: plstrm.h:747
PLINT * xgradient
Definition: plstrm.h:775
plD_tidy_fp pl_tidy
Definition: disptab.h:88
void(* plD_init_fp)(struct PLStream_struct *)
Definition: disptab.h:67
PLFLT diorot
Definition: plstrm.h:661
PLFLT a
Definition: plplot.h:551
void(* plD_eop_fp)(struct PLStream_struct *)
Definition: disptab.h:70
const char * pl_DevName
Definition: disptab.h:80
plD_init_fp pl_init
Definition: disptab.h:83
#define FONT_SHIFT_OFFSET
Definition: svg.c:51
static void svg_attr_values(SVG *, const char *, const char *,...)
Definition: svg.c:960
PLINT colorset
Definition: plstrm.h:569
static void gradient(PLStream *, short *, short *, PLINT)
Definition: svg.c:473
int canvasXSize
Definition: svg.c:66
PLColor * cmap1
Definition: plstrm.h:545
static void poly_line(PLStream *, short *, short *, PLINT, short)
Definition: svg.c:410
short * dev_x
Definition: plstrm.h:582
void plFamInit(PLStream *pls)
Definition: plctrl.c:2751
#define FONT_SIZE_RATIO
Definition: svg.c:49
int PLINT
Definition: plplot.h:181
PLFLT scale
Definition: svg.c:68
static void specify_font(FILE *, PLUNICODE)
Definition: svg.c:1202
#define FONT_SHIFT_RATIO
Definition: svg.c:50
void plD_polyline_svg(PLStream *, short *, short *, PLINT)
Definition: svg.c:319
void plD_bop_svg(PLStream *)
Definition: svg.c:238
void(* plD_line_fp)(struct PLStream_struct *, short, short, short, short)
Definition: disptab.h:68
unsigned char g
Definition: plplot.h:549
void(* plD_esc_fp)(struct PLStream_struct *, PLINT, void *)
Definition: disptab.h:74
void(* plD_polyline_fp)(struct PLStream_struct *, short *, short *, PLINT)
Definition: disptab.h:69
PLINT termin
Definition: plstrm.h:568
#define PIXELS_X
Definition: plplotP.h:304
#define TRUE
Definition: plplotP.h:176
PLINT ylength
Definition: plstrm.h:617
void plD_dispatch_init_svg(PLDispatchTable *pdt)
Definition: svg.c:129
static void svg_open(SVG *, const char *)
Definition: svg.c:915
int gradient_index
Definition: svg.c:71
#define FALSE
Definition: plplotP.h:177
static void svg_attr_value(SVG *, const char *, const char *)
Definition: svg.c:943
void difilt_clip(PLINT *x_coords, PLINT *y_coords)
Definition: plcore.c:1603
static int text_clipping
Definition: svg.c:59
plD_bop_fp pl_bop
Definition: disptab.h:87
short textClipping
Definition: svg.c:64
PLINT dev_gradient
Definition: plstrm.h:773
PLINT verbose
Definition: plstrm.h:527
plD_line_fp pl_line
Definition: disptab.h:84
static void write_unicode(FILE *, PLUNICODE)
Definition: svg.c:1179
static PLINT * buffer
Definition: plfill.c:74
void plD_init_svg(PLStream *)
Definition: svg.c:153
int svgIndent
Definition: svg.c:69
void plP_setpxl(PLFLT xpmm, PLFLT ypmm)
Definition: plcore.c:4238
static void svg_stroke_color(PLStream *)
Definition: svg.c:1073
PLColor * cmap0
Definition: plstrm.h:544
static void svg_open_end(SVG *)
Definition: svg.c:929
static void svg_stroke_width(PLStream *)
Definition: svg.c:1058
#define PLDLLIMPEXP_DRIVER
Definition: pldll.h:81
static PLFLT value(double n1, double n2, double hue)
Definition: plctrl.c:1219
PLINT famadv
Definition: plstrm.h:570
static PLStream * pls[PL_NSTREAMS]
Definition: plcore.h:88
void plP_setphy(PLINT xmin, PLINT xmax, PLINT ymin, PLINT ymax)
Definition: plcore.c:4249
#define plgfci
Definition: plplot.h:735
PLINT family
Definition: plstrm.h:570
PLINT xlength
Definition: plstrm.h:617
static void svg_close(SVG *, const char *)
Definition: svg.c:1011
void plRotationShear(PLFLT *xFormMatrix, PLFLT *rotation, PLFLT *shear, PLFLT *stride)
Definition: plot3d.c:2767
unsigned short unicode_array_len
Definition: plplotP.h:736
short * dev_y
Definition: plstrm.h:582
static int text
Definition: ps.c:77
#define PIXELS_Y
Definition: plplotP.h:305
static int already_warned
Definition: svg.c:57
#define PL_UNUSED(x)
Definition: plplot.h:138
float PLFLT
Definition: plplot.h:163
PLINT graphx
Definition: plstrm.h:568
#define POINTS_PER_INCH
Definition: svg.c:42
PLFLT chrht
Definition: plstrm.h:686
PLINT page
Definition: plstrm.h:578
void(* plD_bop_fp)(struct PLStream_struct *)
Definition: disptab.h:71
#define SVG_Default_X
Definition: svg.c:39
void plD_esc_svg(PLStream *, PLINT, void *)
Definition: svg.c:384
#define PI
Definition: plplotP.h:290
FILE * svgFile
Definition: svg.c:70
void plD_state_svg(PLStream *, PLINT)
unsigned char r
Definition: plplot.h:548
#define PLESC_HAS_TEXT
Definition: plplot.h:290
PLFLT width
Definition: plstrm.h:552
void plwarn(PLCHAR_VECTOR errormsg)
Definition: plctrl.c:1863
PLINT y
Definition: plplotP.h:713
static DrvOpt svg_options[]
Definition: svg.c:60
PLColor curcolor
Definition: plstrm.h:543
plD_state_fp pl_state
Definition: disptab.h:89
static void svg_fill_color(PLStream *)
Definition: svg.c:1094
plD_eop_fp pl_eop
Definition: disptab.h:86
PLINT ncol1
Definition: plstrm.h:539
void plD_eop_svg(PLStream *)
Definition: svg.c:334
#define PLESC_GRADIENT
Definition: plplot.h:305
PLINT x
Definition: plplotP.h:712
plD_polyline_fp pl_polyline
Definition: disptab.h:85
void(* plD_state_fp)(struct PLStream_struct *, PLINT)
Definition: disptab.h:73
static void svg_indent(SVG *)
Definition: svg.c:1043
PLUNICODE * unicode_array
Definition: plplotP.h:735
void * dev
Definition: plstrm.h:594
PLINT bytecnt
Definition: plstrm.h:578
PLINT dev_fill0
Definition: plstrm.h:571
PLFLT * xform
Definition: plplotP.h:709
PLDLLIMPEXP_CXX void fill(PLINT n, const PLFLT *x, const PLFLT *y)
Definition: plstream.cc:246
PLINT dev_eofill
Definition: plstrm.h:788
PLDLLIMPEXP_DRIVER const char * plD_DEVICE_INFO_svg
Definition: svg.c:55
#define GRAPHICS_MODE
Definition: plplotP.h:288
#define PL_FCI_MARK
Definition: plplot.h:370