~ubuntu-branches/ubuntu/raring/python-scipy/raring-proposed

« back to all changes in this revision

Viewing changes to Lib/sandbox/xplt/src/gist/ps.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2007-01-07 14:12:12 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20070107141212-mm0ebkh5b37hcpzn
* Remove build dependency on python-numpy-dev.
* python-scipy: Depend on python-numpy instead of python-numpy-dev.
* Package builds on other archs than i386. Closes: #402783.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * PS.C
 
3
 *
 
4
 * $Id: ps.c 760 2003-08-21 22:22:00Z travo $
 
5
 *
 
6
 * Implement the PostScript engine for GIST.
 
7
 *
 
8
 */
 
9
/*    Copyright (c) 1994.  The Regents of the University of California.
 
10
                    All rights reserved.  */
 
11
 
 
12
#include "pstdio.h"
 
13
#include "ps.h"
 
14
#include "gtext.h"
 
15
 
 
16
extern p_file *GistOpen(const char *name);  /* from gread.c */
 
17
 
 
18
#include "play.h"
 
19
#include <string.h>
 
20
#include <time.h>
 
21
 
 
22
#ifndef CREATE_PS
 
23
#define CREATE_PS(name) p_fopen(name, "w")
 
24
#endif
 
25
 
 
26
static char *psType= "PostScript";
 
27
 
 
28
static char line[80];  /* no lines longer than 78 characters! */
 
29
 
 
30
#define PS_PER_POINT 20
 
31
#define NDC_TO_PS (20.0/ONE_POINT)
 
32
#define DEFAULT_PS_WIDTH (DEFAULT_LINE_WIDTH*NDC_TO_PS)
 
33
#define N_PSFONTS 20
 
34
#define N_PSDASHES 5
 
35
 
 
36
static int PutPrologLine(p_file *file);
 
37
static p_file *CopyProlog(const char *name, const char *title);
 
38
static void InitBB(GpsBBox *bb);
 
39
static void SetPageDefaults(PSEngine *psEngine);
 
40
static void SetPSTransform(GpTransform *toPixels, int landscape);
 
41
static void GetEPSFBox(int landscape, GpsBBox *bb,
 
42
                  int *xll, int *yll, int *xur, int *yur);
 
43
static int PutLine(PSEngine *psEngine);
 
44
static int Append(PSEngine *psEngine, const char *s);
 
45
static int BeginPage(PSEngine *psEngine);
 
46
static int EndClip(PSEngine *psEngine);
 
47
static int BeginClip(PSEngine *psEngine, GpTransform *trans);
 
48
static int EndPage(PSEngine *psEngine);
 
49
static int PutPoints(PSEngine *psEngine, GpPoint *points, long nPoints,
 
50
                     int margin);
 
51
static int ChangePalette(Engine *engine);
 
52
static void Kill(Engine *engine);
 
53
static int Clear(Engine *engine, int always);
 
54
static int Flush(Engine *engine);
 
55
static int SetupColor(PSEngine *psEngine, unsigned long color);
 
56
static int SetupLine(PSEngine *psEngine, GpLineAttribs *gistAl);
 
57
static int CheckClip(PSEngine *psEngine);
 
58
static int DrawLines(Engine *engine, long n, const GpReal *px,
 
59
                     const GpReal *py, int closed, int smooth);
 
60
static int SetupFont(PSEngine *psEngine, GpReal height);
 
61
static int DrawMarkers(Engine *engine, long n, const GpReal *px,
 
62
                       const GpReal *py);
 
63
static int SetupText(PSEngine *psEngine);
 
64
static int DrwText(Engine *engine, GpReal x0, GpReal y0, const char *text);
 
65
static int DrawFill(Engine *engine, long n, const GpReal *px,
 
66
                    const GpReal *py);
 
67
static int DrawCells(Engine *engine, GpReal px, GpReal py, GpReal qx,
 
68
                     GpReal qy, long width, long height, long nColumns,
 
69
                     const GpColor *colors);
 
70
static int DrawDisjoint(Engine *engine, long n, const GpReal *px,
 
71
                        const GpReal *py, const GpReal *qx, const GpReal *qy);
 
72
 
 
73
static int ps_fputs(p_file *file, char *buf);
 
74
 
 
75
/* ------------------------------------------------------------------------ */
 
76
 
 
77
static const char *titleIs;
 
78
static int needUser, needDate;
 
79
static void *pf_stdout = &titleIs;  /* any non-zero address will do */
 
80
 
 
81
static int
 
82
ps_fputs(p_file *file, char *buf)
 
83
{
 
84
  if (file != pf_stdout) return p_fputs(file, buf);
 
85
  if (g_stdout) g_stdout(buf);
 
86
  return 0;
 
87
}
 
88
 
 
89
static int PutPrologLine(p_file *file)
 
90
{
 
91
  if (titleIs && strncmp(line, "%%Title:", 8L)==0) {
 
92
    line[8]= ' ';
 
93
    line[9]= '\0';
 
94
    strncat(line, titleIs, 60L);
 
95
    strcat(line, "\n");
 
96
    titleIs= 0;
 
97
  } else if (needUser && strncmp(line, "%%For:", 6L)==0) {
 
98
    line[6]= ' ';
 
99
    line[7]= '\0';
 
100
    strncat(line, p_getuser(), 60L);
 
101
    strcat(line, "\n");
 
102
    needUser= 0;
 
103
  } else if (needDate && strncmp(line, "%%CreationDate:", 15L)==0) {
 
104
    time_t t= time((time_t *)0);
 
105
    /* ctime returns 26 chars, e.g.- "Sun Jan  3 15:14:13 1988\n\0" */
 
106
    char *st= (t==-1)? "\n" : ctime(&t);
 
107
    line[15]= ' ';
 
108
    line[16]= '\0';
 
109
    strcat(line, st? st : "\n");
 
110
    needDate= 0;
 
111
  }
 
112
  return ps_fputs(file, line);
 
113
}
 
114
 
 
115
static p_file *CopyProlog(const char *name, const char *title)
 
116
{
 
117
  p_file *psps= GistOpen("ps.ps");
 
118
  p_file *file= strcmp(name, "*stdout*")? CREATE_PS(name) : pf_stdout;
 
119
  if (!psps) strcpy(gistError, "unable to open PostScript prolog ps.ps");
 
120
  if (!file) strcpy(gistError, "unable to create PostScript output file");
 
121
 
 
122
  if (psps && file) {
 
123
    titleIs= title;
 
124
    needUser= needDate= 1;
 
125
    for (;;) {
 
126
      if (!p_fgets(psps, line, 79) || PutPrologLine(file)<0) {
 
127
        if (file!=pf_stdout) p_fclose(file);
 
128
        file= 0;
 
129
        strcpy(gistError, "bad PostScript prolog format in ps.ps??");
 
130
        break;
 
131
      }
 
132
      if (strncmp(line, "%%EndSetup", 10L)==0) break;
 
133
    }
 
134
 
 
135
  } else if (file) {
 
136
    if (file!=pf_stdout) p_fclose(file);
 
137
    file= 0;
 
138
  }
 
139
 
 
140
  if (psps) p_fclose(psps);
 
141
  return file;
 
142
}
 
143
 
 
144
static void InitBB(GpsBBox *bb)
 
145
{
 
146
  bb->xll= bb->yll= 0x7ff0;
 
147
  bb->xur= bb->yur= 0;
 
148
}
 
149
 
 
150
static void SetPageDefaults(PSEngine *psEngine)
 
151
{
 
152
  /* Set current state to match state set by GI procedure in ps.ps */
 
153
  psEngine->curClip= 0;
 
154
  psEngine->curColor= P_FG;
 
155
  psEngine->curType= L_SOLID;
 
156
  psEngine->curWidth= 1.0;
 
157
  psEngine->curFont= T_COURIER;
 
158
  psEngine->curHeight= 12.0*ONE_POINT;
 
159
  psEngine->curAlignH= TH_LEFT;
 
160
  psEngine->curAlignV= TV_BASE;
 
161
  psEngine->curOpaque= 0;
 
162
  InitBB(&psEngine->pageBB);
 
163
}
 
164
 
 
165
static void SetPSTransform(GpTransform *toPixels, int landscape)
 
166
{
 
167
  /* PostScript thinks an 8.5-by-11 inch page is 612-by-792 points */
 
168
  toPixels->window.xmin= toPixels->window.ymin= 0.0;
 
169
  if (landscape) {
 
170
    toPixels->window.xmax= 15840.0;
 
171
    toPixels->window.ymax= 12240.0;
 
172
  } else {
 
173
    toPixels->window.xmax= 12240.0;
 
174
    toPixels->window.ymax= 15840.0;
 
175
  }
 
176
  toPixels->viewport.xmin= toPixels->viewport.ymin= 0.0;
 
177
  toPixels->viewport.xmax= toPixels->window.xmax*(1.0/NDC_TO_PS);
 
178
  toPixels->viewport.ymax= toPixels->window.ymax*(1.0/NDC_TO_PS);
 
179
}
 
