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

« back to all changes in this revision

Viewing changes to Lib/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,v 1.2 2003/08/21 22:22:00 travo Exp $
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
 
/* ------------------------------------------------------------------------ */