1 /* This file is part of the GNU plotutils package. Copyright (C) 1995,
2 1996, 1997, 1998, 1999, 2000, 2005, 2008, 2009, Free Software
3 Foundation, Inc.
4
5 The GNU plotutils package is free software. You may redistribute it
6 and/or modify it under the terms of the GNU General Public License as
7 published by the Free Software foundation; either version 2, or (at your
8 option) any later version.
9
10 The GNU plotutils package is distributed in the hope that it will be
11 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with the GNU plotutils package; see the file COPYING. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin St., Fifth Floor,
18 Boston, MA 02110-1301, USA. */
19
20 /* This file defines the initialization for any PSPlotter object, including
21 both private data and public methods. There is a one-to-one
22 correspondence between public methods and user-callable functions in the
23 C API. */
24
25 #include "sys-defines.h"
26 #include "extern.h"
27
28 /* ctime_r() is currently not used, because there is apparently _no_
29 universal way of ensuring that it is declared. On some systems
30 (e.g. Red Hat Linux), `#define _POSIX_SOURCE' will do it. But on other
31 systems, doing `#define _POSIX_SOURCE' **removes** the declaration! */
32 #ifdef HAVE_CTIME_R
33 #undef HAVE_CTIME_R
34 #endif
35
36 #ifdef MSDOS
37 #include <unistd.h> /* for fsync() */
38 #endif
39
40 /* song and dance to define time_t, and declare both time() and ctime() */
41 #ifdef HAVE_SYS_TYPES_H
42 #include <sys/types.h> /* for time_t on some pre-ANSI Unix systems */
43 #endif
44 #ifdef TIME_WITH_SYS_TIME
45 #include <sys/time.h> /* for time() on some pre-ANSI Unix systems */
46 #include <time.h> /* for ctime() */
47 #else /* not TIME_WITH_SYS_TIME, include only one (prefer <sys/time.h>) */
48 #ifdef HAVE_SYS_TIME_H
49 #include <sys/time.h>
50 #else /* not HAVE_SYS_TIME_H */
51 #include <time.h>
52 #endif /* not HAVE_SYS_TIME_H */
53 #endif /* not TIME_WITH_SYS_TIME */
54
55 #include "p_header.h" /* idraw Postscript header (from InterViews) */
56
57 #ifndef LIBPLOTTER
58 /* In libplot, this is the initialization for the function-pointer part of
59 a PSPlotter struct. */
60 const Plotter _pl_p_default_plotter =
61 {
62 /* initialization (after creation) and termination (before deletion) */
63 _pl_p_initialize, _pl_p_terminate,
64 /* page manipulation */
65 _pl_p_begin_page, _pl_p_erase_page, _pl_p_end_page,
66 /* drawing state manipulation */
67 _pl_g_push_state, _pl_g_pop_state,
68 /* internal path-painting methods (endpath() is a wrapper for the first) */
69 _pl_p_paint_path, _pl_p_paint_paths, _pl_g_path_is_flushable, _pl_g_maybe_prepaint_segments,
70 /* internal methods for drawing of markers and points */
71 _pl_g_paint_marker, _pl_p_paint_point,
72 /* internal methods that plot strings in Hershey, non-Hershey fonts */
73 _pl_g_paint_text_string_with_escapes, _pl_p_paint_text_string,
74 _pl_g_get_text_width,
75 /* private low-level `retrieve font' method */
76 _pl_g_retrieve_font,
77 /* `flush output' method, called only if Plotter handles its own output */
78 _pl_g_flush_output,
79 /* error handlers */
80 _pl_g_warning,
81 _pl_g_error,
82 };
83 #endif /* not LIBPLOTTER */
84
85 /* The private `initialize' method, which is invoked when a Plotter is
86 created. It is used for such things as initializing capability flags
87 from the values of class variables, allocating storage, etc. When this
88 is invoked, _plotter points to the Plotter that has just been
89 created. */
90
91 /* For PS Plotter objects, we initialize the used-font array(s). We also
92 determine the page size and the location on the page of the graphics
93 display, so that we'll be able to work out the map from user coordinates
94 to device coordinates in space.c. */
95
96 void
_pl_p_initialize(S___ (Plotter * _plotter))97 _pl_p_initialize (S___(Plotter *_plotter))
98 {
99 #ifndef LIBPLOTTER
100 /* in libplot, manually invoke superclass initialization method */
101 _pl_g_initialize (S___(_plotter));
102 #endif
103
104 /* override generic initializations (which are appropriate to the base
105 Plotter class), as necessary */
106
107 #ifndef LIBPLOTTER
108 /* tag field, differs in derived classes */
109 _plotter->data->type = PL_PS;
110 #endif
111
112 /* output model */
113 _plotter->data->output_model = PL_OUTPUT_PAGES_ALL_AT_ONCE;
114
115 /* user-queryable capabilities: 0/1/2 = no/yes/maybe */
116 _plotter->data->have_wide_lines = 1;
117 _plotter->data->have_dash_array = 1;
118 _plotter->data->have_solid_fill = 1;
119 _plotter->data->have_odd_winding_fill = 1;
120 _plotter->data->have_nonzero_winding_fill = 1;
121 _plotter->data->have_settable_bg = 0;
122 _plotter->data->have_escaped_string_support = 0;
123 _plotter->data->have_ps_fonts = 1;
124 #ifdef USE_LJ_FONTS_IN_PS
125 _plotter->data->have_pcl_fonts = 1;
126 #else
127 _plotter->data->have_pcl_fonts = 0;
128 #endif
129 _plotter->data->have_stick_fonts = 0;
130 _plotter->data->have_extra_stick_fonts = 0;
131 _plotter->data->have_other_fonts = 0;
132
133 /* text and font-related parameters (internal, not queryable by user);
134 note that we don't set kern_stick_fonts, because it was set by the
135 superclass initialization (and it's irrelevant for this Plotter type,
136 anyway) */
137 _plotter->data->default_font_type = PL_F_POSTSCRIPT;
138 _plotter->data->pcl_before_ps = false;
139 _plotter->data->have_horizontal_justification = false;
140 _plotter->data->have_vertical_justification = false;
141 _plotter->data->issue_font_warning = true;
142
143 /* path-related parameters (also internal); note that we
144 don't set max_unfilled_path_length, because it was set by the
145 superclass initialization */
146 _plotter->data->have_mixed_paths = false;
147 _plotter->data->allowed_arc_scaling = AS_NONE;
148 _plotter->data->allowed_ellarc_scaling = AS_NONE;
149 _plotter->data->allowed_quad_scaling = AS_NONE;
150 _plotter->data->allowed_cubic_scaling = AS_NONE;
151 _plotter->data->allowed_box_scaling = AS_ANY;
152 _plotter->data->allowed_circle_scaling = AS_ANY;
153 _plotter->data->allowed_ellipse_scaling = AS_ANY;
154
155 /* color-related parameters (also internal) */
156 _plotter->data->emulate_color = false;
157
158 /* dimensions */
159 _plotter->data->display_model_type = (int)DISP_MODEL_PHYSICAL;
160 _plotter->data->display_coors_type = (int)DISP_DEVICE_COORS_REAL;
161 _plotter->data->flipped_y = false;
162 _plotter->data->imin = 0;
163 _plotter->data->imax = 0;
164 _plotter->data->jmin = 0;
165 _plotter->data->jmax = 0;
166 _plotter->data->xmin = 0.0;
167 _plotter->data->xmax = 0.0;
168 _plotter->data->ymin = 0.0;
169 _plotter->data->ymax = 0.0;
170 _plotter->data->page_data = (plPageData *)NULL;
171
172 /* initialize certain data members from device driver parameters */
173
174 /* Determine range of device coordinates over which the viewport will
175 extend (and hence the transformation from user to device coordinates;
176 see g_space.c). */
177 {
178 /* determine page type, viewport size and location */
179 _set_page_type (_plotter->data);
180
181 /* convert viewport size-and-location data (in terms of inches) to
182 device coordinates (i.e. points) */
183 _plotter->data->xmin = 72 * (_plotter->data->viewport_xorigin
184 + _plotter->data->viewport_xoffset);
185 _plotter->data->xmax = 72 * (_plotter->data->viewport_xorigin
186 + _plotter->data->viewport_xoffset
187 + _plotter->data->viewport_xsize);
188
189 _plotter->data->ymin = 72 * (_plotter->data->viewport_yorigin
190 + _plotter->data->viewport_yoffset);
191 _plotter->data->ymax = 72 * (_plotter->data->viewport_yorigin
192 + _plotter->data->viewport_yoffset
193 + _plotter->data->viewport_ysize);
194 }
195
196 /* compute the NDC to device-frame affine map, set it in Plotter */
197 _compute_ndc_to_device_map (_plotter->data);
198 }
199
200 /* The private `terminate' method, which is invoked when a Plotter is
201 deleted. It may do such things as write to an output stream from
202 internal storage, deallocate storage, etc. When this is invoked,
203 _plotter points to the Plotter that is about to be deleted. */
204
205 /* This version is for Postscript Plotters. It writes out the
206 idraw-derived PS prologue to the output stream, and copies each stored
207 page of graphics to it too, making sure to include the proper DSC
208 [Document Structuring Convention] comment lines at the beginning and the
209 end of the document, and at the beginning and end of each page.
210
211 (PS Plotters differ from most other plotters that do not plot in real
212 time in that they emit output only after all pages have pages have been
213 drawn, rather than at the end of each page. This is necessary for DSC
214 compliance.)
215
216 When this is called, the PS code for the body of each page is stored in
217 a plOutbuf, and the page plOutbufs form a linked list. In this function
218 we write the document header, the document trailer, and the
219 header/trailer for each page, all to separate plOutbufs. We then copy
220 the plOutbufs, one after another, to the output stream. */
221
222 void
_pl_p_terminate(S___ (Plotter * _plotter))223 _pl_p_terminate (S___(Plotter *_plotter))
224 {
225 double x_min, x_max, y_min, y_max;
226 int i, n;
227 time_t clock;
228 plOutbuf *doc_header, *doc_trailer, *current_page;
229 bool ps_font_used_in_doc[PL_NUM_PS_FONTS];
230 #ifdef USE_LJ_FONTS_IN_PS
231 bool pcl_font_used_in_doc[PL_NUM_PCL_FONTS];
232 #endif
233 char *time_string, time_string_buffer[32];
234
235 #ifdef LIBPLOTTER
236 if (_plotter->data->outfp || _plotter->data->outstream)
237 #else
238 if (_plotter->data->outfp)
239 #endif
240 /* have an output stream */
241 {
242 int num_pages = _plotter->data->page_number;
243
244 /* First, prepare the document header (DSC lines, etc.), and write it
245 to a plOutbuf. The header is very long: most of it is simply the
246 idraw header (see p_header.h). */
247 doc_header = _new_outbuf ();
248
249 if (num_pages == 1)
250 /* will plot an EPS file, not just a PS file */
251 sprintf (doc_header->point, "\
252 %%!PS-Adobe-3.0 EPSF-3.0\n");
253 else
254 sprintf (doc_header->point, "\
255 %%!PS-Adobe-3.0\n");
256 _update_buffer (doc_header);
257
258 /* Compute an ASCII representation of the current time, in a
259 reentrant way if we're supporting pthreads (i.e. by using ctime_r
260 if it's available). */
261 time (&clock);
262 #ifdef PTHREAD_SUPPORT
263 #ifdef HAVE_PTHREAD_H
264 #ifdef HAVE_CTIME_R
265 ctime_r (&clock, time_string_buffer);
266 time_string = time_string_buffer;
267 #else
268 time_string = ctime (&clock);
269 #endif
270 #else
271 time_string = ctime (&clock);
272 #endif
273 #else
274 time_string = ctime (&clock);
275 #endif
276
277 sprintf (doc_header->point, "\
278 %%%%Creator: GNU libplot drawing library %s\n\
279 %%%%Title: PostScript plot\n\
280 %%%%CreationDate: %s\
281 %%%%DocumentData: Clean7Bit\n\
282 %%%%LanguageLevel: 1\n\
283 %%%%Pages: %d\n\
284 %%%%PageOrder: Ascend\n\
285 %%%%Orientation: Portrait\n",
286 PL_LIBPLOT_VER_STRING, time_string, num_pages);
287 _update_buffer (doc_header);
288
289 /* emit the bounding box for the document */
290 _bbox_of_outbufs (_plotter->data->first_page, &x_min, &x_max, &y_min, &y_max);
291 if (x_min > x_max || y_min > y_max)
292 /* all pages empty */
293 sprintf (doc_header->point, "\
294 %%%%BoundingBox: 0 0 0 0\n");
295 else
296 sprintf (doc_header->point, "\
297 %%%%BoundingBox: %d %d %d %d\n",
298 IROUND(x_min - 0.5), IROUND(y_min - 0.5),
299 IROUND(x_max + 0.5), IROUND(y_max + 0.5));
300 _update_buffer (doc_header);
301
302 /* determine fonts needed by document, by examining all pages */
303 {
304 current_page = _plotter->data->first_page;
305
306 for (i = 0; i < PL_NUM_PS_FONTS; i++)
307 ps_font_used_in_doc[i] = false;
308 #ifdef USE_LJ_FONTS_IN_PS
309 for (i = 0; i < PL_NUM_PCL_FONTS; i++)
310 pcl_font_used_in_doc[i] = false;
311 #endif
312 while (current_page)
313 {
314 for (i = 0; i < PL_NUM_PS_FONTS; i++)
315 if (current_page->ps_font_used[i])
316 ps_font_used_in_doc[i] = true;
317 #ifdef USE_LJ_FONTS_IN_PS
318 for (i = 0; i < PL_NUM_PCL_FONTS; i++)
319 if (current_page->pcl_font_used[i])
320 pcl_font_used_in_doc[i] = true;
321 #endif
322 current_page = current_page->next;
323 }
324 }
325
326 /* write out list of fonts needed by the document */
327 {
328 bool first_font = true;
329
330 strcpy (doc_header->point, "\
331 %%DocumentNeededResources: ");
332 _update_buffer (doc_header);
333
334 for (i = 0; i < PL_NUM_PS_FONTS; i++)
335 {
336 if (ps_font_used_in_doc[i])
337 {
338 if (first_font == false)
339 {
340 strcpy (doc_header->point, "%%+ ");
341 _update_buffer (doc_header);
342 }
343 strcpy (doc_header->point, "font ");
344 _update_buffer (doc_header);
345 strcpy (doc_header->point, _pl_g_ps_font_info[i].ps_name);
346 _update_buffer (doc_header);
347 strcpy (doc_header->point, "\n");
348 _update_buffer (doc_header);
349 first_font = false;
350 }
351 }
352 #ifdef USE_LJ_FONTS_IN_PS
353 for (i = 0; i < PL_NUM_PCL_FONTS; i++)
354 {
355 if (pcl_font_used_in_doc[i])
356 {
357 if (first_font == false)
358 {
359 strcpy (doc_header->point, "%%+ ");
360 _update_buffer (doc_header);
361 }
362 strcpy (doc_header->point, "font ");
363 _update_buffer (doc_header);
364 /* use replacement font name if any (this is only to
365 support the Tidbits-is-Wingdings botch) */
366 if (_pl_g_pcl_font_info[i].substitute_ps_name)
367 strcpy (doc_header->point, _pl_g_pcl_font_info[i].substitute_ps_name);
368 else
369 strcpy (doc_header->point, _pl_g_pcl_font_info[i].ps_name);
370 _update_buffer (doc_header);
371 strcpy (doc_header->point, "\n");
372 _update_buffer (doc_header);
373 first_font = false;
374 }
375 }
376 #endif
377 if (first_font) /* no fonts needed in document */
378 {
379 strcpy (doc_header->point, "\n");
380 _update_buffer (doc_header);
381 }
382 }
383
384 /* emit final DSC lines in header */
385 if (num_pages > 0)
386 {
387 sprintf (doc_header->point, "\
388 %%%%DocumentSuppliedResources: procset %s %s 0\n",
389 PS_PROCSET_NAME, PS_PROCSET_VERSION);
390 _update_buffer (doc_header);
391 }
392 strcpy (doc_header->point, "\
393 %%EndComments\n\n");
394 _update_buffer (doc_header);
395
396 /* write out list of fonts needed by the document, all over again;
397 this time it's interpreted as the default font list for each page */
398 {
399 bool first_font = true;
400
401 strcpy (doc_header->point, "\
402 %%BeginDefaults\n");
403 _update_buffer (doc_header);
404 strcpy (doc_header->point, "\
405 %%PageResources: ");
406 _update_buffer (doc_header);
407 for (i = 0; i < PL_NUM_PS_FONTS; i++)
408 {
409 if (ps_font_used_in_doc[i])
410 {
411 if (first_font == false)
412 {
413 strcpy (doc_header->point, "%%+ ");
414 _update_buffer (doc_header);
415 }
416 strcpy (doc_header->point, "font ");
417 _update_buffer (doc_header);
418 strcpy (doc_header->point, _pl_g_ps_font_info[i].ps_name);
419 _update_buffer (doc_header);
420 strcpy (doc_header->point, "\n");
421 _update_buffer (doc_header);
422 first_font = false;
423 }
424 }
425 #ifdef USE_LJ_FONTS_IN_PS
426 for (i = 0; i < PL_NUM_PCL_FONTS; i++)
427 {
428 if (pcl_font_used_in_doc[i])
429 {
430 if (first_font == false)
431 {
432 strcpy (doc_header->point, "%%+ ");
433 _update_buffer (doc_header);
434 }
435 strcpy (doc_header->point, "font ");
436 _update_buffer (doc_header);
437 if (_pl_g_pcl_font_info[i].substitute_ps_name)
438 /* this is to support the Tidbits-is-Wingdings botch */
439 strcpy (doc_header->point, _pl_g_pcl_font_info[i].substitute_ps_name);
440 else
441 strcpy (doc_header->point, _pl_g_pcl_font_info[i].ps_name);
442 _update_buffer (doc_header);
443 strcpy (doc_header->point, "\n");
444 _update_buffer (doc_header);
445 first_font = false;
446 }
447 }
448 #endif
449 if (first_font) /* no fonts needed in document */
450 {
451 strcpy (doc_header->point, "\n");
452 _update_buffer (doc_header);
453 }
454
455 strcpy (doc_header->point, "\
456 %%EndDefaults\n\n");
457 _update_buffer (doc_header);
458 }
459
460 /* Document Prolog */
461 strcpy (doc_header->point, "\
462 %%BeginProlog\n");
463 _update_buffer (doc_header);
464 if (num_pages > 1)
465 /* PS [not EPS] file, include procset in document prolog */
466 {
467 sprintf (doc_header->point, "\
468 %%%%BeginResource: procset %s %s 0\n",
469 PS_PROCSET_NAME, PS_PROCSET_VERSION);
470 _update_buffer (doc_header);
471 /* write out idraw-derived PS prologue (makes many definitions) */
472 for (i=0; *_ps_procset[i]; i++)
473 {
474 strcpy (doc_header->point, _ps_procset[i]);
475 _update_buffer (doc_header);
476 }
477 strcpy (doc_header->point, "\
478 %%EndResource\n");
479 _update_buffer (doc_header);
480 }
481 strcpy (doc_header->point, "\
482 %%EndProlog\n\n");
483 _update_buffer (doc_header);
484
485 /* Document Setup */
486 strcpy (doc_header->point, "\
487 %%BeginSetup\n");
488 _update_buffer (doc_header);
489
490 /* tell driver to include any PS [or PCL] fonts that are needed */
491 for (i = 0; i < PL_NUM_PS_FONTS; i++)
492 if (ps_font_used_in_doc[i])
493 {
494 sprintf (doc_header->point, "\
495 %%%%IncludeResource: font %s\n", _pl_g_ps_font_info[i].ps_name);
496 _update_buffer (doc_header);
497 }
498 #ifdef USE_LJ_FONTS_IN_PS
499 for (i = 0; i < PL_NUM_PCL_FONTS; i++)
500 if (pcl_font_used_in_doc[i])
501 {
502 /* this is to support the Tidbits-is-Wingdings botch */
503 if (_pl_g_pcl_font_info[i].substitute_ps_name)
504 sprintf (doc_header->point, "\
505 %%%%IncludeResource: font %s\n", _pl_g_pcl_font_info[i].substitute_ps_name);
506 else
507 sprintf (doc_header->point, "\
508 %%%%IncludeResource: font %s\n", _pl_g_pcl_font_info[i].ps_name);
509 _update_buffer (doc_header);
510 }
511 #endif
512
513 /* push private dictionary on stack */
514 strcpy (doc_header->point, "\
515 /DrawDict 50 dict def\n\
516 DrawDict begin\n");
517 _update_buffer (doc_header);
518
519 /* do ISO-Latin-1 reencoding for any fonts that need it */
520 {
521 bool need_to_reencode = false;
522
523 for (i = 0; i < PL_NUM_PS_FONTS; i++)
524 if (ps_font_used_in_doc[i] && _pl_g_ps_font_info[i].iso8859_1)
525 {
526 need_to_reencode = true;
527 break;
528 }
529 #ifdef USE_LJ_FONTS_IN_PS
530 for (i = 0; i < PL_NUM_PCL_FONTS; i++)
531 if (pcl_font_used_in_doc[i] && _pl_g_pcl_font_info[i].iso8859_1)
532 {
533 need_to_reencode = true;
534 break;
535 }
536 #endif
537 if (need_to_reencode)
538 {
539 strcpy (doc_header->point, _ps_fontproc);
540 _update_buffer (doc_header);
541
542 for (i = 0; i < PL_NUM_PS_FONTS; i++)
543 {
544 if (ps_font_used_in_doc[i] && _pl_g_ps_font_info[i].iso8859_1)
545 {
546 sprintf (doc_header->point, "\
547 /%s reencodeISO def\n",
548 _pl_g_ps_font_info[i].ps_name);
549 _update_buffer (doc_header);
550 }
551 }
552 #ifdef USE_LJ_FONTS_IN_PS
553 for (i = 0; i < PL_NUM_PCL_FONTS; i++)
554 {
555 if (pcl_font_used_in_doc[i] && _pl_g_pcl_font_info[i].iso8859_1)
556 {
557 sprintf (doc_header->point, "\
558 /%s reencodeISO def\n",
559 _pl_g_pcl_font_info[i].ps_name);
560 _update_buffer (doc_header);
561 }
562 }
563 #endif
564 }
565 }
566
567 if (num_pages == 1)
568 /* EPS [not just PS] file, include procset in setup section,
569 so that it will modify only the private dictionary */
570 {
571 sprintf (doc_header->point, "\
572 %%%%BeginResource: procset %s %s 0\n",
573 PS_PROCSET_NAME, PS_PROCSET_VERSION);
574 _update_buffer (doc_header);
575
576 /* write out idraw-derived PS prologue in p_header.h (makes many
577 definitions) */
578 for (i=0; *_ps_procset[i]; i++)
579 {
580 strcpy (doc_header->point, _ps_procset[i]);
581 _update_buffer (doc_header);
582 }
583 strcpy (doc_header->point, "\
584 %%EndResource\n");
585 _update_buffer (doc_header);
586 }
587
588 strcpy (doc_header->point, "\
589 %%EndSetup\n\n");
590 _update_buffer (doc_header);
591
592 /* Document header is now prepared, and stored in a plOutbuf.
593 Now do the same for the doc trailer (much shorter). */
594
595 /* Document Trailer: just pop private dictionary off stack */
596 doc_trailer = _new_outbuf ();
597 strcpy (doc_trailer->point, "\
598 %%Trailer\n\
599 end\n\
600 %%EOF\n");
601 _update_buffer (doc_trailer);
602
603 /* WRITE DOCUMENT HEADER (and free its plOutbuf) */
604 _write_string (_plotter->data, doc_header->base);
605 _delete_outbuf (doc_header);
606
607 /* now loop through pages, emitting each in turn */
608 if (num_pages > 0)
609 {
610 for (current_page = _plotter->data->first_page, n=1;
611 current_page;
612 current_page = current_page->next, n++)
613 {
614 plOutbuf *page_header, *page_trailer;
615
616 /* prepare page header, and store it in a plOutbuf */
617 page_header = _new_outbuf ();
618
619 sprintf (page_header->point, "\
620 %%%%Page: %d %d\n", n, n);
621 _update_buffer (page_header);
622
623 /* write out list of fonts needed by the page */
624 {
625 bool first_font = true;
626
627 strcpy (page_header->point, "\
628 %%PageResources: ");
629 _update_buffer (page_header);
630 for (i = 0; i < PL_NUM_PS_FONTS; i++)
631 {
632 if (current_page->ps_font_used[i])
633 {
634 if (first_font == false)
635 {
636 strcpy (page_header->point, "%%+ ");
637 _update_buffer (page_header);
638 }
639 strcpy (page_header->point, "font ");
640 _update_buffer (page_header);
641 strcpy (page_header->point, _pl_g_ps_font_info[i].ps_name);
642 _update_buffer (page_header);
643 strcpy (page_header->point, "\n");
644 _update_buffer (page_header);
645 first_font = false;
646 }
647 }
648 #ifdef USE_LJ_FONTS_IN_PS
649 for (i = 0; i < PL_NUM_PCL_FONTS; i++)
650 {
651 if (current_page->pcl_font_used[i])
652 {
653 if (first_font == false)
654 {
655 strcpy (page_header->point, "%%+ ");
656 _update_buffer (page_header);
657 }
658 strcpy (page_header->point, "font ");
659 _update_buffer (page_header);
660 if (_pl_g_pcl_font_info[i].substitute_ps_name)
661 /* this is to support the Tidbits-is-Wingdings botch */
662 strcpy (page_header->point, _pl_g_pcl_font_info[i].substitute_ps_name);
663 else
664 strcpy (page_header->point, _pl_g_pcl_font_info[i].ps_name);
665 _update_buffer (page_header);
666 strcpy (page_header->point, "\n");
667 _update_buffer (page_header);
668 first_font = false;
669 }
670 }
671 #endif
672 if (first_font) /* no fonts needed on page */
673 {
674 strcpy (page_header->point, "\n");
675 _update_buffer (page_header);
676 }
677 }
678
679 /* emit the bounding box for the page */
680 _bbox_of_outbuf (current_page, &x_min, &x_max, &y_min, &y_max);
681 if (x_min > x_max || y_min > y_max)
682 /* empty page */
683 sprintf (page_header->point, "\
684 %%%%PageBoundingBox: 0 0 0 0\n");
685 else
686 sprintf (page_header->point, "\
687 %%%%PageBoundingBox: %d %d %d %d\n",
688 IROUND(x_min - 0.5), IROUND(y_min - 0.5),
689 IROUND(x_max + 0.5), IROUND(y_max + 0.5));
690 _update_buffer (page_header);
691 /* Page Setup */
692 strcpy (page_header->point, "\
693 %%BeginPageSetup\n");
694 _update_buffer (page_header);
695 /* emit initialization code (including idraw, PS directives) */
696 /* N.B. `8' below is the version number of the idraw PS format
697 we're producing; see <Unidraw/Components/psformat.h> */
698 strcpy (page_header->point, "\
699 %I Idraw 8\n\n\
700 Begin\n\
701 %I b u\n\
702 %I cfg u\n\
703 %I cbg u\n\
704 %I f u\n\
705 %I p u\n\
706 %I t\n\
707 [ 1 0 0 1 0 0 ] concat\n\
708 /originalCTM matrix currentmatrix def\n\
709 /trueoriginalCTM matrix currentmatrix def\n");
710 _update_buffer (page_header);
711 strcpy (page_header->point, "\
712 %%EndPageSetup\n\n");
713 _update_buffer (page_header);
714
715 /* Page header is now prepared, and stored in a plOutbuf.
716 Do the same for the page trailer (much shorter). */
717
718 page_trailer = _new_outbuf ();
719 /* Page Trailer: includes `showpage' */
720 strcpy (page_trailer->point, "\
721 %%PageTrailer\n\
722 End %I eop\n\
723 showpage\n\n");
724 _update_buffer (page_trailer);
725 /* Page trailer is now ready */
726
727 /* WRITE PS CODE FOR THIS PAGE, including header, trailer */
728 _write_string (_plotter->data, page_header->base);
729 if (current_page->len > 0)
730 _write_string (_plotter->data, current_page->base);
731 _write_string (_plotter->data, page_trailer->base);
732
733 /* free header, trailer plOutbufs */
734 _delete_outbuf (page_trailer);
735 _delete_outbuf (page_header);
736 }
737 }
738
739 /* WRITE DOCUMENT TRAILER (and free its plOutbuf) */
740 _write_string (_plotter->data, doc_trailer->base);
741 _delete_outbuf (doc_trailer);
742 }
743
744 /* delete all plOutbufs in which document pages are stored */
745 current_page = _plotter->data->first_page;
746 while (current_page)
747 {
748 plOutbuf *next_page;
749
750 next_page = current_page->next;
751 _delete_outbuf (current_page);
752 current_page = next_page;
753 }
754
755 /* flush output stream if any */
756 if (_plotter->data->outfp)
757 {
758 if (fflush(_plotter->data->outfp) < 0
759 #ifdef MSDOS
760 /* data can be caught in DOS buffers, so do an fsync() too */
761 || fsync (_plotter->data->outfp) < 0
762 #endif
763 )
764 _plotter->error (R___(_plotter) "the output stream is jammed");
765 }
766 #ifdef LIBPLOTTER
767 else if (_plotter->data->outstream)
768 {
769 _plotter->data->outstream->flush ();
770 if (!(*(_plotter->data->outstream)))
771 _plotter->error (R___(_plotter) "the output stream is jammed");
772 }
773 #endif
774
775 #ifndef LIBPLOTTER
776 /* in libplot, manually invoke superclass termination method */
777 _pl_g_terminate (S___(_plotter));
778 #endif
779 }
780
781 #ifdef LIBPLOTTER
PSPlotter(FILE * infile,FILE * outfile,FILE * errfile)782 PSPlotter::PSPlotter (FILE *infile, FILE *outfile, FILE *errfile)
783 :Plotter (infile, outfile, errfile)
784 {
785 _pl_p_initialize ();
786 }
787
PSPlotter(FILE * outfile)788 PSPlotter::PSPlotter (FILE *outfile)
789 :Plotter (outfile)
790 {
791 _pl_p_initialize ();
792 }
793
PSPlotter(istream & in,ostream & out,ostream & err)794 PSPlotter::PSPlotter (istream& in, ostream& out, ostream& err)
795 : Plotter (in, out, err)
796 {
797 _pl_p_initialize ();
798 }
799
PSPlotter(ostream & out)800 PSPlotter::PSPlotter (ostream& out)
801 : Plotter (out)
802 {
803 _pl_p_initialize ();
804 }
805
PSPlotter()806 PSPlotter::PSPlotter ()
807 {
808 _pl_p_initialize ();
809 }
810
PSPlotter(FILE * infile,FILE * outfile,FILE * errfile,PlotterParams & parameters)811 PSPlotter::PSPlotter (FILE *infile, FILE *outfile, FILE *errfile, PlotterParams ¶meters)
812 :Plotter (infile, outfile, errfile, parameters)
813 {
814 _pl_p_initialize ();
815 }
816
PSPlotter(FILE * outfile,PlotterParams & parameters)817 PSPlotter::PSPlotter (FILE *outfile, PlotterParams ¶meters)
818 :Plotter (outfile, parameters)
819 {
820 _pl_p_initialize ();
821 }
822
PSPlotter(istream & in,ostream & out,ostream & err,PlotterParams & parameters)823 PSPlotter::PSPlotter (istream& in, ostream& out, ostream& err, PlotterParams ¶meters)
824 : Plotter (in, out, err, parameters)
825 {
826 _pl_p_initialize ();
827 }
828
PSPlotter(ostream & out,PlotterParams & parameters)829 PSPlotter::PSPlotter (ostream& out, PlotterParams ¶meters)
830 : Plotter (out, parameters)
831 {
832 _pl_p_initialize ();
833 }
834
PSPlotter(PlotterParams & parameters)835 PSPlotter::PSPlotter (PlotterParams ¶meters)
836 : Plotter (parameters)
837 {
838 _pl_p_initialize ();
839 }
840
~PSPlotter()841 PSPlotter::~PSPlotter ()
842 {
843 /* if luser left the Plotter open, close it */
844 if (_plotter->data->open)
845 _API_closepl ();
846
847 _pl_p_terminate ();
848 }
849 #endif
850