180
 
 
181
static void GetEPSFBox(int landscape, GpsBBox *bb,
 
182
                       int *xll, int *yll, int *xur, int *yur)
 
183
{
 
184
  /* Transform bounding box to
 
185
     Document Structure Comment coordinates for use as EPSF file */
 
186
  int xl, yl, xu, yu;
 
187
 
 
188
  if (bb->xll < bb->xur) {
 
189
    /* this is a valid bounding box */
 
190
    xl= bb->xll/PS_PER_POINT;
 
191
    yl= bb->yll/PS_PER_POINT;
 
192
    xu= 1+(bb->xur-1)/PS_PER_POINT;
 
193
    yu= 1+(bb->yur-1)/PS_PER_POINT;
 
194
 
 
195
  } else {
 
196
    /* this is not a valid bounding box, return whole page */
 
197
    xl= yl= 0;
 
198
    xu= 612;    /* In PostScript, 1 inch is exactly 72 points */
 
199
    yu= 792;
 
200
  }
 
201
 
 
202
  if (landscape) {
 
203
    *xll= 612-yu;  *yll= xl;
 
204
    *xur= 612-yl;  *yur= xu;
 
205
  } else {
 
206
    *xll= xl;  *yll= yl;
 
207
    *xur= xu;  *yur= yu;
 
208
  }
 
209
}
 
210
 
 
211
static int PutLine(PSEngine *psEngine)
 
212
{
 
213
  p_file *file= psEngine->file;
 
214
  char *line= psEngine->line;
 
215
  long nchars= psEngine->nchars;
 
216
 
 
217
  if (!file) {
 
218
    if (psEngine->closed) return 1;
 
219
    file= psEngine->file= CopyProlog(psEngine->filename, psEngine->e.name);
 
220
    if (!file) { psEngine->closed= 1;  return 1; }
 
221
    psEngine->currentPage= 1;
 
222
    SetPageDefaults(psEngine);
 
223
    InitBB(&psEngine->docBB);
 
224
  }
 
225
 
 
226
  line[nchars++]= '\n';
 
227
  line[nchars]= '\0';
 
228
  if (ps_fputs(file, line)<0) {
 
229
    if (file!=pf_stdout) p_fclose(file);
 
230
    psEngine->file= 0;
 
231
    psEngine->closed= 1;
 
232
    strcpy(gistError, "p_fputs failed writing PostScript file");
 
233
    return 1;
 
234
  }
 
235
  line[0]= '\0';
 
236
  psEngine->nchars= 0;
 
237
  return 0;
 
238
}
 
239
 
 
240
static int Append(PSEngine *psEngine, const char *s)
 
241
{
 
242
  long len= s? strlen(s) : 0;
 
243
  long nchars= psEngine->nchars;
 
244
  char *line= psEngine->line;
 
245
 
 
246
  if (nchars+1+len>78) {
 
247
    if (PutLine(psEngine)) return 1;
 
248
    nchars= 0;
 
249
  } else if (nchars>0) {
 
250
    line[nchars++]= ' ';
 
251
  }
 
252
  strcpy(line+nchars, s);
 
253
  psEngine->nchars= nchars+len;
 
254
 
 
255
  return 0;
 
256
}
 
257
 
 
258
static int BeginPage(PSEngine *psEngine)
 
259
{
 
260
  int currentPage= psEngine->currentPage;
 
261
 
 
262
  psEngine->e.marked= 1;
 
263
 
 
264
  /* A change in color table can take place only at the beginning
 
265
     of a page.  ChangePalette strobes the palette in the Engine base
 
266
     class part into the PSEngine palette.  */
 
267
  psEngine->nColors= 0;      /* reset to mono mode */
 
268
  ChangePalette((Engine *)psEngine);
 
269
 
 
270
  if (psEngine->nchars && PutLine(psEngine)) return 1;
 
271
  if (PutLine(psEngine)) return 1;
 
272
 
 
273
  sprintf(line, "%%%%Page: %d %d", currentPage, currentPage);
 
274
  if (Append(psEngine, line) || PutLine(psEngine)) return 1;
 
275
 
 
276
  if (Append(psEngine, "%%PageBoundingBox: (atend)") ||
 
277
      PutLine(psEngine)) return 1;
 
278
 
 
279
  if (Append(psEngine, "GistPrimitives begin /PG save def GI") ||
 
280
      PutLine(psEngine)) return 1;
 
281
 
 
282
  /* Set transform viewport to reflect current page orientation */
 
283
  if (psEngine->landscape != psEngine->e.landscape) {
 
284
    SetPSTransform(&psEngine->e.transform, psEngine->e.landscape);
 
285
    psEngine->landscape= psEngine->e.landscape;
 
286
  }
 
287
  if (psEngine->landscape) {
 
288
    if (Append(psEngine, "LAND") ||
 
289
        PutLine(psEngine)) return 1;
 
290
  }
 
291
 
 
292
  if (psEngine->e.colorMode && psEngine->e.palette &&
 
293
      psEngine->e.nColors>0) {
 
294
    int i, nColors= psEngine->e.nColors;
 
295
    GpColorCell *palette= psEngine->e.palette;
 
296
    long color;
 
297
    sprintf(line, "%d CT", nColors);
 
298
    if (Append(psEngine, line) || PutLine(psEngine)) return 1;
 
299
    for (i=0 ; i<nColors ; i++) {
 
300
      color= P_R(palette[i])<<16 | P_G(palette[i])<<8 | P_B(palette[i]);
 
301
      sprintf(line, "%06lx", color);
 
302
      if (Append(psEngine, line)) return 1;
 
303
    }
 
304
    if (psEngine->nchars && PutLine(psEngine)) return 1;
 
305
    psEngine->colorMode= 1;  /* color table has been written */
 
306
    psEngine->nColors= nColors;
 
307
  } else {
 
308
    psEngine->colorMode= 0;  /* NO color table exists on this page */
 
309
    /* But, if there is a palette, still want to use grays */
 
310
    if (psEngine->e.palette && psEngine->e.nColors>0)
 
311
      psEngine->nColors= psEngine->e.nColors;
 
312
  }
 
313
 
 
314
  if (Append(psEngine, "%%EndPageSetup") || PutLine(psEngine)) return 1;
 
315
  return 0;
 
316
}
 
317
 
 
318
static int EndClip(PSEngine *psEngine)
 
319
{
 
320
  if (psEngine->curClip) {
 
321
    if ((psEngine->nchars && PutLine(psEngine)) ||
 
322
        Append(psEngine, "CLOF")) return 1;
 
323
    psEngine->curClip= 0;
 
324
    /* Restore state at time of CLON */
 
325
    psEngine->curColor= psEngine->clipColor;
 
326
    psEngine->curType= psEngine->clipType;
 
327
    psEngine->curWidth= psEngine->clipWidth;
 
328
    psEngine->curFont= psEngine->clipFont;
 
329
    psEngine->curHeight= psEngine->clipHeight;
 
330
  }
 
331
  return 0;
 
332
}
 
333
 
 
334
static int BeginClip(PSEngine *psEngine, GpTransform *trans)
 
335
{
 
336
  GpReal x[2], y[2];
 
337
  GpPoint *points;
 
338
  int xll, yll, xur, yur;
 
339
  GpBox *port= &trans->viewport;
 
340
  GpBox *box= &psEngine->clipBox;
 
341
 
 
342
  if (!psEngine->e.marked && BeginPage(psEngine)) return 1;
 
343
 
 
344
  if (psEngine->curClip) {
 
345
    if (port->xmin==box->xmin && port->xmax==box->xmax &&
 
346
        port->ymin==box->ymin && port->ymax==box->ymax) return 0;
 
347
    if (EndClip(psEngine)) return 1;
 
348
  }
 
349
 
 
350
  x[0]= trans->window.xmin;  x[1]= trans->window.xmax;
 
351
  y[0]= trans->window.ymin;  y[1]= trans->window.ymax;
 
352
 
 
353
  GpIntPoints(&psEngine->e.map, 3, 2, x, y, &points);
 
354
  if (points[0].x > points[1].x) {
 
355
    xll= points[1].x;  xur= points[0].x;
 
356
  } else {
 
357
    xll= points[0].x;  xur= points[1].x;
 
358
  }
 
359
  if (points[0].y > points[1].y) {
 
360
    yll= points[1].y;  yur= points[0].y;
 
361
  } else {
 
362
    yll= points[0].y;  yur= points[1].y;
 
363
  }
 
364
 
 
365
  sprintf(line, "%d %d %d %d CLON", xur-xll, yur-yll, xll, yll);
 
366
  if (Append(psEngine, line)) return 1;
 
367
  psEngine->curClip= 1;
 
368
  *box= *port;
 
369
 
 
370
  /* Must save state at time of CLON, since CLOF does grestore */
 
371
  psEngine->clipColor= psEngine->curColor;
 
372
  psEngine->clipType= psEngine->curType;
 
373
  psEngine->clipWidth= psEngine->curWidth;
 
374
  psEngine->clipFont= psEngine->curFont;
 
375
  psEngine->clipHeight= psEngine->curHeight;
 
376
  /* Note that text alignment/opacity is not affected by grestore */
 
377
 
 
378
  /* Expand page boundary to include clip boundary */
 
379
  if (xll < psEngine->pageBB.xll) psEngine->pageBB.xll= xll;
 
380
  if (yll < psEngine->pageBB.yll) psEngine->pageBB.yll= yll;
 
381
  if (xur > psEngine->pageBB.xur) psEngine->pageBB.xur= xur;
 
382
  if (yur > psEngine->pageBB.yur) psEngine->pageBB.yur= yur;
 
383
  return 0;
 
384
}
 
