PLplot  5.11.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
plbuf.c
Go to the documentation of this file.
1 // Handle plot buffer.
2 //
3 // Copyright (C) 1992 Maurice LeBrun
4 // Copyright (C) 2004-2015 Alan W. Irwin
5 // Copyright (C) 2005 Thomas J. Duck
6 // Copyright (C) 2006 Jim Dishaw
7 //
8 // This file is part of PLplot.
9 //
10 // PLplot is free software; you can redistribute it and/or modify
11 // it under the terms of the GNU Library General Public License as published
12 // by the Free Software Foundation; either version 2 of the License, or
13 // (at your option) any later version.
14 //
15 // PLplot is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Library General Public License for more details.
19 //
20 // You should have received a copy of the GNU Library General Public License
21 // along with PLplot; if not, write to the Free Software
22 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 //
24 
25 #define NEED_PLDEBUG
26 #include "plplotP.h"
27 #include "drivers.h"
28 #include "metadefs.h"
29 
30 #include <string.h>
31 
32 #if defined ( _MSC_VER ) && _MSC_VER <= 1500
33 // Older versions of Visual Studio (2005 perhaps 2008) do not define uint8_t
34 // The newer versions of Visual Studio will not install on Vista or older
35 // versions of Windows.
36 typedef unsigned char uint8_t;
37 typedef unsigned short int uint16_t;
38 #endif
39 
40 //
41 // Function prototypes
42 //
43 
44 // Public
45 void * plbuf_save( PLStream *pls, void *state );
46 
47 // Private
48 static void check_buffer_size( PLStream *pls, size_t data_size );
49 
50 static int rd_command( PLStream *pls, U_CHAR *p_c );
51 static void rd_data( PLStream *pls, void *buf, size_t buf_size );
52 static void rd_data_no_copy( PLStream *pls, void **buf, size_t buf_size );
53 
54 static void wr_command( PLStream *pls, U_CHAR c );
55 static void wr_data( PLStream *pls, void *buf, size_t buf_size );
56 
57 static void plbuf_control( PLStream *pls, U_CHAR c );
58 static void plbuf_fill( PLStream *pls );
59 static void plbuf_swin( PLStream *pls, PLWindow *plwin );
60 
61 static void rdbuf_init( PLStream *pls );
62 static void rdbuf_line( PLStream *pls );
63 static void rdbuf_polyline( PLStream *pls );
64 static void rdbuf_eop( PLStream *pls );
65 static void rdbuf_bop( PLStream *pls );
66 static void rdbuf_state( PLStream *pls );
67 static void rdbuf_esc( PLStream *pls );
68 static void rdbuf_image( PLStream *pls );
69 static void rdbuf_text( PLStream *pls );
70 static void rdbuf_text_unicode( PLINT op, PLStream *pls );
71 static void rdbuf_fill( PLStream *pls );
72 static void rdbuf_clip( PLStream *pls );
73 static void rdbuf_swin( PLStream *pls );
74 static void rdbuf_di( PLStream *pls );
75 static void rdbuf_setsub( PLStream *pls );
76 static void rdbuf_ssub( PLStream *pls );
77 
78 //--------------------------------------------------------------------------
79 // Plplot internal interface to the plot buffer
80 //--------------------------------------------------------------------------
81 
82 //--------------------------------------------------------------------------
83 // plbuf_init()
84 //
85 // Initialize device.
86 //--------------------------------------------------------------------------
87 
88 void
90 {
91  dbug_enter( "plbuf_init" );
92 
93  // Indicate that this buffer is not being read
94  pls->plbuf_read = FALSE;
95 
96  if ( pls->plbuf_buffer == NULL )
97  {
98  // We have not allocated a buffer, so do it now
99  pls->plbuf_buffer_grow = 128 * 1024;
100 
101  if ( ( pls->plbuf_buffer = malloc( pls->plbuf_buffer_grow ) ) == NULL )
102  plexit( "plbuf_init: Error allocating plot buffer." );
103 
105  pls->plbuf_top = 0;
106  pls->plbuf_readpos = 0;
107  }
108  else
109  {
110  // Buffer is allocated, move the top to the beginning
111  pls->plbuf_top = 0;
112  }
113 }
114 
115 //--------------------------------------------------------------------------
116 // plbuf_eop()
117 //
118 // End of page.
119 //--------------------------------------------------------------------------
120 
121 void
123 {
124  dbug_enter( "plbuf_eop" );
125 
126  wr_command( pls, (U_CHAR) EOP );
127 }
128 
129 //--------------------------------------------------------------------------
130 // plbuf_bop()
131 //
132 // Set up for the next page.
133 // To avoid problems redisplaying partially filled pages, on each BOP the
134 // old data in the buffer is ignored by setting the top back to the
135 // beginning of the buffer.
136 //
137 // Also write state information to ensure the next page is correct.
138 //--------------------------------------------------------------------------
139 
140 void
142 {
143  dbug_enter( "plbuf_bop" );
144 
145  plbuf_tidy( pls );
146 
147  // Move the top to the beginning
148  pls->plbuf_top = 0;
149 
150  wr_command( pls, (U_CHAR) BOP );
151 
152  // Save the current configuration (e.g. colormap, current colors) to
153  // allow plRemakePlot to correctly regenerate the plot
154 
155  // Save the current colors. Do not use the PLSTATE_* commands
156  // because the color might have already been set by the driver
157  // during initialization and this would result in an extraneous
158  // color command being sent. The goal is to preserve the current
159  // color state so that rdbuf_bop can restore it. This needs
160  // to occur immediately after the BOP command so that it can be
161  // read by rdbuf_bop.
162  wr_data( pls, &( pls->icol0 ), sizeof ( pls->icol0 ) );
163  wr_data( pls, &( pls->icol1 ), sizeof ( pls->icol1 ) );
164  wr_data( pls, &( pls->curcolor ), sizeof ( pls->curcolor ) );
165  wr_data( pls, &( pls->curcmap ), sizeof ( pls->curcmap ) );
166  wr_data( pls, &pls->nsubx, sizeof ( pls->nsubx ) );
167  wr_data( pls, &pls->nsuby, sizeof ( pls->nsuby ) );
168 
169  // Save all the other state parameters via the plbuf_state function
170  plbuf_state( pls, PLSTATE_CMAP0 );
171  plbuf_state( pls, PLSTATE_CMAP1 );
172  plbuf_state( pls, PLSTATE_WIDTH );
173  plbuf_state( pls, PLSTATE_FILL );
174  plbuf_state( pls, PLSTATE_CHR );
175  plbuf_state( pls, PLSTATE_SYM );
176 }
177 
178 //--------------------------------------------------------------------------
179 //
180 // plbuf_setsub()
181 //
182 // Set the subpage. Required to carry out commands which apply to just one
183 // sub page such as plclear
184 //--------------------------------------------------------------------------
185 
186 void
188 {
189  dbug_enter( "plbuf_setsub" );
190 
191  wr_command( pls, (U_CHAR) SETSUB );
192  wr_data( pls, &pls->cursub, sizeof ( pls->cursub ) );
193 }
194 
195 //--------------------------------------------------------------------------
196 //
197 // plbuf_ssub()
198 //
199 // Set the number of subpages. Required to carry out commands which apply to
200 // just one sub page such as plclear
201 //--------------------------------------------------------------------------
202 
203 void
205 {
206  dbug_enter( "plbuf_setsub" );
207 
208  wr_command( pls, (U_CHAR) SSUB );
209  wr_data( pls, &pls->nsubx, sizeof ( pls->nsubx ) );
210  wr_data( pls, &pls->nsuby, sizeof ( pls->nsuby ) );
211 }
212 
213 //--------------------------------------------------------------------------
214 // plbuf_tidy()
215 //
216 // Close graphics file
217 //--------------------------------------------------------------------------
218 
219 void
221 {
222  dbug_enter( "plbuf_tidy" );
223 }
224 
225 //--------------------------------------------------------------------------
226 // plbuf_line()
227 //
228 // Draw a line in the current color from (x1,y1) to (x2,y2).
229 //--------------------------------------------------------------------------
230 
231 void
232 plbuf_line( PLStream *pls, short x1a, short y1a, short x2a, short y2a )
233 {
234  short xpl[2], ypl[2];
235 
236  dbug_enter( "plbuf_line" );
237 
238  wr_command( pls, (U_CHAR) LINE );
239 
240  xpl[0] = x1a;
241  xpl[1] = x2a;
242  ypl[0] = y1a;
243  ypl[1] = y2a;
244 
245  //store the clipping information first
246  //wr_data( pls, &pls->clpxmi, sizeof ( pls->clpxmi ) );
247 // wr_data( pls, &pls->clpxma, sizeof ( pls->clpxma ) );
248 // wr_data( pls, &pls->clpymi, sizeof ( pls->clpymi ) );
249 // wr_data( pls, &pls->clpyma, sizeof ( pls->clpyma ) );
250 
251  //then the line data
252  wr_data( pls, xpl, sizeof ( short ) * 2 );
253  wr_data( pls, ypl, sizeof ( short ) * 2 );
254 }
255 
256 //--------------------------------------------------------------------------
257 // plbuf_polyline()
258 //
259 // Draw a polyline in the current color.
260 //--------------------------------------------------------------------------
261 
262 void
263 plbuf_polyline( PLStream *pls, short *xa, short *ya, PLINT npts )
264 {
265  dbug_enter( "plbuf_polyline" );
266 
267  wr_command( pls, (U_CHAR) POLYLINE );
268 
269  //store the clipping information first
270  //wr_data( pls, &pls->clpxmi, sizeof ( pls->clpxmi ) );
271 // wr_data( pls, &pls->clpxma, sizeof ( pls->clpxma ) );
272 // wr_data( pls, &pls->clpymi, sizeof ( pls->clpymi ) );
273 // wr_data( pls, &pls->clpyma, sizeof ( pls->clpyma ) );
274 
275  //then the number of points
276  wr_data( pls, &npts, sizeof ( PLINT ) );
277 
278  //then the point data
279  wr_data( pls, xa, sizeof ( short ) * (size_t) npts );
280  wr_data( pls, ya, sizeof ( short ) * (size_t) npts );
281 }
282 
283 //--------------------------------------------------------------------------
284 // plbuf_state()
285 //
286 // Handle change in PLStream state (color, pen width, fill attribute, etc).
287 //--------------------------------------------------------------------------
288 
289 void
291 {
292  dbug_enter( "plbuf_state" );
293 
294  wr_command( pls, (U_CHAR) CHANGE_STATE );
295  wr_command( pls, (U_CHAR) op );
296 
297  switch ( op )
298  {
299  case PLSTATE_WIDTH:
300  wr_data( pls, &( pls->width ), sizeof ( pls->width ) );
301  break;
302 
303  case PLSTATE_COLOR0:
304  wr_data( pls, &( pls->icol0 ), sizeof ( pls->icol0 ) );
305  if ( pls->icol0 == PL_RGB_COLOR )
306  {
307  wr_data( pls, &( pls->curcolor.r ), sizeof ( pls->curcolor.r ) );
308  wr_data( pls, &( pls->curcolor.g ), sizeof ( pls->curcolor.g ) );
309  wr_data( pls, &( pls->curcolor.b ), sizeof ( pls->curcolor.b ) );
310  wr_data( pls, &( pls->curcolor.a ), sizeof ( pls->curcolor.a ) );
311  }
312  break;
313 
314  case PLSTATE_COLOR1:
315  wr_data( pls, &( pls->icol1 ), sizeof ( pls->icol1 ) );
316  break;
317 
318  case PLSTATE_FILL:
319  wr_data( pls, &( pls->patt ), sizeof ( pls->patt ) );
320  wr_data( pls, &( pls->nps ), sizeof ( pls->nps ) );
321  wr_data( pls, &( pls->inclin[0] ), sizeof ( pls->inclin ) );
322  wr_data( pls, &( pls->delta[0] ), sizeof ( pls->delta ) );
323  break;
324 
325  case PLSTATE_CMAP0:
326  // Save the number of colors in the palatte
327  wr_data( pls, &( pls->ncol0 ), sizeof ( pls->ncol0 ) );
328  // Save the color palatte
329  wr_data( pls, &( pls->cmap0[0] ), sizeof ( PLColor ) * pls->ncol0 );
330  break;
331 
332  case PLSTATE_CMAP1:
333  // Save the number of colors in the palatte
334  wr_data( pls, &( pls->ncol1 ), sizeof ( pls->ncol1 ) );
335  // Save the color palatte
336  wr_data( pls, &( pls->cmap1[0] ), sizeof ( PLColor ) * pls->ncol1 );
337  break;
338 
339  case PLSTATE_CHR:
340  //save the chrdef and chrht parameters
341  wr_data( pls, &( pls->chrdef ), sizeof ( pls->chrdef ) );
342  wr_data( pls, &( pls->chrht ), sizeof ( pls->chrht ) );
343  break;
344 
345  case PLSTATE_SYM:
346  //save the symdef and symht parameters
347  wr_data( pls, &( pls->symdef ), sizeof ( pls->symdef ) );
348  wr_data( pls, &( pls->symht ), sizeof ( pls->symht ) );
349  break;
350  }
351 }
352 
353 
354 //--------------------------------------------------------------------------
355 // plbuf_image()
356 //
357 // write image described in points pls->dev_x[], pls->dev_y[], pls->dev_z[].
358 // pls->nptsX, pls->nptsY.
359 //--------------------------------------------------------------------------
360 
361 static void
363 {
364  PLINT npts = pls->dev_nptsX * pls->dev_nptsY;
365 
366  dbug_enter( "plbuf_image" );
367 
368  wr_data( pls, &pls->dev_nptsX, sizeof ( PLINT ) );
369  wr_data( pls, &pls->dev_nptsY, sizeof ( PLINT ) );
370 
371  wr_data( pls, &img_dt->xmin, sizeof ( PLFLT ) );
372  wr_data( pls, &img_dt->ymin, sizeof ( PLFLT ) );
373  wr_data( pls, &img_dt->dx, sizeof ( PLFLT ) );
374  wr_data( pls, &img_dt->dy, sizeof ( PLFLT ) );
375 
376  wr_data( pls, &pls->dev_zmin, sizeof ( short ) );
377  wr_data( pls, &pls->dev_zmax, sizeof ( short ) );
378 
379  wr_data( pls, pls->dev_ix, sizeof ( short ) * (size_t) npts );
380  wr_data( pls, pls->dev_iy, sizeof ( short ) * (size_t) npts );
381  wr_data( pls, pls->dev_z,
382  sizeof ( unsigned short )
383  * (size_t) ( ( pls->dev_nptsX - 1 ) * ( pls->dev_nptsY - 1 ) ) );
384 }
385 
386 //--------------------------------------------------------------------------
387 // plbuf_text()
388 //
389 // Handle text call.
390 //--------------------------------------------------------------------------
391 
392 static void
394 {
395  dbug_enter( "plbuf_text" );
396 
397  // Check for missing data.
398  if ( text == NULL )
399  return;
400 
401  // Store the state information needed to render the text
402 
403  wr_data( pls, &pls->chrht, sizeof ( pls->chrht ) );
404  wr_data( pls, &pls->diorot, sizeof ( pls->diorot ) );
405  //wr_data( pls, &pls->clpxmi, sizeof ( pls->clpxmi ) );
406 // wr_data( pls, &pls->clpxma, sizeof ( pls->clpxma ) );
407 // wr_data( pls, &pls->clpymi, sizeof ( pls->clpymi ) );
408 // wr_data( pls, &pls->clpyma, sizeof ( pls->clpyma ) );
409 
410  // Store the text layout information
411 
412  wr_data( pls, &text->base, sizeof ( text->base ) );
413  wr_data( pls, &text->just, sizeof ( text->just ) );
414  wr_data( pls, text->xform, sizeof ( text->xform[0] ) * 4 );
415  wr_data( pls, &text->x, sizeof ( text->x ) );
416  wr_data( pls, &text->y, sizeof ( text->y ) );
417  wr_data( pls, &text->refx, sizeof ( text->refx ) );
418  wr_data( pls, &text->refy, sizeof ( text->refy ) );
419  wr_data( pls, &text->font_face, sizeof ( text->font_face ) );
420 
421  // Store the text
422 
423  if ( pls->dev_unicode )
424  {
425  PLUNICODE fci;
426 
427  // Retrieve and store the font characterization integer
428  plgfci( &fci );
429 
430  wr_data( pls, &fci, sizeof ( fci ) );
431 
432  wr_data( pls, &text->unicode_array_len, sizeof ( U_SHORT ) );
433  if ( text->unicode_array_len )
434  wr_data( pls,
435  text->unicode_array,
436  sizeof ( PLUNICODE ) * text->unicode_array_len );
437  }
438  else
439  {
440  U_SHORT len;
441 
442  // len + 1 to copy the NUL termination
443  len = strlen( text->string ) + 1;
444  wr_data( pls, &len, sizeof ( len ) );
445  if ( len > 0 )
446  wr_data( pls, (void *) text->string, sizeof ( char ) * len );
447  }
448 }
449 
450 //--------------------------------------------------------------------------
451 // plbuf_text_unicode()
452 //
453 // Handle text buffering for the new unicode pathway.
454 //--------------------------------------------------------------------------
455 
456 static void
458 {
459  PLUNICODE fci;
460 
461  dbug_enter( "plbuf_text_unicode" );
462 }
463 
464 
465 //--------------------------------------------------------------------------
466 // plbuf_esc()
467 //
468 // Escape function. Note that any data written must be in device
469 // independent form to maintain the transportability of the metafile.
470 //
471 // Functions:
472 //
473 // PLESC_FILL Fill polygon
474 // PLESC_SWIN Set plot window parameters
475 // PLESC_IMAGE Draw image
476 // PLESC_HAS_TEXT Draw PostScript text
477 // PLESC_CLEAR Clear Background
478 // PLESC_START_RASTERIZE
479 // PLESC_END_RASTERIZE Start and stop rasterization
480 //--------------------------------------------------------------------------
481 
482 void
483 plbuf_esc( PLStream *pls, PLINT op, void *ptr )
484 {
485  plbuffer *buffer;
486  dbug_enter( "plbuf_esc" );
487 
488  wr_command( pls, (U_CHAR) ESCAPE );
489  wr_command( pls, (U_CHAR) op );
490 
491  switch ( op )
492  {
493  case PLESC_FILL:
494  plbuf_fill( pls );
495  break;
496 
497  case PLESC_SWIN:
498  plbuf_swin( pls, (PLWindow *) ptr );
499  break;
500 
501  case PLESC_IMAGE:
502  plbuf_image( pls, (IMG_DT *) ptr );
503  break;
504 
505  // Unicode and non-Unicode text handling
506  case PLESC_HAS_TEXT:
507  plbuf_text( pls, (EscText *) ptr );
508  break;
509 
510  // Alternate Unicode text handling
511  case PLESC_BEGIN_TEXT:
512  case PLESC_TEXT_CHAR:
513  case PLESC_CONTROL_CHAR:
514  case PLESC_END_TEXT:
515  // The alternative unicode processing is not correctly implemented
516  // and is currently only used by Cairo, which handles its own
517  // redraws. Skip further processing for now
518 
519  //plbuf_text_unicode( pls, (EscText *) ptr );
520  break;
521 
522  case PLESC_IMPORT_BUFFER:
523  {
524  size_t extraSize;
525  buffer = (plbuffer *) ptr;
526  extraSize = buffer->size > pls->plbuf_top ? buffer->size - pls->plbuf_top : 0;
527  check_buffer_size( pls, extraSize );
528  memcpy( pls->plbuf_buffer, buffer->buffer, buffer->size );
529  pls->plbuf_top = buffer->size;
530  break;
531  }
532 
533  case PLESC_APPEND_BUFFER:
534  buffer = (plbuffer *) ptr;
535  check_buffer_size( pls, buffer->size );
536  memcpy( (char *) ( pls->plbuf_buffer ) + pls->plbuf_top, buffer->buffer, buffer->size );
537  pls->plbuf_top += buffer->size;
538  break;
539 
541  plFlushBuffer( pls, FALSE, (size_t) ( -1 ) );
542  break;
543 
544 #if 0
545  // These are a no-op. They just need an entry in the buffer.
546  case PLESC_CLEAR:
548  case PLESC_END_RASTERIZE:
549  break;
550 #endif
551  }
552 }
553 
554 //--------------------------------------------------------------------------
555 // plbuf_di()
556 //
557 // Driver interface function. Saves all info needed for a call to pldi_ini()
558 // e.g.orientation etc.
559 //--------------------------------------------------------------------------
561 {
563 
564  wr_data( pls, &pls->difilt, sizeof ( pls->difilt ) );
565  wr_data( pls, &pls->dipxmin, sizeof ( pls->dipxmin ) );
566  wr_data( pls, &pls->dipymin, sizeof ( pls->dipymin ) );
567  wr_data( pls, &pls->dipxmax, sizeof ( pls->dipxmax ) );
568  wr_data( pls, &pls->dipymax, sizeof ( pls->dipymax ) );
569  wr_data( pls, &pls->aspect, sizeof ( pls->aspect ) );
570  wr_data( pls, &pls->mar, sizeof ( pls->mar ) );
571  wr_data( pls, &pls->jx, sizeof ( pls->jx ) );
572  wr_data( pls, &pls->jy, sizeof ( pls->jy ) );
573  wr_data( pls, &pls->diorot, sizeof ( pls->diorot ) );
574  wr_data( pls, &pls->dimxmin, sizeof ( pls->dimxmin ) );
575  wr_data( pls, &pls->dimymin, sizeof ( pls->dimymin ) );
576  wr_data( pls, &pls->dimxmax, sizeof ( pls->dimxmax ) );
577  wr_data( pls, &pls->dimymax, sizeof ( pls->dimymax ) );
578  wr_data( pls, &pls->dimxpmm, sizeof ( pls->dimxpmm ) );
579  wr_data( pls, &pls->dimypmm, sizeof ( pls->dimypmm ) );
580 }
581 
582 //--------------------------------------------------------------------------
583 // plbuf_fill()
584 //
585 // Fill polygon described in points pls->dev_x[] and pls->dev_y[].
586 //--------------------------------------------------------------------------
587 
588 static void
590 {
591  dbug_enter( "plbuf_fill" );
592 
593  wr_data( pls, &pls->dev_npts, sizeof ( PLINT ) );
594  wr_data( pls, pls->dev_x, sizeof ( short ) * (size_t) pls->dev_npts );
595  wr_data( pls, pls->dev_y, sizeof ( short ) * (size_t) pls->dev_npts );
596 }
597 
598 //--------------------------------------------------------------------------
599 // plbuf_clip
600 //
601 // Set the clipping limits
602 //--------------------------------------------------------------------------
603 void
605 {
606  dbug_enter( "plbuf_clip" );
607 
608  wr_command( pls, (U_CHAR) CLIP );
609 
610  wr_data( pls, &pls->clpxmi, sizeof ( pls->clpxmi ) );
611  wr_data( pls, &pls->clpxma, sizeof ( pls->clpxma ) );
612  wr_data( pls, &pls->clpymi, sizeof ( pls->clpymi ) );
613  wr_data( pls, &pls->clpyma, sizeof ( pls->clpyma ) );
614 }
615 
616 //--------------------------------------------------------------------------
617 // plbuf_swin()
618 //
619 // Set up plot window parameters.
620 //--------------------------------------------------------------------------
621 
622 static void
624 {
625  dbug_enter( "plbuf_swin" );
626 
627  wr_data( pls, &plwin->dxmi, sizeof ( plwin->dxmi ) );
628  wr_data( pls, &plwin->dxma, sizeof ( plwin->dxma ) );
629  wr_data( pls, &plwin->dymi, sizeof ( plwin->dymi ) );
630  wr_data( pls, &plwin->dyma, sizeof ( plwin->dyma ) );
631 
632  wr_data( pls, &plwin->wxmi, sizeof ( plwin->wxmi ) );
633  wr_data( pls, &plwin->wxma, sizeof ( plwin->wxma ) );
634  wr_data( pls, &plwin->wymi, sizeof ( plwin->wymi ) );
635  wr_data( pls, &plwin->wyma, sizeof ( plwin->wyma ) );
636 }
637 
638 //--------------------------------------------------------------------------
639 // Routines to read from & process the plot buffer.
640 //--------------------------------------------------------------------------
641 
642 //--------------------------------------------------------------------------
643 // plbuf_write()
644 //
645 // Provides an interface for other parts of PLplot (e.g. plmetafile.c) to
646 // write into the buffer. The reason why wr_command and wr_data are not
647 // exposed is to help the optimizer to inline those two functions.
648 //--------------------------------------------------------------------------
649 void plbuf_write( PLStream *pls, void *data, size_t bytes )
650 {
651  wr_data( pls, data, bytes );
652 }
653 
654 //--------------------------------------------------------------------------
655 // rdbuf_init()
656 //
657 // Initialize device.
658 //--------------------------------------------------------------------------
659 
660 static void
662 {
663  dbug_enter( "rdbuf_init" );
664 }
665 
666 //--------------------------------------------------------------------------
667 // rdbuf_eop()
668 //
669 // End of page.
670 //--------------------------------------------------------------------------
671 
672 static void
674 {
675  dbug_enter( "rdbuf_eop" );
676 }
677 
678 //--------------------------------------------------------------------------
679 // rdbuf_bop()
680 //
681 // Set up for the next page.
682 //--------------------------------------------------------------------------
683 
684 static void
686 {
687  U_CHAR cmd = 0;
688  int nRead;
689 
690  dbug_enter( "rdbuf_bop" );
691 
692  pls->nplwin = 0;
693 
694  // Read the current color state from the plot buffer
695  rd_data( pls, &( pls->icol0 ), sizeof ( pls->icol0 ) );
696  rd_data( pls, &( pls->icol1 ), sizeof ( pls->icol1 ) );
697  rd_data( pls, &( pls->curcolor ), sizeof ( pls->curcolor ) );
698  rd_data( pls, &( pls->curcmap ), sizeof ( pls->curcmap ) );
699  rd_data( pls, &( pls->nsubx ), sizeof ( pls->nsubx ) );
700  rd_data( pls, &( pls->nsuby ), sizeof ( pls->nsuby ) );
701 
702  // We need to read the colormaps that were stored by plbuf_bop
703  // now because when plP_state is used to set the color, a wrong
704  // colormap will be used if it was changed.
705 
706  // Read the command (should be CHANGE_STATE PLSTATE_CMAP0)
707  nRead = rd_command( pls, &cmd );
708  if ( nRead == 0 || cmd != CHANGE_STATE )
709  {
710  plabort( "rdbuf_bop: Error reading first change state" );
711  return;
712  }
713  plbuf_control( pls, cmd );
714 
715  // Read the command (should be CHANGE_STATE PLSTATE_CMAP1)
716  nRead = rd_command( pls, &cmd );
717  if ( nRead == 0 || cmd != CHANGE_STATE )
718  {
719  plabort( "rdbuf_bop: Error reading second change state" );
720  return;
721  }
722  plbuf_control( pls, cmd );
723 
724  // Read the command (should be CHANGE_STATE PLSTATE_WIDTH)
725  nRead = rd_command( pls, &cmd );
726  if ( nRead == 0 || cmd != CHANGE_STATE )
727  {
728  plabort( "rdbuf_bop: Error reading third change state" );
729  return;
730  }
731  plbuf_control( pls, cmd );
732 
733  // Read the command (should be CHANGE_STATE PLSTATE_FILL)
734  nRead = rd_command( pls, &cmd );
735  if ( nRead == 0 || cmd != CHANGE_STATE )
736  {
737  plabort( "rdbuf_bop: Error reading fourth change state" );
738  return;
739  }
740  plbuf_control( pls, cmd );
741 
742  // Read the command (should be CHANGE_STATE PLSTATE_CHR)
743  nRead = rd_command( pls, &cmd );
744  if ( nRead == 0 || cmd != CHANGE_STATE )
745  {
746  plabort( "rdbuf_bop: Error reading fifth change state" );
747  return;
748  }
749  plbuf_control( pls, cmd );
750 
751  // Read the command (should be CHANGE_STATE PLSTATE_SYM)
752  nRead = rd_command( pls, &cmd );
753  if ( nRead == 0 || cmd != CHANGE_STATE )
754  {
755  plabort( "rdbuf_bop: Error reading sixth change state" );
756  return;
757  }
758  plbuf_control( pls, cmd );
759 
760  // and now we can set the color
761  if ( pls->curcmap == 0 )
762  {
764  }
765  else
766  {
768  }
769 
770  plP_bop();
771 }
772 
773 //--------------------------------------------------------------------------
774 // rdbuf_setsub()
775 //
776 // set the subpage
777 //--------------------------------------------------------------------------
778 
779 static void
781 {
782  rd_data( pls, (void *) ( &pls->cursub ), sizeof ( pls->cursub ) );
783  plP_setsub();
784 }
785 
786 //--------------------------------------------------------------------------
787 // rdbuf_ssub()
788 //
789 // set the subpage number of subpages
790 //--------------------------------------------------------------------------
791 
792 static void
794 {
795  rd_data( pls, (void *) ( &pls->nsubx ), sizeof ( pls->nsubx ) );
796  rd_data( pls, (void *) ( &pls->nsuby ), sizeof ( pls->nsuby ) );
797  c_plssub( pls->nsubx, pls->nsuby );
798 }
799 
800 //--------------------------------------------------------------------------
801 // rdbuf_line()
802 //
803 // Draw a line in the current color from (x1,y1) to (x2,y2).
804 //--------------------------------------------------------------------------
805 
806 static void
808 {
809  short *xpl, *ypl;
810  PLINT npts = 2;
811 
812  dbug_enter( "rdbuf_line" );
813 
814  //read the clipping data first
815  //rd_data( pls, &pls->clpxmi, sizeof ( pls->clpxmi ) );
816 // rd_data( pls, &pls->clpxma, sizeof ( pls->clpxma ) );
817 // rd_data( pls, &pls->clpymi, sizeof ( pls->clpymi ) );
818 // rd_data( pls, &pls->clpyma, sizeof ( pls->clpyma ) );
819 
820  //then the line data
821  // Use the "no copy" version because the endpoint data array does
822  // not need to persist outside of this function
823  rd_data_no_copy( pls, (void **) &xpl, sizeof ( short ) * (size_t) npts );
824  rd_data_no_copy( pls, (void **) &ypl, sizeof ( short ) * (size_t) npts );
825 
826  plP_line( xpl, ypl );
827 }
828 
829 //--------------------------------------------------------------------------
830 // rdbuf_polyline()
831 //
832 // Draw a polyline in the current color.
833 //--------------------------------------------------------------------------
834 
835 static void
837 {
838  short *xpl, *ypl;
839  PLINT npts;
840 
841  dbug_enter( "rdbuf_polyline" );
842 
843  //read the clipping data first
844  //rd_data( pls, &pls->clpxmi, sizeof ( pls->clpxmi ) );
845 // rd_data( pls, &pls->clpxma, sizeof ( pls->clpxma ) );
846 // rd_data( pls, &pls->clpymi, sizeof ( pls->clpymi ) );
847 // rd_data( pls, &pls->clpyma, sizeof ( pls->clpyma ) );
848 
849  //then the number of points
850  rd_data( pls, &npts, sizeof ( PLINT ) );
851 
852  //then the line data
853  // Use the "no copy" version because the node data array does
854  // not need to persist outside of ths function
855  rd_data_no_copy( pls, (void **) &xpl, sizeof ( short ) * (size_t) npts );
856  rd_data_no_copy( pls, (void **) &ypl, sizeof ( short ) * (size_t) npts );
857 
858  plP_polyline( xpl, ypl, npts );
859 }
860 
861 //--------------------------------------------------------------------------
862 // rdbuf_state()
863 //
864 // Handle change in PLStream state (color, pen width, fill attribute, etc).
865 //--------------------------------------------------------------------------
866 
867 static void
869 {
870  U_CHAR op;
871 
872  dbug_enter( "rdbuf_state" );
873 
874  rd_data( pls, &op, sizeof ( U_CHAR ) );
875 
876  switch ( op )
877  {
878  case PLSTATE_WIDTH: {
879  rd_data( pls, &( pls->width ), sizeof ( pls->width ) );
881 
882  break;
883  }
884 
885  case PLSTATE_COLOR0: {
886  U_CHAR r, g, b;
887  PLFLT a;
888 
889  rd_data( pls, &( pls->icol0 ), sizeof ( pls->icol0 ) );
890  if ( pls->icol0 == PL_RGB_COLOR )
891  {
892  rd_data( pls, &r, sizeof ( U_CHAR ) );
893  rd_data( pls, &g, sizeof ( U_CHAR ) );
894  rd_data( pls, &b, sizeof ( U_CHAR ) );
895  rd_data( pls, &a, sizeof ( U_CHAR ) );
896  }
897  else
898  {
899  if ( pls->icol0 >= pls->ncol0 )
900  {
901  char buffer[256];
902  snprintf( buffer, 256,
903  "rdbuf_state: Invalid color map entry: %d",
904  pls->icol0 );
905  plabort( buffer );
906  return;
907  }
908  r = pls->cmap0[pls->icol0].r;
909  g = pls->cmap0[pls->icol0].g;
910  b = pls->cmap0[pls->icol0].b;
911  a = pls->cmap0[pls->icol0].a;
912  }
913  pls->curcolor.r = r;
914  pls->curcolor.g = g;
915  pls->curcolor.b = b;
916  pls->curcolor.a = a;
917  pls->curcmap = 0;
918 
920  break;
921  }
922 
923  case PLSTATE_COLOR1: {
924  rd_data( pls, &( pls->icol1 ), sizeof ( pls->icol1 ) );
925 
926  pls->curcolor.r = pls->cmap1[pls->icol1].r;
927  pls->curcolor.g = pls->cmap1[pls->icol1].g;
928  pls->curcolor.b = pls->cmap1[pls->icol1].b;
929  pls->curcolor.a = pls->cmap1[pls->icol1].a;
930  pls->curcmap = 1;
931 
933  break;
934  }
935 
936  case PLSTATE_FILL: {
937  PLINT patt, nps, inclin[2], delta[2];
938  rd_data( pls, &patt, sizeof ( patt ) );
939  rd_data( pls, &nps, sizeof ( nps ) );
940  rd_data( pls, &inclin[0], sizeof ( inclin ) );
941  rd_data( pls, &delta[0], sizeof ( delta ) );
942  if ( nps != 0 )
943  c_plpat( nps, inclin, delta );
944  pls->patt = patt; //this must be second as c_plpat sets pls->patt to an nvalid value
945  break;
946  }
947 
948  case PLSTATE_CMAP0: {
949  PLINT ncol;
950  size_t size;
951 
952  rd_data( pls, &ncol, sizeof ( ncol ) );
953 
954  // Calculate the memory size for this color palatte
955  size = (size_t) ncol * sizeof ( PLColor );
956 
957  if ( pls->ncol0 == 0 || pls->ncol0 != ncol )
958  {
959  // The current palatte is empty or the current palatte is not
960  // correctly sized, thus we need allocate a new one
961 
962  // If we have a colormap, discard it because we do not use
963  // realloc(). We are going to read the colormap from the buffer
964  if ( pls->cmap0 != NULL )
965  free( pls->cmap0 );
966 
967  if ( ( pls->cmap0 = (PLColor *) malloc( size ) ) == NULL )
968  {
969  plexit( "Insufficient memory for colormap 0" );
970  }
971  }
972 
973  // Now read the colormap from the buffer
974  rd_data( pls, &( pls->cmap0[0] ), size );
975  pls->ncol0 = ncol;
976 
978  break;
979  }
980 
981  case PLSTATE_CMAP1: {
982  PLINT ncol;
983  size_t size;
984 
985  rd_data( pls, &ncol, sizeof ( ncol ) );
986 
987  // Calculate the memory size for this color palatte
988  size = (size_t) ncol * sizeof ( PLColor );
989 
990  if ( pls->ncol1 == 0 || pls->ncol1 != ncol )
991  {
992  // The current palatte is empty or the current palatte is not
993  // correctly sized, thus we need allocate a new one
994 
995  // If we have a colormap, discard it because we do not use
996  // realloc(). We are going to read the colormap from the buffer
997  if ( pls->cmap1 != NULL )
998  free( pls->cmap1 );
999 
1000  if ( ( pls->cmap1 = (PLColor *) malloc( size ) ) == NULL )
1001  {
1002  plexit( "Insufficient memory for colormap 1" );
1003  }
1004  }
1005 
1006  // Now read the colormap from the buffer
1007  rd_data( pls, &( pls->cmap1[0] ), size );
1008  pls->ncol1 = ncol;
1009 
1011  break;
1012  }
1013 
1014  case PLSTATE_CHR: {
1015  //read the chrdef and chrht parameters
1016  rd_data( pls, &( pls->chrdef ), sizeof ( pls->chrdef ) );
1017  rd_data( pls, &( pls->chrht ), sizeof ( pls->chrht ) );
1018  break;
1019  }
1020 
1021  case PLSTATE_SYM: {
1022  //read the symdef and symht parameters
1023  rd_data( pls, &( pls->symdef ), sizeof ( pls->symdef ) );
1024  rd_data( pls, &( pls->symht ), sizeof ( pls->symht ) );
1025  break;
1026  }
1027  }
1028 }
1029 
1030 //--------------------------------------------------------------------------
1031 // rdbuf_esc()
1032 //
1033 // Escape function.
1034 // Must fill data structure with whatever data that was written,
1035 // then call escape function.
1036 //
1037 // Note: it is best to only call the escape function for op-codes that
1038 // are known to be supported.
1039 //
1040 // Functions:
1041 //
1042 // PLESC_FILL Fill polygon
1043 // PLESC_SWIN Set plot window parameters
1044 // PLESC_IMAGE Draw image
1045 // PLESC_HAS_TEXT Draw PostScript text
1046 // PLESC_BEGIN_TEXT Commands for the alternative unicode text
1047 // PLESC_TEXT_CHAR handling path
1048 // PLESC_CONTROL_CHAR
1049 // PLESC_END_TEXT
1050 // PLESC_CLEAR Clear Background
1051 //--------------------------------------------------------------------------
1052 
1053 static void
1055 {
1056  U_CHAR op;
1057 
1058  dbug_enter( "rdbuf_esc" );
1059 
1060  rd_data( pls, &op, sizeof ( U_CHAR ) );
1061 
1062  switch ( op )
1063  {
1064  case PLESC_FILL:
1065  rdbuf_fill( pls );
1066  break;
1067  case PLESC_SWIN:
1068  rdbuf_swin( pls );
1069  break;
1070  case PLESC_IMAGE:
1071  rdbuf_image( pls );
1072  break;
1073  case PLESC_HAS_TEXT:
1074  rdbuf_text( pls );
1075  break;
1076  case PLESC_BEGIN_TEXT:
1077  case PLESC_TEXT_CHAR:
1078  case PLESC_CONTROL_CHAR:
1079  case PLESC_END_TEXT:
1080  // Disable for now because alternative unicode processing is
1081  // not correctly implemented
1082 
1083  //rdbuf_text_unicode( op, pls );
1084  break;
1085  case PLESC_IMPORT_BUFFER:
1086  // Place holder until an appropriate action is determined.
1087  // Should this even be an ESC operation?
1088  break;
1089  case PLESC_CLEAR:
1090  plP_esc( PLESC_CLEAR, NULL );
1091  break;
1092  case PLESC_START_RASTERIZE:
1093  plP_esc( PLESC_START_RASTERIZE, NULL );
1094  break;
1095  case PLESC_END_RASTERIZE:
1096  plP_esc( PLESC_END_RASTERIZE, NULL );
1097  break;
1098  }
1099 }
1100 
1101 //--------------------------------------------------------------------------
1102 // rdbuf_fill()
1103 //
1104 // Fill polygon described by input points.
1105 //--------------------------------------------------------------------------
1106 
1107 static void
1109 {
1110  short *xpl, *ypl;
1111  PLINT npts;
1112 
1113  dbug_enter( "rdbuf_fill" );
1114 
1115  rd_data( pls, &npts, sizeof ( PLINT ) );
1116 
1117  rd_data_no_copy( pls, (void **) &xpl, sizeof ( short ) * (size_t) npts );
1118  rd_data_no_copy( pls, (void **) &ypl, sizeof ( short ) * (size_t) npts );
1119 
1120  plP_fill( xpl, ypl, npts );
1121 }
1122 
1123 //--------------------------------------------------------------------------
1124 //
1125 // rdbuf_clip()
1126 //
1127 //
1128 //--------------------------------------------------------------------------
1129 static void
1131 {
1132  rd_data( pls, &pls->clpxmi, sizeof ( pls->clpxmi ) );
1133  rd_data( pls, &pls->clpxma, sizeof ( pls->clpxma ) );
1134  rd_data( pls, &pls->clpymi, sizeof ( pls->clpymi ) );
1135  rd_data( pls, &pls->clpyma, sizeof ( pls->clpyma ) );
1136 }
1137 
1138 //--------------------------------------------------------------------------
1139 // rdbuf_image()
1140 //
1141 // .
1142 //--------------------------------------------------------------------------
1143 
1144 static void
1146 {
1147  // Unnecessarily initialize dev_iy and dev_z to quiet -O1
1148  // -Wuninitialized warnings which are false alarms. (If something
1149  // goes wrong with the dev_ix malloc below any further use of
1150  // dev_iy and dev_z does not occur. Similarly, if something goes
1151  // wrong with the dev_iy malloc below any further use of dev_z
1152  // does not occur.)
1153  short *dev_ix, *dev_iy = NULL;
1154  unsigned short *dev_z = NULL, dev_zmin, dev_zmax;
1155  PLINT nptsX, nptsY, npts;
1156  PLFLT xmin, ymin, dx, dy;
1157 
1158  dbug_enter( "rdbuf_image" );
1159 
1160  rd_data( pls, &nptsX, sizeof ( PLINT ) );
1161  rd_data( pls, &nptsY, sizeof ( PLINT ) );
1162  npts = nptsX * nptsY;
1163 
1164  rd_data( pls, &xmin, sizeof ( PLFLT ) );
1165  rd_data( pls, &ymin, sizeof ( PLFLT ) );
1166  rd_data( pls, &dx, sizeof ( PLFLT ) );
1167  rd_data( pls, &dy, sizeof ( PLFLT ) );
1168 
1169  rd_data( pls, &dev_zmin, sizeof ( short ) );
1170  rd_data( pls, &dev_zmax, sizeof ( short ) );
1171 
1172  // NOTE: Even though for memory buffered version all the data is in memory,
1173  // we still allocate and copy the data because I think that method works
1174  // better in a multithreaded environment. I could be wrong.
1175  //
1176  if ( ( ( dev_ix = (short *) malloc( (size_t) npts * sizeof ( short ) ) ) == NULL ) ||
1177  ( ( dev_iy = (short *) malloc( (size_t) npts * sizeof ( short ) ) ) == NULL ) ||
1178  ( ( dev_z = (unsigned short *) malloc( (size_t) ( ( nptsX - 1 ) * ( nptsY - 1 ) ) * sizeof ( unsigned short ) ) ) == NULL ) )
1179  plexit( "rdbuf_image: Insufficient memory" );
1180 
1181  rd_data( pls, dev_ix, sizeof ( short ) * (size_t) npts );
1182  rd_data( pls, dev_iy, sizeof ( short ) * (size_t) npts );
1183  rd_data( pls, dev_z,
1184  sizeof ( unsigned short )
1185  * (size_t) ( ( nptsX - 1 ) * ( nptsY - 1 ) ) );
1186 
1187  //
1188  // COMMENTED OUT by Hezekiah Carty
1189  // Commented (hopefullly temporarily) until the dev_fastimg rendering
1190  // path can be updated to support the new plimage internals. In the
1191  // meantime this function is not actually used so the issue of how to
1192  // update the code to support the new interface can be ignored.
1193  //
1194  //plP_image(dev_ix, dev_iy, dev_z, nptsX, nptsY, xmin, ymin, dx, dy, dev_zmin, dev_zmax);
1195 
1196  free( dev_ix );
1197  free( dev_iy );
1198  free( dev_z );
1199 }
1200 
1201 //--------------------------------------------------------------------------
1202 // rdbuf_swin()
1203 //
1204 // Set up plot window parameters.
1205 //--------------------------------------------------------------------------
1206 
1207 static void
1209 {
1210  PLWindow plwin;
1211 
1212  dbug_enter( "rdbuf_swin" );
1213 
1214  rd_data( pls, &plwin.dxmi, sizeof ( plwin.dxmi ) );
1215  rd_data( pls, &plwin.dxma, sizeof ( plwin.dxma ) );
1216  rd_data( pls, &plwin.dymi, sizeof ( plwin.dymi ) );
1217  rd_data( pls, &plwin.dyma, sizeof ( plwin.dyma ) );
1218 
1219  rd_data( pls, &plwin.wxmi, sizeof ( plwin.wxmi ) );
1220  rd_data( pls, &plwin.wxma, sizeof ( plwin.wxma ) );
1221  rd_data( pls, &plwin.wymi, sizeof ( plwin.wymi ) );
1222  rd_data( pls, &plwin.wyma, sizeof ( plwin.wyma ) );
1223 
1224  plP_swin( &plwin );
1225 }
1226 
1227 
1228 //--------------------------------------------------------------------------
1229 // rdbuf_swin()
1230 //
1231 // Set up driver interface data
1232 //--------------------------------------------------------------------------
1233 static void
1235 {
1236  PLINT difilt;
1237  PLFLT rot;
1238  PLFLT dimxmin, dimxmax, dimymin, dimymax, dimxpmm, dimypmm;
1239  PLFLT dipxmin, dipymin, dipxmax, dipymax;
1240  PLFLT aspect, mar, jx, jy;
1241  rd_data( pls, &difilt, sizeof ( difilt ) );
1242  rd_data( pls, &dipxmin, sizeof ( dipxmin ) );
1243  rd_data( pls, &dipymin, sizeof ( dipymin ) );
1244  rd_data( pls, &dipxmax, sizeof ( dipxmax ) );
1245  rd_data( pls, &dipymax, sizeof ( dipymax ) );
1246  rd_data( pls, &aspect, sizeof ( aspect ) );
1247  rd_data( pls, &mar, sizeof ( mar ) );
1248  rd_data( pls, &jx, sizeof ( jx ) );
1249  rd_data( pls, &jy, sizeof ( jy ) );
1250  rd_data( pls, &rot, sizeof ( rot ) );
1251  rd_data( pls, &dimxmin, sizeof ( dimxmin ) );
1252  rd_data( pls, &dimymin, sizeof ( dimymin ) );
1253  rd_data( pls, &dimxmax, sizeof ( dimxmax ) );
1254  rd_data( pls, &dimymax, sizeof ( dimymax ) );
1255  rd_data( pls, &dimxpmm, sizeof ( dimxpmm ) );
1256  rd_data( pls, &dimypmm, sizeof ( dimypmm ) );
1257  if ( difilt & PLDI_MAP )
1258  c_plsdimap( dimxmin, dimxmax, dimymin, dimymax, dimxpmm, dimypmm );
1259  if ( difilt & PLDI_ORI )
1260  c_plsdiori( rot );
1261  if ( difilt & PLDI_PLT )
1262  c_plsdiplt( dipxmin, dipymin, dipxmax, dipymax );
1263  if ( difilt & PLDI_DEV )
1264  c_plsdidev( mar, aspect, jx, jy );
1265 }
1266 
1267 //--------------------------------------------------------------------------
1268 // rdbuf_text()
1269 //
1270 // Render text through the driver.
1271 //--------------------------------------------------------------------------
1272 
1273 static void
1275 {
1276  EscText text;
1277  PLFLT xform[4];
1278 
1279  dbug_enter( "rdbuf_text" );
1280 
1281  text.xform = xform;
1282 
1283  // Read the state information
1284 
1285  rd_data( pls, &pls->chrht, sizeof ( pls->chrht ) );
1286  rd_data( pls, &pls->diorot, sizeof ( pls->diorot ) );
1287  //rd_data( pls, &pls->clpxmi, sizeof ( pls->clpxmi ) );
1288 // rd_data( pls, &pls->clpxma, sizeof ( pls->clpxma ) );
1289 // rd_data( pls, &pls->clpymi, sizeof ( pls->clpymi ) );
1290 // rd_data( pls, &pls->clpyma, sizeof ( pls->clpyma ) );
1291 
1292  // Read the text layout information
1293 
1294  rd_data( pls, &text.base, sizeof ( text.base ) );
1295  rd_data( pls, &text.just, sizeof ( text.just ) );
1296  rd_data( pls, text.xform, sizeof ( text.xform[0] ) * 4 );
1297  rd_data( pls, &text.x, sizeof ( text.x ) );
1298  rd_data( pls, &text.y, sizeof ( text.y ) );
1299  rd_data( pls, &text.refx, sizeof ( text.refx ) );
1300  rd_data( pls, &text.refy, sizeof ( text.refy ) );
1301  rd_data( pls, &text.font_face, sizeof ( text.font_face ) );
1302 
1303  // Initialize text arrays to NULL. This protects drivers that
1304  // determine the text representation by looking at which members
1305  // are set.
1306  text.unicode_array_len = 0;
1307  text.unicode_array = NULL;
1308  text.string = NULL;
1309 
1310  // Read in the text
1311  if ( pls->dev_unicode )
1312  {
1313  PLUNICODE fci;
1314 
1315  rd_data( pls, &fci, sizeof ( fci ) );
1316  plsfci( fci );
1317 
1318  rd_data( pls, &text.unicode_array_len, sizeof ( U_SHORT ) );
1319  if ( text.unicode_array_len )
1320  {
1321  // Set the pointer to the unicode data in the buffer. This avoids
1322  // allocating and freeing memory
1324  pls,
1325  (void **) ( &text.unicode_array ),
1326  sizeof ( PLUNICODE ) * text.unicode_array_len );
1327  }
1328  }
1329  else
1330  {
1331  U_SHORT len;
1332 
1333  rd_data( pls, &len, sizeof ( len ) );
1334  if ( len > 0 )
1335  {
1336  // Set the pointer to the string data in the buffer. This avoids
1337  // allocating and freeing memory
1339  pls,
1340  (void **) ( &text.string ),
1341  sizeof ( char ) * len );
1342  }
1343  }
1344 
1345  plP_esc( PLESC_HAS_TEXT, &text );
1346 }
1347 
1348 //--------------------------------------------------------------------------
1349 // rdbuf_text_unicode()
1350 //
1351 // Draw text for the new unicode handling pathway.
1352 // This currently does nothing but is here as a placehlder for the future
1353 //--------------------------------------------------------------------------
1354 
1355 static void
1357 {
1358  dbug_enter( "rdbuf_text_unicode" );
1359 }
1360 
1361 //--------------------------------------------------------------------------
1362 // plRemakePlot()
1363 //
1364 // Rebuilds plot from plot buffer, usually in response to a window
1365 // resize or exposure event.
1366 //--------------------------------------------------------------------------
1367 
1368 void
1370 {
1371  plFlushBuffer( pls, TRUE, (size_t) ( -1 ) );
1372 }
1373 
1374 //--------------------------------------------------------------------------
1375 // plFlushBuffer( )
1376 //
1377 // Flush the current contents of the buffer to the plot either restarting
1378 // from the beginning of the buffer or continuing from the current read
1379 // location. Setting amount to -1 will flush to the end, setting it to
1380 // another value flushes until at least that amount has been flushed then
1381 // stops
1382 //--------------------------------------------------------------------------
1383 
1384 void
1385 plFlushBuffer( PLStream *pls, PLBOOL restart, size_t amount )
1386 {
1387  U_CHAR c;
1389  PLINT cursub;
1390 
1391  dbug_enter( "plRemakePlot" );
1392 
1393  // Change the status of the flags before checking for a buffer.
1394  // Actually, more thought is needed if we want to support multithreaded
1395  // code correctly, specifically the case where two threads are using
1396  // the same plot stream (e.g. one thread is drawing the plot and another
1397  // thread is processing window manager messages).
1398  //
1399  plbuf_write = pls->plbuf_write;
1400  cursub = pls->cursub;
1401  pls->plbuf_write = FALSE;
1402  pls->plbuf_read = TRUE;
1403 
1404  if ( pls->plbuf_buffer )
1405  {
1406  // State saving variables
1407  PLStream *save_current_pls;
1408  size_t finalReadPos;
1409 
1410  // Save state
1411 
1412  // Need to change where plsc (current plot stream) points to before
1413  // processing the commands. If we have multiple plot streams, this
1414  // will prevent the commands from going to the wrong plot stream.
1415  //
1416  save_current_pls = plsc;
1417 
1418  // Make the current plot stream the one passed by the caller
1419  plsc = pls;
1420 
1421  if ( restart )
1422  {
1423  pls->plbuf_readpos = 0;
1424 
1425  //end any current page on the destination stream.
1426  //This will do nothing if we are already at the end
1427  //of a page.
1428  //Doing this ensures that the first bop command in the
1429  //buffer actually does something
1430  //plP_eop();
1431  }
1432 
1433  finalReadPos = amount == (size_t) ( -1 ) ? pls->plbuf_top : MIN( pls->plbuf_readpos + amount, pls->plbuf_top );
1434 
1435  // Replay the plot command buffer
1436  while ( rd_command( pls, &c ) && pls->plbuf_readpos < finalReadPos )
1437  {
1438  plbuf_control( pls, c );
1439  }
1440 
1441  // Restore the original current plot stream
1442  plsc = save_current_pls;
1443  }
1444 
1445  // Restore the state of the passed plot stream
1446  pls->plbuf_read = FALSE;
1447  pls->plbuf_write = plbuf_write;
1448  pls->cursub = cursub;
1449 }
1450 
1451 //--------------------------------------------------------------------------
1452 // plbuf_control()
1453 //
1454 // Processes commands read from the plot buffer.
1455 //--------------------------------------------------------------------------
1456 
1457 static void
1459 {
1460  static U_CHAR c_old = 0;
1461  static U_CHAR esc_old = 0;
1462 
1463  dbug_enter( "plbuf_control" );
1464 
1465  //#define CLOSE 2
1466  //#define LINETO 10
1467  //#define END_OF_FIELD 255
1468 
1469  switch ( (int) c )
1470  {
1471  case INITIALIZE:
1472  rdbuf_init( pls );
1473  break;
1474 
1475  case EOP:
1476  rdbuf_eop( pls );
1477  break;
1478 
1479  case BOP0:
1480  case BOP:
1481  rdbuf_bop( pls );
1482  break;
1483 
1484  case CHANGE_STATE:
1485  rdbuf_state( pls );
1486  break;
1487 
1488  case LINE:
1489  rdbuf_line( pls );
1490  break;
1491 
1492  case POLYLINE:
1493  rdbuf_polyline( pls );
1494  break;
1495 
1496  case ESCAPE:
1497  esc_old = *( (U_CHAR *) ( pls->plbuf_buffer ) + pls->plbuf_readpos );
1498  rdbuf_esc( pls );
1499  break;
1500 
1501  case DRIVER_INTERFACE:
1502  rdbuf_di( pls );
1503  break;
1504 
1505  case SETSUB:
1506  rdbuf_setsub( pls );
1507  break;
1508 
1509  case SSUB:
1510  rdbuf_ssub( pls );
1511  break;
1512 
1513  case CLIP:
1514  rdbuf_clip( pls );
1515  break;
1516 
1517  // Obsolete commands, left here to maintain compatibility with previous
1518  // version of plot metafiles
1519  case SWITCH_TO_TEXT: // Obsolete, replaced by ESCAPE
1520  case SWITCH_TO_GRAPH: // Obsolete, replaced by ESCAPE
1521  case NEW_COLOR: // Obsolete, replaced by CHANGE_STATE
1522  case NEW_COLOR1:
1523  case NEW_WIDTH: // Obsolete, replaced by CHANGE_STATE
1524  case ADVANCE: // Obsolete, BOP/EOP used instead
1525  pldebug( "plbuf_control", "Obsolete command %d, ignoring\n", c );
1526  break;
1527 
1528  default:
1529  pldebug( "plbuf_control", "Unrecognized command %d, previous %d\n",
1530  c, c_old );
1531  plexit( "Unrecognized command" );
1532  }
1533  c_old = c;
1534 }
1535 
1536 //--------------------------------------------------------------------------
1537 // rd_command()
1538 //
1539 // Read & return the next command
1540 //--------------------------------------------------------------------------
1541 
1542 static int
1544 {
1545  int count;
1546 
1547  if ( pls->plbuf_readpos < pls->plbuf_top )
1548  {
1549  *p_c = *(U_CHAR *) ( (uint8_t *) pls->plbuf_buffer + pls->plbuf_readpos );
1550 
1551  // Advance the buffer position to maintain two-byte alignment
1552  pls->plbuf_readpos += sizeof ( uint16_t );
1553 
1554  count = sizeof ( U_CHAR );
1555  }
1556  else
1557  {
1558  count = 0;
1559  }
1560 
1561  return ( count );
1562 }
1563 
1564 //--------------------------------------------------------------------------
1565 // rd_data()
1566 //
1567 // Read the data associated with the command
1568 //--------------------------------------------------------------------------
1569 
1570 static void
1571 rd_data( PLStream *pls, void *buf, size_t buf_size )
1572 {
1573  memcpy( buf, (uint8_t *) pls->plbuf_buffer + pls->plbuf_readpos, buf_size );
1574 
1575  // Advance position but maintain alignment
1576  pls->plbuf_readpos += ( buf_size + ( buf_size % sizeof ( uint16_t ) ) );
1577 }
1578 
1579 //--------------------------------------------------------------------------
1580 // rd_data_no_copy()
1581 //
1582 // Read the data associated with the command by setting a pointer to the
1583 // position in the plot buffer. This avoids having to allocate space
1584 // and doing a memcpy. Useful for commands that do not need the data
1585 // to persist (like LINE and POLYLINE). Do not use for commands that
1586 // has data that needs to persist or are freed elsewhere (like COLORMAPS).
1587 //--------------------------------------------------------------------------
1588 
1589 static void
1590 rd_data_no_copy( PLStream *pls, void **buf, size_t buf_size )
1591 {
1592  ( *buf ) = (uint8_t *) pls->plbuf_buffer + pls->plbuf_readpos;
1593 
1594  // Advance position but maintain alignment
1595  pls->plbuf_readpos += ( buf_size + ( buf_size % sizeof ( uint16_t ) ) );
1596 }
1597 
1598 //--------------------------------------------------------------------------
1599 // check_buffer_size()
1600 //
1601 // Checks that the buffer has space to store the desired amount of data.
1602 // If not, the buffer is resized to accomodate the request
1603 //--------------------------------------------------------------------------
1604 static void
1605 check_buffer_size( PLStream *pls, size_t data_size )
1606 {
1607  size_t required_size;
1608 
1609  required_size = pls->plbuf_top + data_size;
1610 
1611  if ( required_size >= pls->plbuf_buffer_size )
1612  {
1613  if ( pls->plbuf_buffer_grow == 0 )
1614  pls->plbuf_buffer_grow = 128 * 1024;
1615 
1616  // Not enough space, need to grow the buffer before memcpy
1617  // Must make sure the increase is enough for this data, so
1618  // Determine the amount of space required and grow in multiples
1619  // of plbuf_buffer_grow
1620  pls->plbuf_buffer_size += pls->plbuf_buffer_grow *
1621  ( ( required_size
1622  - pls->plbuf_buffer_size )
1623  / pls->plbuf_buffer_grow
1624  + 1 );
1625 
1626  if ( pls->verbose )
1627  printf( "Growing buffer to %d KB\n",
1628  (int) ( pls->plbuf_buffer_size / 1024 ) );
1629 
1630  if ( ( pls->plbuf_buffer
1631  = realloc( pls->plbuf_buffer, pls->plbuf_buffer_size )
1632  ) == NULL )
1633  plexit( "plbuf buffer grow: Plot buffer grow failed" );
1634  }
1635 }
1636 
1637 //--------------------------------------------------------------------------
1638 // wr_command()
1639 //
1640 // Write the next command
1641 //--------------------------------------------------------------------------
1642 
1643 static void
1645 {
1646  check_buffer_size( pls, sizeof ( uint16_t ) );
1647 
1648  *(U_CHAR *) ( (uint8_t *) pls->plbuf_buffer + pls->plbuf_top ) = c;
1649 
1650  // Advance buffer position to maintain two-byte alignment. This
1651  // will waste a little bit of space, but it prevents memory
1652  // alignment problems
1653  pls->plbuf_top += sizeof ( uint16_t );
1654 }
1655 
1656 //--------------------------------------------------------------------------
1657 // wr_data()
1658 //
1659 // Write the data associated with a command
1660 //--------------------------------------------------------------------------
1661 
1662 static void
1663 wr_data( PLStream *pls, void *buf, size_t buf_size )
1664 {
1665  check_buffer_size( pls, buf_size + ( buf_size % sizeof ( uint16_t ) ) );
1666  memcpy( (uint8_t *) pls->plbuf_buffer + pls->plbuf_top, buf, buf_size );
1667 
1668  // Advance position but maintain alignment
1669  pls->plbuf_top += ( buf_size + ( buf_size % sizeof ( uint16_t ) ) );
1670 }
1671 
1672 
1673 //--------------------------------------------------------------------------
1674 // Plot buffer state saving
1675 //--------------------------------------------------------------------------
1676 
1677 // plbuf_save(state)
1678 //
1679 // Saves the current state of the plot into a save buffer. The
1680 // original code used a temporary file for the plot buffer and memory
1681 // to perserve colormaps. That method does not offer a clean break
1682 // between using memory buffers and file buffers. This function
1683 // preserves the same functionality by returning a data structure that
1684 // saves the plot buffer.
1685 //
1686 // The caller passes an existing save buffer for reuse or NULL
1687 // to force the allocation of a new buffer. Since one malloc()
1688 // is used for everything, the entire save buffer can be freed
1689 // with one free() call.
1690 //
1691 //
1692 struct _state
1693 {
1694  size_t size; // Size of the save buffer
1695  int valid; // Flag to indicate a valid save state
1698  size_t plbuf_top;
1700 };
1701 
1702 void * plbuf_save( PLStream *pls, void *state )
1703 {
1704  size_t save_size;
1705  struct _state *plot_state = (struct _state *) state;
1706  PLINT i;
1707  U_CHAR *buf; // Assume that this is byte-sized
1708 
1709  dbug_enter( "plbuf_save" );
1710 
1711  // If the plot buffer is not being used, there is no state to save
1712  if ( !pls->plbuf_write )
1713  return NULL;
1714 
1715  pls->plbuf_write = FALSE;
1716  pls->plbuf_read = TRUE;
1717 
1718  // Determine the size of the buffer required to save everything.
1719  save_size = sizeof ( struct _state );
1720 
1721  // Only copy as much of the plot buffer that is being used
1722  save_size += pls->plbuf_top;
1723 
1724  // If a buffer exists, determine if we need to resize it
1725  if ( state != NULL )
1726  {
1727  // We have a save buffer, is it smaller than the current size
1728  // requirement?
1729  if ( plot_state->size < save_size )
1730  {
1731  // Yes, reallocate a larger one
1732  if ( ( plot_state = (struct _state *) realloc( state, save_size ) ) == NULL )
1733  {
1734  // NOTE: If realloc fails, then plot_state will be NULL.
1735  // This will leave the original buffer untouched, thus we
1736  // mark it as invalid and return it back to the caller.
1737  //
1738  plwarn( "plbuf: Unable to reallocate sufficient memory to save state" );
1739  plot_state->valid = 0;
1740 
1741  return state;
1742  }
1743  plot_state->size = save_size;
1744  }
1745  }
1746  else
1747  {
1748  // A buffer does not exist, so we need to allocate one
1749  if ( ( plot_state = (struct _state *) malloc( save_size ) ) == NULL )
1750  {
1751  plwarn( "plbuf: Unable to allocate sufficient memory to save state" );
1752 
1753  return NULL;
1754  }
1755  plot_state->size = save_size;
1756  }
1757 
1758  // At this point we have an appropriately sized save buffer.
1759  // We need to invalidate the state of the save buffer, since it
1760  // will not be valid until after everything is copied. We use
1761  // this approach vice freeing the memory and returning a NULL pointer
1762  // in order to prevent allocating and freeing memory needlessly.
1763  //
1764  plot_state->valid = 0;
1765 
1766  // Point buf to the space after the struct _state
1767  buf = (U_CHAR *) ( plot_state + 1 );
1768 
1769  // Again, note, that we only copy the portion of the plot buffer that
1770  // is being used
1771  plot_state->plbuf_buffer_size = pls->plbuf_top;
1772  plot_state->plbuf_top = pls->plbuf_top;
1773  plot_state->plbuf_readpos = 0;
1774 
1775  // Create a pointer that points in the space we allocated after
1776  // struct _state
1777  plot_state->plbuf_buffer = (void *) buf;
1778  buf += pls->plbuf_top;
1779 
1780  // Copy the plot buffer to our new buffer. Again, I must stress, that
1781  // we only are copying the portion of the plot buffer that is being used
1782  //
1783  if ( memcpy( plot_state->plbuf_buffer, pls->plbuf_buffer, pls->plbuf_top ) == NULL )
1784  {
1785  // This should never be NULL
1786  plwarn( "plbuf: Got a NULL in memcpy!" );
1787  return (void *) plot_state;
1788  }
1789 
1790  pls->plbuf_write = TRUE;
1791  pls->plbuf_read = FALSE;
1792 
1793  plot_state->valid = 1;
1794  return (void *) plot_state;
1795 }
1796 
1797 // plbuf_restore(PLStream *, state)
1798 //
1799 // Restores the passed state
1800 //
1801 void plbuf_restore( PLStream *pls, void *state )
1802 {
1803  struct _state *new_state = (struct _state *) state;
1804 
1805  dbug_enter( "plbuf_restore" );
1806 
1807  pls->plbuf_buffer = new_state->plbuf_buffer;
1808  pls->plbuf_buffer_size = new_state->plbuf_buffer_size;
1809  pls->plbuf_top = new_state->plbuf_top;
1810  pls->plbuf_readpos = new_state->plbuf_readpos;
1811 }
1812 
1813 // plbuf_switch(PLStream *, state)
1814 //
1815 // Makes the passed state the current one. Preserves the previous state
1816 // by returning a save buffer.
1817 //
1818 // NOTE: The current implementation can cause a memory leak under the
1819 // following scenario:
1820 // 1) plbuf_save() is called
1821 // 2) plbuf_switch() is called
1822 // 3) Commands are called which cause the plot buffer to grow
1823 // 4) plbuf_swtich() is called
1824 //
1825 void * plbuf_switch( PLStream *pls, void *state )
1826 {
1827  struct _state *new_state = (struct _state *) state;
1828  struct _state *prev_state;
1829  size_t save_size;
1830 
1831  dbug_enter( "plbuf_switch" );
1832 
1833  // No saved state was passed, return a NULL--we hope the caller
1834  // is smart enough to notice
1835  //
1836  if ( state == NULL )
1837  return NULL;
1838 
1839  if ( !new_state->valid )
1840  {
1841  plwarn( "plbuf: Attempting to switch to an invalid saved state" );
1842  return NULL;
1843  }
1844 
1845  save_size = sizeof ( struct _state );
1846 
1847  if ( ( prev_state = (struct _state *) malloc( save_size ) ) == NULL )
1848  {
1849  plwarn( "plbuf: Unable to allocate memory to save state" );
1850  return NULL;
1851  }
1852 
1853  // Set some housekeeping variables
1854  prev_state->size = save_size;
1855  prev_state->valid = 1;
1856 
1857  // Preserve the existing state
1858  prev_state->plbuf_buffer = pls->plbuf_buffer;
1859  prev_state->plbuf_buffer_size = pls->plbuf_buffer_size;
1860  prev_state->plbuf_top = pls->plbuf_top;
1861  prev_state->plbuf_readpos = pls->plbuf_readpos;
1862 
1863  plbuf_restore( pls, new_state );
1864 
1865  return (void *) prev_state;
1866 }