385
 
 
386
static int EndPage(PSEngine *psEngine)
 
387
{
 
388
  char *line= psEngine->line;
 
389
  int xll, yll, xur, yur;
 
390
 
 
391
  if (EndClip(psEngine)) return 1;
 
392
 
 
393
  if ((psEngine->nchars && PutLine(psEngine)) ||
 
394
      Append(psEngine, "PG restore") || PutLine(psEngine)) return 1;
 
395
  if (Append(psEngine, "showpage") || PutLine(psEngine)) return 1;
 
396
  if (Append(psEngine, "end") || PutLine(psEngine)) return 1;
 
397
  if (Append(psEngine, "%%PageTrailer") || PutLine(psEngine)) return 1;
 
398
 
 
399
  GetEPSFBox(psEngine->e.landscape, &psEngine->pageBB,
 
400
             &xll, &yll, &xur, &yur);
 
401
  if (xll < psEngine->docBB.xll) psEngine->docBB.xll= xll;
 
402
  if (yll < psEngine->docBB.yll) psEngine->docBB.yll= yll;
 
403
  if (xur > psEngine->docBB.xur) psEngine->docBB.xur= xur;
 
404
  if (yur > psEngine->docBB.yur) psEngine->docBB.yur= yur;
 
405
  sprintf(line, "%%%%PageBoundingBox: %d %d %d %d", xll, yll, xur, yur);
 
406
  if (Append(psEngine, line) || PutLine(psEngine)) return 1;
 
407
 
 
408
  psEngine->currentPage++;
 
409
  psEngine->e.marked= 0;
 
410
  SetPageDefaults(psEngine);
 
411
  if (psEngine->file!=pf_stdout) p_fflush(psEngine->file);
 
412
  return 0;
 
413
}
 
414
 
 
415
static char hexChar[17]= "0123456789abcdef";
 
416
 
 
417
static int PutPoints(PSEngine *psEngine, GpPoint *points, long nPoints,
 
418
                     int margin)
 
419
{
 
420
  int ix, iy, i;
 
421
  int xll= 0x7ff0, yll= 0x7ff0, xur= 0, yur= 0;
 
422
  char *now, *line= psEngine->line;
 
423
  int perLine, nchars= psEngine->nchars;
 
424
 
 
425
  if (!psEngine->e.marked && BeginPage(psEngine)) return 1;
 
426
 
 
427
  if (nchars<=0) {
 
428
    now= line;
 
429
    perLine= 9;
 
430
  } else if (nchars<70) {
 
431
    now= line+nchars;
 
432
    perLine= (78-nchars)/8;
 
433
  } else {
 
434
    if (PutLine(psEngine)) return 1;
 
435
    nchars= 0;
 
436
    now= line;
 
437
    perLine= 9;
 
438
  }
 
439
 
 
440
  /* Dump the points in hex 9 (72 chars) to a line */
 
441
  while (nPoints>0) {
 
442
    for (i=0 ; i<perLine ; i++) {
 
443
      ix= points->x;
 
444
      iy= points->y;
 
445
      points++;
 
446
      if (ix<0) ix= xll;           /* be sure x in range, set xll, xur */
 
447
      else if (ix>0x7ff0) ix= xur;
 
448
      else if (ix<xll) xll= ix;
 
449
      else if (ix>xur) xur= ix;
 
450
      if (iy<0) iy= yll;           /* be sure y in range, set yll, yur */
 
451
      else if (iy>0x7ff0) iy= yur;
 
452
      else if (iy<yll) yll= iy;
 
453
      else if (iy>yur) yur= iy;
 
454
      *now++= hexChar[ix>>12];
 
455
      *now++= hexChar[(ix>>8)&0xf];
 
456
      *now++= hexChar[(ix>>4)&0xf];
 
457
      *now++= hexChar[ix&0xf];
 
458
      *now++= hexChar[iy>>12];
 
459
      *now++= hexChar[(iy>>8)&0xf];
 
460
      *now++= hexChar[(iy>>4)&0xf];
 
461
      *now++= hexChar[iy&0xf];
 
462
      nchars+= 8;
 
463
      nPoints--;
 
464
      if (nPoints==0) break;
 
465
    }
 
466
    psEngine->nchars= nchars;
 
467
    if (PutLine(psEngine)) return 1;
 
468
    nchars= 0;
 
469
    now= line;
 
470
    perLine= 9;
 
471
  }
 
472
 
 
473
  /* Adjust the bounding box for the current page */
 
474
  if (xll<xur && !psEngine->curClip) {
 
475
    xll-= margin;
 
476
    xur+= margin;
 
477
    yll-= margin;
 
478
    yur+= margin;
 
479
    if (xll<psEngine->pageBB.xll) psEngine->pageBB.xll= xll;
 
480
    if (xur>psEngine->pageBB.xur) psEngine->pageBB.xur= xur;
 
481
    if (yll<psEngine->pageBB.yll) psEngine->pageBB.yll= yll;
 
482
    if (yur>psEngine->pageBB.yur) psEngine->pageBB.yur= yur;
 
483
  }
 
484
 
 
485
  return 0;
 
486
}
 
487
 
 
488
/* ------------------------------------------------------------------------ */
 
489
 
 
490
static int ChangePalette(Engine *engine)
 
491
{
 
492
  PSEngine *psEngine= (PSEngine *)engine;
 
493
  int nColors= engine->nColors;
 
494
 
 
495
  if (nColors<=0 || !engine->palette) {
 
496
    /* new color table is void-- don't allow indexed colors */
 
497
    psEngine->colorMode= 0;
 
498
    psEngine->nColors= 0;
 
499
 
 
500
  } else {
 
501
    /* remember current color mode, then set to mono mode until
 
502
       new color table can be written in BeginPage */
 
503
    psEngine->colorMode= 0;
 
504
    psEngine->nColors= 0;    /* don't index into table before BeginPage */
 
505
  }
 
506
 
 
507
  engine->colorChange= 0;
 
508
  return 256;
 
509
}
 
510
 
 
511
/* ------------------------------------------------------------------------ */
 
512
 
 
513
static char *psFontNames[N_PSFONTS]= {
 
514
  "Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique",
 
515
  "Times-Roman", "Times-Bold", "Times-Italic", "Times-BoldItalic",
 
516
  "Helvetica", "Helvetica-Bold", "Helvetica-Oblique", "Helvetica-BoldOblique",
 
517
  "Symbol", "Symbol", "Symbol", "Symbol",
 
518
  "NewCenturySchlbk-Roman", "NewCenturySchlbk-Bold",
 
519
  "NewCenturySchlbk-Italic", "NewCenturySchlbk-BoldItalic" };
 
520
 
 
521
static void Kill(Engine *engine)
 
522
{
 
523
  PSEngine *psEngine= (PSEngine *)engine;
 
524
  long fonts= psEngine->fonts;
 
525
  int i, xll, yll, xur, yur;
 
526
  int bad= 0;
 
527
 
 
528
  if (psEngine->e.marked) bad= EndPage(psEngine);
 
529
 
 
530
  if (psEngine->file) {
 
531
    if (!bad) bad= PutLine(psEngine);
 
532
    if (!bad) bad= Append(psEngine, "%%Trailer");
 
533
    if (!bad) bad= PutLine(psEngine);
 
534
 
 
535
    sprintf(line, "%%%%Pages: %d", psEngine->currentPage-1);
 
536
    if (!bad) bad= Append(psEngine, line);
 
537
    if (!bad) bad= PutLine(psEngine);
 
538
 
 
539
    xll= psEngine->docBB.xll;
 
540
    xur= psEngine->docBB.xur;
 
541
    if (xll < xur) {
 
542
      yll= psEngine->docBB.yll;
 
543
      yur= psEngine->docBB.yur;
 
544
    } else {
 
545
      xll= yll= 0;
 
546
      xur= 612;
 
547
      yur= 792;
 
548
    }
 
549
    sprintf(line, "%%%%BoundingBox: %d %d %d %d", xll, yll, xur, yur);
 
550
    if (!bad) bad= Append(psEngine, line);
 
551
    if (!bad) bad= PutLine(psEngine);
 
552
 
 
553
    strcpy(line, "%%DocumentFonts: ");
 
554
    for (i=0 ; i<N_PSFONTS ; i++) {
 
555
      if ((1<<i) & fonts) {
 
556
        strcat(line, psFontNames[i]);
 
557
        if (!bad) bad= Append(psEngine, line);
 
558
        if (!bad) bad= PutLine(psEngine);
 
559
        strcpy(line, "%%+ ");
 
560
      }
 
561
    }
 
562
 
 
563
    if (psEngine->file!=pf_stdout) p_fclose(psEngine->file);
 
564
  }
 
565
  GpDelEngine(engine);
 
566
}
 
567
 
 
568
static int Clear(Engine *engine, int always)
 
569
{
 
570
  PSEngine *psEngine= (PSEngine *)engine;
 
571
  if (always || engine->marked) EndPage(psEngine);
 
572
  engine->marked= 0;
 
573
  return 0;
 
574
}
 
575
 
 
576
static int Flush(Engine *engine)
 
577
{
 
578
  PSEngine *psEngine= (PSEngine *)engine;
 
579
  if (psEngine->file && psEngine->file!=pf_stdout)
 
580
    p_fflush(psEngine->file);
 
581
  return 0;
 
582
}
 
583
 
 
584
/* ------------------------------------------------------------------------ */
 
585
 
 
586
static char *colorCommands[14]= {
 
587
  "BG", "FG", "BLK", "WHT", "RED", "GRN", "BLU", "CYA", "MAG", "YEL",
 
588
  "GYD", "GYC", "GYB", "GYA" };
 
589
 
 
590
static int SetupColor(PSEngine *psEngine, unsigned long color)
 
591
{
 
592
  int nColors= psEngine->nColors;
 
593
 
 
594
  if (!psEngine->e.marked && BeginPage(psEngine)) return 1;
 
595
  if (color==psEngine->curColor) return 0;
 
596
 
 
597
  if (color<240UL) {
 
598
    /* "CI index C"-- "CI" omitted if current color is indexed */
 
599
    unsigned long c;
 
600
    GpColorCell *palette= psEngine->e.palette;
 
601
    if (nColors>0) {
 
602
      if (color>=(unsigned long)nColors) color= nColors-1;
 
603
      if (psEngine->colorMode) c= color;  /* this page has a color table */
 
604
      else c= (P_R(palette[color])+
 
605
               P_G(palette[color])+P_B(palette[color]))/3;  /* mono page */
 
606
    } else {
 
607
      if (color>255) color= 255;
 
608
      c= color;         /* No palette ==> no color table on page */
 
609
    }
 
610
    if (psEngine->curColor>=240UL) {
 
611
      if (Append(psEngine, "CI")) return 1;
 
612
    }
 
613
    sprintf(line, "%ld C", c);
 
614
    if (Append(psEngine, line)) return 1;
 
615
  } else if (color<256UL) {
 
616
    /* standard color command FG, RED, etc. */
 
617
    if (color<P_GRAYA) color= P_FG;
 
618
    if (Append(psEngine, colorCommands[255UL-color])) return 1;
 
619
  } else {
 
620
    sprintf(line, "16#%lx C", color);
 
621
    if (Append(psEngine, line)) return 1;
 
622
  }
 
623
  psEngine->curColor= color;
 
624
 
 
625
  return 0;
 
626
}
 
627
 
 
628
static int SetupLine(PSEngine *psEngine, GpLineAttribs *gistAl)
 
629
{
 
630
  int changeLW= (psEngine->curWidth!=gistAl->width);
 
631
  if (SetupColor(psEngine, gistAl->color)) return 1;
 
632
 
 
633
  if (changeLW) {
 
634
    int lwidth;
 
635
 
 
636
    lwidth= (int)(DEFAULT_PS_WIDTH*gistAl->width);
 
637
    sprintf(line, "%d LW", lwidth);
 
638
    if (Append(psEngine, line)) return 1;
 
639
 
 
640
    psEngine->curWidth= gistAl->width;
 
641
  }
 
642
 
 
643
  /* WARNING--
 
644
     the dash pattern is a function of the line width (see pscom.ps) */
 
645
  if (psEngine->curType!=gistAl->type ||
 
646
      (changeLW && gistAl->type!=L_SOLID)) {
 
647
    int ltype= gistAl->type;
 
648
    if (ltype==L_NONE) return 1;
 
649
 
 
650
    if (ltype<0 || ltype>N_PSDASHES) ltype= L_SOLID;
 
651
    sprintf(line, "%d DSH", ltype-1);
 
652
    if (Append(psEngine, line)) return 1;
 
653
 
 
654
    psEngine->curType= gistAl->type;
 
655
  }
 
656
 
 
657
  return 0;
 
658
}
 
659
 
 
660
static int CheckClip(PSEngine *psEngine)
 
661
{
 
662
  if (gistClip) return BeginClip(psEngine, &gistT);
 
663
  else if (psEngine->curClip) return EndClip(psEngine);
 
664
  return 0;
 
665
}
 
666
 
 
667
static int DrawLines(Engine *engine, long n, const GpReal *px,
 
668
                     const GpReal *py, int closed, int smooth)
 
669
{
 
670
  PSEngine *psEngine= (PSEngine *)engine;
 
671
  GpXYMap *map= &engine->map;
 
672
  long maxPoints= 4050, nPoints;
 
673
  long np= n + (closed?1:0);
 
674
  int firstPass= 1, markEnd= 0;
 
675
  GpPoint firstPoint, *points;
 
676
  int size;
 
677
 
 
678
  if (CheckClip(psEngine)) return 1;
 
679
  if (n<1) return 0;
 
680
  if (SetupLine(psEngine, &gistA.l)) return 1;
 
681
  if (psEngine->curClip) size= 0;
 
682
  else size= (int)(psEngine->curWidth*0.5*DEFAULT_PS_WIDTH);
 
683
 
 
684
  if (np>90) {
 
685
    long nLines= (np-1)/9 + 1;  /* 9 points is 72 characters */
 
686
    if (psEngine->nchars && PutLine(psEngine)) return 1;
 
687
    sprintf(line, "%%%%BeginData: %ld ASCII Lines", nLines+1);
 
688
    if (Append(psEngine, line) || PutLine(psEngine)) return 1;
 
689
    markEnd= 1;
 
690
  }
 
691
  sprintf(line, smooth? "%ld LS" : "%ld L", np);
 
692
  if (Append(psEngine, line) || PutLine(psEngine)) return 1;
 
693
 
 
694
  while ((nPoints=
 
695
          GpIntPoints(map, maxPoints, n, px, py, &points))) {
 
696
    if (closed) {
 
697
      if (firstPass) {
 
698
        firstPoint= points[0];
 
699
        firstPass= 0;
 
700
      }
 
701
      if (n==nPoints) {
 
702
        n++;
 
703
        points[nPoints++]= firstPoint;
 
704
      }
 
705
    }
 
706
    if (PutPoints(psEngine, points, nPoints, size)) return 1;
 
707
    if (n==nPoints) break;
 
708
    n-= nPoints;
 
709
    px+= nPoints;
 
710
    py+= nPoints;
 
711
  }
 
712
 
 
713
  if (markEnd) {
 
714
    if (Append(psEngine, "%%EndData") || PutLine(psEngine)) return 1;
 
715
  }
 
716
 
 
717
  return 0;
 
718
}
 
719
 
 
720
/* ------------------------------------------------------------------------ */
 
721
 
 
722
static char *psFontCommands[N_PSFONTS]= {
 
723
  "0 Cour", "1 Cour", "2 Cour", "3 Cour",
 
724
  "0 Tims", "1 Tims", "2 Tims", "3 Tims",
 
725
  "0 Helv", "1 Helv", "2 Helv", "3 Helv",
 
726
  "0 Symb", "1 Symb", "2 Symb", "3 Symb",
 
727
  "0 NCen", "1 NCen", "2 NCen", "3 NCen" };
 
728
 
 
729
static int SetupFont(PSEngine *psEngine, GpReal height)
 
730
{
 
731
  int font= gistA.t.font;
 
732
  if (font<0 || font>=N_PSFONTS) font= 0;
 
733
  if (psEngine->curFont!=font ||
 
734
      psEngine->curHeight!=height) {
 
735
    int ptSz= (int)(gistA.t.height*NDC_TO_PS+0.5);
 
736
    int lnSp= ptSz;   /* LnSp same as PtSz for now */
 
737
    if (Append(psEngine, psFontCommands[font])) return 1;
 
738
    sprintf(line, "%d %d FNT", ptSz, lnSp);
 
739
    if (Append(psEngine, line)) return 1;
 
740
    psEngine->curFont= font;
 
741
    psEngine->curHeight= height;
 
742
    psEngine->fonts|= (1<<font);
 
743
  }
 
744
  return 0;
 
745
}
 
746
 
 
747
static int DrawMarkers(Engine *engine, long n, const GpReal *px,
 
748
                       const GpReal *py)
 
749
{
 
750
  PSEngine *psEngine= (PSEngine *)engine;
 
751
  GpXYMap *map= &engine->map;
 
752
  long maxPoints= 4050, nPoints;
 
753
  int type, markEnd= 0;
 
754
  GpPoint *points;
 
755
  int size;
 
756
  char typeString[8];
 
757
 
 
758
  if (n<1 || gistA.m.type<=0) return 0;
 
759
  if (CheckClip(psEngine)) return 1;
 
760
  if (SetupColor(psEngine, gistA.m.color) ||
 
761
      SetupFont(psEngine, gistA.m.size*DEFAULT_MARKER_SIZE)) return 1;
 
762
  if (psEngine->curClip) size= 0;
 
763
  else size= (int)(psEngine->curHeight*NDC_TO_PS);
 
764
 
 
765
  if (gistA.m.type>32 && gistA.m.type<127) {
 
766
    char *now= typeString;
 
767
    *now++= '(';
 
768
    if (gistA.m.type=='(' || gistA.m.type==')' || gistA.m.type=='\\')
 
769
      *now++= '\\';
 
770
    *now++= type= gistA.m.type;
 
771
    *now++= ')';
 
772
    *now++= '\0';
 
773
  } else {
 
774
    if (gistA.m.type<0 || gistA.m.type>M_CROSS) type= M_ASTERISK;
 
775
    else type= gistA.m.type;
 
776
    sprintf(typeString, "%d", type-1);
 
777
  }
 
778
 
 
779
  if (n>90) {
 
780
    long nLines= (n-1)/9 + 1;  /* 9 points is 72 characters */
 
781
    if (psEngine->nchars && PutLine(psEngine)) return 1;
 
782
    sprintf(line, "%%%%BeginData: %ld ASCII Lines", nLines+1);
 
783
    if (Append(psEngine, line) || PutLine(psEngine)) return 1;
 
784
    markEnd= 1;
 
785
  }
 
786
  if (Append(psEngine, typeString)) return 1;  /* "(A)" or "1", e.g. */
 
787
  sprintf(line, type<32? "%ld MS" : "%ld M", n);
 
788
  if (Append(psEngine, line) || PutLine(psEngine)) return 1;
 
789
 
 
790
  while ((nPoints=
 
791
          GpIntPoints(map, maxPoints, n, px, py, &points))) {
 
792
    if (PutPoints(psEngine, points, nPoints, size)) return 1;
 
793
    if (n==nPoints) break;
 
794
    n-= nPoints;
 
795
    px+= nPoints;
 
796
    py+= nPoints;
 
797
  }
 
798
 
 
799
  if (markEnd) {
 
800
    if (Append(psEngine, "%%EndData") || PutLine(psEngine)) return 1;
 
801
  }
 
802
 
 
803
  return 0;
 
804
}
 
805
 
 
806
/* ------------------------------------------------------------------------ */
 
807
 
 
808
static char *psHCommands[3]= { "/LF", "/CN", "/RT" };
 
809
static char *psVCommands[5]= { "/TP", "/CP", "/HF", "/BA", "/BT" };
 
810
 
 
811
static int SetupText(PSEngine *psEngine)
 
812
{
 
813
  int opq;
 
814
  int h= gistA.t.alignH, v= gistA.t.alignV;
 
815
  GtGetAlignment(&gistA.t, &h, &v);
 
816
 
 
817
  if (SetupColor(psEngine, gistA.t.color)) return 1;
 
818
 
 
819
  if (psEngine->curAlignH!=h || psEngine->curAlignV!=v) {
 
820
    sprintf(line, "%s %s JUS", psHCommands[h-1], psVCommands[v-1]);
 
821
    if (Append(psEngine, line)) return 1;
 
822
    psEngine->curAlignH= h;
 
823
    psEngine->curAlignV= v;
 
824
  }
 
825
 
 
826
  opq= gistA.t.opaque;
 
827
  /* if (gistA.t.orient!=TX_RIGHT) opq= 1; let this be X only limitation */
 
828
  if (psEngine->curOpaque != (opq!=0)) {
 
829
    if (opq) Append(psEngine, "1 OPQ");
 
830
    else if (Append(psEngine, "0 OPQ")) return 1;
 
831
    psEngine->curOpaque= (opq!=0);
 
832
  }
 
833
 
 
834
  if (psEngine->curFont!=gistA.t.font ||
 
835
      psEngine->curHeight!=gistA.t.height) {
 
836
    if (SetupFont(psEngine, gistA.t.height)) return 1;
 
837
  }
 
838
  return 0;
 
839
}
 
840
 
 
841
static int break_line_now(PSEngine *psEngine, char **nw, int *nchs);
 
842
 
 
843
static int DrwText(Engine *engine, GpReal x0, GpReal y0, const char *text)
 
844
{
 
845
  PSEngine *psEngine= (PSEngine *)engine;
 
846
  int ix, iy, nlines;
 
847
  GpReal width, height, lineHeight;
 
848
  GpXYMap *map= &engine->map;
 
849
  GpBox *wind= &engine->transform.window;
 
850
  GpReal xmin, xmax, ymin, ymax;
 
851
  int xll, yll, xur, yur, alignH, alignV;
 
852
  int count, nchars, firstPass;
 
853
  char *now, c;
 
854
  const char *t;
 
855
  int state= 0;
 
856
 
 
857
  if (CheckClip(psEngine) || SetupText(psEngine)) return 1;
 
858
  alignH= psEngine->curAlignH;
 
859
  alignV= psEngine->curAlignV;
 
860
  /* Compute text location in PostScript coordinates.  */
 
861
  x0= map->x.scale*x0 + map->x.offset;
 
862
  y0= map->y.scale*y0 + map->y.offset;
 
863
 
 
864
  /* handle multi-line strings */
 
865
  nlines= GtTextShape(text, &gistA.t, (WidthFunction)0, &width);
 
866
  lineHeight= gistA.t.height * NDC_TO_PS;
 
867
  width*= 0.6*lineHeight;
 
868
  height= lineHeight*(GpReal)nlines;
 
869
 
 
870
  /* Reject if and only if the specified point is off of the current
 
871
     page by more than the approximate size of the text.  Note that
 
872
     the entire block of text is either accepted or rejected --
 
873
     PostScript does the clipping.  */
 
874
  if (wind->xmax>wind->xmin) { xmin= wind->xmin; xmax= wind->xmax; }
 
875
  else { xmin= wind->xmax; xmax= wind->xmin; }
 
876
  if (wind->ymax>wind->ymin) { ymin= wind->ymin; ymax= wind->ymax; }
 
877
  else { ymin= wind->ymax; ymax= wind->ymin; }
 
878
  if (gistA.t.orient==TX_RIGHT || gistA.t.orient==TX_LEFT) {
 
879
    if (x0<xmin-width || x0>xmax+width ||
 
880
        y0<ymin-height || y0>ymax+height) return 0;
 
881
  } else {
 
882
    if (x0<xmin-height || x0>xmax+height ||
 
883
        y0<ymin-width || y0>ymax+width) return 0;
 
884
  }
 
885
 
 
886
  /* Adjust y0 (or x0) to represent topmost line */
 
887
  if (nlines > 1) {
 
888
    if (gistA.t.orient==TX_RIGHT) {
 
889
      if (alignV==TV_BASE || alignV==TV_BOTTOM) y0+= height-lineHeight;
 
890
      if (alignV==TV_HALF) y0+= 0.5*(height-lineHeight);
 
891
    } else if (gistA.t.orient==TX_LEFT) {
 
892
      if (alignV==TV_BASE || alignV==TV_BOTTOM) y0-= height-lineHeight;
 
893
      if (alignV==TV_HALF) y0-= 0.5*(height-lineHeight);
 
894
    } else if (gistA.t.orient==TX_UP) {
 
895
      if (alignV==TV_BASE || alignV==TV_BOTTOM) x0-= height-lineHeight;
 
896
      if (alignV==TV_HALF) x0-= 0.5*(height-lineHeight);
 
897
    } else {
 
898
      if (alignV==TV_BASE || alignV==TV_BOTTOM) x0+= height-lineHeight;
 
899
      if (alignV==TV_HALF) x0+= 0.5*(height-lineHeight);
 
900
    }
 
901
  }
 
902
 
 
903
  ix= (int)x0;
 
904
  iy= (int)y0;
 
905
 
 
906
  /* Guess at the bounding box for the text */
 
907
  if (!psEngine->curClip) {
 
908
    if (gistA.t.orient==TX_RIGHT) {
 
909
 
 
910
      if (alignH==TH_CENTER) x0 -= 0.5*width;
 
911
      else if (alignH==TH_RIGHT) x0 -= width;
 
912
 
 
913
      if (alignV==TV_TOP || alignV==TV_CAP) y0 -= height;
 
914
      else if (alignV==TV_HALF) y0 -= height-0.4*lineHeight;
 
915
      else if (alignV==TV_BASE) y0 -= height-0.8*lineHeight;
 
916
      else if (alignV==TV_BOTTOM) y0 -= height-lineHeight;
 
917
 
 
918
    } else if (gistA.t.orient==TX_LEFT) {
 
919
 
 
920
      if (alignH==TH_CENTER) x0 -= 0.5*width;
 
921
      else if (alignH==TH_LEFT) x0 -= width;
 
922
 
 
923
      if (alignV==TV_HALF) y0 -= .4*lineHeight;
 
924
      else if (alignV==TV_BASE) y0 -= 0.8*lineHeight;
 
925
      else if (alignV==TV_BOTTOM) y0 -= lineHeight;
 
926
 
 
927
    } else if (gistA.t.orient==TX_UP) {
 
928
      
 
929
      if (alignH==TH_CENTER) y0 -= 0.5*width;
 
930
      else if (alignH==TH_RIGHT) y0 -= width;
 
931
 
 
932
      if (alignV==TV_HALF) x0 -= 0.4*lineHeight;
 
933
      else if (alignV==TV_BASE) x0 -= 0.8*lineHeight;
 
934
      else if (alignV==TV_BOTTOM) x0 -= lineHeight;
 
935
 
 
936
    } else { /* TX_DOWN */
 
937
 
 
938
      if (alignH==TH_CENTER) y0 -= 0.5*width;
 
939
      else if (alignH==TH_LEFT) y0 -= width;
 
940
 
 
941
      if (alignV==TV_TOP || alignV==TV_CAP) x0 -= height;
 
942
      else if (alignV==TV_HALF) x0 -= height-0.4*lineHeight;
 
943
      else if (alignV==TV_BASE) x0 -= height-0.8*lineHeight;
 
944
      else if (alignV==TV_BOTTOM) x0 -= height-lineHeight;
 
945
 
 
946
    }
 
947
 
 
948
    if (x0>xmin) xmin= x0;
 
949
    if (x0+width<xmax) xmax= x0+width;
 
950
    if (y0>ymin) ymin= y0;
 
951
    if (y0+height<ymax) ymax= y0+height;    
 
952
 
 
953
    xll= (int)xmin;
 
954
    xur= (int)xmax;
 
955
    yll= (int)ymin;
 
956
    yur= (int)ymax;
 
957
    if (xll<psEngine->pageBB.xll) psEngine->pageBB.xll= xll;
 
958
    if (xur>psEngine->pageBB.xur) psEngine->pageBB.xur= xur;
 
959
    if (yll<psEngine->pageBB.yll) psEngine->pageBB.yll= yll;
 
960
    if (yur>psEngine->pageBB.yur) psEngine->pageBB.yur= yur;
 
961
  }
 
962
 
 
963
  if (nlines>1 || gistA.t.orient!=TX_RIGHT) {
 
964
    if (Append(psEngine, "[")) return 1;
 
965
  }
 
966
 
 
967
  nchars= psEngine->nchars;
 
968
  now= psEngine->line+nchars;
 
969
  firstPass= 1;
 
970
  while ((t= GtNextLine(text, &count, gistA.t.orient)) || firstPass) {
 
971
    text= t;
 
972
    firstPass= 0;
 
973
    state= 0;
 
974
 
 
975
    if (nchars > 70) {
 
976
      psEngine->nchars= nchars;
 
977
      if (PutLine(psEngine)) return 1;
 
978
      nchars= 0;
 
979
      now= psEngine->line;
 
980
    }
 
981
    *now++= ' ';
 
982
    *now++= '(';
 
983
    nchars+= 2;
 
984
 
 
985
    while (count--) {
 
986
      if (nchars>72 && break_line_now(psEngine, &now, &nchars)) return 1;
 
987
 
 
988
      c= *text;
 
989
      if (c>=32 && c<127) {
 
990
        if (gtDoEscapes) {
 
991
          if (c=='!' && count) {
 
992
            c= text[1];  /* peek at next char */
 
993
            if (c=='!' || c=='^' || c=='_') {
 
994
              count--;
 
995
              text++;
 
996
              goto normal;
 
997
            }
 
998
            if (nchars>68 &&
 
999
                break_line_now(psEngine, &now, &nchars)) return 1;
 
1000
            strcpy(now, "\\024");  /* DC4 is ps.ps escape char */
 
1001
            now+= 4;
 
1002
            nchars+= 4;
 
1003
            psEngine->fonts|= (1<<T_SYMBOL);  /* symbol font used */
 
1004
            if (c==']') {
 
1005
              *now++= '^';         /* !] means ^ (perp) in symbol font */
 
1006
              nchars++;
 
1007
              text+= 2;
 
1008
              count--;
 
1009
              continue;
 
1010
            }
 
1011
            goto escape;
 
1012
          } else if (c=='^') {
 
1013
            if (state!=0) {
 
1014
              /* terminate current super or subscript escape */
 
1015
              strcpy(now, "\\021");  /* DC1 is ps.ps escape char */
 
1016
              now+= 4;
 
1017
              nchars+= 4;
 
1018
            }
 
1019
            if (state!=1) {
 
1020
              /* intialize superscript escape */
 
1021
              if (nchars>64 &&
 
1022
                  break_line_now(psEngine, &now, &nchars)) return 1;
 
1023
              strcpy(now, "\\021\\022");  /* DC1DC2 is ps.ps escape seq */
 
1024
              now+= 8;
 
1025
              nchars+= 8;
 
1026
              state= 1;
 
1027
            } else {
 
1028
              state= 0;
 
1029
            }
 
1030
            goto escape;
 
1031
          } else if (c=='_') {
 
1032
            if (state!=0) {
 
1033
              /* terminate current super or subscript escape */
 
1034
              if (nchars>68 &&
 
1035
                  break_line_now(psEngine, &now, &nchars)) return 1;
 
1036
              strcpy(now, "\\021");  /* DC1 is ps.ps escape char */
 
1037
              now+= 4;
 
1038
              nchars+= 4;
 
1039
            }
 
1040
            if (state!=2) {
 
1041
              /* intialize subscript escape */
 
1042
              if (nchars>64 &&
 
1043
                  break_line_now(psEngine, &now, &nchars)) return 1;
 
1044
              strcpy(now, "\\021\\023");  /* DC1DC3 is ps.ps escape seq */
 
1045
              now+= 8;
 
1046
              nchars+= 8;
 
1047
              state= 2;
 
1048
            } else {
 
1049
              state= 0;
 
1050
            }
 
1051
            goto escape;
 
1052
          }
 
1053
        }
 
1054
        /* ordinary printing character */
 
1055
        if (c=='(' || c==')' || c=='\\') {
 
1056
          *now++= '\\';
 
1057
          nchars++;
 
1058
        }
 
1059
      normal:
 
1060
        *now++= c;
 
1061
        nchars++;
 
1062
      } else {
 
1063
        /* non-printing characters rendered as \ooo */
 
1064
        if (c=='\t') {
 
1065
          *now++= '\\';
 
1066
          *now++= 't';
 
1067
          nchars+= 2;
 
1068
        } else if (c<'\021' || c>'\024') {
 
1069
          /* DC1 through DC4 have special meaning in ps.ps, skip them */
 
1070
          sprintf(now, "\\%03o", (int)((unsigned char)c));
 
1071
          now+= 4;
 
1072
          nchars+= 4;
 
1073
        }
 
1074
      }
 
1075
    escape:
 
1076
      text++;
 
1077
    }
 
1078
    if (state!=0) {
 
1079
      /* terminate current super or subscript escape */
 
1080
      strcpy(now, "\\021");  /* DC1 is ps.ps escape char */
 
1081
      now+= 4;
 
1082
      nchars+= 4;
 
1083
    }
 
1084
 
 
1085
    *now++= ')';
 
1086
    nchars++;
 
1087
    *now= '\0';
 
1088
  }
 
1089
  psEngine->nchars= nchars;
 
1090
 
 
1091
  if (gistA.t.orient==TX_RIGHT) {
 
1092
    sprintf(line, nlines>1? "] %d %d TA" : "%d %d T", ix, iy);
 
1093
  } else {
 
1094
    int angle;
 
1095
    if (gistA.t.orient==TX_LEFT) angle= 180;
 
1096
    else if (gistA.t.orient==TX_UP) angle= 90;
 
1097
    else angle= 270;
 
1098
    sprintf(line, "] %d %d %d TR", angle, ix, iy);
 
1099
  }
 
1100
  if (Append(psEngine, line)) return 1;
 
1101
 
 
1102
  return 0;
 
1103
}
 
1104
 
 
1105
static int break_line_now(PSEngine *psEngine, char **nw, int *nchs)
 
1106
{
 
1107
  char *now= *nw;
 
1108
  *now++= '\\';
 
1109
  *now= '\0';
 
1110
  psEngine->nchars= *nchs+1;
 
1111
  if (PutLine(psEngine)) return 1;
 
1112
  *nchs= 0;
 
1113
  *nw= psEngine->line;
 
1114
  return 0;
 
1115
}
 
1116
 
 
1117
/* ------------------------------------------------------------------------ */
 
1118
 
 
1119
static int DrawFill(Engine *engine, long n, const GpReal *px,
 
1120
                    const GpReal *py)
 
1121
{
 
1122
  PSEngine *psEngine= (PSEngine *)engine;
 
1123
  GpXYMap *map= &engine->map;
 
1124
  long maxPoints= 4050, nPoints;
 
1125
  int markEnd= 0;
 
1126
  GpPoint *points;
 
1127
  int value= 0;
 
1128
 
 
1129
  /* For now, only FillSolid style supported */
 
1130
 
 
1131
  if (n<1) return 0;
 
1132
  if (CheckClip(psEngine) || SetupColor(psEngine, gistA.f.color)) return 1;
 
1133
 
 
1134
  if (n>90) {
 
1135
    long nLines= (n-1)/9 + 1;  /* 9 points is 72 characters */
 
1136
    if (psEngine->nchars && PutLine(psEngine)) return 1;
 
1137
    sprintf(line, "%%%%BeginData: %ld ASCII Lines", nLines+1);
 
1138
    if (Append(psEngine, line) || PutLine(psEngine)) return 1;
 
1139
    markEnd= 1;
 
1140
  }
 
1141
  if (gistA.e.type==L_NONE) sprintf(line, "%ld F", n);
 
1142
  else sprintf(line, "%ld E", n);
 
1143
  if (Append(psEngine, line) || PutLine(psEngine)) return 1;
 
1144
 
 
1145
  while ((nPoints=
 
1146
          GpIntPoints(map, maxPoints, n, px, py, &points))) {
 
1147
    if (PutPoints(psEngine, points, nPoints, 0)) return 1;
 
1148
    if (n==nPoints) break;
 
1149
    n-= nPoints;
 
1150
    px+= nPoints;
 
1151
    py+= nPoints;
 
1152
    value= 1;   /* Polygons with >4050 sides won't be filled correctly */
 
1153
  }
 
1154
  if (gistA.e.type!=L_NONE) {
 
1155
    /* setup for edge (usually different color than fill), then draw it */
 
1156
    if (SetupLine(psEngine, &gistA.e)) return 1;
 
1157
    if (Append(psEngine, "0 E") || PutLine(psEngine)) return 1;
 
1158
  }
 
1159
 
 
1160
  if (markEnd) {
 
1161
    if (Append(psEngine, "%%EndData") || PutLine(psEngine)) return 1;
 
1162
  }
 
1163
 
 
1164
  return value;
 
1165
}
 
1166
 
 
1167
/* ------------------------------------------------------------------------ */
 
1168
 
 
1169
static int DrawCells(Engine *engine, GpReal px, GpReal py, GpReal qx,
 
1170
                     GpReal qy, long width, long height, long nColumns,
 
1171
                     const GpColor *colors)
 
1172
{
 
1173
  PSEngine *psEngine= (PSEngine *)engine;
 
1174
  GpXYMap *map= &psEngine->e.map;
 
1175
  int nColors= psEngine->nColors;
 
1176
  GpColorCell *palette;
 
1177
  int ix, iy, idx, idy, depth;
 
1178
  long i, j, off;
 
1179
  int markEnd= 0;
 
1180
  long nLines;
 
1181
  char *now= psEngine->line;
 
1182
  int nc, ncmax, color, colorMode;
 
1183
 
 
1184
  if (!psEngine->e.marked && BeginPage(psEngine)) return 1;
 
1185
  if (CheckClip(psEngine)) return 1;
 
1186
 
 
1187
  /* Transform corner coordinates, clipping and adjusting width,
 
1188
     height, nColumns, and colors as necessary.  */
 
1189
  width = GpClipCells(&map->x, &px, &qx,
 
1190
                      gistT.window.xmin, gistT.window.xmax, width, &off);
 
1191
  colors += gistA.rgb? 3*off : off;
 
1192
  height = GpClipCells(&map->y, &py, &qy,
 
1193
                       gistT.window.ymin, gistT.window.ymax, height, &off);
 
1194
  colors += gistA.rgb? 3*nColumns*off : nColumns*off;
 
1195
 
 
1196
  if (width<=0 || height<=0) return 0;
 
1197
  ix= (int)px;
 
1198
  iy= (int)py;
 
1199
  idx= (int)(qx-px);
 
1200
  idy= (int)(qy-py);
 
1201
 
 
1202
  /* Set bounding box for image if necessary */
 
1203
  if (!psEngine->curClip) {
 
1204
    GpBox *wind= &engine->transform.window;
 
1205
    GpReal xmin, xmax, ymin, ymax;
 
1206
    int xll, yll, xur, yur;
 
1207
    if (wind->xmax>wind->xmin) { xmin= wind->xmin; xmax= wind->xmax; }
 
1208
    else { xmin= wind->xmax; xmax= wind->xmin; }
 
1209
    if (wind->ymax>wind->ymin) { ymin= wind->ymin; ymax= wind->ymax; }
 
1210
    else { ymin= wind->ymax; ymax= wind->ymin; }
 
1211
 
 
1212
    if (px<qx) {
 
1213
      if (px>xmin) xmin= px;
 
1214
      if (qx<xmax) xmax= qx;
 
1215
    } else {
 
1216
      if (qx>xmin) xmin= qx;
 
1217
      if (px<xmax) xmax= px;
 
1218
    }
 
1219
    if (py<qy) {
 
1220
      if (py>ymin) ymin= py;
 
1221
      if (qy<ymax) ymax= qy;
 
1222
    } else {
 
1223
      if (qy>ymin) ymin= qy;
 
1224
      if (py<ymax) ymax= py;
 
1225
    }
 
1226
 
 
1227
    xll= (int)xmin;
 
1228
    xur= (int)xmax;
 
1229
    yll= (int)ymin;
 
1230
    yur= (int)ymax;
 
1231
    if (xll<psEngine->pageBB.xll) psEngine->pageBB.xll= xll;
 
1232
    if (xur>psEngine->pageBB.xur) psEngine->pageBB.xur= xur;
 
1233
    if (yll<psEngine->pageBB.yll) psEngine->pageBB.yll= yll;
 
1234
    if (yur>psEngine->pageBB.yur) psEngine->pageBB.yur= yur;
 
1235
  }
 
1236
 
 
1237
  /* Use 4 bit depth if the color table is small, otherwise use
 
1238
     8 bit depth.  */
 
1239
  if (nColors>0) {
 
1240
    /* Image value will be either  */
 
1241
    colorMode= psEngine->colorMode;
 
1242
    if (colorMode) {
 
1243
      palette= 0;                     /* palette already written */
 
1244
      if (nColors>16) depth= 8;
 
1245
      else depth= 4;
 
1246
    } else {
 
1247
      palette= psEngine->e.palette;   /* must lookup gray level now */
 
1248
      depth= 8;
 
1249
    }
 
1250
  } else {
 
1251
    /* Must assume image varies over maximum possible range */
 
1252
    colorMode= 1;  /* That is, use index without trying palette lookup */
 
1253
    depth= 8;
 
1254
    palette= 0;
 
1255
  }
 
1256
 
 
1257
  if (gistA.rgb) {
 
1258
    /* Write the 6 arguments to the J procedure */
 
1259
    sprintf(line, "%d %d %d %d %d %d",
 
1260
            (int)width, (int)height, idx, idy, ix, iy);
 
1261
  } else {
 
1262
    /* Write the 7 arguments to the I procedure */
 
1263
    sprintf(line, "%d %d %d %d %d %d %d",
 
1264
            (int)width, (int)height, depth, idx, idy, ix, iy);
 
1265
  }
 
1266
  if (Append(psEngine, line)) return 1;
 
1267
 
 
1268
  if (gistA.rgb) {
 
1269
    nLines= 6*width*height;
 
1270
    ncmax = 72;   /* 12 cells (72 chars) per line */
 
1271
  } else {
 
1272
    nLines= width*height;
 
1273
    depth= (depth==8);
 
1274
    if (depth) nLines*= 2;
 
1275
    else if (nLines&1L) nLines++;
 
1276
    ncmax = 76;   /* Will put 76 or 38 cells per line */
 
1277
  }
 
1278
  nLines= 1+(nLines-1)/ncmax;
 
1279
  if (nLines>10) {
 
1280
    if (psEngine->nchars && PutLine(psEngine)) return 1;
 
1281
    sprintf(line, "%%%%BeginData: %ld ASCII Lines", nLines+1);
 
1282
    if (Append(psEngine, line) || PutLine(psEngine)) return 1;
 
1283
    markEnd= 1;
 
1284
  }
 
1285
  if (Append(psEngine, gistA.rgb?"J":"I") || PutLine(psEngine)) return 1;
 
1286
 
 
1287
  i= j= 0;
 
1288
  while (nLines--) {
 
1289
    for (nc=0 ; nc<ncmax ; ) {
 
1290
      if (i>=width) {
 
1291
        height--;
 
1292
        if (height<=0) break;
 
1293
        i= 0;
 
1294
        j+= nColumns;
 
1295
      }
 
1296
      if (gistA.rgb) {
 
1297
        const GpColor *ccell = &colors[3*(i+j)];
 
1298
        now[nc++] = hexChar[ccell[0]>>4];
 
1299
        now[nc++] = hexChar[ccell[0]&0xf];
 
1300
        now[nc++] = hexChar[ccell[1]>>4];
 
1301
        now[nc++] = hexChar[ccell[1]&0xf];
 
1302
        now[nc++] = hexChar[ccell[2]>>4];
 
1303
        now[nc++] = hexChar[ccell[2]&0xf];
 
1304
      } else {
 
1305
        color= colors[i+j];
 
1306
        i++;
 
1307
        if (color>=nColors && nColors>0) color= nColors-1;
 
1308
        if (!colorMode) color= (P_R(palette[color])+
 
1309
                                P_G(palette[color])+P_B(palette[color]))/3;
 
1310
        if (depth) {  /* 2 hex chars per cell */
 
1311
          now[nc++]= hexChar[color>>4];
 
1312
          now[nc++]= hexChar[color&0xf];
 
1313
        } else {      /* 1 hex char per cell */
 
1314
          now[nc++]= hexChar[color];
 
1315
        }
 
1316
      }
 
1317
    }
 
1318
    now[nc]= '\0';
 
1319
    psEngine->nchars= nc;
 
1320
    if (PutLine(psEngine)) return 1;
 
1321
  }
 
1322
 
 
1323
  if (markEnd) {
 
1324
    if (Append(psEngine, "%%EndData") || PutLine(psEngine)) return 1;
 
1325
  }
 
1326
 
 
1327
  return 0;
 
1328
}
 
1329
 
 
1330
/* ------------------------------------------------------------------------ */
 
1331
 
 
1332
static int DrawDisjoint(Engine *engine, long n, const GpReal *px,
 
1333
                        const GpReal *py, const GpReal *qx, const GpReal *qy)
 
1334
{
 
1335
  PSEngine *psEngine= (PSEngine *)engine;
 
1336
  GpXYMap *map= &engine->map;
 
1337
  long maxSegs= 2025, nSegs;
 
1338
  int markEnd= 0;
 
1339
  GpSegment *segs;
 
1340
  int size;
 
1341
 
 
1342
  if (CheckClip(psEngine)) return 1;
 
1343
  if (n<1 || SetupLine(psEngine, &gistA.l)) return 0;
 
1344
  if (psEngine->curClip) size= 0;
 
1345
  else size= (int)(psEngine->curWidth*0.5*DEFAULT_PS_WIDTH);
 
1346
 
 
1347
  if (n>45) {
 
1348
    long nLines= (2*n-1)/9 + 1;  /* 9 points is 72 characters */
 
1349
    if (psEngine->nchars && PutLine(psEngine)) return 1;
 
1350
    sprintf(line, "%%%%BeginData: %ld ASCII Lines", nLines+1);
 
1351
    if (Append(psEngine, line) || PutLine(psEngine)) return 1;
 
1352
    markEnd= 1;
 
1353
  }
 
1354
  sprintf(line, "%ld D", n);
 
1355
  if (Append(psEngine, line) || PutLine(psEngine)) return 1;
 
1356
 
 
1357
  while ((nSegs=
 
1358
          GpIntSegs(map, maxSegs, n, px, py, qx, qy, &segs))) {
 
1359
    /* This cast from GpPoint to GpSegment is lazy programming,
 
1360
       but I don't know of any platforms it will not work on... */
 
1361
    if (PutPoints(psEngine, (GpPoint *)segs, 2*nSegs, size)) return 1;
 
1362
    if (n==nSegs) break;
 
1363
    n-= nSegs;
 
1364
    px+= nSegs;
 
1365
    py+= nSegs;
 
1366
    qx+= nSegs;
 
1367
    qy+= nSegs;
 
1368
  }
 
1369
 
 
1370
  if (markEnd) {
 
1371
    if (Append(psEngine, "%%EndData") || PutLine(psEngine)) return 1;
 
1372
  }
 
1373
 
 
1374
  return 0;
 
1375
}
 
1376
 
 
1377
/* ------------------------------------------------------------------------ */
 
1378
 
 
1379
Engine *GpPSEngine(char *name, int landscape, int mode, char *file)
 
1380
{
 
1381
  PSEngine *psEngine;
 
1382
  long flen= file? strlen(file) : 0;
 
1383
  long engineSize= sizeof(PSEngine)+flen+1;
 
1384
  GpTransform toPixels;
 
1385
 
 
1386
  if (flen<=0) return 0;
 
1387
 
 
1388
  SetPSTransform(&toPixels, landscape);
 
1389
 
 
1390
  psEngine=
 
1391
    (PSEngine *)GpNewEngine(engineSize, name, psType, &toPixels, landscape,
 
1392
                            &Kill, &Clear, &Flush, &GpComposeMap,
 
1393
                            &ChangePalette, &DrawLines, &DrawMarkers,
 
1394
                            &DrwText, &DrawFill, &DrawCells,
 
1395
                            &DrawDisjoint);
 
1396
 
 
1397
  if (!psEngine) {
 
1398
    strcpy(gistError, "memory manager failed in GpPSEngine");
 
1399
    return 0;
 
1400
  }
 
1401
 
 
1402
  psEngine->filename= (char *)(psEngine+1);
 
1403
  strcpy(psEngine->filename, file);
 
1404
  psEngine->file= 0;
 
1405
  psEngine->closed= 0;
 
1406
 
 
1407
  SetPageDefaults(psEngine);
 
1408
  psEngine->e.colorMode= mode;
 
1409
  psEngine->colorMode= 0;
 
1410
  psEngine->nColors= 0;
 
1411
 
 
1412
  psEngine->landscape= landscape;
 
1413
  psEngine->docBB.xll= psEngine->docBB.xur=
 
1414
    psEngine->docBB.yll= psEngine->docBB.yur= 0;
 
1415
  psEngine->currentPage= 1;
 
1416
  psEngine->fonts|= (1<<T_COURIER);
 
1417
 
 
1418
  psEngine->clipColor= psEngine->curColor;
 
1419
  psEngine->clipType= psEngine->curType;
 
1420
  psEngine->clipWidth= psEngine->curWidth;
 
1421
  psEngine->clipFont= psEngine->curFont;
 
1422
  psEngine->clipHeight= psEngine->curHeight;
 
1423
 
 
1424
  psEngine->clipBox.xmin= psEngine->clipBox.xmax=
 
1425
    psEngine->clipBox.ymin= psEngine->clipBox.ymax= 0.0;
 
1426
 
 
1427
  psEngine->line[0]= '\0';
 
1428
  psEngine->nchars= 0;
 
1429
 
 
1430
  return (Engine *)psEngine;
 
1431
}
 
1432
 
 
1433
PSEngine *GisPSEngine(Engine *engine)
 
1434
{
 
1435
  return (engine && engine->type==psType)? (PSEngine *)engine : 0;
 
1436
}
 
1437
 
 
1438
/* ------------------------------------------------------------------------ */