The R Project SVN R

Rev

Rev 27680 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 27680 Rev 27683
1
/*
1
/*
2
 *  R : A Computer Language for Statistical Data Analysis
2
 *  R : A Computer Language for Statistical Data Analysis
3
 *  Copyright (C) 1995, 1996  Robert Gentleman and Ross Ihaka
3
 *  Copyright (C) 1995, 1996  Robert Gentleman and Ross Ihaka
4
 *  Copyright (C) 1998--2003  Robert Gentleman, Ross Ihaka and the
4
 *  Copyright (C) 1998--2003  Robert Gentleman, Ross Ihaka and the
5
 *                            R Development Core Team
5
 *                            R Development Core Team
6
 *
6
 *
7
 *  This program is free software; you can redistribute it and/or modify
7
 *  This program is free software; you can redistribute it and/or modify
8
 *  it under the terms of the GNU General Public License as published by
8
 *  it under the terms of the GNU General Public License as published by
9
 *  the Free Software Foundation; either version 2 of the License, or
9
 *  the Free Software Foundation; either version 2 of the License, or
10
 *  (at your option) any later version.
10
 *  (at your option) any later version.
11
 *
11
 *
12
 *  This program is distributed in the hope that it will be useful,
12
 *  This program is distributed in the hope that it will be useful,
13
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 *  GNU General Public License for more details.
15
 *  GNU General Public License for more details.
16
 *
16
 *
17
 *  You should have received a copy of the GNU General Public License
17
 *  You should have received a copy of the GNU General Public License
18
 *  along with this program; if not, write to the Free Software
18
 *  along with this program; if not, write to the Free Software
19
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
 */
20
 */
21
 
21
 
22
#ifdef HAVE_CONFIG_H
22
#ifdef HAVE_CONFIG_H
23
#include <config.h>
23
#include <config.h>
24
#endif
24
#endif
25
 
25
 
26
#include <stdio.h>
26
#include <stdio.h>
27
#include <ctype.h>
27
#include <ctype.h>
28
 
28
 
29
#include "Defn.h"
29
#include "Defn.h"
30
#include "Rmath.h" /* for rround */
30
#include "Rmath.h" /* for rround */
31
#include "Graphics.h"
31
#include "Graphics.h"
32
#include <R_ext/Error.h>
32
#include <R_ext/Error.h>
33
#include "Fileio.h"
33
#include "Fileio.h"
34
#include <Rdevices.h>
34
#include <Rdevices.h>
35
 
35
 
36
#ifdef HAVE_ERRNO_H
36
#ifdef HAVE_ERRNO_H
37
#include <errno.h>
37
#include <errno.h>
38
#else
38
#else
39
extern int errno;
39
extern int errno;
40
#endif
40
#endif
41
 
41
 
42
 
42
 
43
#define INVALID_COL 0xff0a0b0c
43
#define INVALID_COL 0xff0a0b0c
44
 
44
 
45
/* Define this to use hyphen except in -[0-9] */
45
/* Define this to use hyphen except in -[0-9] */
46
#undef USE_HYPHEN
46
#undef USE_HYPHEN
47
/* In ISOLatin1, minus is 45 and hyphen is 173 */
47
/* In ISOLatin1, minus is 45 and hyphen is 173 */
48
#ifdef USE_HYPHEN
48
#ifdef USE_HYPHEN
49
static char PS_hyphen = 173;
49
static char PS_hyphen = 173;
50
#endif
50
#endif
51
 
51
 
52
#define USERAFM 999
52
#define USERAFM 999
53
 
53
 
54
/* Part 0.  AFM File Names */
54
/* Part 0.  AFM File Names */
55
 
55
 
56
/* This structure gives the set of font names for each type face. */
56
/* This structure gives the set of font names for each type face. */
57
/* They also give the afm file names. */
57
/* They also give the afm file names. */
58
 
58
 
59
static const struct {
59
static const struct {
60
    char const *family;
60
    char const *family;
61
    char const *afmfile[5];
61
    char const *afmfile[5];
62
}
62
}
63
Family [] = {
63
Family [] = {
64
 
64
 
65
    { "AvantGarde",
65
    { "AvantGarde",
66
      {"agw_____.afm", "agd_____.afm", "agwo____.afm", "agdo____.afm",
66
      {"agw_____.afm", "agd_____.afm", "agwo____.afm", "agdo____.afm",
67
       "sy______.afm"}
67
       "sy______.afm"}
68
    },
68
    },
69
 
69
 
70
    { "Bookman",
70
    { "Bookman",
71
      {"bkl_____.afm", "bkd_____.afm", "bkli____.afm", "bkdi____.afm",
71
      {"bkl_____.afm", "bkd_____.afm", "bkli____.afm", "bkdi____.afm",
72
       "sy______.afm"}
72
       "sy______.afm"}
73
    },
73
    },
74
 
74
 
75
    { "Courier",
75
    { "Courier",
76
      {"com_____.afm", "cob_____.afm", "coo_____.afm", "cobo____.afm",
76
      {"com_____.afm", "cob_____.afm", "coo_____.afm", "cobo____.afm",
77
       "sy______.afm"}
77
       "sy______.afm"}
78
    },
78
    },
79
 
79
 
80
    { "Helvetica",
80
    { "Helvetica",
81
      {"hv______.afm", "hvb_____.afm", "hvo_____.afm", "hvbo____.afm",
81
      {"hv______.afm", "hvb_____.afm", "hvo_____.afm", "hvbo____.afm",
82
       "sy______.afm"}
82
       "sy______.afm"}
83
    },
83
    },
84
 
84
 
85
    { "Helvetica-Narrow",
85
    { "Helvetica-Narrow",
86
      {"hvn_____.afm", "hvnb____.afm", "hvno____.afm", "hvnbo___.afm",
86
      {"hvn_____.afm", "hvnb____.afm", "hvno____.afm", "hvnbo___.afm",
87
       "sy______.afm"}
87
       "sy______.afm"}
88
    },
88
    },
89
 
89
 
90
    { "NewCenturySchoolbook",
90
    { "NewCenturySchoolbook",
91
      {"ncr_____.afm", "ncb_____.afm", "nci_____.afm", "ncbi____.afm",
91
      {"ncr_____.afm", "ncb_____.afm", "nci_____.afm", "ncbi____.afm",
92
       "sy______.afm"}
92
       "sy______.afm"}
93
    },
93
    },
94
 
94
 
95
    { "Palatino",
95
    { "Palatino",
96
      {"por_____.afm", "pob_____.afm", "poi_____.afm", "pobi____.afm",
96
      {"por_____.afm", "pob_____.afm", "poi_____.afm", "pobi____.afm",
97
       "sy______.afm"}
97
       "sy______.afm"}
98
    },
98
    },
99
 
99
 
100
    { "Times",
100
    { "Times",
101
      {"tir_____.afm", "tib_____.afm", "tii_____.afm", "tibi____.afm",
101
      {"tir_____.afm", "tib_____.afm", "tii_____.afm", "tibi____.afm",
102
       "sy______.afm"}
102
       "sy______.afm"}
103
    },
103
    },
104
 
104
 
105
    /* URW equivalents */
105
    /* URW equivalents */
106
    { "URWGothic",
106
    { "URWGothic",
107
      {"a010013l.afm", "a010015l.afm", "a010033l.afm", "a010035l.afm",
107
      {"a010013l.afm", "a010015l.afm", "a010033l.afm", "a010035l.afm",
108
       "s050000l.afm"}
108
       "s050000l.afm"}
109
    },
109
    },
110
 
110
 
111
    { "URWBookman",
111
    { "URWBookman",
112
      {"b018012l.afm", "b018015l.afm", "b018032l.afm", "b018035l.afm",
112
      {"b018012l.afm", "b018015l.afm", "b018032l.afm", "b018035l.afm",
113
       "s050000l.afm"}
113
       "s050000l.afm"}
114
    },
114
    },
115
 
115
 
116
    { "NimbusMon",
116
    { "NimbusMon",
117
      {"n022003l.afm", "n022004l.afm", "n022023l.afm", "n022024l.afm",
117
      {"n022003l.afm", "n022004l.afm", "n022023l.afm", "n022024l.afm",
118
       "s050000l.afm"}
118
       "s050000l.afm"}
119
    },
119
    },
120
 
120
 
121
    { "NimbusSan",
121
    { "NimbusSan",
122
      {"n019003l.afm", "n019004l.afm", "n019023l.afm", "n019024l.afm",
122
      {"n019003l.afm", "n019004l.afm", "n019023l.afm", "n019024l.afm",
123
       "s050000l.afm"}
123
       "s050000l.afm"}
124
    },
124
    },
125
 
125
 
126
    { "URWHelvetica",
126
    { "URWHelvetica",
127
      {"n019003l.afm", "n019004l.afm", "n019023l.afm", "n019024l.afm",
127
      {"n019003l.afm", "n019004l.afm", "n019023l.afm", "n019024l.afm",
128
       "s050000l.afm"}
128
       "s050000l.afm"}
129
    },
129
    },
130
 
130
 
131
    { "NimbusSanCond",
131
    { "NimbusSanCond",
132
      {"n019043l.afm", "n019044l.afm", "n019063l.afm", "n019064l.afm",
132
      {"n019043l.afm", "n019044l.afm", "n019063l.afm", "n019064l.afm",
133
       "s050000l.afm"}
133
       "s050000l.afm"}
134
    },
134
    },
135
 
135
 
136
    { "CenturySch",
136
    { "CenturySch",
137
      {"c059013l.afm", "c059016l.afm", "c059033l.afm", "c059036l.afm",
137
      {"c059013l.afm", "c059016l.afm", "c059033l.afm", "c059036l.afm",
138
       "s050000l.afm"}
138
       "s050000l.afm"}
139
    },
139
    },
140
 
140
 
141
    { "URWPalladio",
141
    { "URWPalladio",
142
      {"p052003l.afm", "p052004l.afm", "p052023l.afm", "p052024l.afm",
142
      {"p052003l.afm", "p052004l.afm", "p052023l.afm", "p052024l.afm",
143
       "s050000l.afm"}
143
       "s050000l.afm"}
144
    },
144
    },
145
 
145
 
146
    { "NimbusRom",
146
    { "NimbusRom",
147
      {"n021003l.afm", "n021004l.afm", "n021023l.afm", "n021024l.afm",
147
      {"n021003l.afm", "n021004l.afm", "n021023l.afm", "n021024l.afm",
148
       "s050000l.afm"}
148
       "s050000l.afm"}
149
    },
149
    },
150
 
150
 
151
   { "URWTimes",
151
   { "URWTimes",
152
      {"n021003l.afm", "n021004l.afm", "n021023l.afm", "n021024l.afm",
152
      {"n021003l.afm", "n021004l.afm", "n021023l.afm", "n021024l.afm",
153
       "s050000l.afm"}
153
       "s050000l.afm"}
154
    },
154
    },
155
 
155
 
156
    /* Computer Modern as recoded by Brian D'Urso */
156
    /* Computer Modern as recoded by Brian D'Urso */
157
    { "ComputerModern",
157
    { "ComputerModern",
158
      {"CM_regular_10.afm", "CM_boldx_10.afm", "CM_italic_10.afm",
158
      {"CM_regular_10.afm", "CM_boldx_10.afm", "CM_italic_10.afm",
159
       "CM_boldx_italic_10.afm", "CM_symbol_10.afm"}
159
       "CM_boldx_italic_10.afm", "CM_symbol_10.afm"}
160
    },
160
    },
161
 
161
 
162
    { NULL }
162
    { NULL }
163
};
163
};
164
 
164
 
165
 
165
 
166
static char familyname[5][50];
166
static char familyname[5][50];
167
 
167
 
168
/* Part 1.  AFM File Parsing.  */
168
/* Part 1.  AFM File Parsing.  */
169
 
169
 
170
/* These are the basic entities in the AFM file */
170
/* These are the basic entities in the AFM file */
171
 
171
 
172
#define BUFSIZE 512
172
#define BUFSIZE 512
173
#define NA_SHORT -30000
173
#define NA_SHORT -30000
174
 
174
 
175
typedef struct {
175
typedef struct {
176
    unsigned char c1;
176
    unsigned char c1;
177
    unsigned char c2;
177
    unsigned char c2;
178
    short kern;
178
    short kern;
179
} KP;
179
} KP;
180
 
180
 
181
typedef struct {
181
typedef struct {
182
    short FontBBox[4];
182
    short FontBBox[4];
183
    short CapHeight;
183
    short CapHeight;
184
    short XHeight;
184
    short XHeight;
185
    short Descender;
185
    short Descender;
186
    short Ascender;
186
    short Ascender;
187
    struct {
187
    struct {
188
	short WX;
188
	short WX;
189
	short BBox[4];
189
	short BBox[4];
190
    } CharInfo[256];
190
    } CharInfo[256];
191
    KP *KernPairs;
191
    KP *KernPairs;
192
    short KPstart[256];
192
    short KPstart[256];
193
    short KPend[256];
193
    short KPend[256];
194
    short nKP;
194
    short nKP;
195
} FontMetricInfo;
195
} FontMetricInfo;
196
 
196
 
197
enum {
197
enum {
198
    Empty,
198
    Empty,
199
    StartFontMetrics,
199
    StartFontMetrics,
200
    Comment,
200
    Comment,
201
    FontName,
201
    FontName,
202
    EncodingScheme,
202
    EncodingScheme,
203
    FullName,
203
    FullName,
204
    FamilyName,
204
    FamilyName,
205
    Weight,
205
    Weight,
206
    ItalicAngle,
206
    ItalicAngle,
207
    IsFixedPitch,
207
    IsFixedPitch,
208
    UnderlinePosition,
208
    UnderlinePosition,
209
    UnderlineThickness,
209
    UnderlineThickness,
210
    Version,
210
    Version,
211
    Notice,
211
    Notice,
212
    FontBBox,
212
    FontBBox,
213
    CapHeight,
213
    CapHeight,
214
    XHeight,
214
    XHeight,
215
    Descender,
215
    Descender,
216
    Ascender,
216
    Ascender,
217
    StartCharMetrics,
217
    StartCharMetrics,
218
    C,
218
    C,
219
    EndCharMetrics,
219
    EndCharMetrics,
220
    StartKernData,
220
    StartKernData,
221
    StartKernPairs,
221
    StartKernPairs,
222
    KPX,
222
    KPX,
223
    EndKernPairs,
223
    EndKernPairs,
224
    EndKernData,
224
    EndKernData,
225
    StartComposites,
225
    StartComposites,
226
    CC,
226
    CC,
227
    EndComposites,
227
    EndComposites,
228
    EndFontMetrics,
228
    EndFontMetrics,
229
    Unknown
229
    Unknown
230
};
230
};
231
 
231
 
232
static const struct {
232
static const struct {
233
    const char *keyword;
233
    const char *keyword;
234
    const int code;
234
    const int code;
235
}
235
}
236
KeyWordDictionary[] = {
236
KeyWordDictionary[] = {
237
    { "StartFontMetrics",    StartFontMetrics },
237
    { "StartFontMetrics",    StartFontMetrics },
238
    { "Comment",	     Comment },
238
    { "Comment",	     Comment },
239
    { "FontName",	     FontName },
239
    { "FontName",	     FontName },
240
    { "EncodingScheme",	     EncodingScheme },
240
    { "EncodingScheme",	     EncodingScheme },
241
    { "FullName",	     FullName },
241
    { "FullName",	     FullName },
242
    { "FamilyName",	     FamilyName },
242
    { "FamilyName",	     FamilyName },
243
    { "Weight",		     Weight },
243
    { "Weight",		     Weight },
244
    { "ItalicAngle",	     ItalicAngle },
244
    { "ItalicAngle",	     ItalicAngle },
245
    { "IsFixedPitch",	     IsFixedPitch },
245
    { "IsFixedPitch",	     IsFixedPitch },
246
    { "UnderlinePosition",   UnderlinePosition },
246
    { "UnderlinePosition",   UnderlinePosition },
247
    { "UnderlineThickness",  UnderlineThickness },
247
    { "UnderlineThickness",  UnderlineThickness },
248
    { "Version",	     Version },
248
    { "Version",	     Version },
249
    { "Notice",		     Notice },
249
    { "Notice",		     Notice },
250
    { "FontBBox",	     FontBBox },
250
    { "FontBBox",	     FontBBox },
251
    { "CapHeight",	     CapHeight },
251
    { "CapHeight",	     CapHeight },
252
    { "XHeight",	     XHeight },
252
    { "XHeight",	     XHeight },
253
    { "Descender",	     Descender },
253
    { "Descender",	     Descender },
254
    { "Ascender",	     Ascender },
254
    { "Ascender",	     Ascender },
255
    { "StartCharMetrics",    StartCharMetrics },
255
    { "StartCharMetrics",    StartCharMetrics },
256
    { "C ",		     C },
256
    { "C ",		     C },
257
    { "EndCharMetrics",	     EndCharMetrics },
257
    { "EndCharMetrics",	     EndCharMetrics },
258
    { "StartKernData",	     StartKernData },
258
    { "StartKernData",	     StartKernData },
259
    { "StartKernPairs",	     StartKernPairs },
259
    { "StartKernPairs",	     StartKernPairs },
260
    { "KPX ",		     KPX },
260
    { "KPX ",		     KPX },
261
    { "EndKernPairs",	     EndKernPairs },
261
    { "EndKernPairs",	     EndKernPairs },
262
    { "EndKernData",	     EndKernData },
262
    { "EndKernData",	     EndKernData },
263
    { "StartComposites",     StartComposites },
263
    { "StartComposites",     StartComposites },
264
    { "CC ",		     CC },
264
    { "CC ",		     CC },
265
    { "EndComposites",	     EndComposites },
265
    { "EndComposites",	     EndComposites },
266
    { "EndFontMetrics",	     EndFontMetrics },
266
    { "EndFontMetrics",	     EndFontMetrics },
267
    { NULL,		     Unknown },
267
    { NULL,		     Unknown },
268
};
268
};
269
 
269
 
270
static int MatchKey(char const * l, char const * k)
270
static int MatchKey(char const * l, char const * k)
271
{
271
{
272
    while (*k)
272
    while (*k)
273
	if (*k++ != *l++) return 0;
273
	if (*k++ != *l++) return 0;
274
    return 1;
274
    return 1;
275
}
275
}
276
 
276
 
277
static int KeyType(const char * const s)
277
static int KeyType(const char * const s)
278
{
278
{
279
    int i;
279
    int i;
280
    if (*s == '\n')
280
    if (*s == '\n')
281
	return Empty;
281
	return Empty;
282
    for (i = 0; KeyWordDictionary[i].keyword; i++)
282
    for (i = 0; KeyWordDictionary[i].keyword; i++)
283
	if (MatchKey(s, KeyWordDictionary[i].keyword))
283
	if (MatchKey(s, KeyWordDictionary[i].keyword))
284
	    return KeyWordDictionary[i].code;
284
	    return KeyWordDictionary[i].code;
285
    return Unknown;
285
    return Unknown;
286
}
286
}
287
 
287
 
288
static char *SkipToNextItem(char *p)
288
static char *SkipToNextItem(char *p)
289
{
289
{
290
    while (!isspace((int)*p)) p++;
290
    while (!isspace((int)*p)) p++;
291
    while (isspace((int)*p)) p++;
291
    while (isspace((int)*p)) p++;
292
    return p;
292
    return p;
293
}
293
}
294
 
294
 
295
static char *SkipToNextKey(char *p)
295
static char *SkipToNextKey(char *p)
296
{
296
{
297
    while (*p != ';') p++;
297
    while (*p != ';') p++;
298
    p++;
298
    p++;
299
    while (isspace((int)*p)) p++;
299
    while (isspace((int)*p)) p++;
300
    return p;
300
    return p;
301
}
301
}
302
 
302
 
303
static int GetFontBBox(char *buf, FontMetricInfo *metrics)
303
static int GetFontBBox(char *buf, FontMetricInfo *metrics)
304
{
304
{
305
    if (sscanf(buf, "FontBBox %hd %hd %hd %hd",
305
    if (sscanf(buf, "FontBBox %hd %hd %hd %hd",
306
	      &(metrics->FontBBox[0]),
306
	      &(metrics->FontBBox[0]),
307
	      &(metrics->FontBBox[1]),
307
	      &(metrics->FontBBox[1]),
308
	      &(metrics->FontBBox[2]),
308
	      &(metrics->FontBBox[2]),
309
	      &(metrics->FontBBox[3])) != 4) return 0;
309
	      &(metrics->FontBBox[3])) != 4) return 0;
310
#ifdef DEBUG_PS
310
#ifdef DEBUG_PS
311
    Rprintf("FontBBox %d %d %d %d\n",
311
    Rprintf("FontBBox %d %d %d %d\n",
312
	    (metrics->FontBBox[0]),
312
	    (metrics->FontBBox[0]),
313
	    (metrics->FontBBox[1]),
313
	    (metrics->FontBBox[1]),
314
	    (metrics->FontBBox[2]),
314
	    (metrics->FontBBox[2]),
315
	    (metrics->FontBBox[3]));
315
	    (metrics->FontBBox[3]));
316
#endif
316
#endif
317
    return 1;
317
    return 1;
318
}
318
}
319
 
319
 
320
static char charnames[256][25];
320
static char charnames[256][25];
321
static char encnames[256][25];
321
static char encnames[256][25];
322
 
322
 
323
/* If reencode > 0, remap to new encoding */
323
/* If reencode > 0, remap to new encoding */
324
static int GetCharInfo(char *buf, FontMetricInfo *metrics, int reencode)
324
static int GetCharInfo(char *buf, FontMetricInfo *metrics, int reencode)
325
{
325
{
326
    char *p = buf, charname[25];
326
    char *p = buf, charname[25];
327
    int nchar, nchar2=-1, i;
327
    int nchar, nchar2=-1, i;
328
    short WX;
328
    short WX;
329
 
329
 
330
    if (!MatchKey(buf, "C ")) return 0;
330
    if (!MatchKey(buf, "C ")) return 0;
331
    p = SkipToNextItem(p);
331
    p = SkipToNextItem(p);
332
    sscanf(p, "%d", &nchar);
332
    sscanf(p, "%d", &nchar);
333
    if (nchar < 0 && !reencode) return 1;
333
    if (nchar < 0 && !reencode) return 1;
334
    p = SkipToNextKey(p);
334
    p = SkipToNextKey(p);
335
 
335
 
336
    if (!MatchKey(p, "WX")) return 0;
336
    if (!MatchKey(p, "WX")) return 0;
337
    p = SkipToNextItem(p);
337
    p = SkipToNextItem(p);
338
    sscanf(p, "%hd", &WX);
338
    sscanf(p, "%hd", &WX);
339
    p = SkipToNextKey(p);
339
    p = SkipToNextKey(p);
340
 
340
 
341
    if (!MatchKey(p, "N ")) return 0;
341
    if (!MatchKey(p, "N ")) return 0;
342
    p = SkipToNextItem(p);
342
    p = SkipToNextItem(p);
343
    if(reencode) {
343
    if(reencode) {
344
	sscanf(p, "%s", charname);
344
	sscanf(p, "%s", charname);
345
#ifdef DEBUG_PS
345
#ifdef DEBUG_PS
346
	Rprintf("char name %s\n", charname);
346
	Rprintf("char name %s\n", charname);
347
#endif
347
#endif
348
	/* a few chars appear twice in ISOLatin1 */
348
	/* a few chars appear twice in ISOLatin1 */
349
	nchar = nchar2 = -1;
349
	nchar = nchar2 = -1;
350
	for (i = 0; i < 256; i++)
350
	for (i = 0; i < 256; i++)
351
	    if(!strcmp(charname, encnames[i])) {
351
	    if(!strcmp(charname, encnames[i])) {
352
		strcpy(charnames[i], charname);
352
		strcpy(charnames[i], charname);
353
		if(nchar == -1) nchar = i; else nchar2 = i;
353
		if(nchar == -1) nchar = i; else nchar2 = i;
354
	    }
354
	    }
355
	if (nchar == -1) return 1;
355
	if (nchar == -1) return 1;
356
    } else {
356
    } else {
357
	sscanf(p, "%s", charnames[nchar]);
357
	sscanf(p, "%s", charnames[nchar]);
358
    }
358
    }
359
    metrics->CharInfo[nchar].WX = WX;
359
    metrics->CharInfo[nchar].WX = WX;
360
    p = SkipToNextKey(p);
360
    p = SkipToNextKey(p);
361
 
361
 
362
    if (!MatchKey(p, "B ")) return 0;
362
    if (!MatchKey(p, "B ")) return 0;
363
    p = SkipToNextItem(p);
363
    p = SkipToNextItem(p);
364
    sscanf(p, "%hd %hd %hd %hd",
364
    sscanf(p, "%hd %hd %hd %hd",
365
	   &(metrics->CharInfo[nchar].BBox[0]),
365
	   &(metrics->CharInfo[nchar].BBox[0]),
366
	   &(metrics->CharInfo[nchar].BBox[1]),
366
	   &(metrics->CharInfo[nchar].BBox[1]),
367
	   &(metrics->CharInfo[nchar].BBox[2]),
367
	   &(metrics->CharInfo[nchar].BBox[2]),
368
	   &(metrics->CharInfo[nchar].BBox[3]));
368
	   &(metrics->CharInfo[nchar].BBox[3]));
369
 
369
 
370
#ifdef DEBUG_PS
370
#ifdef DEBUG_PS
371
    Rprintf("nchar = %d %d %d %d %d %d\n", nchar,
371
    Rprintf("nchar = %d %d %d %d %d %d\n", nchar,
372
	    metrics->CharInfo[nchar].WX,
372
	    metrics->CharInfo[nchar].WX,
373
	    metrics->CharInfo[nchar].BBox[0],
373
	    metrics->CharInfo[nchar].BBox[0],
374
	    metrics->CharInfo[nchar].BBox[1],
374
	    metrics->CharInfo[nchar].BBox[1],
375
	    metrics->CharInfo[nchar].BBox[2],
375
	    metrics->CharInfo[nchar].BBox[2],
376
	    metrics->CharInfo[nchar].BBox[3]);
376
	    metrics->CharInfo[nchar].BBox[3]);
377
#endif
377
#endif
378
    if (nchar2 > 0) {
378
    if (nchar2 > 0) {
379
	metrics->CharInfo[nchar2].WX = WX;
379
	metrics->CharInfo[nchar2].WX = WX;
380
	sscanf(p, "%hd %hd %hd %hd",
380
	sscanf(p, "%hd %hd %hd %hd",
381
	       &(metrics->CharInfo[nchar2].BBox[0]),
381
	       &(metrics->CharInfo[nchar2].BBox[0]),
382
	       &(metrics->CharInfo[nchar2].BBox[1]),
382
	       &(metrics->CharInfo[nchar2].BBox[1]),
383
	       &(metrics->CharInfo[nchar2].BBox[2]),
383
	       &(metrics->CharInfo[nchar2].BBox[2]),
384
	       &(metrics->CharInfo[nchar2].BBox[3]));
384
	       &(metrics->CharInfo[nchar2].BBox[3]));
385
 
385
 
386
#ifdef DEBUG_PS
386
#ifdef DEBUG_PS
387
	Rprintf("nchar = %d %d %d %d %d %d\n", nchar2,
387
	Rprintf("nchar = %d %d %d %d %d %d\n", nchar2,
388
		metrics->CharInfo[nchar2].WX,
388
		metrics->CharInfo[nchar2].WX,
389
		metrics->CharInfo[nchar2].BBox[0],
389
		metrics->CharInfo[nchar2].BBox[0],
390
		metrics->CharInfo[nchar2].BBox[1],
390
		metrics->CharInfo[nchar2].BBox[1],
391
		metrics->CharInfo[nchar2].BBox[2],
391
		metrics->CharInfo[nchar2].BBox[2],
392
		metrics->CharInfo[nchar2].BBox[3]);
392
		metrics->CharInfo[nchar2].BBox[3]);
393
#endif
393
#endif
394
    }
394
    }
395
    return 1;
395
    return 1;
396
}
396
}
397
 
397
 
398
static int GetKPX(char *buf, int nkp, FontMetricInfo *metrics)
398
static int GetKPX(char *buf, int nkp, FontMetricInfo *metrics)
399
{
399
{
400
    char *p = buf, c1[50], c2[50];
400
    char *p = buf, c1[50], c2[50];
401
    int i, done = 0;
401
    int i, done = 0;
402
 
402
 
403
    p = SkipToNextItem(p);
403
    p = SkipToNextItem(p);
404
    sscanf(p, "%s %s %hd", c1, c2, &(metrics->KernPairs[nkp].kern));
404
    sscanf(p, "%s %s %hd", c1, c2, &(metrics->KernPairs[nkp].kern));
405
    for(i = 0; i < 256; i++) {
405
    for(i = 0; i < 256; i++) {
406
	if (!strcmp(c1, charnames[i])) {
406
	if (!strcmp(c1, charnames[i])) {
407
	    metrics->KernPairs[nkp].c1 = i;
407
	    metrics->KernPairs[nkp].c1 = i;
408
	    done++;
408
	    done++;
409
	    break;
409
	    break;
410
	}
410
	}
411
    }
411
    }
412
    for(i = 0; i < 256; i++)
412
    for(i = 0; i < 256; i++)
413
	if (!strcmp(c2, charnames[i])) {
413
	if (!strcmp(c2, charnames[i])) {
414
	    metrics->KernPairs[nkp].c2 = i;
414
	    metrics->KernPairs[nkp].c2 = i;
415
	    done++;
415
	    done++;
416
	    break;
416
	    break;
417
	}
417
	}
418
    return (done==2);
418
    return (done==2);
419
}
419
}
420
 
420
 
421
/* Encode File Parsing.  */
421
/* Encode File Parsing.  */
422
/* Statics here are OK, as all the calls are in one initialization
422
/* Statics here are OK, as all the calls are in one initialization
423
   so no concurrency (until threads?) */
423
   so no concurrency (until threads?) */
424
 
424
 
425
typedef struct {
425
typedef struct {
426
  /* Probably can make buf and p0 local variables. Only p needs to be
426
  /* Probably can make buf and p0 local variables. Only p needs to be
427
     stored across calls. Need to investigate this more closely. */
427
     stored across calls. Need to investigate this more closely. */
428
  char buf[1000];
428
  char buf[1000];
429
  char *p;
429
  char *p;
430
  char *p0;
430
  char *p0;
431
} EncodingInputState;
431
} EncodingInputState;
432
 
432
 
433
/* read in the next encoding item, separated by white space. */
433
/* read in the next encoding item, separated by white space. */
434
static int GetNextItem(FILE *fp, char *dest, int c, EncodingInputState *state)
434
static int GetNextItem(FILE *fp, char *dest, int c, EncodingInputState *state)
435
{
435
{
436
    if (c < 0) state->p = NULL;
436
    if (c < 0) state->p = NULL;
437
    while (1) {
437
    while (1) {
438
	if (feof(fp)) { state->p = NULL; return 1; }
438
	if (feof(fp)) { state->p = NULL; return 1; }
439
	if (!state->p || *state->p == '\n' || *state->p == '\0') {
439
	if (!state->p || *state->p == '\n' || *state->p == '\0') {
440
	    state->p = fgets(state->buf, 1000, fp);
440
	    state->p = fgets(state->buf, 1000, fp);
441
	}
441
	}
442
	/* check for incomplete encoding file */
442
	/* check for incomplete encoding file */
443
	if(!state->p) return 1;
443
	if(!state->p) return 1;
444
	while (isspace((int)* state->p)) state->p++;
444
	while (isspace((int)* state->p)) state->p++;
445
	if (state->p == '\0' || *state->p == '%'|| *state->p == '\n') { state->p = NULL; continue; }
445
	if (state->p == '\0' || *state->p == '%'|| *state->p == '\n') { state->p = NULL; continue; }
446
	state->p0 = state->p;
446
	state->p0 = state->p;
447
	while (!isspace((int)*state->p)) state->p++;
447
	while (!isspace((int)*state->p)) state->p++;
448
	if (state->p != '\0') *state->p++ = '\0';
448
	if (state->p != '\0') *state->p++ = '\0';
449
	if(c == 45) strcpy(dest, "/minus"); else strcpy(dest, state->p0);
449
	if(c == 45) strcpy(dest, "/minus"); else strcpy(dest, state->p0);
450
	break;
450
	break;
451
    }
451
    }
452
    return 0;
452
    return 0;
453
}
453
}
454
 
454
 
455
static char enccode[5000];
455
static char enccode[5000];
456
 
456
 
457
/* Load encoding array from a file: defaults to the R_HOME/afm directory */
457
/* Load encoding array from a file: defaults to the R_HOME/afm directory */
458
static int
458
static int
459
LoadEncoding(char *encpath, char *encname, Rboolean isPDF)
459
LoadEncoding(char *encpath, char *encname, Rboolean isPDF)
460
{
460
{
461
    char buf[BUFSIZE];
461
    char buf[BUFSIZE];
462
    int i;
462
    int i;
463
    FILE *fp;
463
    FILE *fp;
464
    EncodingInputState state;
464
    EncodingInputState state;
465
    state.p = state.p0 = NULL;
465
    state.p = state.p0 = NULL;
466
 
466
 
467
    if(strchr(encpath, FILESEP[0])) strcpy(buf, encpath);
467
    if(strchr(encpath, FILESEP[0])) strcpy(buf, encpath);
468
    else snprintf(buf, BUFSIZE,"%s%safm%s%s", R_Home, FILESEP, FILESEP, encpath);
468
    else snprintf(buf, BUFSIZE,"%s%safm%s%s", R_Home, FILESEP, FILESEP, encpath);
469
#ifdef DEBUG_PS
469
#ifdef DEBUG_PS
470
    Rprintf("encoding path is %s\n", buf);
470
    Rprintf("encoding path is %s\n", buf);
471
#endif
471
#endif
472
    if (!(fp = R_fopen(R_ExpandFileName(buf), "r"))) {
472
    if (!(fp = R_fopen(R_ExpandFileName(buf), "r"))) {
473
	strcat(buf, ".enc");
473
	strcat(buf, ".enc");
474
	if (!(fp = R_fopen(R_ExpandFileName(buf), "r"))) return 0;
474
	if (!(fp = R_fopen(R_ExpandFileName(buf), "r"))) return 0;
475
    }
475
    }
476
    if (GetNextItem(fp, buf, -1, &state)) return 0; /* encoding name */
476
    if (GetNextItem(fp, buf, -1, &state)) return 0; /* encoding name */
477
    strcpy(encname, buf+1);
477
    strcpy(encname, buf+1);
478
    if (!isPDF) snprintf(enccode, 5000, "/%s [\n", encname);
478
    if (!isPDF) snprintf(enccode, 5000, "/%s [\n", encname);
479
    else enccode[0] = '\0';
479
    else enccode[0] = '\0';
480
    if (GetNextItem(fp, buf, 0, &state)) { fclose(fp); return 0;} /* [ */
480
    if (GetNextItem(fp, buf, 0, &state)) { fclose(fp); return 0;} /* [ */
481
    for(i = 0; i < 256; i++) {
481
    for(i = 0; i < 256; i++) {
482
	if (GetNextItem(fp, buf, i, &state)) { fclose(fp); return 0; }
482
	if (GetNextItem(fp, buf, i, &state)) { fclose(fp); return 0; }
483
	strcpy(encnames[i], buf+1);
483
	strcpy(encnames[i], buf+1);
484
	strcat(enccode, " /"); strcat(enccode, encnames[i]);
484
	strcat(enccode, " /"); strcat(enccode, encnames[i]);
485
	if(i%8 == 7) strcat(enccode, "\n");
485
	if(i%8 == 7) strcat(enccode, "\n");
486
    }
486
    }
487
    if (GetNextItem(fp, buf, 0, &state)) { fclose(fp); return 0;} /* ] */
487
    if (GetNextItem(fp, buf, 0, &state)) { fclose(fp); return 0;} /* ] */
488
    fclose(fp);
488
    fclose(fp);
489
    if (!isPDF) strcat(enccode,"]\n");
489
    if (!isPDF) strcat(enccode,"]\n");
490
    return 1;
490
    return 1;
491
}
491
}
492
 
492
 
493
 
493
 
494
 
494
 
495
/* Load font metrics from a file: defaults to the R_HOME/afm directory */
495
/* Load font metrics from a file: defaults to the R_HOME/afm directory */
496
 
496
 
497
static int
497
static int
498
PostScriptLoadFontMetrics(const char * const fontpath, FontMetricInfo *metrics,
498
PostScriptLoadFontMetrics(const char * const fontpath, FontMetricInfo *metrics,
499
			  char *fontname, int reencode)
499
			  char *fontname, int reencode)
500
{
500
{
501
    char buf[BUFSIZE], *p;
501
    char buf[BUFSIZE], *p;
502
    int mode, i = 0, j, ii, nKPX=0;
502
    int mode, i = 0, j, ii, nKPX=0;
503
    FILE *fp;
503
    FILE *fp;
504
 
504
 
505
    if(strchr(fontpath, FILESEP[0])) strcpy(buf, fontpath);
505
    if(strchr(fontpath, FILESEP[0])) strcpy(buf, fontpath);
506
    else snprintf(buf, BUFSIZE, "%s%safm%s%s", R_Home, FILESEP, FILESEP, fontpath);
506
    else snprintf(buf, BUFSIZE, "%s%safm%s%s", R_Home, FILESEP, FILESEP, fontpath);
507
#ifdef DEBUG_PS
507
#ifdef DEBUG_PS
508
    Rprintf("afmpath is %s\n", buf);
508
    Rprintf("afmpath is %s\n", buf);
509
    Rprintf("reencode is %d\n", reencode);
509
    Rprintf("reencode is %d\n", reencode);
510
#endif
510
#endif
511
 
511
 
512
    if (!(fp = R_fopen(R_ExpandFileName(buf), "r"))) return 0;
512
    if (!(fp = R_fopen(R_ExpandFileName(buf), "r"))) return 0;
513
 
513
 
514
    mode = 0;
514
    mode = 0;
515
    for (ii = 0; ii < 256; ii++) {
515
    for (ii = 0; ii < 256; ii++) {
516
	charnames[ii][0] = '\0';
516
	charnames[ii][0] = '\0';
517
	metrics->CharInfo[ii].WX = NA_SHORT;
517
	metrics->CharInfo[ii].WX = NA_SHORT;
518
	for(j = 0; j < 4; j++) metrics->CharInfo[ii].BBox[j] = 0;
518
	for(j = 0; j < 4; j++) metrics->CharInfo[ii].BBox[j] = 0;
519
    }
519
    }
520
    while (fgets(buf, BUFSIZE, fp)) {
520
    while (fgets(buf, BUFSIZE, fp)) {
521
	switch(KeyType(buf)) {
521
	switch(KeyType(buf)) {
522
 
522
 
523
	case StartFontMetrics:
523
	case StartFontMetrics:
524
	    mode = StartFontMetrics;
524
	    mode = StartFontMetrics;
525
	    break;
525
	    break;
526
 
526
 
527
	case EndFontMetrics:
527
	case EndFontMetrics:
528
	    mode = 0;
528
	    mode = 0;
529
	    break;
529
	    break;
530
 
530
 
531
	case FontBBox:
531
	case FontBBox:
532
	    if (!GetFontBBox(buf, metrics)) goto pserror;
532
	    if (!GetFontBBox(buf, metrics)) goto pserror;
533
	    break;
533
	    break;
534
 
534
 
535
	case C:
535
	case C:
536
	    if (mode != StartFontMetrics) goto pserror;
536
	    if (mode != StartFontMetrics) goto pserror;
537
	    if (!GetCharInfo(buf, metrics, reencode)) goto pserror;
537
	    if (!GetCharInfo(buf, metrics, reencode)) goto pserror;
538
	    break;
538
	    break;
539
 
539
 
540
	case StartKernData:
540
	case StartKernData:
541
	    mode = StartKernData;
541
	    mode = StartKernData;
542
	    break;
542
	    break;
543
 
543
 
544
	case StartKernPairs:
544
	case StartKernPairs:
545
	    if(mode != StartKernData) goto pserror;
545
	    if(mode != StartKernData) goto pserror;
546
	    p = SkipToNextItem(buf);
546
	    p = SkipToNextItem(buf);
547
	    sscanf(p, "%d", &nKPX);
547
	    sscanf(p, "%d", &nKPX);
548
	    if(nKPX > 0) {
548
	    if(nKPX > 0) {
549
		/* nPKX == 0 should not happen, but has */
549
		/* nPKX == 0 should not happen, but has */
550
		metrics->KernPairs = (KP *) malloc(nKPX * sizeof(KP));
550
		metrics->KernPairs = (KP *) malloc(nKPX * sizeof(KP));
551
		if (!metrics->KernPairs) goto pserror;
551
		if (!metrics->KernPairs) goto pserror;
552
	    }
552
	    }
553
	    break;
553
	    break;
554
 
554
 
555
	case KPX:
555
	case KPX:
556
	    if(mode != StartKernData || i >= nKPX) goto pserror;
556
	    if(mode != StartKernData || i >= nKPX) goto pserror;
557
	    if (GetKPX(buf, i, metrics)) i++;
557
	    if (GetKPX(buf, i, metrics)) i++;
558
	    break;
558
	    break;
559
 
559
 
560
	case EndKernData:
560
	case EndKernData:
561
	    mode = 0;
561
	    mode = 0;
562
	    break;
562
	    break;
563
 
563
 
564
	case Unknown:
564
	case Unknown:
565
	    warning("unknown AFM entity encountered");
565
	    warning("unknown AFM entity encountered");
566
	    break;
566
	    break;
567
 
567
 
568
	case FontName:
568
	case FontName:
569
	    p = SkipToNextItem(buf);
569
	    p = SkipToNextItem(buf);
570
	    sscanf(p, "%[^\n\f\r]", fontname);
570
	    sscanf(p, "%[^\n\f\r]", fontname);
571
	    break;
571
	    break;
572
 
572
 
573
	case Empty:
573
	case Empty:
574
	default:
574
	default:
575
	    break;
575
	    break;
576
	}
576
	}
577
    }
577
    }
578
    metrics->nKP = i;
578
    metrics->nKP = i;
579
    fclose(fp);
579
    fclose(fp);
580
    /* Make an index for kern-pair searches: relies on having contiguous
580
    /* Make an index for kern-pair searches: relies on having contiguous
581
       blocks by first char for efficiency, but works in all cases. */
581
       blocks by first char for efficiency, but works in all cases. */
582
    {
582
    {
583
	short ind, tmp;
583
	short ind, tmp;
584
	for (j = 0; j < 256; j++) {
584
	for (j = 0; j < 256; j++) {
585
	    metrics->KPstart[j] = i;
585
	    metrics->KPstart[j] = i;
586
	    metrics->KPend[j] = 0;
586
	    metrics->KPend[j] = 0;
587
	}
587
	}
588
	for (j = 0; j < i; j++) {
588
	for (j = 0; j < i; j++) {
589
	    ind = metrics->KernPairs[j].c1;
589
	    ind = metrics->KernPairs[j].c1;
590
	    tmp = metrics->KPstart[ind];
590
	    tmp = metrics->KPstart[ind];
591
	    if(j < tmp) metrics->KPstart[ind] = j;
591
	    if(j < tmp) metrics->KPstart[ind] = j;
592
	    tmp = metrics->KPend[ind];
592
	    tmp = metrics->KPend[ind];
593
	    if(j > tmp) metrics->KPend[ind] = j;
593
	    if(j > tmp) metrics->KPend[ind] = j;
594
	}
594
	}
595
    }
595
    }
596
    return 1;
596
    return 1;
597
 pserror:
597
 pserror:
598
    fclose(fp);
598
    fclose(fp);
599
    return 0;
599
    return 0;
600
}
600
}
601
 
601
 
602
static double
602
static double
603
PostScriptStringWidth(unsigned char *p, FontMetricInfo *metrics)
603
PostScriptStringWidth(unsigned char *p, FontMetricInfo *metrics)
604
{
604
{
605
    int sum = 0, i;
605
    int sum = 0, i;
606
    short wx;
606
    short wx;
607
    unsigned char p1, p2;
607
    unsigned char p1, p2;
608
    for ( ; *p; p++) {
608
    for ( ; *p; p++) {
609
#ifdef USE_HYPHEN
609
#ifdef USE_HYPHEN
610
	if (*p == '-' && !isdigit(p[1]))
610
	if (*p == '-' && !isdigit(p[1]))
611
	    wx = metrics->CharInfo[(int)PS_hyphen].WX;
611
	    wx = metrics->CharInfo[(int)PS_hyphen].WX;
612
	else
612
	else
613
#endif
613
#endif
614
	    wx = metrics->CharInfo[*p].WX;
614
	    wx = metrics->CharInfo[*p].WX;
615
	if(wx == NA_SHORT)
615
	if(wx == NA_SHORT)
616
	    warning("font width unknown for character %d", *p);
616
	    warning("font width unknown for character %d", *p);
617
	else sum += wx;
617
	else sum += wx;
618
 
618
 
619
	/* check for kerning adjustment */
619
	/* check for kerning adjustment */
620
	p1 = p[0]; p2 = p[1];
620
	p1 = p[0]; p2 = p[1];
621
	for (i =  metrics->KPstart[p1]; i < metrics->KPend[p1]; i++)
621
	for (i =  metrics->KPstart[p1]; i < metrics->KPend[p1]; i++)
622
	/* second test is a safety check: should all start with p1  */
622
	/* second test is a safety check: should all start with p1  */
623
	    if(metrics->KernPairs[i].c2 == p2 &&
623
	    if(metrics->KernPairs[i].c2 == p2 &&
624
	       metrics->KernPairs[i].c1 == p1) {
624
	       metrics->KernPairs[i].c1 == p1) {
625
		sum += metrics->KernPairs[i].kern;
625
		sum += metrics->KernPairs[i].kern;
626
		break;
626
		break;
627
	    }
627
	    }
628
    }
628
    }
629
    return 0.001 * sum;
629
    return 0.001 * sum;
630
}
630
}
631
 
631
 
632
static void
632
static void
633
PostScriptMetricInfo(int c, double *ascent, double *descent,
633
PostScriptMetricInfo(int c, double *ascent, double *descent,
634
		     double *width, FontMetricInfo *metrics)
634
		     double *width, FontMetricInfo *metrics)
635
{
635
{
636
    short wx;
636
    short wx;
637
 
637
 
638
    if (c == 0) {
638
    if (c == 0) {
639
	*ascent = 0.001 * metrics->FontBBox[3];
639
	*ascent = 0.001 * metrics->FontBBox[3];
640
	*descent = -0.001 * metrics->FontBBox[1];
640
	*descent = -0.001 * metrics->FontBBox[1];
641
	*width = 0.001 * (metrics->FontBBox[2] - metrics->FontBBox[0]);
641
	*width = 0.001 * (metrics->FontBBox[2] - metrics->FontBBox[0]);
642
    }
642
    }
643
    else {
643
    else {
644
	*ascent = 0.001 * metrics->CharInfo[c].BBox[3];
644
	*ascent = 0.001 * metrics->CharInfo[c].BBox[3];
645
	*descent = -0.001 * metrics->CharInfo[c].BBox[1];
645
	*descent = -0.001 * metrics->CharInfo[c].BBox[1];
646
	wx = metrics->CharInfo[c].WX;
646
	wx = metrics->CharInfo[c].WX;
647
	if(wx == NA_SHORT) {
647
	if(wx == NA_SHORT) {
648
	    warning("font metrics unknown for character %d", c);
648
	    warning("font metrics unknown for character %d", c);
649
	    wx = 0;
649
	    wx = 0;
650
	}
650
	}
651
	*width = 0.001 * wx;
651
	*width = 0.001 * wx;
652
    }
652
    }
653
}
653
}
654
 
654
 
655
 
655
 
656
/*  Part 2.  Graphics Support Code.  */
656
/*  Part 2.  Graphics Support Code.  */
657
 
657
 
658
static const char * const TypeFaceDef[] = { "R", "B", "I", "BI", "S" };
658
static const char * const TypeFaceDef[] = { "R", "B", "I", "BI", "S" };
659
 
659
 
660
static void PSEncodeFont(FILE *fp, char *encname)
660
static void PSEncodeFont(FILE *fp, char *encname)
661
{
661
{
662
    int i;
662
    int i;
663
 
663
 
664
    /* include encoding unless it is ISOLatin1Encoding, which is predefined */
664
    /* include encoding unless it is ISOLatin1Encoding, which is predefined */
665
    if (strcmp(encname, "ISOLatin1Encoding"))
665
    if (strcmp(encname, "ISOLatin1Encoding"))
666
	fprintf(fp, "%% begin encoding\n%s def\n%% end encoding\n", enccode);
666
	fprintf(fp, "%% begin encoding\n%s def\n%% end encoding\n", enccode);
667
 
667
 
668
    if(strcmp(familyname[4], "CMSY10 CMBSY10 CMMI10") == 0) {
668
    if(strcmp(familyname[4], "CMSY10 CMBSY10 CMMI10") == 0) {
669
	/* use different ps fragment for CM fonts */
669
	/* use different ps fragment for CM fonts */
670
	fprintf(fp, "%% begin encoding\n");
670
	fprintf(fp, "%% begin encoding\n");
671
	fprintf(fp, "/SymbolEncoding [\n");
671
	fprintf(fp, "/SymbolEncoding [\n");
672
	fprintf(fp, " /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n");
672
	fprintf(fp, " /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n");
673
	fprintf(fp, " /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n");
673
	fprintf(fp, " /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n");
674
	fprintf(fp, " /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n");
674
	fprintf(fp, " /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n");
675
	fprintf(fp, " /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n");
675
	fprintf(fp, " /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n");
676
	fprintf(fp, " /space /exclam /universal /numbersign /existential /percent /ampersand /suchthat\n");
676
	fprintf(fp, " /space /exclam /universal /numbersign /existential /percent /ampersand /suchthat\n");
677
	fprintf(fp, " /parenleft /parenright /asteriskmath /plus /comma /minus /period /slash\n");
677
	fprintf(fp, " /parenleft /parenright /asteriskmath /plus /comma /minus /period /slash\n");
678
	fprintf(fp, " /zero /one /two /three /four /five /six /seven\n");
678
	fprintf(fp, " /zero /one /two /three /four /five /six /seven\n");
679
	fprintf(fp, " /eight /nine /colon /semicolon /less /equal /greater /question\n");
679
	fprintf(fp, " /eight /nine /colon /semicolon /less /equal /greater /question\n");
680
	fprintf(fp, " /congruent /Alpha /Beta /Chi /Delta /Epsilon /Phi /Gamma\n");
680
	fprintf(fp, " /congruent /Alpha /Beta /Chi /Delta /Epsilon /Phi /Gamma\n");
681
	fprintf(fp, " /Eta /Iota /theta1 /Kappa /Lambda /Mu /Nu /Omicron\n");
681
	fprintf(fp, " /Eta /Iota /theta1 /Kappa /Lambda /Mu /Nu /Omicron\n");
682
	fprintf(fp, " /Pi /Theta /Rho /Sigma /Tau /Upsilon /sigma1 /Omega\n");
682
	fprintf(fp, " /Pi /Theta /Rho /Sigma /Tau /Upsilon /sigma1 /Omega\n");
683
	fprintf(fp, " /Xi /Psi /Zeta /bracketleft /therefore /bracketright /perpendicular /underscore\n");
683
	fprintf(fp, " /Xi /Psi /Zeta /bracketleft /therefore /bracketright /perpendicular /underscore\n");
684
	fprintf(fp, " /radicalex /alpha /beta /chi /delta /epsilon /phi /gamma\n");
684
	fprintf(fp, " /radicalex /alpha /beta /chi /delta /epsilon /phi /gamma\n");
685
	fprintf(fp, " /eta /iota /phi1 /kappa /lambda /mu /nu /omicron\n");
685
	fprintf(fp, " /eta /iota /phi1 /kappa /lambda /mu /nu /omicron\n");
686
	fprintf(fp, " /pi /theta /rho /sigma /tau /upsilon /omega1 /omega\n");
686
	fprintf(fp, " /pi /theta /rho /sigma /tau /upsilon /omega1 /omega\n");
687
	fprintf(fp, " /xi /psi /zeta /braceleft /bar /braceright /similar /.notdef\n");
687
	fprintf(fp, " /xi /psi /zeta /braceleft /bar /braceright /similar /.notdef\n");
688
	fprintf(fp, " /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n");
688
	fprintf(fp, " /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n");
689
	fprintf(fp, " /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n");
689
	fprintf(fp, " /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n");
690
	fprintf(fp, " /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n");
690
	fprintf(fp, " /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n");
691
	fprintf(fp, " /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n");
691
	fprintf(fp, " /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n");
692
	fprintf(fp, " /Euro /Upsilon1 /minute /lessequal /fraction /infinity /florin /club\n");
692
	fprintf(fp, " /Euro /Upsilon1 /minute /lessequal /fraction /infinity /florin /club\n");
693
	fprintf(fp, " /diamond /heart /spade /arrowboth /arrowleft /arrowup /arrowright /arrowdown\n");
693
	fprintf(fp, " /diamond /heart /spade /arrowboth /arrowleft /arrowup /arrowright /arrowdown\n");
694
	fprintf(fp, " /degree /plusminus /second /greaterequal /multiply /proportional /partialdiff /bullet\n");
694
	fprintf(fp, " /degree /plusminus /second /greaterequal /multiply /proportional /partialdiff /bullet\n");
695
	fprintf(fp, " /divide /notequal /equivalence /approxequal /ellipsis /arrowvertex /arrowhorizex /carriagereturn\n");
695
	fprintf(fp, " /divide /notequal /equivalence /approxequal /ellipsis /arrowvertex /arrowhorizex /carriagereturn\n");
696
	fprintf(fp, " /aleph /Ifraktur /Rfraktur /weierstrass /circlemultiply /circleplus /emptyset /intersection\n");
696
	fprintf(fp, " /aleph /Ifraktur /Rfraktur /weierstrass /circlemultiply /circleplus /emptyset /intersection\n");
697
	fprintf(fp, " /union /propersuperset /reflexsuperset /notsubset /propersubset /reflexsubset /element /notelement\n");
697
	fprintf(fp, " /union /propersuperset /reflexsuperset /notsubset /propersubset /reflexsubset /element /notelement\n");
698
	fprintf(fp, " /angle /gradient /registerserif /copyrightserif /trademarkserif /product /radical /dotmath\n");
698
	fprintf(fp, " /angle /gradient /registerserif /copyrightserif /trademarkserif /product /radical /dotmath\n");
699
	fprintf(fp, " /logicalnot /logicaland /logicalor /arrowdblboth /arrowdblleft /arrowdblup /arrowdblright /arrowdbldown\n");
699
	fprintf(fp, " /logicalnot /logicaland /logicalor /arrowdblboth /arrowdblleft /arrowdblup /arrowdblright /arrowdbldown\n");
700
	fprintf(fp, " /lozenge /angleleft /registersans /copyrightsans /trademarksans /summation /parenlefttp /parenleftex\n");
700
	fprintf(fp, " /lozenge /angleleft /registersans /copyrightsans /trademarksans /summation /parenlefttp /parenleftex\n");
701
	fprintf(fp, " /parenleftbt /bracketlefttp /bracketleftex /bracketleftbt /bracelefttp /braceleftmid /braceleftbt /braceex\n");
701
	fprintf(fp, " /parenleftbt /bracketlefttp /bracketleftex /bracketleftbt /bracelefttp /braceleftmid /braceleftbt /braceex\n");
702
	fprintf(fp, " /.notdef /angleright /integral /integraltp /integralex /integralbt /parenrighttp /parenrightex\n");
702
	fprintf(fp, " /.notdef /angleright /integral /integraltp /integralex /integralbt /parenrighttp /parenrightex\n");
703
	fprintf(fp, " /parenrightbt /bracketrighttp /bracketrightex /bracketrightbt /bracerighttp /bracerightmid /bracerightbt /.notdef\n");
703
	fprintf(fp, " /parenrightbt /bracketrighttp /bracketrightex /bracketrightbt /bracerighttp /bracerightmid /bracerightbt /.notdef\n");
704
	fprintf(fp, "] def\n");
704
	fprintf(fp, "] def\n");
705
	fprintf(fp, "%% end encoding\n");
705
	fprintf(fp, "%% end encoding\n");
706
	fprintf(fp, "/mergefonts\n");
706
	fprintf(fp, "/mergefonts\n");
707
	fprintf(fp, "{ /targetencoding exch def\n");
707
	fprintf(fp, "{ /targetencoding exch def\n");
708
	fprintf(fp, "  /fontarray exch def\n");
708
	fprintf(fp, "  /fontarray exch def\n");
709
	fprintf(fp, "  fontarray 0 get dup maxlength dict begin\n");
709
	fprintf(fp, "  fontarray 0 get dup maxlength dict begin\n");
710
	fprintf(fp, "  { 1 index /FID ne { def } { pop pop } ifelse } forall\n");
710
	fprintf(fp, "  { 1 index /FID ne { def } { pop pop } ifelse } forall\n");
711
	fprintf(fp, "  %% Create a new dictionary\n");
711
	fprintf(fp, "  %% Create a new dictionary\n");
712
	fprintf(fp, "  /CharStrings 256 dict def\n");
712
	fprintf(fp, "  /CharStrings 256 dict def\n");
713
	fprintf(fp, "  %% Add a definition of .notdef\n");
713
	fprintf(fp, "  %% Add a definition of .notdef\n");
714
	fprintf(fp, "  fontarray\n");
714
	fprintf(fp, "  fontarray\n");
715
	fprintf(fp, "  { /CharStrings get dup /.notdef known\n");
715
	fprintf(fp, "  { /CharStrings get dup /.notdef known\n");
716
	fprintf(fp, "    { /.notdef get /result exch def exit }\n");
716
	fprintf(fp, "    { /.notdef get /result exch def exit }\n");
717
	fprintf(fp, "    { pop } ifelse\n");
717
	fprintf(fp, "    { pop } ifelse\n");
718
	fprintf(fp, "  } forall\n");
718
	fprintf(fp, "  } forall\n");
719
	fprintf(fp, "  CharStrings /.notdef result put\n");
719
	fprintf(fp, "  CharStrings /.notdef result put\n");
720
	fprintf(fp, "  %% Add in the other definitions\n");
720
	fprintf(fp, "  %% Add in the other definitions\n");
721
	fprintf(fp, "  targetencoding\n");
721
	fprintf(fp, "  targetencoding\n");
722
	fprintf(fp, "  { /code exch def\n");
722
	fprintf(fp, "  { /code exch def\n");
723
	fprintf(fp, "    %% Check that it is not a .notdef\n");
723
	fprintf(fp, "    %% Check that it is not a .notdef\n");
724
	fprintf(fp, "    code /.notdef eq\n");
724
	fprintf(fp, "    code /.notdef eq\n");
725
	fprintf(fp, "    { /.notdef }\n");
725
	fprintf(fp, "    { /.notdef }\n");
726
	fprintf(fp, "    { fontarray\n");
726
	fprintf(fp, "    { fontarray\n");
727
	fprintf(fp, "      { /CharStrings get dup code known\n");
727
	fprintf(fp, "      { /CharStrings get dup code known\n");
728
	fprintf(fp, "        { code get /result exch def /found true def exit }\n");
728
	fprintf(fp, "        { code get /result exch def /found true def exit }\n");
729
	fprintf(fp, "        { pop /found false def } ifelse\n");
729
	fprintf(fp, "        { pop /found false def } ifelse\n");
730
	fprintf(fp, "      } forall\n");
730
	fprintf(fp, "      } forall\n");
731
	fprintf(fp, "      %% define character if it was found and accumulate encoding\n");
731
	fprintf(fp, "      %% define character if it was found and accumulate encoding\n");
732
	fprintf(fp, "      found { CharStrings code result put code } { /.notdef } ifelse\n");
732
	fprintf(fp, "      found { CharStrings code result put code } { /.notdef } ifelse\n");
733
	fprintf(fp, "    } ifelse\n");
733
	fprintf(fp, "    } ifelse\n");
734
	fprintf(fp, "  } forall\n");
734
	fprintf(fp, "  } forall\n");
735
	fprintf(fp, "  %% grab new encoding off of stack\n");
735
	fprintf(fp, "  %% grab new encoding off of stack\n");
736
	fprintf(fp, "  256 array astore /Encoding exch def\n");
736
	fprintf(fp, "  256 array astore /Encoding exch def\n");
737
	fprintf(fp, "  %% Undefine some local variables\n");
737
	fprintf(fp, "  %% Undefine some local variables\n");
738
	fprintf(fp, "  currentdict /fontarray undef\n");
738
	fprintf(fp, "  currentdict /fontarray undef\n");
739
	fprintf(fp, "  currentdict /targetencoding undef\n");
739
	fprintf(fp, "  currentdict /targetencoding undef\n");
740
	fprintf(fp, "  currentdict /code undef\n");
740
	fprintf(fp, "  currentdict /code undef\n");
741
	fprintf(fp, "  currentdict /result undef\n");
741
	fprintf(fp, "  currentdict /result undef\n");
742
	fprintf(fp, "  currentdict /found undef\n");
742
	fprintf(fp, "  currentdict /found undef\n");
743
	fprintf(fp, "  %% Leave new font on the stack\n");
743
	fprintf(fp, "  %% Leave new font on the stack\n");
744
	fprintf(fp, "  currentdict\n");
744
	fprintf(fp, "  currentdict\n");
745
	fprintf(fp, "  end\n");
745
	fprintf(fp, "  end\n");
746
	fprintf(fp, "} def\n");
746
	fprintf(fp, "} def\n");
747
	fprintf(fp, "%%%%IncludeResource: font CMR10\n");
747
	fprintf(fp, "%%%%IncludeResource: font CMR10\n");
748
	fprintf(fp, "%%%%IncludeResource: font CMSY10\n");
748
	fprintf(fp, "%%%%IncludeResource: font CMSY10\n");
749
	fprintf(fp, "[ /CMR10 findfont /CMSY10 findfont ] %s mergefonts\n", encname);
749
	fprintf(fp, "[ /CMR10 findfont /CMSY10 findfont ] %s mergefonts\n", encname);
750
	fprintf(fp, "/Font1 exch definefont pop\n");
750
	fprintf(fp, "/Font1 exch definefont pop\n");
751
	fprintf(fp, "%%%%IncludeResource: font CMBX10\n");
751
	fprintf(fp, "%%%%IncludeResource: font CMBX10\n");
752
	fprintf(fp, "%%%%IncludeResource: font CMBSY10\n");
752
	fprintf(fp, "%%%%IncludeResource: font CMBSY10\n");
753
	fprintf(fp, "[ /CMBX10 findfont /CMBSY10 findfont ] %s mergefonts\n", encname);
753
	fprintf(fp, "[ /CMBX10 findfont /CMBSY10 findfont ] %s mergefonts\n", encname);
754
	fprintf(fp, "/Font2 exch definefont pop\n");
754
	fprintf(fp, "/Font2 exch definefont pop\n");
755
	fprintf(fp, "%%%%IncludeResource: font CMSL10\n");
755
	fprintf(fp, "%%%%IncludeResource: font CMSL10\n");
756
	fprintf(fp, "[ /CMSL10 findfont /CMSY10 findfont ] %s mergefonts\n", encname);
756
	fprintf(fp, "[ /CMSL10 findfont /CMSY10 findfont ] %s mergefonts\n", encname);
757
	fprintf(fp, "/Font3 exch definefont pop\n");
757
	fprintf(fp, "/Font3 exch definefont pop\n");
758
	fprintf(fp, "%%%%IncludeResource: font CMBXSL10\n");
758
	fprintf(fp, "%%%%IncludeResource: font CMBXSL10\n");
759
	fprintf(fp, "[ /CMBXSL10 findfont /CMBSY10 findfont ] %s mergefonts\n", encname);
759
	fprintf(fp, "[ /CMBXSL10 findfont /CMBSY10 findfont ] %s mergefonts\n", encname);
760
	fprintf(fp, "/Font4 exch definefont pop\n");
760
	fprintf(fp, "/Font4 exch definefont pop\n");
761
	fprintf(fp, "%%%%IncludeResource: font CMMI10\n");
761
	fprintf(fp, "%%%%IncludeResource: font CMMI10\n");
762
	fprintf(fp, "[ /CMR10 findfont /CMSY10 findfont /CMMI10 findfont ] SymbolEncoding mergefonts\n");
762
	fprintf(fp, "[ /CMR10 findfont /CMSY10 findfont /CMMI10 findfont ] SymbolEncoding mergefonts\n");
763
	fprintf(fp, "/Font5 exch definefont pop\n");
763
	fprintf(fp, "/Font5 exch definefont pop\n");
764
    } else {
764
    } else {
765
  	for (i = 0; i < 4 ; i++) {
765
  	for (i = 0; i < 4 ; i++) {
766
	    fprintf(fp, "%%%%IncludeResource: font %s\n", familyname[i]);
766
	    fprintf(fp, "%%%%IncludeResource: font %s\n", familyname[i]);
767
	    fprintf(fp, "/%s findfont\n", familyname[i]);
767
	    fprintf(fp, "/%s findfont\n", familyname[i]);
768
	    fprintf(fp, "dup length dict begin\n");
768
	    fprintf(fp, "dup length dict begin\n");
769
	    fprintf(fp, "  {1 index /FID ne {def} {pop pop} ifelse} forall\n");
769
	    fprintf(fp, "  {1 index /FID ne {def} {pop pop} ifelse} forall\n");
770
	    fprintf(fp, "  /Encoding %s def\n", encname);
770
	    fprintf(fp, "  /Encoding %s def\n", encname);
771
	    fprintf(fp, "  currentdict\n");
771
	    fprintf(fp, "  currentdict\n");
772
	    fprintf(fp, "  end\n");
772
	    fprintf(fp, "  end\n");
773
	    fprintf(fp, "/Font%d exch definefont pop\n", i + 1);
773
	    fprintf(fp, "/Font%d exch definefont pop\n", i + 1);
774
   	}
774
   	}
775
	fprintf(fp, "%%%%IncludeResource: font %s\n", familyname[4]);
775
	fprintf(fp, "%%%%IncludeResource: font %s\n", familyname[4]);
776
   	fprintf(fp, "/%s findfont\n", familyname[4]);
776
   	fprintf(fp, "/%s findfont\n", familyname[4]);
777
   	fprintf(fp, "dup length dict begin\n");
777
   	fprintf(fp, "dup length dict begin\n");
778
   	fprintf(fp, "  {1 index /FID ne {def} {pop pop} ifelse} forall\n");
778
   	fprintf(fp, "  {1 index /FID ne {def} {pop pop} ifelse} forall\n");
779
   	fprintf(fp, "  currentdict\n");
779
   	fprintf(fp, "  currentdict\n");
780
   	fprintf(fp, "  end\n");
780
   	fprintf(fp, "  end\n");
781
   	fprintf(fp, "/Font5 exch definefont pop\n");
781
   	fprintf(fp, "/Font5 exch definefont pop\n");
782
    }
782
    }
783
}
783
}
784
 
784
 
785
/* The variables "paperwidth" and "paperheight" give the dimensions */
785
/* The variables "paperwidth" and "paperheight" give the dimensions */
786
/* of the (unrotated) printer page in points whereas the graphics */
786
/* of the (unrotated) printer page in points whereas the graphics */
787
/* region box is for the rotated page. */
787
/* region box is for the rotated page. */
788
 
788
 
789
static void PSFileHeader(FILE *fp, char* encname,
789
static void PSFileHeader(FILE *fp, char* encname,
790
			 char *papername, double paperwidth,
790
			 char *papername, double paperwidth,
791
			 double paperheight, Rboolean landscape,
791
			 double paperheight, Rboolean landscape,
792
			 int EPSFheader, Rboolean paperspecial,
792
			 int EPSFheader, Rboolean paperspecial,
793
			 double left, double bottom, double right, double top,
793
			 double left, double bottom, double right, double top,
794
			 char *title)
794
			 char *title)
795
{
795
{
796
    int i;
796
    int i;
797
    SEXP prolog;
797
    SEXP prolog;
798
 
798
 
799
    if(EPSFheader)
799
    if(EPSFheader)
800
	fprintf(fp, "%%!PS-Adobe-3.0 EPSF-3.0\n");
800
	fprintf(fp, "%%!PS-Adobe-3.0 EPSF-3.0\n");
801
    else
801
    else
802
	fprintf(fp, "%%!PS-Adobe-3.0\n");
802
	fprintf(fp, "%%!PS-Adobe-3.0\n");
803
    fprintf(fp, "%%%%DocumentNeededResources: font %s\n", familyname[0]);
803
    fprintf(fp, "%%%%DocumentNeededResources: font %s\n", familyname[0]);
804
    for (i = 1; i < 5; i++)
804
    for (i = 1; i < 5; i++)
805
	fprintf(fp, "%%%%+ font %s\n", familyname[i]);
805
	fprintf(fp, "%%%%+ font %s\n", familyname[i]);
806
 
806
 
807
    if(!EPSFheader)
807
    if(!EPSFheader)
808
	fprintf(fp, "%%%%DocumentMedia: %s %.0f %.0f 0 () ()\n",
808
	fprintf(fp, "%%%%DocumentMedia: %s %.0f %.0f 0 () ()\n",
809
		papername, paperwidth, paperheight);
809
		papername, paperwidth, paperheight);
810
    fprintf(fp, "%%%%Title: %s\n", title);
810
    fprintf(fp, "%%%%Title: %s\n", title);
811
    fprintf(fp, "%%%%Creator: R Software\n");
811
    fprintf(fp, "%%%%Creator: R Software\n");
812
    fprintf(fp, "%%%%Pages: (atend)\n");
812
    fprintf(fp, "%%%%Pages: (atend)\n");
813
    if (!EPSFheader && !paperspecial) { /* gs gets confused by this */
813
    if (!EPSFheader && !paperspecial) { /* gs gets confused by this */
814
	if (landscape)
814
	if (landscape)
815
	    fprintf(fp, "%%%%Orientation: Landscape\n");
815
	    fprintf(fp, "%%%%Orientation: Landscape\n");
816
	else
816
	else
817
	    fprintf(fp, "%%%%Orientation: Portrait\n");
817
	    fprintf(fp, "%%%%Orientation: Portrait\n");
818
    }
818
    }
819
    fprintf(fp, "%%%%BoundingBox: %.0f %.0f %.0f %.0f\n",
819
    fprintf(fp, "%%%%BoundingBox: %.0f %.0f %.0f %.0f\n",
820
	    left, bottom, right, top);
820
	    left, bottom, right, top);
821
    fprintf(fp, "%%%%EndComments\n");
821
    fprintf(fp, "%%%%EndComments\n");
822
    fprintf(fp, "%%%%BeginProlog\n");
822
    fprintf(fp, "%%%%BeginProlog\n");
823
    if (landscape)
823
    if (landscape)
824
	fprintf(fp, "/bp  { gs %.2f 0 translate 90 rotate gs } def\n", paperwidth);
824
	fprintf(fp, "/bp  { gs %.2f 0 translate 90 rotate gs } def\n", paperwidth);
825
    else
825
    else
826
	fprintf(fp, "/bp  { gs gs } def\n");
826
	fprintf(fp, "/bp  { gs gs } def\n");
827
    prolog = findVar(install(".ps.prolog"), R_GlobalEnv);
827
    prolog = findVar(install(".ps.prolog"), R_GlobalEnv);
828
    if(prolog == R_UnboundValue) {
828
    if(prolog == R_UnboundValue) {
829
	/* if no object is visible, look in the graphics namespace */
829
	/* if no object is visible, look in the graphics namespace */
830
	SEXP graphicsNS = R_FindNamespace(ScalarString(mkChar("graphics")));
830
	SEXP graphicsNS = R_FindNamespace(ScalarString(mkChar("graphics")));
831
	prolog = findVar(install(".ps.prolog"), graphicsNS);
831
	prolog = findVar(install(".ps.prolog"), graphicsNS);
832
    }
832
    }
833
    if(!isString(prolog))
833
    if(!isString(prolog))
834
	error("Object .ps.prolog is not a character vector");
834
	error("Object .ps.prolog is not a character vector");
835
    fprintf(fp, "%% begin .ps.prolog\n");
835
    fprintf(fp, "%% begin .ps.prolog\n");
836
    for (i = 0; i < length(prolog); i++)
836
    for (i = 0; i < length(prolog); i++)
837
	fprintf(fp, "%s\n", CHAR(STRING_ELT(prolog, i)));
837
	fprintf(fp, "%s\n", CHAR(STRING_ELT(prolog, i)));
838
    fprintf(fp, "%% end   .ps.prolog\n");
838
    fprintf(fp, "%% end   .ps.prolog\n");
839
    PSEncodeFont(fp, encname);
839
    PSEncodeFont(fp, encname);
840
    fprintf(fp, "%%%%EndProlog\n");
840
    fprintf(fp, "%%%%EndProlog\n");
841
}
841
}
842
 
842
 
843
static void PostScriptFileTrailer(FILE *fp, int pageno)
843
static void PostScriptFileTrailer(FILE *fp, int pageno)
844
{
844
{
845
    fprintf(fp, "ep\n");
845
    fprintf(fp, "ep\n");
846
    fprintf(fp, "%%%%Trailer\n");
846
    fprintf(fp, "%%%%Trailer\n");
847
    fprintf(fp, "%%%%Pages: %d\n", pageno);
847
    fprintf(fp, "%%%%Pages: %d\n", pageno);
848
    fprintf(fp, "%%%%EOF\n");
848
    fprintf(fp, "%%%%EOF\n");
849
}
849
}
850
 
850
 
851
static void PostScriptStartPage(FILE *fp, int pageno)
851
static void PostScriptStartPage(FILE *fp, int pageno)
852
{
852
{
853
    fprintf(fp, "%%%%Page: %d %d\n", pageno, pageno);
853
    fprintf(fp, "%%%%Page: %d %d\n", pageno, pageno);
854
    fprintf(fp, "bp\n");
854
    fprintf(fp, "bp\n");
855
}
855
}
856
 
856
 
857
static void PostScriptEndPage(FILE *fp)
857
static void PostScriptEndPage(FILE *fp)
858
{
858
{
859
    fprintf(fp, "ep\n");
859
    fprintf(fp, "ep\n");
860
}
860
}
861
 
861
 
862
static void PostScriptSetClipRect(FILE *fp, double x0, double x1,
862
static void PostScriptSetClipRect(FILE *fp, double x0, double x1,
863
				  double y0, double y1)
863
				  double y0, double y1)
864
{
864
{
865
    fprintf(fp, "%.2f %.2f %.2f %.2f cl\n", x0, y0, x1, y1);
865
    fprintf(fp, "%.2f %.2f %.2f %.2f cl\n", x0, y0, x1, y1);
866
}
866
}
867
 
867
 
868
static void PostScriptSetLineWidth(FILE *fp, double linewidth)
868
static void PostScriptSetLineWidth(FILE *fp, double linewidth)
869
{
869
{
870
    fprintf(fp, "%.2f setlinewidth\n", linewidth);
870
    fprintf(fp, "%.2f setlinewidth\n", linewidth);
871
}
871
}
872
 
872
 
873
static void PostScriptSetFont(FILE *fp, int typeface, double size)
873
static void PostScriptSetFont(FILE *fp, int typeface, double size)
874
{
874
{
875
    fprintf(fp, "/ps %.0f def %s %.0f s\n", size, TypeFaceDef[typeface], size);
875
    fprintf(fp, "/ps %.0f def %s %.0f s\n", size, TypeFaceDef[typeface], size);
876
}
876
}
877
 
877
 
878
static void
878
static void
879
PostScriptSetLineTexture(FILE *fp, char *dashlist, int nlty, double lwd)
879
PostScriptSetLineTexture(FILE *fp, char *dashlist, int nlty, double lwd)
880
{
880
{
881
/* use same macro for Postscript and PDF */
881
/* use same macro for Postscript and PDF */
882
#define PP_SetLineTexture(_CMD_)						\
882
#define PP_SetLineTexture(_CMD_)						\
883
    double dash;								\
883
    double dash;								\
884
    int i;									\
884
    int i;									\
885
    fprintf(fp,"[");								\
885
    fprintf(fp,"[");								\
886
    for (i = 0; i < nlty; i++) {						\
886
    for (i = 0; i < nlty; i++) {						\
887
	dash = (lwd >= 1 ? lwd: 1) *						\
887
	dash = (lwd >= 1 ? lwd: 1) *						\
888
	    ((i % 2) ? dashlist[i] + 1						\
888
	    ((i % 2) ? dashlist[i] + 1						\
889
	     :((nlty == 1 && dashlist[i] == 1.) ? 1. : dashlist[i] - 1));	\
889
	     :((nlty == 1 && dashlist[i] == 1.) ? 1. : dashlist[i] - 1));	\
890
	if (dash < 0) dash = 0;							\
890
	if (dash < 0) dash = 0;							\
891
	fprintf(fp," %.2f", dash);						\
891
	fprintf(fp," %.2f", dash);						\
892
    }										\
892
    }										\
893
    fprintf(fp,"] 0 %s\n", _CMD_)
893
    fprintf(fp,"] 0 %s\n", _CMD_)
894
 
894
 
895
    PP_SetLineTexture("setdash");
895
    PP_SetLineTexture("setdash");
896
}
896
}
897
 
897
 
898
 
898
 
899
static void PostScriptMoveTo(FILE *fp, double x, double y)
899
static void PostScriptMoveTo(FILE *fp, double x, double y)
900
{
900
{
901
    fprintf(fp, "%.2f %.2f m\n", x, y);
901
    fprintf(fp, "%.2f %.2f m\n", x, y);
902
}
902
}
903
 
903
 
904
static void PostScriptRLineTo(FILE *fp, double x0, double y0,
904
static void PostScriptRLineTo(FILE *fp, double x0, double y0,
905
			      double x1, double y1)
905
			      double x1, double y1)
906
{
906
{
907
    double x = rround(x1, 2) - rround(x0, 2),
907
    double x = rround(x1, 2) - rround(x0, 2),
908
	y = rround(y1, 2) - rround(y0, 2);
908
	y = rround(y1, 2) - rround(y0, 2);
909
    /* Warning: some machines seem to compute these differently from
909
    /* Warning: some machines seem to compute these differently from
910
       others, and we do want to diff the output.  x and y should be
910
       others, and we do want to diff the output.  x and y should be
911
       above around 0.01 or negligible (1e-14), and it is the latter case
911
       above around 0.01 or negligible (1e-14), and it is the latter case
912
       we are watching out for here.
912
       we are watching out for here.
913
    */
913
    */
914
 
914
 
915
    if(fabs(x) < 0.005) fprintf(fp, "0"); else fprintf(fp, "%.2f", x);
915
    if(fabs(x) < 0.005) fprintf(fp, "0"); else fprintf(fp, "%.2f", x);
916
    if(fabs(y) < 0.005) fprintf(fp, " 0"); else fprintf(fp, " %.2f", y);
916
    if(fabs(y) < 0.005) fprintf(fp, " 0"); else fprintf(fp, " %.2f", y);
917
    fprintf(fp, " l\n");
917
    fprintf(fp, " l\n");
918
}
918
}
919
 
919
 
920
static void PostScriptStartPath(FILE *fp)
920
static void PostScriptStartPath(FILE *fp)
921
{
921
{
922
    fprintf(fp, "np\n");
922
    fprintf(fp, "np\n");
923
}
923
}
924
 
924
 
925
static void PostScriptEndPath(FILE *fp)
925
static void PostScriptEndPath(FILE *fp)
926
{
926
{
927
    fprintf(fp, "o\n");
927
    fprintf(fp, "o\n");
928
}
928
}
929
 
929
 
930
static void PostScriptRectangle(FILE *fp, double x0, double y0,
930
static void PostScriptRectangle(FILE *fp, double x0, double y0,
931
				double x1, double y1)
931
				double x1, double y1)
932
{
932
{
933
    fprintf(fp, "%.2f %.2f %.2f %.2f r ", x0, y0, x1-x0, y1-y0);
933
    fprintf(fp, "%.2f %.2f %.2f %.2f r ", x0, y0, x1-x0, y1-y0);
934
}
934
}
935
 
935
 
936
static void PostScriptCircle(FILE *fp, double x, double y, double r)
936
static void PostScriptCircle(FILE *fp, double x, double y, double r)
937
{
937
{
938
    fprintf(fp, "%.2f %.2f %.2f c ", x, y, r);
938
    fprintf(fp, "%.2f %.2f %.2f c ", x, y, r);
939
}
939
}
940
 
940
 
941
static void PostScriptWriteString(FILE *fp, char *str)
941
static void PostScriptWriteString(FILE *fp, char *str)
942
{
942
{
943
    fputc('(', fp);
943
    fputc('(', fp);
944
    for ( ; *str; str++)
944
    for ( ; *str; str++)
945
	switch(*str) {
945
	switch(*str) {
946
	case '\n':
946
	case '\n':
947
	    fprintf(fp, "\\n");
947
	    fprintf(fp, "\\n");
948
	    break;
948
	    break;
949
	case '\\':
949
	case '\\':
950
	    fprintf(fp, "\\\\");
950
	    fprintf(fp, "\\\\");
951
	    break;
951
	    break;
952
	case '-':
952
	case '-':
953
#ifdef USE_HYPHEN
953
#ifdef USE_HYPHEN
954
	    if (!isdigit((int)str[1]))
954
	    if (!isdigit((int)str[1]))
955
		fputc(PS_hyphen, fp);
955
		fputc(PS_hyphen, fp);
956
	    else
956
	    else
957
#endif
957
#endif
958
		fputc(*str, fp);
958
		fputc(*str, fp);
959
	    break;
959
	    break;
960
	case '(':
960
	case '(':
961
	case ')':
961
	case ')':
962
	    fprintf(fp, "\\%c", *str);
962
	    fprintf(fp, "\\%c", *str);
963
	    break;
963
	    break;
964
	default:
964
	default:
965
	    fputc(*str, fp);
965
	    fputc(*str, fp);
966
	    break;
966
	    break;
967
	}
967
	}
968
    fputc(')', fp);
968
    fputc(')', fp);
969
}
969
}
970
 
970
 
971
static void PostScriptText(FILE *fp, double x, double y,
971
static void PostScriptText(FILE *fp, double x, double y,
972
			   char *str, double xc, double yc, double rot)
972
			   char *str, double xc, double yc, double rot)
973
{
973
{
974
    fprintf(fp, "%.2f %.2f ", x, y);
974
    fprintf(fp, "%.2f %.2f ", x, y);
975
    PostScriptWriteString(fp, str);
975
    PostScriptWriteString(fp, str);
976
 
976
 
977
    if(xc == 0) fprintf(fp, " 0");
977
    if(xc == 0) fprintf(fp, " 0");
978
    else if(xc == 0.5) fprintf(fp, " .5");
978
    else if(xc == 0.5) fprintf(fp, " .5");
979
    else if(xc == 1) fprintf(fp, " 1");
979
    else if(xc == 1) fprintf(fp, " 1");
980
    else fprintf(fp, " %.2f", xc);
980
    else fprintf(fp, " %.2f", xc);
981
 
981
 
982
    if(yc == 0) fprintf(fp, " 0");
982
    if(yc == 0) fprintf(fp, " 0");
983
    else if(yc == 0.5) fprintf(fp, " .5");
983
    else if(yc == 0.5) fprintf(fp, " .5");
984
    else if(yc == 1) fprintf(fp, " 1");
984
    else if(yc == 1) fprintf(fp, " 1");
985
    else fprintf(fp, " %.2f", yc);
985
    else fprintf(fp, " %.2f", yc);
986
 
986
 
987
    if(rot == 0) fprintf(fp, " 0");
987
    if(rot == 0) fprintf(fp, " 0");
988
    else if(rot == 90) fprintf(fp, " 90");
988
    else if(rot == 90) fprintf(fp, " 90");
989
    else fprintf(fp, " %.2f", rot);
989
    else fprintf(fp, " %.2f", rot);
990
 
990
 
991
    fprintf(fp, " t\n");
991
    fprintf(fp, " t\n");
992
}
992
}
993
 
993
 
994
 
994
 
995
/* Part 3.  Device Driver State. */
995
/* Part 3.  Device Driver State. */
996
 
996
 
997
typedef struct {
997
typedef struct {
998
    char filename[PATH_MAX];
998
    char filename[PATH_MAX];
999
    int open_type;
999
    int open_type;
1000
 
1000
 
1001
    char papername[64];	/* paper name */
1001
    char papername[64];	/* paper name */
1002
    int paperwidth;	/* paper width in big points (1/72 in) */
1002
    int paperwidth;	/* paper width in big points (1/72 in) */
1003
    int paperheight;	/* paper height in big points */
1003
    int paperheight;	/* paper height in big points */
1004
    Rboolean landscape;	/* landscape mode */
1004
    Rboolean landscape;	/* landscape mode */
1005
    int pageno;		/* page number */
1005
    int pageno;		/* page number */
1006
 
1006
 
1007
    int fontfamily;	/* font family */
1007
    int fontfamily;	/* font family */
1008
    char encpath[PATH_MAX]; /* font encoding file */
1008
    char encpath[PATH_MAX]; /* font encoding file */
1009
    char encname[100]; /* font encoding */
1009
    char encname[100]; /* font encoding */
1010
    char **afmpaths;	/* for user-specified family */
1010
    char **afmpaths;	/* for user-specified family */
1011
    int maxpointsize;
1011
    int maxpointsize;
1012
 
1012
 
1013
    double width;	/* plot width in inches */
1013
    double width;	/* plot width in inches */
1014
    double height;	/* plot height in inches */
1014
    double height;	/* plot height in inches */
1015
    double pagewidth;	/* page width in inches */
1015
    double pagewidth;	/* page width in inches */
1016
    double pageheight;	/* page height in inches */
1016
    double pageheight;	/* page height in inches */
1017
    Rboolean pagecentre;/* centre image on page? */
1017
    Rboolean pagecentre;/* centre image on page? */
1018
    Rboolean printit;	/* print page at close? */
1018
    Rboolean printit;	/* print page at close? */
1019
    char command[PATH_MAX];
1019
    char command[PATH_MAX];
1020
    char title[1024];
1020
    char title[1024];
1021
 
1021
 
1022
    FILE *psfp;		/* output file */
1022
    FILE *psfp;		/* output file */
1023
 
1023
 
1024
    Rboolean onefile;	/* EPSF header etc*/
1024
    Rboolean onefile;	/* EPSF header etc*/
1025
    Rboolean paperspecial;	/* suppress %%Orientation */
1025
    Rboolean paperspecial;	/* suppress %%Orientation */
1026
 
1026
 
1027
    /* This group of variables track the current device status.
1027
    /* This group of variables track the current device status.
1028
     * They should only be set by routines that emit PostScript code. */
1028
     * They should only be set by routines that emit PostScript code. */
1029
    struct {
1029
    struct {
1030
	double lwd;		 /* line width */
1030
	double lwd;		 /* line width */
1031
	int lty;		 /* line type */
1031
	int lty;		 /* line type */
1032
	int fontstyle;	         /* font style, R, B, I, BI, S */
1032
	int fontstyle;	         /* font style, R, B, I, BI, S */
1033
	int fontsize;	         /* font size in points */
1033
	int fontsize;	         /* font size in points */
1034
	rcolor col;		 /* color */
1034
	rcolor col;		 /* color */
1035
	rcolor fill;	         /* fill color */
1035
	rcolor fill;	         /* fill color */
1036
    } current;
1036
    } current;
1037
 
1037
 
1038
    FontMetricInfo metrics[5];	/* font metrics */
1038
    FontMetricInfo metrics[5];	/* font metrics */
1039
}
1039
}
1040
PostScriptDesc;
1040
PostScriptDesc;
1041
 
1041
 
1042
 
1042
 
1043
/* Device Driver Actions */
1043
/* Device Driver Actions */
1044
 
1044
 
1045
static void PS_Activate(NewDevDesc *dd);
1045
static void PS_Activate(NewDevDesc *dd);
1046
static void PS_Circle(double x, double y, double r,
1046
static void PS_Circle(double x, double y, double r,
1047
		      R_GE_gcontext *gc,
1047
		      R_GE_gcontext *gc,
1048
		      NewDevDesc *dd);
1048
		      NewDevDesc *dd);
1049
static void PS_Clip(double x0, double x1, double y0, double y1,
1049
static void PS_Clip(double x0, double x1, double y0, double y1,
1050
		     NewDevDesc *dd);
1050
		     NewDevDesc *dd);
1051
static void PS_Close(NewDevDesc *dd);
1051
static void PS_Close(NewDevDesc *dd);
1052
static void PS_Deactivate(NewDevDesc *dd);
1052
static void PS_Deactivate(NewDevDesc *dd);
1053
static void PS_Hold(NewDevDesc *dd);
1053
static void PS_Hold(NewDevDesc *dd);
1054
static Rboolean PS_Locator(double *x, double *y, NewDevDesc *dd);
1054
static Rboolean PS_Locator(double *x, double *y, NewDevDesc *dd);
1055
static void PS_Line(double x1, double y1, double x2, double y2,
1055
static void PS_Line(double x1, double y1, double x2, double y2,
1056
		    R_GE_gcontext *gc,
1056
		    R_GE_gcontext *gc,
1057
		    NewDevDesc *dd);
1057
		    NewDevDesc *dd);
1058
static void PS_MetricInfo(int c, 
1058
static void PS_MetricInfo(int c, 
1059
			  R_GE_gcontext *gc,
1059
			  R_GE_gcontext *gc,
1060
			  double* ascent, double* descent,
1060
			  double* ascent, double* descent,
1061
			  double* width, NewDevDesc *dd);
1061
			  double* width, NewDevDesc *dd);
1062
static void PS_Mode(int mode, NewDevDesc *dd);
1062
static void PS_Mode(int mode, NewDevDesc *dd);
1063
static void PS_NewPage(R_GE_gcontext *gc,
1063
static void PS_NewPage(R_GE_gcontext *gc,
1064
		       NewDevDesc *dd);
1064
		       NewDevDesc *dd);
1065
static Rboolean PS_Open(NewDevDesc*, PostScriptDesc*);
1065
static Rboolean PS_Open(NewDevDesc*, PostScriptDesc*);
1066
static void PS_Polygon(int n, double *x, double *y,
1066
static void PS_Polygon(int n, double *x, double *y,
1067
		       R_GE_gcontext *gc,
1067
		       R_GE_gcontext *gc,
1068
		       NewDevDesc *dd);
1068
		       NewDevDesc *dd);
1069
static void PS_Polyline(int n, double *x, double *y,
1069
static void PS_Polyline(int n, double *x, double *y,
1070
			R_GE_gcontext *gc,
1070
			R_GE_gcontext *gc,
1071
			NewDevDesc *dd);
1071
			NewDevDesc *dd);
1072
static void PS_Rect(double x0, double y0, double x1, double y1,
1072
static void PS_Rect(double x0, double y0, double x1, double y1,
1073
		    R_GE_gcontext *gc,
1073
		    R_GE_gcontext *gc,
1074
		    NewDevDesc *dd);
1074
		    NewDevDesc *dd);
1075
static void PS_Size(double *left, double *right,
1075
static void PS_Size(double *left, double *right,
1076
		     double *bottom, double *top,
1076
		     double *bottom, double *top,
1077
		     NewDevDesc *dd);
1077
		     NewDevDesc *dd);
1078
static double PS_StrWidth(char *str, 
1078
static double PS_StrWidth(char *str, 
1079
			  R_GE_gcontext *gc,
1079
			  R_GE_gcontext *gc,
1080
			  NewDevDesc *dd);
1080
			  NewDevDesc *dd);
1081
static void PS_Text(double x, double y, char *str,
1081
static void PS_Text(double x, double y, char *str,
1082
		    double rot, double hadj,
1082
		    double rot, double hadj,
1083
		    R_GE_gcontext *gc,
1083
		    R_GE_gcontext *gc,
1084
		    NewDevDesc *dd);
1084
		    NewDevDesc *dd);
1085
 
1085
 
1086
 
1086
 
1087
 
1087
 
1088
/* PostScript Support (formerly in PostScript.c) */
1088
/* PostScript Support (formerly in PostScript.c) */
1089
 
1089
 
1090
static void PostScriptSetCol(FILE *fp, double r, double g, double b)
1090
static void PostScriptSetCol(FILE *fp, double r, double g, double b)
1091
{
1091
{
1092
    if(r == 0) fprintf(fp, "0");
1092
    if(r == 0) fprintf(fp, "0");
1093
    else if (r == 1) fprintf(fp, "1");
1093
    else if (r == 1) fprintf(fp, "1");
1094
    else fprintf(fp, "%.4f", r);
1094
    else fprintf(fp, "%.4f", r);
1095
    if(g == 0) fprintf(fp, " 0");
1095
    if(g == 0) fprintf(fp, " 0");
1096
    else if (g == 1) fprintf(fp, " 1");
1096
    else if (g == 1) fprintf(fp, " 1");
1097
    else fprintf(fp, " %.4f", g);
1097
    else fprintf(fp, " %.4f", g);
1098
    if(b == 0) fprintf(fp, " 0");
1098
    if(b == 0) fprintf(fp, " 0");
1099
    else if (b == 1) fprintf(fp, " 1");
1099
    else if (b == 1) fprintf(fp, " 1");
1100
    else fprintf(fp, " %.4f", b);
1100
    else fprintf(fp, " %.4f", b);
1101
    fprintf(fp," rgb\n");
1101
    fprintf(fp," rgb\n");
1102
}
1102
}
1103
 
1103
 
1104
static void PostScriptSetFill(FILE *fp, double r, double g, double b)
1104
static void PostScriptSetFill(FILE *fp, double r, double g, double b)
1105
{
1105
{
1106
    fprintf(fp,"/bg { ");
1106
    fprintf(fp,"/bg { ");
1107
    if(r == 0) fprintf(fp, "0");
1107
    if(r == 0) fprintf(fp, "0");
1108
    else if (r == 1) fprintf(fp, "1");
1108
    else if (r == 1) fprintf(fp, "1");
1109
    else fprintf(fp, "%.4f", r);
1109
    else fprintf(fp, "%.4f", r);
1110
    if(g == 0) fprintf(fp, " 0");
1110
    if(g == 0) fprintf(fp, " 0");
1111
    else if (g == 1) fprintf(fp, " 1");
1111
    else if (g == 1) fprintf(fp, " 1");
1112
    else fprintf(fp, " %.4f", g);
1112
    else fprintf(fp, " %.4f", g);
1113
    if(b == 0) fprintf(fp, " 0");
1113
    if(b == 0) fprintf(fp, " 0");
1114
    else if (b == 1) fprintf(fp, " 1");
1114
    else if (b == 1) fprintf(fp, " 1");
1115
    else fprintf(fp, " %.4f", b);
1115
    else fprintf(fp, " %.4f", b);
1116
    fprintf(fp," } def\n");
1116
    fprintf(fp," } def\n");
1117
}
1117
}
1118
 
1118
 
1119
 
1119
 
1120
 
1120
 
1121
/* Driver Support Routines */
1121
/* Driver Support Routines */
1122
 
1122
 
1123
static void SetColor(int, NewDevDesc*);
1123
static void SetColor(int, NewDevDesc*);
1124
static void SetFill(int, NewDevDesc*);
1124
static void SetFill(int, NewDevDesc*);
1125
static void SetFont(int, int, NewDevDesc*);
1125
static void SetFont(int, int, NewDevDesc*);
1126
static void SetLineStyle(int newlty, double newlwd, NewDevDesc *dd);
1126
static void SetLineStyle(int newlty, double newlwd, NewDevDesc *dd);
1127
static void Invalidate(NewDevDesc*);
1127
static void Invalidate(NewDevDesc*);
1128
static int  MatchFamily(char *name);
1128
static int  MatchFamily(char *name);
1129
 
1129
 
1130
 
1130
 
1131
static Rboolean
1131
static Rboolean
1132
innerPSDeviceDriver(NewDevDesc *dd, char *file, char *paper, char *family,
1132
innerPSDeviceDriver(NewDevDesc *dd, char *file, char *paper, char *family,
1133
		    char **afmpaths, char *encoding,
1133
		    char **afmpaths, char *encoding,
1134
		    char *bg, char *fg,
1134
		    char *bg, char *fg,
1135
		    double width, double height,
1135
		    double width, double height,
1136
		    Rboolean horizontal, double ps,
1136
		    Rboolean horizontal, double ps,
1137
		    Rboolean onefile, Rboolean pagecentre,
1137
		    Rboolean onefile, Rboolean pagecentre,
1138
		    Rboolean printit, char *cmd, char *title)
1138
		    Rboolean printit, char *cmd, char *title)
1139
{
1139
{
1140
    /* If we need to bail out with some sort of "error"
1140
    /* If we need to bail out with some sort of "error"
1141
       then we must free(dd) */
1141
       then we must free(dd) */
1142
 
1142
 
1143
    double xoff, yoff, pointsize;
1143
    double xoff, yoff, pointsize;
1144
    rcolor setbg, setfg;
1144
    rcolor setbg, setfg;
1145
 
1145
 
1146
    PostScriptDesc *pd;
1146
    PostScriptDesc *pd;
1147
 
1147
 
1148
    /* Check and extract the device parameters */
1148
    /* Check and extract the device parameters */
1149
 
1149
 
1150
    if(strlen(file) > PATH_MAX - 1) {
1150
    if(strlen(file) > PATH_MAX - 1) {
1151
	free(dd);
1151
	free(dd);
1152
	error("filename too long in postscript");
1152
	error("filename too long in postscript");
1153
    }
1153
    }
1154
 
1154
 
1155
    /* allocate new postscript device description */
1155
    /* allocate new postscript device description */
1156
    if (!(pd = (PostScriptDesc *) malloc(sizeof(PostScriptDesc))))
1156
    if (!(pd = (PostScriptDesc *) malloc(sizeof(PostScriptDesc))))
1157
	return FALSE;
1157
	return FALSE;
1158
 
1158
 
1159
    /* from here on, if need to bail out with "error", must also */
1159
    /* from here on, if need to bail out with "error", must also */
1160
    /* free(pd) */
1160
    /* free(pd) */
1161
 
1161
 
1162
    /* initialise postscript device description */
1162
    /* initialise postscript device description */
1163
    strcpy(pd->filename, file);
1163
    strcpy(pd->filename, file);
1164
    strcpy(pd->papername, paper);
1164
    strcpy(pd->papername, paper);
1165
    strncpy(pd->title, title, 1024);
1165
    strncpy(pd->title, title, 1024);
1166
    pd->fontfamily = strcmp(family, "User") ? MatchFamily(family) : USERAFM;
1166
    pd->fontfamily = strcmp(family, "User") ? MatchFamily(family) : USERAFM;
1167
    if(strlen(encoding) > PATH_MAX - 1) {
1167
    if(strlen(encoding) > PATH_MAX - 1) {
1168
	free(dd);
1168
	free(dd);
1169
	free(pd);
1169
	free(pd);
1170
	error("encoding path is too long");
1170
	error("encoding path is too long");
1171
    }
1171
    }
1172
    strcpy(pd->encpath, encoding);
1172
    strcpy(pd->encpath, encoding);
1173
    pd->afmpaths = afmpaths;
1173
    pd->afmpaths = afmpaths;
1174
 
1174
 
1175
    setbg = str2col(bg);
1175
    setbg = str2col(bg);
1176
    setfg = str2col(fg);
1176
    setfg = str2col(fg);
1177
 
1177
 
1178
    pd->width = width;
1178
    pd->width = width;
1179
    pd->height = height;
1179
    pd->height = height;
1180
    pd->landscape = horizontal;
1180
    pd->landscape = horizontal;
1181
    pointsize = floor(ps);
1181
    pointsize = floor(ps);
1182
    if(setbg == NA_INTEGER && setfg == NA_INTEGER) {
1182
    if(setbg == NA_INTEGER && setfg == NA_INTEGER) {
1183
	free(dd);
1183
	free(dd);
1184
	free(pd);
1184
	free(pd);
1185
	error("invalid foreground/background color (postscript)");
1185
	error("invalid foreground/background color (postscript)");
1186
    }
1186
    }
1187
    pd->printit = printit;
1187
    pd->printit = printit;
1188
    if(strlen(cmd) > PATH_MAX - 1) {
1188
    if(strlen(cmd) > PATH_MAX - 1) {
1189
	free(dd);
1189
	free(dd);
1190
	free(pd);
1190
	free(pd);
1191
	error("`command' is too long");
1191
	error("`command' is too long");
1192
    }
1192
    }
1193
    strcpy(pd->command, cmd);
1193
    strcpy(pd->command, cmd);
1194
    if (printit && strlen(cmd) == 0)
1194
    if (printit && strlen(cmd) == 0)
1195
	error("postscript(print.it=T) used with an empty print command");
1195
	error("postscript(print.it=T) used with an empty print command");
1196
    strcpy(pd->command, cmd);
1196
    strcpy(pd->command, cmd);
1197
 
1197
 
1198
 
1198
 
1199
    /* Deal with paper and plot size and orientation */
1199
    /* Deal with paper and plot size and orientation */
1200
 
1200
 
1201
    pd->paperspecial = FALSE;
1201
    pd->paperspecial = FALSE;
1202
    if(!strcmp(pd->papername, "Default") ||
1202
    if(!strcmp(pd->papername, "Default") ||
1203
       !strcmp(pd->papername, "default")) {
1203
       !strcmp(pd->papername, "default")) {
1204
	SEXP s = STRING_ELT(GetOption(install("papersize"), R_NilValue), 0);
1204
	SEXP s = STRING_ELT(GetOption(install("papersize"), R_NilValue), 0);
1205
	if(s != NA_STRING && strlen(CHAR(s)) > 0)
1205
	if(s != NA_STRING && strlen(CHAR(s)) > 0)
1206
	    strcpy(pd->papername, CHAR(s));
1206
	    strcpy(pd->papername, CHAR(s));
1207
	else strcpy(pd->papername, "a4");
1207
	else strcpy(pd->papername, "a4");
1208
    }
1208
    }
1209
    if(!strcmp(pd->papername, "A4") ||
1209
    if(!strcmp(pd->papername, "A4") ||
1210
       !strcmp(pd->papername, "a4")) {
1210
       !strcmp(pd->papername, "a4")) {
1211
	pd->pagewidth  = 21.0 / 2.54;
1211
	pd->pagewidth  = 21.0 / 2.54;
1212
	pd->pageheight = 29.7  /2.54;
1212
	pd->pageheight = 29.7  /2.54;
1213
    }
1213
    }
1214
    else if(!strcmp(pd->papername, "Letter") ||
1214
    else if(!strcmp(pd->papername, "Letter") ||
1215
	    !strcmp(pd->papername, "letter")) {
1215
	    !strcmp(pd->papername, "letter")) {
1216
	pd->pagewidth  =  8.5;
1216
	pd->pagewidth  =  8.5;
1217
	pd->pageheight = 11.0;
1217
	pd->pageheight = 11.0;
1218
    }
1218
    }
1219
    else if(!strcmp(pd->papername, "Legal") ||
1219
    else if(!strcmp(pd->papername, "Legal") ||
1220
	    !strcmp(pd->papername, "legal")) {
1220
	    !strcmp(pd->papername, "legal")) {
1221
	pd->pagewidth  =  8.5;
1221
	pd->pagewidth  =  8.5;
1222
	pd->pageheight = 14.0;
1222
	pd->pageheight = 14.0;
1223
    }
1223
    }
1224
    else if(!strcmp(pd->papername, "Executive") ||
1224
    else if(!strcmp(pd->papername, "Executive") ||
1225
	    !strcmp(pd->papername, "executive")) {
1225
	    !strcmp(pd->papername, "executive")) {
1226
	pd->pagewidth  =  7.25;
1226
	pd->pagewidth  =  7.25;
1227
	pd->pageheight = 10.5;
1227
	pd->pageheight = 10.5;
1228
    }
1228
    }
1229
    else if(!strcmp(pd->papername, "special")) {
1229
    else if(!strcmp(pd->papername, "special")) {
1230
	if(pd->landscape) {
1230
	if(pd->landscape) {
1231
	    pd->pagewidth  = height;
1231
	    pd->pagewidth  = height;
1232
	    pd->pageheight =  width;
1232
	    pd->pageheight =  width;
1233
	} else {
1233
	} else {
1234
	    pd->pagewidth  =  width;
1234
	    pd->pagewidth  =  width;
1235
	    pd->pageheight = height;
1235
	    pd->pageheight = height;
1236
	}
1236
	}
1237
	pd->paperspecial = TRUE;
1237
	pd->paperspecial = TRUE;
1238
    }
1238
    }
1239
    else {
1239
    else {
1240
	free(dd);
1240
	free(dd);
1241
	free(pd);
1241
	free(pd);
1242
	error("invalid page type `%s' (postscript)", pd->papername);
1242
	error("invalid page type `%s' (postscript)", pd->papername);
1243
    }
1243
    }
1244
    pd->pagecentre = pagecentre;
1244
    pd->pagecentre = pagecentre;
1245
    pd->paperwidth = 72 * pd->pagewidth;
1245
    pd->paperwidth = 72 * pd->pagewidth;
1246
    pd->paperheight = 72 * pd->pageheight;
1246
    pd->paperheight = 72 * pd->pageheight;
1247
    pd->onefile = onefile;
1247
    pd->onefile = onefile;
1248
    if(pd->landscape) {
1248
    if(pd->landscape) {
1249
	double tmp;
1249
	double tmp;
1250
	tmp = pd->pagewidth;
1250
	tmp = pd->pagewidth;
1251
	pd->pagewidth = pd->pageheight;
1251
	pd->pagewidth = pd->pageheight;
1252
	pd->pageheight = tmp;
1252
	pd->pageheight = tmp;
1253
    }
1253
    }
1254
    if(strcmp(pd->papername, "special"))
1254
    if(strcmp(pd->papername, "special"))
1255
    {
1255
    {
1256
	if(pd->width < 0.1 || pd->width > pd->pagewidth-0.5)
1256
	if(pd->width < 0.1 || pd->width > pd->pagewidth-0.5)
1257
	    pd->width = pd->pagewidth-0.5;
1257
	    pd->width = pd->pagewidth-0.5;
1258
	if(pd->height < 0.1 || pd->height > pd->pageheight-0.5)
1258
	if(pd->height < 0.1 || pd->height > pd->pageheight-0.5)
1259
	    pd->height = pd->pageheight-0.5;
1259
	    pd->height = pd->pageheight-0.5;
1260
    }
1260
    }
1261
    if(pagecentre)
1261
    if(pagecentre)
1262
    {
1262
    {
1263
	xoff = (pd->pagewidth - pd->width)/2.0;
1263
	xoff = (pd->pagewidth - pd->width)/2.0;
1264
	yoff = (pd->pageheight - pd->height)/2.0;
1264
	yoff = (pd->pageheight - pd->height)/2.0;
1265
    } else {
1265
    } else {
1266
	xoff = yoff = 0.0;
1266
	xoff = yoff = 0.0;
1267
    }
1267
    }
1268
    pd->maxpointsize = 72.0 * ((pd->pageheight > pd->pagewidth) ?
1268
    pd->maxpointsize = 72.0 * ((pd->pageheight > pd->pagewidth) ?
1269
			       pd->pageheight : pd->pagewidth);
1269
			       pd->pageheight : pd->pagewidth);
1270
    pd->pageno = 0;
1270
    pd->pageno = 0;
1271
 
1271
 
1272
    /* Base Pointsize */
1272
    /* Base Pointsize */
1273
    /* Nominal Character Sizes in Pixels */
1273
    /* Nominal Character Sizes in Pixels */
1274
    /* Only right for 12 point font. */
1274
    /* Only right for 12 point font. */
1275
    /* Max pointsize suggested by Peter Dalgaard */
1275
    /* Max pointsize suggested by Peter Dalgaard */
1276
 
1276
 
1277
    if(pointsize < 6.0) pointsize = 6.0;
1277
    if(pointsize < 6.0) pointsize = 6.0;
1278
    if(pointsize > pd->maxpointsize) pointsize = pd->maxpointsize;
1278
    if(pointsize > pd->maxpointsize) pointsize = pd->maxpointsize;
1279
    dd->startps = pointsize;
1279
    dd->startps = pointsize;
1280
    dd->startfont = 1;
1280
    dd->startfont = 1;
1281
    dd->startlty = 0;
1281
    dd->startlty = 0;
1282
    dd->startfill = setbg;
1282
    dd->startfill = setbg;
1283
    dd->startcol = setfg;
1283
    dd->startcol = setfg;
1284
    dd->startgamma = 1;
1284
    dd->startgamma = 1;
1285
 
1285
 
1286
    /* Set graphics parameters that must be set by device driver. */
1286
    /* Set graphics parameters that must be set by device driver. */
1287
    /* Page dimensions in points. */
1287
    /* Page dimensions in points. */
1288
 
1288
 
1289
    dd->left = 72 * xoff;			/* left */
1289
    dd->left = 72 * xoff;			/* left */
1290
    dd->right = 72 * (xoff + pd->width);	/* right */
1290
    dd->right = 72 * (xoff + pd->width);	/* right */
1291
    dd->bottom = 72 * yoff;			/* bottom */
1291
    dd->bottom = 72 * yoff;			/* bottom */
1292
    dd->top = 72 * (yoff + pd->height);	/* top */
1292
    dd->top = 72 * (yoff + pd->height);	/* top */
1293
 
1293
 
1294
    dd->cra[0] = 0.9 * pointsize;
1294
    dd->cra[0] = 0.9 * pointsize;
1295
    dd->cra[1] = 1.2 * pointsize;
1295
    dd->cra[1] = 1.2 * pointsize;
1296
 
1296
 
1297
    /* Character Addressing Offsets */
1297
    /* Character Addressing Offsets */
1298
    /* These offsets should center a single */
1298
    /* These offsets should center a single */
1299
    /* plotting character over the plotting point. */
1299
    /* plotting character over the plotting point. */
1300
    /* Pure guesswork and eyeballing ... */
1300
    /* Pure guesswork and eyeballing ... */
1301
 
1301
 
1302
    dd->xCharOffset =  0.4900;
1302
    dd->xCharOffset =  0.4900;
1303
    dd->yCharOffset =  0.3333;
1303
    dd->yCharOffset =  0.3333;
1304
    dd->yLineBias = 0.2;
1304
    dd->yLineBias = 0.2;
1305
 
1305
 
1306
    /* Inches per Raster Unit */
1306
    /* Inches per Raster Unit */
1307
    /* We use points (72 dots per inch) */
1307
    /* We use points (72 dots per inch) */
1308
 
1308
 
1309
    dd->ipr[0] = 1.0/72.0;
1309
    dd->ipr[0] = 1.0/72.0;
1310
    dd->ipr[1] = 1.0/72.0;
1310
    dd->ipr[1] = 1.0/72.0;
1311
    /* GREset(.)  dd->gp.mkh = dd->gp.cra[0] * dd->gp.ipr[0]; */
1311
    /* GREset(.)  dd->gp.mkh = dd->gp.cra[0] * dd->gp.ipr[0]; */
1312
 
1312
 
1313
    dd->canResizePlot = 0;
1313
    dd->canResizePlot = 0;
1314
    dd->canChangeFont = 1;
1314
    dd->canChangeFont = 1;
1315
    dd->canRotateText = 1;
1315
    dd->canRotateText = 1;
1316
    dd->canResizeText = 1;
1316
    dd->canResizeText = 1;
1317
    dd->canClip = 1;
1317
    dd->canClip = 1;
1318
    dd->canHAdj = 2;
1318
    dd->canHAdj = 2;
1319
    dd->canChangeGamma = FALSE;
1319
    dd->canChangeGamma = FALSE;
1320
 
1320
 
1321
    /*	Start the driver */
1321
    /*	Start the driver */
1322
 
1322
 
1323
    pd->pageno = 0;
1323
    pd->pageno = 0;
1324
    if(!PS_Open(dd, pd)) {
1324
    if(!PS_Open(dd, pd)) {
1325
	free(pd);
1325
	free(pd);
1326
	return FALSE;
1326
	return FALSE;
1327
    }
1327
    }
1328
 
1328
 
1329
    dd->newDevStruct = 1;
1329
    dd->newDevStruct = 1;
1330
 
1330
 
1331
    dd->open	      = PS_Open;
1331
    dd->open	      = PS_Open;
1332
    dd->close      = PS_Close;
1332
    dd->close      = PS_Close;
1333
    dd->activate   = PS_Activate;
1333
    dd->activate   = PS_Activate;
1334
    dd->deactivate = PS_Deactivate;
1334
    dd->deactivate = PS_Deactivate;
1335
    dd->size     = PS_Size;
1335
    dd->size     = PS_Size;
1336
    dd->newPage    = PS_NewPage;
1336
    dd->newPage    = PS_NewPage;
1337
    dd->clip	      = PS_Clip;
1337
    dd->clip	      = PS_Clip;
1338
    dd->text	      = PS_Text;
1338
    dd->text	      = PS_Text;
1339
    dd->strWidth   = PS_StrWidth;
1339
    dd->strWidth   = PS_StrWidth;
1340
    dd->metricInfo = PS_MetricInfo;
1340
    dd->metricInfo = PS_MetricInfo;
1341
    dd->rect	      = PS_Rect;
1341
    dd->rect	      = PS_Rect;
1342
    dd->circle     = PS_Circle;
1342
    dd->circle     = PS_Circle;
1343
    dd->line	      = PS_Line;
1343
    dd->line	      = PS_Line;
1344
    dd->polygon    = PS_Polygon;
1344
    dd->polygon    = PS_Polygon;
1345
    dd->polyline   = PS_Polyline;
1345
    dd->polyline   = PS_Polyline;
1346
    dd->locator    = PS_Locator;
1346
    dd->locator    = PS_Locator;
1347
    dd->mode	      = PS_Mode;
1347
    dd->mode	      = PS_Mode;
1348
    dd->hold	      = PS_Hold;
1348
    dd->hold	      = PS_Hold;
1349
 
1349
 
1350
    dd->deviceSpecific = (void *) pd;
1350
    dd->deviceSpecific = (void *) pd;
1351
    dd->displayListOn = FALSE;
1351
    dd->displayListOn = FALSE;
1352
    return TRUE;
1352
    return TRUE;
1353
}
1353
}
1354
 
1354
 
1355
/* Do this to avoid having to change Rdevices.h
1355
/* Do this to avoid having to change Rdevices.h
1356
 * This will be cleaned up when GraphicsDevice.h replaces
1356
 * This will be cleaned up when GraphicsDevice.h replaces
1357
 * Rdevices.h
1357
 * Rdevices.h
1358
 */
1358
 */
1359
Rboolean
1359
Rboolean
1360
PSDeviceDriver(DevDesc *dd, char *file, char *paper, char *family,
1360
PSDeviceDriver(DevDesc *dd, char *file, char *paper, char *family,
1361
	       char **afmpaths, char *encoding,
1361
	       char **afmpaths, char *encoding,
1362
	       char *bg, char *fg,
1362
	       char *bg, char *fg,
1363
	       double width, double height,
1363
	       double width, double height,
1364
	       Rboolean horizontal, double ps,
1364
	       Rboolean horizontal, double ps,
1365
	       Rboolean onefile, Rboolean pagecentre,
1365
	       Rboolean onefile, Rboolean pagecentre,
1366
	       Rboolean printit, char *cmd, char *title)
1366
	       Rboolean printit, char *cmd, char *title)
1367
{
1367
{
1368
    return innerPSDeviceDriver((NewDevDesc*) dd, file, paper, family,
1368
    return innerPSDeviceDriver((NewDevDesc*) dd, file, paper, family,
1369
			       afmpaths, encoding, bg, fg, width, height,
1369
			       afmpaths, encoding, bg, fg, width, height,
1370
			       horizontal, ps, onefile, pagecentre,
1370
			       horizontal, ps, onefile, pagecentre,
1371
			       printit, cmd, title);
1371
			       printit, cmd, title);
1372
}
1372
}
1373
 
1373
 
1374
static int MatchFamily(char *name)
1374
static int MatchFamily(char *name)
1375
{
1375
{
1376
    int i;
1376
    int i;
1377
    for(i = 0; Family[i].family != NULL; i++)
1377
    for(i = 0; Family[i].family != NULL; i++)
1378
	if(!strcmp(name, Family[i].family)) return i;
1378
	if(!strcmp(name, Family[i].family)) return i;
1379
    warning("unknown postscript font family, using %s",
1379
    warning("unknown postscript font family, using %s",
1380
	    Family[3].family);
1380
	    Family[3].family);
1381
    return 3;
1381
    return 3;
1382
}
1382
}
1383
 
1383
 
1384
static void SetColor(int color, NewDevDesc *dd)
1384
static void SetColor(int color, NewDevDesc *dd)
1385
{
1385
{
1386
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
1386
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
1387
    if(color != pd->current.col) {
1387
    if(color != pd->current.col) {
1388
	PostScriptSetCol(pd->psfp,
1388
	PostScriptSetCol(pd->psfp,
1389
			 R_RED(color)/255.0,
1389
			 R_RED(color)/255.0,
1390
			 R_GREEN(color)/255.0,
1390
			 R_GREEN(color)/255.0,
1391
			 R_BLUE(color)/255.0);
1391
			 R_BLUE(color)/255.0);
1392
	pd->current.col = color;
1392
	pd->current.col = color;
1393
    }
1393
    }
1394
}
1394
}
1395
 
1395
 
1396
static void SetFill(int color, NewDevDesc *dd)
1396
static void SetFill(int color, NewDevDesc *dd)
1397
{
1397
{
1398
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
1398
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
1399
    if(color != pd->current.fill) {
1399
    if(color != pd->current.fill) {
1400
	PostScriptSetFill(pd->psfp,
1400
	PostScriptSetFill(pd->psfp,
1401
			  R_RED(color)/255.0,
1401
			  R_RED(color)/255.0,
1402
			  R_GREEN(color)/255.0,
1402
			  R_GREEN(color)/255.0,
1403
			  R_BLUE(color)/255.0);
1403
			  R_BLUE(color)/255.0);
1404
	pd->current.fill = color;
1404
	pd->current.fill = color;
1405
    }
1405
    }
1406
}
1406
}
1407
 
1407
 
1408
/* Note that the line texture is scaled by the line width. */
1408
/* Note that the line texture is scaled by the line width. */
1409
 
1409
 
1410
static void SetLineStyle(int newlty, double newlwd, NewDevDesc *dd)
1410
static void SetLineStyle(int newlty, double newlwd, NewDevDesc *dd)
1411
{
1411
{
1412
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
1412
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
1413
    char dashlist[8];
1413
    char dashlist[8];
1414
    int i;
1414
    int i;
1415
 
1415
 
1416
    if (pd->current.lty != newlty || pd->current.lwd != newlwd) {
1416
    if (pd->current.lty != newlty || pd->current.lwd != newlwd) {
1417
	pd->current.lwd = newlwd;
1417
	pd->current.lwd = newlwd;
1418
	pd->current.lty = newlty;
1418
	pd->current.lty = newlty;
1419
	PostScriptSetLineWidth(pd->psfp, newlwd * 0.75);
1419
	PostScriptSetLineWidth(pd->psfp, newlwd * 0.75);
1420
	/* process lty : */
1420
	/* process lty : */
1421
	for(i = 0; i < 8 && newlty & 15 ; i++) {
1421
	for(i = 0; i < 8 && newlty & 15 ; i++) {
1422
	    dashlist[i] = newlty & 15;
1422
	    dashlist[i] = newlty & 15;
1423
	    newlty = newlty >> 4;
1423
	    newlty = newlty >> 4;
1424
	}
1424
	}
1425
	PostScriptSetLineTexture(pd->psfp, dashlist, i, newlwd * 0.75);
1425
	PostScriptSetLineTexture(pd->psfp, dashlist, i, newlwd * 0.75);
1426
    }
1426
    }
1427
}
1427
}
1428
 
1428
 
1429
static void SetFont(int style, int size, NewDevDesc *dd)
1429
static void SetFont(int style, int size, NewDevDesc *dd)
1430
{
1430
{
1431
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
1431
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
1432
    if(style < 1 || style > 5)
1432
    if(style < 1 || style > 5) {
-
 
1433
	warning("attempt to use invalid font %d replaced by font 1", style);
1433
	style = 1;
1434
	style = 1;
-
 
1435
    }
1434
    if(size < 1 || size > pd->maxpointsize)
1436
    if(size < 1 || size > pd->maxpointsize)
1435
	size = 10;
1437
	size = 10;
1436
    if(size != pd->current.fontsize || style != pd->current.fontstyle) {
1438
    if(size != pd->current.fontsize || style != pd->current.fontstyle) {
1437
	PostScriptSetFont(pd->psfp, style-1, size);
1439
	PostScriptSetFont(pd->psfp, style-1, size);
1438
	pd->current.fontsize = size;
1440
	pd->current.fontsize = size;
1439
	pd->current.fontstyle = style;
1441
	pd->current.fontstyle = style;
1440
    }
1442
    }
1441
}
1443
}
1442
 
1444
 
1443
#ifdef Win32
1445
#ifdef Win32
1444
/* exists, but does not work on GUI processes */
1446
/* exists, but does not work on GUI processes */
1445
# undef HAVE_POPEN
1447
# undef HAVE_POPEN
1446
#endif
1448
#endif
1447
 
1449
 
1448
static Rboolean PS_Open(NewDevDesc *dd, PostScriptDesc *pd)
1450
static Rboolean PS_Open(NewDevDesc *dd, PostScriptDesc *pd)
1449
{
1451
{
1450
    char buf[512];
1452
    char buf[512];
1451
    int i;
1453
    int i;
1452
 
1454
 
1453
    if (!LoadEncoding(pd->encpath, pd->encname, FALSE)) {
1455
    if (!LoadEncoding(pd->encpath, pd->encname, FALSE)) {
1454
	warning("problem loading encoding file");
1456
	warning("problem loading encoding file");
1455
	return FALSE;
1457
	return FALSE;
1456
    }
1458
    }
1457
    for(i = 0; i < 5 ; i++) {
1459
    for(i = 0; i < 5 ; i++) {
1458
        char const *p;
1460
        char const *p;
1459
	if(pd->fontfamily == USERAFM) p = pd->afmpaths[i];
1461
	if(pd->fontfamily == USERAFM) p = pd->afmpaths[i];
1460
	else p = Family[pd->fontfamily].afmfile[i];
1462
	else p = Family[pd->fontfamily].afmfile[i];
1461
	if(!PostScriptLoadFontMetrics(p, &(pd->metrics[i]),
1463
	if(!PostScriptLoadFontMetrics(p, &(pd->metrics[i]),
1462
				      familyname[i], (i < 4)?1:0)) {
1464
				      familyname[i], (i < 4)?1:0)) {
1463
	    warning("cannot read afm file %s", p);
1465
	    warning("cannot read afm file %s", p);
1464
	    return FALSE;
1466
	    return FALSE;
1465
	}
1467
	}
1466
    }
1468
    }
1467
 
1469
 
1468
    if (strlen(pd->filename) == 0) {
1470
    if (strlen(pd->filename) == 0) {
1469
#ifndef HAVE_POPEN
1471
#ifndef HAVE_POPEN
1470
	warning("printing via file = \"\" is not implemented in this version");
1472
	warning("printing via file = \"\" is not implemented in this version");
1471
	return FALSE;
1473
	return FALSE;
1472
#else
1474
#else
1473
	if(strlen(pd->command) == 0) return FALSE;
1475
	if(strlen(pd->command) == 0) return FALSE;
1474
        errno = 0;
1476
        errno = 0;
1475
	pd->psfp = R_popen(pd->command, "w");
1477
	pd->psfp = R_popen(pd->command, "w");
1476
	pd->open_type = 1;
1478
	pd->open_type = 1;
1477
        if (!pd->psfp || errno != 0) {
1479
        if (!pd->psfp || errno != 0) {
1478
            warning("cannot open `postscript' pipe to `%s'", pd->command);
1480
            warning("cannot open `postscript' pipe to `%s'", pd->command);
1479
            return FALSE;
1481
            return FALSE;
1480
        }
1482
        }
1481
#endif
1483
#endif
1482
    } else if (pd->filename[0] == '|') {
1484
    } else if (pd->filename[0] == '|') {
1483
#ifndef HAVE_POPEN
1485
#ifndef HAVE_POPEN
1484
	warning("file = \"|cmd\" is not implemented in this version");
1486
	warning("file = \"|cmd\" is not implemented in this version");
1485
	return FALSE;
1487
	return FALSE;
1486
#else
1488
#else
1487
	errno = 0;
1489
	errno = 0;
1488
	pd->psfp = R_popen(pd->filename + 1, "w");
1490
	pd->psfp = R_popen(pd->filename + 1, "w");
1489
	pd->open_type = 1;
1491
	pd->open_type = 1;
1490
	if (!pd->psfp || errno != 0) {
1492
	if (!pd->psfp || errno != 0) {
1491
	    warning("cannot open `postscript' pipe to `%s'", pd->filename + 1);
1493
	    warning("cannot open `postscript' pipe to `%s'", pd->filename + 1);
1492
	    return FALSE;
1494
	    return FALSE;
1493
	}
1495
	}
1494
#endif
1496
#endif
1495
    } else {
1497
    } else {
1496
	snprintf(buf, 512, pd->filename, pd->pageno + 1); /* page 1 to start */
1498
	snprintf(buf, 512, pd->filename, pd->pageno + 1); /* page 1 to start */
1497
	pd->psfp = R_fopen(R_ExpandFileName(buf), "w");
1499
	pd->psfp = R_fopen(R_ExpandFileName(buf), "w");
1498
	pd->open_type = 0;
1500
	pd->open_type = 0;
1499
    }
1501
    }
1500
    if (!pd->psfp) {
1502
    if (!pd->psfp) {
1501
	warning("cannot open `postscript' file argument `%s'", buf);
1503
	warning("cannot open `postscript' file argument `%s'", buf);
1502
	return FALSE;
1504
	return FALSE;
1503
    }
1505
    }
1504
 
1506
 
1505
    if(pd->landscape)
1507
    if(pd->landscape)
1506
	PSFileHeader(pd->psfp,
1508
	PSFileHeader(pd->psfp,
1507
		     pd->encname,
1509
		     pd->encname,
1508
		     pd->papername,
1510
		     pd->papername,
1509
		     pd->paperwidth,
1511
		     pd->paperwidth,
1510
		     pd->paperheight,
1512
		     pd->paperheight,
1511
		     pd->landscape,
1513
		     pd->landscape,
1512
		     !(pd->onefile),
1514
		     !(pd->onefile),
1513
		     pd->paperspecial,
1515
		     pd->paperspecial,
1514
		     dd->bottom,
1516
		     dd->bottom,
1515
		     dd->left,
1517
		     dd->left,
1516
		     dd->top,
1518
		     dd->top,
1517
		     dd->right,
1519
		     dd->right,
1518
		     pd->title);
1520
		     pd->title);
1519
    else
1521
    else
1520
	PSFileHeader(pd->psfp,
1522
	PSFileHeader(pd->psfp,
1521
		     pd->encname,
1523
		     pd->encname,
1522
		     pd->papername,
1524
		     pd->papername,
1523
		     pd->paperwidth,
1525
		     pd->paperwidth,
1524
		     pd->paperheight,
1526
		     pd->paperheight,
1525
		     pd->landscape,
1527
		     pd->landscape,
1526
		     !(pd->onefile),
1528
		     !(pd->onefile),
1527
		     pd->paperspecial,
1529
		     pd->paperspecial,
1528
		     dd->left,
1530
		     dd->left,
1529
		     dd->bottom,
1531
		     dd->bottom,
1530
		     dd->right,
1532
		     dd->right,
1531
		     dd->top,
1533
		     dd->top,
1532
		     pd->title);
1534
		     pd->title);
1533
 
1535
 
1534
    return TRUE;
1536
    return TRUE;
1535
}
1537
}
1536
 
1538
 
1537
/* The driver keeps track of the current values of colors, fonts and
1539
/* The driver keeps track of the current values of colors, fonts and
1538
   line parameters, to save emitting some PostScript. In some cases,
1540
   line parameters, to save emitting some PostScript. In some cases,
1539
   the state becomes unknown, notably after changing the clipping and
1541
   the state becomes unknown, notably after changing the clipping and
1540
   at the start of a new page, so we have the following routine to
1542
   at the start of a new page, so we have the following routine to
1541
   invalidate the saved values, which in turn causes the parameters to
1543
   invalidate the saved values, which in turn causes the parameters to
1542
   be set before usage. */
1544
   be set before usage. */
1543
 
1545
 
1544
static void Invalidate(NewDevDesc *dd)
1546
static void Invalidate(NewDevDesc *dd)
1545
{
1547
{
1546
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
1548
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
1547
 
1549
 
1548
    pd->current.fontsize = -1;
1550
    pd->current.fontsize = -1;
1549
    pd->current.fontstyle = -1;
1551
    pd->current.fontstyle = -1;
1550
    pd->current.lwd = -1;
1552
    pd->current.lwd = -1;
1551
    pd->current.lty = -1;
1553
    pd->current.lty = -1;
1552
    pd->current.col = INVALID_COL;
1554
    pd->current.col = INVALID_COL;
1553
    pd->current.fill = INVALID_COL;
1555
    pd->current.fill = INVALID_COL;
1554
}
1556
}
1555
 
1557
 
1556
static void PS_Clip(double x0, double x1, double y0, double y1, NewDevDesc *dd)
1558
static void PS_Clip(double x0, double x1, double y0, double y1, NewDevDesc *dd)
1557
{
1559
{
1558
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
1560
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
1559
 
1561
 
1560
    PostScriptSetClipRect(pd->psfp, x0, x1, y0, y1);
1562
    PostScriptSetClipRect(pd->psfp, x0, x1, y0, y1);
1561
    /* clipping does grestore so invalidate monitor variables */
1563
    /* clipping does grestore so invalidate monitor variables */
1562
    Invalidate(dd);
1564
    Invalidate(dd);
1563
}
1565
}
1564
 
1566
 
1565
static void PS_Size(double *left, double *right,
1567
static void PS_Size(double *left, double *right,
1566
		    double *bottom, double *top,
1568
		    double *bottom, double *top,
1567
		    NewDevDesc *dd)
1569
		    NewDevDesc *dd)
1568
{
1570
{
1569
    *left = dd->left;
1571
    *left = dd->left;
1570
    *right = dd->right;
1572
    *right = dd->right;
1571
    *bottom = dd->bottom;
1573
    *bottom = dd->bottom;
1572
    *top = dd->top;
1574
    *top = dd->top;
1573
}
1575
}
1574
 
1576
 
1575
static void PostScriptClose(NewDevDesc *dd);
1577
static void PostScriptClose(NewDevDesc *dd);
1576
 
1578
 
1577
static void PS_NewPage(R_GE_gcontext *gc,
1579
static void PS_NewPage(R_GE_gcontext *gc,
1578
		       NewDevDesc *dd)
1580
		       NewDevDesc *dd)
1579
{
1581
{
1580
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
1582
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
1581
 
1583
 
1582
 
1584
 
1583
    if(pd->onefile) {
1585
    if(pd->onefile) {
1584
	if(++pd->pageno > 1) PostScriptEndPage(pd->psfp);
1586
	if(++pd->pageno > 1) PostScriptEndPage(pd->psfp);
1585
    } else if(pd->pageno > 0) {
1587
    } else if(pd->pageno > 0) {
1586
	PostScriptClose(dd);
1588
	PostScriptClose(dd);
1587
	PS_Open(dd, pd);
1589
	PS_Open(dd, pd);
1588
	pd->pageno++;
1590
	pd->pageno++;
1589
    } else pd->pageno++;
1591
    } else pd->pageno++;
1590
    PostScriptStartPage(pd->psfp, pd->pageno);
1592
    PostScriptStartPage(pd->psfp, pd->pageno);
1591
    Invalidate(dd);
1593
    Invalidate(dd);
1592
 
1594
 
1593
    if(R_ALPHA(gc->fill) == 0) {
1595
    if(R_ALPHA(gc->fill) == 0) {
1594
	/*
1596
	/*
1595
	 * Override some gc settings
1597
	 * Override some gc settings
1596
	 */
1598
	 */
1597
	gc->col = NA_INTEGER;
1599
	gc->col = NA_INTEGER;
1598
	PS_Rect(0, 0, 72.0 * pd->pagewidth, 72.0 * pd->pageheight, gc, dd);
1600
	PS_Rect(0, 0, 72.0 * pd->pagewidth, 72.0 * pd->pageheight, gc, dd);
1599
    }
1601
    }
1600
}
1602
}
1601
 
1603
 
1602
#ifdef Win32
1604
#ifdef Win32
1603
int   runcmd(char *cmd, int wait, int visible, char *finput);
1605
int   runcmd(char *cmd, int wait, int visible, char *finput);
1604
#endif
1606
#endif
1605
static void PostScriptClose(NewDevDesc *dd)
1607
static void PostScriptClose(NewDevDesc *dd)
1606
{
1608
{
1607
    char buff[PATH_MAX];
1609
    char buff[PATH_MAX];
1608
    int err = 0;
1610
    int err = 0;
1609
 
1611
 
1610
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
1612
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
1611
 
1613
 
1612
    PostScriptFileTrailer(pd->psfp, pd->pageno);
1614
    PostScriptFileTrailer(pd->psfp, pd->pageno);
1613
    if(pd->open_type == 1)
1615
    if(pd->open_type == 1)
1614
	pclose(pd->psfp);
1616
	pclose(pd->psfp);
1615
    else {
1617
    else {
1616
	fclose(pd->psfp);
1618
	fclose(pd->psfp);
1617
	if (pd->printit) {
1619
	if (pd->printit) {
1618
	    strcpy(buff, pd->command);
1620
	    strcpy(buff, pd->command);
1619
	    strcat(buff, " ");
1621
	    strcat(buff, " ");
1620
	    strcat(buff, pd->filename);
1622
	    strcat(buff, pd->filename);
1621
/*	    Rprintf("buff is %s\n", buff); */
1623
/*	    Rprintf("buff is %s\n", buff); */
1622
#ifdef Unix
1624
#ifdef Unix
1623
	    err = R_system(buff);
1625
	    err = R_system(buff);
1624
#endif
1626
#endif
1625
#ifdef Win32
1627
#ifdef Win32
1626
	    err = runcmd(buff, 0, 0, NULL);
1628
	    err = runcmd(buff, 0, 0, NULL);
1627
#endif
1629
#endif
1628
	    if (err)
1630
	    if (err)
1629
		warning("error from postscript() in running:\n    %s", buff);
1631
		warning("error from postscript() in running:\n    %s", buff);
1630
	}
1632
	}
1631
    }
1633
    }
1632
}
1634
}
1633
 
1635
 
1634
static void PS_Close(NewDevDesc *dd)
1636
static void PS_Close(NewDevDesc *dd)
1635
{
1637
{
1636
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
1638
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
1637
 
1639
 
1638
    PostScriptClose(dd);
1640
    PostScriptClose(dd);
1639
    free(pd);
1641
    free(pd);
1640
}
1642
}
1641
 
1643
 
1642
static void PS_Activate(NewDevDesc *dd) {}
1644
static void PS_Activate(NewDevDesc *dd) {}
1643
static void PS_Deactivate(NewDevDesc *dd) {}
1645
static void PS_Deactivate(NewDevDesc *dd) {}
1644
 
1646
 
1645
static double PS_StrWidth(char *str,
1647
static double PS_StrWidth(char *str,
1646
			  R_GE_gcontext *gc,
1648
			  R_GE_gcontext *gc,
1647
			  NewDevDesc *dd)
1649
			  NewDevDesc *dd)
1648
{
1650
{
1649
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
1651
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
1650
    int face = gc->fontface;
1652
    int face = gc->fontface;
1651
 
1653
 
1652
    if(face < 1 || face > 5) face = 1;
1654
    if(face < 1 || face > 5) face = 1;
1653
    return floor(gc->cex * gc->ps + 0.5) *
1655
    return floor(gc->cex * gc->ps + 0.5) *
1654
	PostScriptStringWidth((unsigned char *)str,
1656
	PostScriptStringWidth((unsigned char *)str,
1655
			      &(pd->metrics[face-1]));
1657
			      &(pd->metrics[face-1]));
1656
}
1658
}
1657
 
1659
 
1658
static void PS_MetricInfo(int c, 
1660
static void PS_MetricInfo(int c, 
1659
			  R_GE_gcontext *gc,
1661
			  R_GE_gcontext *gc,
1660
			  double* ascent, double* descent,
1662
			  double* ascent, double* descent,
1661
			  double* width, NewDevDesc *dd)
1663
			  double* width, NewDevDesc *dd)
1662
{
1664
{
1663
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
1665
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
1664
    int face = gc->fontface;
1666
    int face = gc->fontface;
1665
 
1667
 
1666
    if(face < 1 || face > 5) face = 1;
1668
    if(face < 1 || face > 5) face = 1;
1667
 
1669
 
1668
    PostScriptMetricInfo(c, ascent, descent, width,
1670
    PostScriptMetricInfo(c, ascent, descent, width,
1669
			 &(pd->metrics[face-1]));
1671
			 &(pd->metrics[face-1]));
1670
    *ascent = floor(gc->cex * gc->ps + 0.5) * *ascent;
1672
    *ascent = floor(gc->cex * gc->ps + 0.5) * *ascent;
1671
    *descent = floor(gc->cex * gc->ps + 0.5) * *descent;
1673
    *descent = floor(gc->cex * gc->ps + 0.5) * *descent;
1672
    *width = floor(gc->cex * gc->ps + 0.5) * *width;
1674
    *width = floor(gc->cex * gc->ps + 0.5) * *width;
1673
}
1675
}
1674
 
1676
 
1675
static void PS_Rect(double x0, double y0, double x1, double y1,
1677
static void PS_Rect(double x0, double y0, double x1, double y1,
1676
		    R_GE_gcontext *gc,
1678
		    R_GE_gcontext *gc,
1677
		    NewDevDesc *dd)
1679
		    NewDevDesc *dd)
1678
{
1680
{
1679
    int code;
1681
    int code;
1680
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
1682
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
1681
 
1683
 
1682
    /* code is set as follows */
1684
    /* code is set as follows */
1683
    /* code == 0, nothing to draw */
1685
    /* code == 0, nothing to draw */
1684
    /* code == 1, outline only */
1686
    /* code == 1, outline only */
1685
    /* code == 2, fill only */
1687
    /* code == 2, fill only */
1686
    /* code == 3, outline and fill */
1688
    /* code == 3, outline and fill */
1687
 
1689
 
1688
    code = 2 * (R_ALPHA(gc->fill) == 0) + (R_ALPHA(gc->col) == 0);
1690
    code = 2 * (R_ALPHA(gc->fill) == 0) + (R_ALPHA(gc->col) == 0);
1689
 
1691
 
1690
    if (code) {
1692
    if (code) {
1691
	if(code & 2)
1693
	if(code & 2)
1692
	    SetFill(gc->fill, dd);
1694
	    SetFill(gc->fill, dd);
1693
	if(code & 1) {
1695
	if(code & 1) {
1694
	    SetColor(gc->col, dd);
1696
	    SetColor(gc->col, dd);
1695
	    SetLineStyle(gc->lty, gc->lwd, dd);
1697
	    SetLineStyle(gc->lty, gc->lwd, dd);
1696
	}
1698
	}
1697
	PostScriptRectangle(pd->psfp, x0, y0, x1, y1);
1699
	PostScriptRectangle(pd->psfp, x0, y0, x1, y1);
1698
	fprintf(pd->psfp, "p%d\n", code);
1700
	fprintf(pd->psfp, "p%d\n", code);
1699
    }
1701
    }
1700
}
1702
}
1701
 
1703
 
1702
static void PS_Circle(double x, double y, double r,
1704
static void PS_Circle(double x, double y, double r,
1703
		      R_GE_gcontext *gc,
1705
		      R_GE_gcontext *gc,
1704
		      NewDevDesc *dd)
1706
		      NewDevDesc *dd)
1705
{
1707
{
1706
    int code;
1708
    int code;
1707
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
1709
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
1708
 
1710
 
1709
    /* code is set as follows */
1711
    /* code is set as follows */
1710
    /* code == 0, nothing to draw */
1712
    /* code == 0, nothing to draw */
1711
    /* code == 1, outline only */
1713
    /* code == 1, outline only */
1712
    /* code == 2, fill only */
1714
    /* code == 2, fill only */
1713
    /* code == 3, outline and fill */
1715
    /* code == 3, outline and fill */
1714
 
1716
 
1715
    code = 2 * (R_ALPHA(gc->fill) == 0) + (R_ALPHA(gc->col) == 0);
1717
    code = 2 * (R_ALPHA(gc->fill) == 0) + (R_ALPHA(gc->col) == 0);
1716
 
1718
 
1717
    if (code) {
1719
    if (code) {
1718
	if(code & 2)
1720
	if(code & 2)
1719
	    SetFill(gc->fill, dd);
1721
	    SetFill(gc->fill, dd);
1720
	if(code & 1) {
1722
	if(code & 1) {
1721
	    SetColor(gc->col, dd);
1723
	    SetColor(gc->col, dd);
1722
	    SetLineStyle(gc->lty, gc->lwd, dd);
1724
	    SetLineStyle(gc->lty, gc->lwd, dd);
1723
	}
1725
	}
1724
	PostScriptCircle(pd->psfp, x, y, r);
1726
	PostScriptCircle(pd->psfp, x, y, r);
1725
	fprintf(pd->psfp, "p%d\n", code);
1727
	fprintf(pd->psfp, "p%d\n", code);
1726
    }
1728
    }
1727
}
1729
}
1728
 
1730
 
1729
static void PS_Line(double x1, double y1, double x2, double y2,
1731
static void PS_Line(double x1, double y1, double x2, double y2,
1730
		    R_GE_gcontext *gc,
1732
		    R_GE_gcontext *gc,
1731
		    NewDevDesc *dd)
1733
		    NewDevDesc *dd)
1732
{
1734
{
1733
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
1735
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
1734
 
1736
 
1735
    /* FIXME : clip to the device extents here */
1737
    /* FIXME : clip to the device extents here */
1736
    if(R_ALPHA(gc->col) == 0) {
1738
    if(R_ALPHA(gc->col) == 0) {
1737
	SetColor(gc->col, dd);
1739
	SetColor(gc->col, dd);
1738
	SetLineStyle(gc->lty, gc->lwd, dd);
1740
	SetLineStyle(gc->lty, gc->lwd, dd);
1739
	PostScriptStartPath(pd->psfp);
1741
	PostScriptStartPath(pd->psfp);
1740
	PostScriptMoveTo(pd->psfp, x1, y1);
1742
	PostScriptMoveTo(pd->psfp, x1, y1);
1741
	PostScriptRLineTo(pd->psfp, x1, y1, x2, y2);
1743
	PostScriptRLineTo(pd->psfp, x1, y1, x2, y2);
1742
	/* fprintf(pd->psfp, "%.2f %.2f rl\n", x2 - x1, y2 - y1);*/
1744
	/* fprintf(pd->psfp, "%.2f %.2f rl\n", x2 - x1, y2 - y1);*/
1743
	PostScriptEndPath(pd->psfp);
1745
	PostScriptEndPath(pd->psfp);
1744
    }
1746
    }
1745
}
1747
}
1746
 
1748
 
1747
static void PS_Polygon(int n, double *x, double *y,
1749
static void PS_Polygon(int n, double *x, double *y,
1748
		       R_GE_gcontext *gc,
1750
		       R_GE_gcontext *gc,
1749
		       NewDevDesc *dd)
1751
		       NewDevDesc *dd)
1750
{
1752
{
1751
    PostScriptDesc *pd;
1753
    PostScriptDesc *pd;
1752
    int i, code;
1754
    int i, code;
1753
 
1755
 
1754
    pd = (PostScriptDesc *) dd->deviceSpecific;
1756
    pd = (PostScriptDesc *) dd->deviceSpecific;
1755
 
1757
 
1756
    /* code is set as follows */
1758
    /* code is set as follows */
1757
    /* code == 0, nothing to draw */
1759
    /* code == 0, nothing to draw */
1758
    /* code == 1, outline only */
1760
    /* code == 1, outline only */
1759
    /* code == 2, fill only */
1761
    /* code == 2, fill only */
1760
    /* code == 3, outline and fill */
1762
    /* code == 3, outline and fill */
1761
 
1763
 
1762
    code = 2 * (R_ALPHA(gc->fill) == 0) + (R_ALPHA(gc->col) == 0);
1764
    code = 2 * (R_ALPHA(gc->fill) == 0) + (R_ALPHA(gc->col) == 0);
1763
 
1765
 
1764
    if (code) {
1766
    if (code) {
1765
	if(code & 2)
1767
	if(code & 2)
1766
	    SetFill(gc->fill, dd);
1768
	    SetFill(gc->fill, dd);
1767
	if(code & 1) {
1769
	if(code & 1) {
1768
	    SetColor(gc->col, dd);
1770
	    SetColor(gc->col, dd);
1769
	    SetLineStyle(gc->lty, gc->lwd, dd);
1771
	    SetLineStyle(gc->lty, gc->lwd, dd);
1770
	}
1772
	}
1771
	fprintf(pd->psfp, "np\n");
1773
	fprintf(pd->psfp, "np\n");
1772
	fprintf(pd->psfp, " %.2f %.2f m\n", x[0], y[0]);
1774
	fprintf(pd->psfp, " %.2f %.2f m\n", x[0], y[0]);
1773
	for(i = 1 ; i < n ; i++)
1775
	for(i = 1 ; i < n ; i++)
1774
	    if (i % 100 == 0)
1776
	    if (i % 100 == 0)
1775
		fprintf(pd->psfp, "%.2f %.2f lineto\n", x[i], y[i]);
1777
		fprintf(pd->psfp, "%.2f %.2f lineto\n", x[i], y[i]);
1776
	    else
1778
	    else
1777
		PostScriptRLineTo(pd->psfp, x[i-1], y[i-1], x[i], y[i]);
1779
		PostScriptRLineTo(pd->psfp, x[i-1], y[i-1], x[i], y[i]);
1778
	fprintf(pd->psfp, "cp p%d\n", code);
1780
	fprintf(pd->psfp, "cp p%d\n", code);
1779
    }
1781
    }
1780
}
1782
}
1781
 
1783
 
1782
static void PS_Polyline(int n, double *x, double *y,
1784
static void PS_Polyline(int n, double *x, double *y,
1783
			R_GE_gcontext *gc,
1785
			R_GE_gcontext *gc,
1784
			NewDevDesc *dd)
1786
			NewDevDesc *dd)
1785
{
1787
{
1786
    PostScriptDesc *pd;
1788
    PostScriptDesc *pd;
1787
    int i;
1789
    int i;
1788
 
1790
 
1789
    pd = (PostScriptDesc*) dd->deviceSpecific;
1791
    pd = (PostScriptDesc*) dd->deviceSpecific;
1790
    if(R_ALPHA(gc->col) == 0) {
1792
    if(R_ALPHA(gc->col) == 0) {
1791
	SetColor(gc->col, dd);
1793
	SetColor(gc->col, dd);
1792
	SetLineStyle(gc->lty, gc->lwd, dd);
1794
	SetLineStyle(gc->lty, gc->lwd, dd);
1793
	fprintf(pd->psfp, "np\n");
1795
	fprintf(pd->psfp, "np\n");
1794
	fprintf(pd->psfp, "%.2f %.2f m\n", x[0], y[0]);
1796
	fprintf(pd->psfp, "%.2f %.2f m\n", x[0], y[0]);
1795
	for(i = 1 ; i < n ; i++) {
1797
	for(i = 1 ; i < n ; i++) {
1796
	    /* split up solid lines (only) into chunks of size 1000 */
1798
	    /* split up solid lines (only) into chunks of size 1000 */
1797
	    if(gc->lty == 0 && i%1000 == 0)
1799
	    if(gc->lty == 0 && i%1000 == 0)
1798
		fprintf(pd->psfp, "currentpoint o m\n");
1800
		fprintf(pd->psfp, "currentpoint o m\n");
1799
	    if (i % 100 == 0)
1801
	    if (i % 100 == 0)
1800
		fprintf(pd->psfp, "%.2f %.2f lineto\n", x[i], y[i]);
1802
		fprintf(pd->psfp, "%.2f %.2f lineto\n", x[i], y[i]);
1801
	    else
1803
	    else
1802
		PostScriptRLineTo(pd->psfp, x[i-1], y[i-1], x[i], y[i]);
1804
		PostScriptRLineTo(pd->psfp, x[i-1], y[i-1], x[i], y[i]);
1803
	}
1805
	}
1804
	fprintf(pd->psfp, "o\n");
1806
	fprintf(pd->psfp, "o\n");
1805
    }
1807
    }
1806
}
1808
}
1807
 
1809
 
1808
 
1810
 
1809
static void PS_Text(double x, double y, char *str,
1811
static void PS_Text(double x, double y, char *str,
1810
		    double rot, double hadj,
1812
		    double rot, double hadj,
1811
		    R_GE_gcontext *gc,
1813
		    R_GE_gcontext *gc,
1812
		    NewDevDesc *dd)
1814
		    NewDevDesc *dd)
1813
{
1815
{
1814
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
1816
    PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
1815
 
1817
 
1816
    SetFont(gc->fontface, (int)floor(gc->cex * gc->ps + 0.5), dd);
1818
    SetFont(gc->fontface, (int)floor(gc->cex * gc->ps + 0.5), dd);
1817
    if(R_ALPHA(gc->col) == 0) {
1819
    if(R_ALPHA(gc->col) == 0) {
1818
	SetColor(gc->col, dd);
1820
	SetColor(gc->col, dd);
1819
	PostScriptText(pd->psfp, x, y, str, hadj, 0.0, rot);
1821
	PostScriptText(pd->psfp, x, y, str, hadj, 0.0, rot);
1820
    }
1822
    }
1821
}
1823
}
1822
 
1824
 
1823
static Rboolean PS_Locator(double *x, double *y, NewDevDesc *dd)
1825
static Rboolean PS_Locator(double *x, double *y, NewDevDesc *dd)
1824
{
1826
{
1825
    return FALSE;
1827
    return FALSE;
1826
}
1828
}
1827
 
1829
 
1828
static void PS_Mode(int mode, NewDevDesc* dd)
1830
static void PS_Mode(int mode, NewDevDesc* dd)
1829
{
1831
{
1830
}
1832
}
1831
 
1833
 
1832
static void PS_Hold(NewDevDesc *dd)
1834
static void PS_Hold(NewDevDesc *dd)
1833
{
1835
{
1834
}
1836
}
1835
 
1837
 
1836
 
1838
 
1837
 
1839
 
1838
/***********************************************************************
1840
/***********************************************************************
1839
 
1841
 
1840
                 XFig driver shares font handling
1842
                 XFig driver shares font handling
1841
 
1843
 
1842
************************************************************************/
1844
************************************************************************/
1843
 
1845
 
1844
 
1846
 
1845
 
1847
 
1846
typedef struct {
1848
typedef struct {
1847
    char filename[PATH_MAX];
1849
    char filename[PATH_MAX];
1848
 
1850
 
1849
    char papername[64];	 /* paper name */
1851
    char papername[64];	 /* paper name */
1850
    int paperwidth;	 /* paper width in big points (1/72 in) */
1852
    int paperwidth;	 /* paper width in big points (1/72 in) */
1851
    int paperheight;	 /* paper height in big points */
1853
    int paperheight;	 /* paper height in big points */
1852
    Rboolean landscape;	 /* landscape mode */
1854
    Rboolean landscape;	 /* landscape mode */
1853
    int pageno;		 /* page number */
1855
    int pageno;		 /* page number */
1854
 
1856
 
1855
    int fontfamily;	 /* font family */
1857
    int fontfamily;	 /* font family */
1856
    int fontnum;	 /* font number in XFig */
1858
    int fontnum;	 /* font number in XFig */
1857
    int fontstyle;	 /* font style, R, B, I, BI, S */
1859
    int fontstyle;	 /* font style, R, B, I, BI, S */
1858
    int fontsize;	 /* font size in points */
1860
    int fontsize;	 /* font size in points */
1859
    int maxpointsize;
1861
    int maxpointsize;
1860
 
1862
 
1861
    double width;	 /* plot width in inches */
1863
    double width;	 /* plot width in inches */
1862
    double height;	 /* plot height in inches */
1864
    double height;	 /* plot height in inches */
1863
    double pagewidth;	 /* page width in inches */
1865
    double pagewidth;	 /* page width in inches */
1864
    double pageheight;	 /* page height in inches */
1866
    double pageheight;	 /* page height in inches */
1865
    Rboolean pagecentre;      /* centre image on page? */
1867
    Rboolean pagecentre;      /* centre image on page? */
1866
 
1868
 
1867
    double lwd;		 /* current line width */
1869
    double lwd;		 /* current line width */
1868
    int lty;		 /* current line type */
1870
    int lty;		 /* current line type */
1869
    rcolor col;		 /* current color */
1871
    rcolor col;		 /* current color */
1870
    rcolor fill;	 /* current fill color */
1872
    rcolor fill;	 /* current fill color */
1871
    rcolor bg;		 /* background color */
1873
    rcolor bg;		 /* background color */
1872
    int XFigColors[534];
1874
    int XFigColors[534];
1873
    int nXFigColors;
1875
    int nXFigColors;
1874
 
1876
 
1875
    FILE *psfp;		 /* output file */
1877
    FILE *psfp;		 /* output file */
1876
    FILE *tmpfp;         /* temp file */
1878
    FILE *tmpfp;         /* temp file */
1877
    char tmpname[PATH_MAX];
1879
    char tmpname[PATH_MAX];
1878
 
1880
 
1879
    Rboolean onefile;
1881
    Rboolean onefile;
1880
    int ymax;            /* used to invert coord system */
1882
    int ymax;            /* used to invert coord system */
1881
 
1883
 
1882
    FontMetricInfo metrics[5];	/* font metrics */
1884
    FontMetricInfo metrics[5];	/* font metrics */
1883
 
1885
 
1884
} XFigDesc;
1886
} XFigDesc;
1885
 
1887
 
1886
static void
1888
static void
1887
XF_FileHeader(FILE *fp, char *papername, Rboolean landscape, Rboolean onefile)
1889
XF_FileHeader(FILE *fp, char *papername, Rboolean landscape, Rboolean onefile)
1888
{
1890
{
1889
    fprintf(fp, "#FIG 3.2\n");
1891
    fprintf(fp, "#FIG 3.2\n");
1890
    fprintf(fp, landscape ? "Landscape\n" : "Portrait\n");
1892
    fprintf(fp, landscape ? "Landscape\n" : "Portrait\n");
1891
    fprintf(fp, "Flush Left\nInches\n");
1893
    fprintf(fp, "Flush Left\nInches\n");
1892
    /* Fix */fprintf(fp, "%s\n", papername);
1894
    /* Fix */fprintf(fp, "%s\n", papername);
1893
    fprintf(fp, "100.0\n");
1895
    fprintf(fp, "100.0\n");
1894
    fprintf(fp, onefile ? "Multiple\n" : "Single\n");
1896
    fprintf(fp, onefile ? "Multiple\n" : "Single\n");
1895
    fprintf(fp, "-2\n"); /* no background */
1897
    fprintf(fp, "-2\n"); /* no background */
1896
    fprintf(fp, "1200 2\n"); /* coordinate system */
1898
    fprintf(fp, "1200 2\n"); /* coordinate system */
1897
    fprintf(fp, "# End of XFig header\n");
1899
    fprintf(fp, "# End of XFig header\n");
1898
}
1900
}
1899
 
1901
 
1900
static void XF_FileTrailer(FILE *fp)
1902
static void XF_FileTrailer(FILE *fp)
1901
{
1903
{
1902
    fprintf(fp, "# end of XFig file\n");
1904
    fprintf(fp, "# end of XFig file\n");
1903
}
1905
}
1904
 
1906
 
1905
 
1907
 
1906
static void XF_EndPage(FILE *fp)
1908
static void XF_EndPage(FILE *fp)
1907
{
1909
{
1908
    fprintf(fp, "# end of XFig page\n");
1910
    fprintf(fp, "# end of XFig page\n");
1909
}
1911
}
1910
 
1912
 
1911
static void XF_WriteString(FILE *fp, char *str)
1913
static void XF_WriteString(FILE *fp, char *str)
1912
{
1914
{
1913
    unsigned int c;
1915
    unsigned int c;
1914
    for ( ; *str; str++) {
1916
    for ( ; *str; str++) {
1915
	c = (unsigned char)*str;
1917
	c = (unsigned char)*str;
1916
	if (c > 127) {
1918
	if (c > 127) {
1917
	    fprintf(fp, "\\%o", c);
1919
	    fprintf(fp, "\\%o", c);
1918
	} else {
1920
	} else {
1919
	    switch(*str) {
1921
	    switch(*str) {
1920
	    case '\n':
1922
	    case '\n':
1921
		fprintf(fp, "\\n");
1923
		fprintf(fp, "\\n");
1922
		break;
1924
		break;
1923
	    case '\\':
1925
	    case '\\':
1924
		fprintf(fp, "\\\\");
1926
		fprintf(fp, "\\\\");
1925
		break;
1927
		break;
1926
	    default:
1928
	    default:
1927
		fputc(*str, fp);
1929
		fputc(*str, fp);
1928
		break;
1930
		break;
1929
	    }
1931
	    }
1930
	}
1932
	}
1931
    }
1933
    }
1932
}
1934
}
1933
 
1935
 
1934
static int XF_SetColor(int color, XFigDesc *pd)
1936
static int XF_SetColor(int color, XFigDesc *pd)
1935
{
1937
{
1936
    int i;
1938
    int i;
1937
    if (color <0 || color > 0xffffff) return -1;
1939
    if (color <0 || color > 0xffffff) return -1;
1938
    for (i = 0; i < pd->nXFigColors; i++)
1940
    for (i = 0; i < pd->nXFigColors; i++)
1939
    {
1941
    {
1940
	if(color == pd->XFigColors[i]) return i;
1942
	if(color == pd->XFigColors[i]) return i;
1941
    }
1943
    }
1942
    if(pd->nXFigColors == 534) {
1944
    if(pd->nXFigColors == 534) {
1943
	error("run out of colors in xfig()");
1945
	error("run out of colors in xfig()");
1944
    }
1946
    }
1945
    /* new colour */
1947
    /* new colour */
1946
    fprintf(pd->psfp, "0 %d #%02x%02x%02x\n", pd->nXFigColors,
1948
    fprintf(pd->psfp, "0 %d #%02x%02x%02x\n", pd->nXFigColors,
1947
	    R_RED(color), R_GREEN(color), R_BLUE(color));
1949
	    R_RED(color), R_GREEN(color), R_BLUE(color));
1948
    pd->XFigColors[pd->nXFigColors] = color;
1950
    pd->XFigColors[pd->nXFigColors] = color;
1949
    return pd->nXFigColors++;
1951
    return pd->nXFigColors++;
1950
}
1952
}
1951
 
1953
 
1952
static void XFconvert(double *x, double *y, XFigDesc *pd)
1954
static void XFconvert(double *x, double *y, XFigDesc *pd)
1953
{
1955
{
1954
    (*x) *= 16.667;
1956
    (*x) *= 16.667;
1955
    (*y) = pd->ymax - 16.667*(*y);
1957
    (*y) = pd->ymax - 16.667*(*y);
1956
}
1958
}
1957
 
1959
 
1958
 
1960
 
1959
static int XF_SetLty(int lty)
1961
static int XF_SetLty(int lty)
1960
{
1962
{
1961
    switch(lty) {
1963
    switch(lty) {
1962
    case LTY_SOLID:
1964
    case LTY_SOLID:
1963
	return 0;
1965
	return 0;
1964
    case LTY_DASHED:
1966
    case LTY_DASHED:
1965
	return 1;
1967
	return 1;
1966
    case LTY_DOTTED:
1968
    case LTY_DOTTED:
1967
	return 2;
1969
	return 2;
1968
    case LTY_DOTDASH:
1970
    case LTY_DOTDASH:
1969
	return 3;
1971
	return 3;
1970
    default:
1972
    default:
1971
	warning("unimplemented line texture %u: using Dash-double-dotted",
1973
	warning("unimplemented line texture %u: using Dash-double-dotted",
1972
		lty);
1974
		lty);
1973
	return 4;
1975
	return 4;
1974
    }
1976
    }
1975
}
1977
}
1976
 
1978
 
1977
/* Device Driver Actions */
1979
/* Device Driver Actions */
1978
 
1980
 
1979
static void XFig_Activate(NewDevDesc *dd);
1981
static void XFig_Activate(NewDevDesc *dd);
1980
static void XFig_Circle(double x, double y, double r,
1982
static void XFig_Circle(double x, double y, double r,
1981
			R_GE_gcontext *gc,
1983
			R_GE_gcontext *gc,
1982
			NewDevDesc *dd);
1984
			NewDevDesc *dd);
1983
static void XFig_Clip(double x0, double x1, double y0, double y1,
1985
static void XFig_Clip(double x0, double x1, double y0, double y1,
1984
		     NewDevDesc *dd);
1986
		     NewDevDesc *dd);
1985
static void XFig_Close(NewDevDesc *dd);
1987
static void XFig_Close(NewDevDesc *dd);
1986
static void XFig_Deactivate(NewDevDesc *dd);
1988
static void XFig_Deactivate(NewDevDesc *dd);
1987
static void XFig_Hold(NewDevDesc *dd);
1989
static void XFig_Hold(NewDevDesc *dd);
1988
static Rboolean XFig_Locator(double *x, double *y, NewDevDesc *dd);
1990
static Rboolean XFig_Locator(double *x, double *y, NewDevDesc *dd);
1989
static void XFig_Line(double x1, double y1, double x2, double y2,
1991
static void XFig_Line(double x1, double y1, double x2, double y2,
1990
		      R_GE_gcontext *gc,
1992
		      R_GE_gcontext *gc,
1991
		      NewDevDesc *dd);
1993
		      NewDevDesc *dd);
1992
static void XFig_MetricInfo(int c, 
1994
static void XFig_MetricInfo(int c, 
1993
			    R_GE_gcontext *gc,
1995
			    R_GE_gcontext *gc,
1994
			    double* ascent, double* descent,
1996
			    double* ascent, double* descent,
1995
			    double* width, NewDevDesc *dd);
1997
			    double* width, NewDevDesc *dd);
1996
static void XFig_Mode(int mode, NewDevDesc *dd);
1998
static void XFig_Mode(int mode, NewDevDesc *dd);
1997
static void XFig_NewPage(R_GE_gcontext *gc, NewDevDesc *dd);
1999
static void XFig_NewPage(R_GE_gcontext *gc, NewDevDesc *dd);
1998
static void XFig_Polygon(int n, double *x, double *y,
2000
static void XFig_Polygon(int n, double *x, double *y,
1999
			 R_GE_gcontext *gc,
2001
			 R_GE_gcontext *gc,
2000
			 NewDevDesc *dd);
2002
			 NewDevDesc *dd);
2001
static void XFig_Polyline(int n, double *x, double *y,
2003
static void XFig_Polyline(int n, double *x, double *y,
2002
			  R_GE_gcontext *gc,
2004
			  R_GE_gcontext *gc,
2003
			  NewDevDesc *dd);
2005
			  NewDevDesc *dd);
2004
static void XFig_Rect(double x0, double y0, double x1, double y1,
2006
static void XFig_Rect(double x0, double y0, double x1, double y1,
2005
		      R_GE_gcontext *gc,
2007
		      R_GE_gcontext *gc,
2006
		      NewDevDesc *dd);
2008
		      NewDevDesc *dd);
2007
static void XFig_Size(double *left, double *right,
2009
static void XFig_Size(double *left, double *right,
2008
		     double *bottom, double *top,
2010
		     double *bottom, double *top,
2009
		     NewDevDesc *dd);
2011
		     NewDevDesc *dd);
2010
static double XFig_StrWidth(char *str, 
2012
static double XFig_StrWidth(char *str, 
2011
			    R_GE_gcontext *gc,
2013
			    R_GE_gcontext *gc,
2012
			    NewDevDesc *dd);
2014
			    NewDevDesc *dd);
2013
static void XFig_Text(double x, double y, char *str,
2015
static void XFig_Text(double x, double y, char *str,
2014
		      double rot, double hadj,
2016
		      double rot, double hadj,
2015
		      R_GE_gcontext *gc,
2017
		      R_GE_gcontext *gc,
2016
		      NewDevDesc *dd);
2018
		      NewDevDesc *dd);
2017
static Rboolean XFig_Open(NewDevDesc*, XFigDesc*);
2019
static Rboolean XFig_Open(NewDevDesc*, XFigDesc*);
2018
 
2020
 
2019
static const int XFig_basenums[] = {4, 8, 12, 16, 20, 24, 28, 0};
2021
static const int XFig_basenums[] = {4, 8, 12, 16, 20, 24, 28, 0};
2020
 
2022
 
2021
 
2023
 
2022
/* Driver Support Routines */
2024
/* Driver Support Routines */
2023
 
2025
 
2024
static Rboolean
2026
static Rboolean
2025
innerXFigDeviceDriver(NewDevDesc *dd, char *file, char *paper, char *family,
2027
innerXFigDeviceDriver(NewDevDesc *dd, char *file, char *paper, char *family,
2026
		      char *bg, char *fg,
2028
		      char *bg, char *fg,
2027
		      double width, double height,
2029
		      double width, double height,
2028
		      Rboolean horizontal, double ps,
2030
		      Rboolean horizontal, double ps,
2029
		      Rboolean onefile, Rboolean pagecentre)
2031
		      Rboolean onefile, Rboolean pagecentre)
2030
{
2032
{
2031
    /* If we need to bail out with some sort of "error" */
2033
    /* If we need to bail out with some sort of "error" */
2032
    /* then we must free(dd) */
2034
    /* then we must free(dd) */
2033
 
2035
 
2034
    double xoff, yoff, pointsize;
2036
    double xoff, yoff, pointsize;
2035
    XFigDesc *pd;
2037
    XFigDesc *pd;
2036
 
2038
 
2037
    /* Check and extract the device parameters */
2039
    /* Check and extract the device parameters */
2038
 
2040
 
2039
    if(strlen(file) > PATH_MAX - 1) {
2041
    if(strlen(file) > PATH_MAX - 1) {
2040
	free(dd);
2042
	free(dd);
2041
	error("filename too long in xfig");
2043
	error("filename too long in xfig");
2042
    }
2044
    }
2043
 
2045
 
2044
    /* allocate new xfig device description */
2046
    /* allocate new xfig device description */
2045
    if (!(pd = (XFigDesc *) malloc(sizeof(XFigDesc))))
2047
    if (!(pd = (XFigDesc *) malloc(sizeof(XFigDesc))))
2046
	return 0;
2048
	return 0;
2047
 
2049
 
2048
    /* from here on, if need to bail out with "error", must also */
2050
    /* from here on, if need to bail out with "error", must also */
2049
    /* free(pd) */
2051
    /* free(pd) */
2050
 
2052
 
2051
    /* initialize xfig device description */
2053
    /* initialize xfig device description */
2052
    strcpy(pd->filename, file);
2054
    strcpy(pd->filename, file);
2053
    strcpy(pd->papername, paper);
2055
    strcpy(pd->papername, paper);
2054
    pd->fontfamily = MatchFamily(family);
2056
    pd->fontfamily = MatchFamily(family);
2055
    pd->fontnum = XFig_basenums[pd->fontfamily];
2057
    pd->fontnum = XFig_basenums[pd->fontfamily];
2056
    pd->bg = str2col(bg);
2058
    pd->bg = str2col(bg);
2057
    pd->col = str2col(fg);
2059
    pd->col = str2col(fg);
2058
    pd->fill = NA_INTEGER;
2060
    pd->fill = NA_INTEGER;
2059
    pd->width = width;
2061
    pd->width = width;
2060
    pd->height = height;
2062
    pd->height = height;
2061
    pd->landscape = horizontal;
2063
    pd->landscape = horizontal;
2062
    pointsize = floor(ps);
2064
    pointsize = floor(ps);
2063
    if(pd->bg == NA_INTEGER && pd->col == NA_INTEGER) {
2065
    if(pd->bg == NA_INTEGER && pd->col == NA_INTEGER) {
2064
	free(dd);
2066
	free(dd);
2065
	free(pd);
2067
	free(pd);
2066
	error("invalid foreground/background color (xfig)");
2068
	error("invalid foreground/background color (xfig)");
2067
    }
2069
    }
2068
 
2070
 
2069
 
2071
 
2070
    /* Deal with paper and plot size and orientation */
2072
    /* Deal with paper and plot size and orientation */
2071
 
2073
 
2072
    if(!strcmp(pd->papername, "Default") ||
2074
    if(!strcmp(pd->papername, "Default") ||
2073
       !strcmp(pd->papername, "default")) {
2075
       !strcmp(pd->papername, "default")) {
2074
	SEXP s = STRING_ELT(GetOption(install("papersize"), R_NilValue), 0);
2076
	SEXP s = STRING_ELT(GetOption(install("papersize"), R_NilValue), 0);
2075
	if(s != NA_STRING && strlen(CHAR(s)) > 0)
2077
	if(s != NA_STRING && strlen(CHAR(s)) > 0)
2076
	    strcpy(pd->papername, CHAR(s));
2078
	    strcpy(pd->papername, CHAR(s));
2077
	else strcpy(pd->papername, "A4");
2079
	else strcpy(pd->papername, "A4");
2078
    }
2080
    }
2079
    if(!strcmp(pd->papername, "A4") ||
2081
    if(!strcmp(pd->papername, "A4") ||
2080
       !strcmp(pd->papername, "a4")) {
2082
       !strcmp(pd->papername, "a4")) {
2081
	strcpy(pd->papername, "A4");
2083
	strcpy(pd->papername, "A4");
2082
	pd->pagewidth  = 21.0 / 2.54;
2084
	pd->pagewidth  = 21.0 / 2.54;
2083
	pd->pageheight = 29.7 / 2.54;
2085
	pd->pageheight = 29.7 / 2.54;
2084
    }
2086
    }
2085
    else if(!strcmp(pd->papername, "Letter") ||
2087
    else if(!strcmp(pd->papername, "Letter") ||
2086
	    !strcmp(pd->papername, "letter")) {
2088
	    !strcmp(pd->papername, "letter")) {
2087
	strcpy(pd->papername, "Letter");
2089
	strcpy(pd->papername, "Letter");
2088
	pd->pagewidth  =  8.5;
2090
	pd->pagewidth  =  8.5;
2089
	pd->pageheight = 11.0;
2091
	pd->pageheight = 11.0;
2090
    }
2092
    }
2091
    else if(!strcmp(pd->papername, "Legal") ||
2093
    else if(!strcmp(pd->papername, "Legal") ||
2092
	    !strcmp(pd->papername, "legal")) {
2094
	    !strcmp(pd->papername, "legal")) {
2093
	strcpy(pd->papername, "Legal");
2095
	strcpy(pd->papername, "Legal");
2094
	pd->pagewidth  =  8.5;
2096
	pd->pagewidth  =  8.5;
2095
	pd->pageheight = 14.0;
2097
	pd->pageheight = 14.0;
2096
    }
2098
    }
2097
    else {
2099
    else {
2098
	free(dd);
2100
	free(dd);
2099
	free(pd);
2101
	free(pd);
2100
	error("invalid page type `%s' (xfig)", pd->papername);
2102
	error("invalid page type `%s' (xfig)", pd->papername);
2101
    }
2103
    }
2102
    pd->pagecentre = pagecentre;
2104
    pd->pagecentre = pagecentre;
2103
    pd->paperwidth = 72 * pd->pagewidth;
2105
    pd->paperwidth = 72 * pd->pagewidth;
2104
    pd->paperheight = 72 * pd->pageheight;
2106
    pd->paperheight = 72 * pd->pageheight;
2105
    if(!onefile) {
2107
    if(!onefile) {
2106
	char *p = strrchr(pd->filename, '%');
2108
	char *p = strrchr(pd->filename, '%');
2107
	if(!p)
2109
	if(!p)
2108
	    warning("xfig(%s, onefile=FALSE) will only return the last plot", pd->filename);
2110
	    warning("xfig(%s, onefile=FALSE) will only return the last plot", pd->filename);
2109
    }
2111
    }
2110
    if(pd->landscape) {
2112
    if(pd->landscape) {
2111
	double tmp;
2113
	double tmp;
2112
	tmp = pd->pagewidth;
2114
	tmp = pd->pagewidth;
2113
	pd->pagewidth = pd->pageheight;
2115
	pd->pagewidth = pd->pageheight;
2114
	pd->pageheight = tmp;
2116
	pd->pageheight = tmp;
2115
    }
2117
    }
2116
    if(pd->width < 0.1 || pd->width > pd->pagewidth-0.5)
2118
    if(pd->width < 0.1 || pd->width > pd->pagewidth-0.5)
2117
	pd->width = pd->pagewidth-0.5;
2119
	pd->width = pd->pagewidth-0.5;
2118
    if(pd->height < 0.1 || pd->height > pd->pageheight-0.5)
2120
    if(pd->height < 0.1 || pd->height > pd->pageheight-0.5)
2119
	pd->height = pd->pageheight-0.5;
2121
	pd->height = pd->pageheight-0.5;
2120
    if(pagecentre) {
2122
    if(pagecentre) {
2121
	xoff = (pd->pagewidth - pd->width)/2.0;
2123
	xoff = (pd->pagewidth - pd->width)/2.0;
2122
	yoff = (pd->pageheight - pd->height)/2.0;
2124
	yoff = (pd->pageheight - pd->height)/2.0;
2123
    } else {
2125
    } else {
2124
	xoff = yoff = 0.0;
2126
	xoff = yoff = 0.0;
2125
    }
2127
    }
2126
    if(pagecentre)
2128
    if(pagecentre)
2127
	pd->ymax = (int)(1200.0 * pd->pageheight);
2129
	pd->ymax = (int)(1200.0 * pd->pageheight);
2128
    else
2130
    else
2129
	pd->ymax = (int)(1200.0 * pd->height);
2131
	pd->ymax = (int)(1200.0 * pd->height);
2130
    pd->onefile = onefile;
2132
    pd->onefile = onefile;
2131
    pd->maxpointsize = 72.0 * ((pd->pageheight > pd->pagewidth) ?
2133
    pd->maxpointsize = 72.0 * ((pd->pageheight > pd->pagewidth) ?
2132
			       pd->pageheight : pd->pagewidth);
2134
			       pd->pageheight : pd->pagewidth);
2133
    pd->pageno = 0;
2135
    pd->pageno = 0;
2134
    /* Base Pointsize */
2136
    /* Base Pointsize */
2135
    /* Nominal Character Sizes in Pixels */
2137
    /* Nominal Character Sizes in Pixels */
2136
    /* Only right for 12 point font. */
2138
    /* Only right for 12 point font. */
2137
    /* Max pointsize suggested by Peter Dalgaard */
2139
    /* Max pointsize suggested by Peter Dalgaard */
2138
 
2140
 
2139
    if(pointsize < 6.0) pointsize = 6.0;
2141
    if(pointsize < 6.0) pointsize = 6.0;
2140
    if(pointsize > pd->maxpointsize) pointsize = pd->maxpointsize;
2142
    if(pointsize > pd->maxpointsize) pointsize = pd->maxpointsize;
2141
    dd->startps = pointsize;
2143
    dd->startps = pointsize;
2142
    dd->startlty = LTY_SOLID;
2144
    dd->startlty = LTY_SOLID;
2143
    dd->startfont = 1;
2145
    dd->startfont = 1;
2144
    dd->startfill = pd->bg;
2146
    dd->startfill = pd->bg;
2145
    dd->startcol = pd->col;
2147
    dd->startcol = pd->col;
2146
    dd->startgamma = 1;
2148
    dd->startgamma = 1;
2147
 
2149
 
2148
    /* Set graphics parameters that must be set by device driver. */
2150
    /* Set graphics parameters that must be set by device driver. */
2149
    /* Page dimensions in points. */
2151
    /* Page dimensions in points. */
2150
 
2152
 
2151
    dd->left = 72 * xoff;			/* left */
2153
    dd->left = 72 * xoff;			/* left */
2152
    dd->right = 72 * (xoff + pd->width);	/* right */
2154
    dd->right = 72 * (xoff + pd->width);	/* right */
2153
    dd->bottom = 72 * yoff;		/* bottom */
2155
    dd->bottom = 72 * yoff;		/* bottom */
2154
    dd->top = 72 * (yoff + pd->height);	/* top */
2156
    dd->top = 72 * (yoff + pd->height);	/* top */
2155
 
2157
 
2156
    dd->cra[0] = 0.9 * pointsize;
2158
    dd->cra[0] = 0.9 * pointsize;
2157
    dd->cra[1] = 1.2 * pointsize;
2159
    dd->cra[1] = 1.2 * pointsize;
2158
 
2160
 
2159
    /* Character Addressing Offsets */
2161
    /* Character Addressing Offsets */
2160
    /* These offsets should center a single */
2162
    /* These offsets should center a single */
2161
    /* plotting character over the plotting point. */
2163
    /* plotting character over the plotting point. */
2162
    /* Pure guesswork and eyeballing ... */
2164
    /* Pure guesswork and eyeballing ... */
2163
 
2165
 
2164
    dd->xCharOffset =  0.4900;
2166
    dd->xCharOffset =  0.4900;
2165
    dd->yCharOffset =  0.3333;
2167
    dd->yCharOffset =  0.3333;
2166
    dd->yLineBias = 0.2;
2168
    dd->yLineBias = 0.2;
2167
 
2169
 
2168
    /* Inches per Raster Unit */
2170
    /* Inches per Raster Unit */
2169
    /* 1200 dpi */
2171
    /* 1200 dpi */
2170
    dd->ipr[0] = 1.0/72.0;
2172
    dd->ipr[0] = 1.0/72.0;
2171
    dd->ipr[1] = 1.0/72.0;
2173
    dd->ipr[1] = 1.0/72.0;
2172
 
2174
 
2173
    dd->canResizePlot = 0;
2175
    dd->canResizePlot = 0;
2174
    dd->canChangeFont = 1;
2176
    dd->canChangeFont = 1;
2175
    dd->canRotateText = 1;
2177
    dd->canRotateText = 1;
2176
    dd->canResizeText = 1;
2178
    dd->canResizeText = 1;
2177
    dd->canClip = 0;
2179
    dd->canClip = 0;
2178
    dd->canHAdj = 1; /* 0, 0.5, 1 */
2180
    dd->canHAdj = 1; /* 0, 0.5, 1 */
2179
    dd->canChangeGamma = FALSE;
2181
    dd->canChangeGamma = FALSE;
2180
 
2182
 
2181
    pd->XFigColors[7] = 0xffffff;
2183
    pd->XFigColors[7] = 0xffffff;
2182
    pd->nXFigColors = 32;
2184
    pd->nXFigColors = 32;
2183
 
2185
 
2184
    /*	Start the driver */
2186
    /*	Start the driver */
2185
 
2187
 
2186
    if(!XFig_Open(dd, pd)) {
2188
    if(!XFig_Open(dd, pd)) {
2187
	free(pd);
2189
	free(pd);
2188
	return 0;
2190
	return 0;
2189
    }
2191
    }
2190
 
2192
 
2191
    dd->newDevStruct = 1;
2193
    dd->newDevStruct = 1;
2192
 
2194
 
2193
    dd->open	      = XFig_Open;
2195
    dd->open	      = XFig_Open;
2194
    dd->close      = XFig_Close;
2196
    dd->close      = XFig_Close;
2195
    dd->activate   = XFig_Activate;
2197
    dd->activate   = XFig_Activate;
2196
    dd->deactivate = XFig_Deactivate;
2198
    dd->deactivate = XFig_Deactivate;
2197
    dd->size     = XFig_Size;
2199
    dd->size     = XFig_Size;
2198
    dd->newPage    = XFig_NewPage;
2200
    dd->newPage    = XFig_NewPage;
2199
    dd->clip	      = XFig_Clip;
2201
    dd->clip	      = XFig_Clip;
2200
    dd->text	      = XFig_Text;
2202
    dd->text	      = XFig_Text;
2201
    dd->strWidth   = XFig_StrWidth;
2203
    dd->strWidth   = XFig_StrWidth;
2202
    dd->metricInfo = XFig_MetricInfo;
2204
    dd->metricInfo = XFig_MetricInfo;
2203
    dd->rect	      = XFig_Rect;
2205
    dd->rect	      = XFig_Rect;
2204
    dd->circle     = XFig_Circle;
2206
    dd->circle     = XFig_Circle;
2205
    dd->line	      = XFig_Line;
2207
    dd->line	      = XFig_Line;
2206
    dd->polygon    = XFig_Polygon;
2208
    dd->polygon    = XFig_Polygon;
2207
    dd->polyline   = XFig_Polyline;
2209
    dd->polyline   = XFig_Polyline;
2208
    dd->locator    = XFig_Locator;
2210
    dd->locator    = XFig_Locator;
2209
    dd->mode	      = XFig_Mode;
2211
    dd->mode	      = XFig_Mode;
2210
    dd->hold	      = XFig_Hold;
2212
    dd->hold	      = XFig_Hold;
2211
 
2213
 
2212
    dd->deviceSpecific = (void *) pd;
2214
    dd->deviceSpecific = (void *) pd;
2213
    dd->displayListOn = FALSE;
2215
    dd->displayListOn = FALSE;
2214
    return 1;
2216
    return 1;
2215
}
2217
}
2216
 
2218
 
2217
Rboolean
2219
Rboolean
2218
XFigDeviceDriver(DevDesc *dd, char *file, char *paper, char *family,
2220
XFigDeviceDriver(DevDesc *dd, char *file, char *paper, char *family,
2219
		 char *bg, char *fg,
2221
		 char *bg, char *fg,
2220
		 double width, double height,
2222
		 double width, double height,
2221
		 Rboolean horizontal, double ps,
2223
		 Rboolean horizontal, double ps,
2222
		 Rboolean onefile, Rboolean pagecentre)
2224
		 Rboolean onefile, Rboolean pagecentre)
2223
{
2225
{
2224
    return innerXFigDeviceDriver((NewDevDesc*) dd, file, paper, family,
2226
    return innerXFigDeviceDriver((NewDevDesc*) dd, file, paper, family,
2225
				 bg, fg, width, height, horizontal,
2227
				 bg, fg, width, height, horizontal,
2226
				 ps, onefile, pagecentre);
2228
				 ps, onefile, pagecentre);
2227
}
2229
}
2228
 
2230
 
2229
static Rboolean XFig_Open(NewDevDesc *dd, XFigDesc *pd)
2231
static Rboolean XFig_Open(NewDevDesc *dd, XFigDesc *pd)
2230
{
2232
{
2231
    char buf[512], name[50];
2233
    char buf[512], name[50];
2232
    int i;
2234
    int i;
2233
 
2235
 
2234
    if (!LoadEncoding("ISOLatin1.enc", buf, FALSE))
2236
    if (!LoadEncoding("ISOLatin1.enc", buf, FALSE))
2235
	error("problem loading encoding file");
2237
	error("problem loading encoding file");
2236
    for(i = 0; i < 4 ; i++) {
2238
    for(i = 0; i < 4 ; i++) {
2237
	if(!PostScriptLoadFontMetrics(Family[pd->fontfamily].afmfile[i],
2239
	if(!PostScriptLoadFontMetrics(Family[pd->fontfamily].afmfile[i],
2238
				      &(pd->metrics[i]), name, 1)) {
2240
				      &(pd->metrics[i]), name, 1)) {
2239
	    warning("cannot read afm file %s",
2241
	    warning("cannot read afm file %s",
2240
		    Family[pd->fontfamily].afmfile[i]);
2242
		    Family[pd->fontfamily].afmfile[i]);
2241
	    return FALSE;
2243
	    return FALSE;
2242
	}
2244
	}
2243
    }
2245
    }
2244
    if(!PostScriptLoadFontMetrics("sy______.afm",
2246
    if(!PostScriptLoadFontMetrics("sy______.afm",
2245
				  &(pd->metrics[4]), name, 0)) {
2247
				  &(pd->metrics[4]), name, 0)) {
2246
	warning("cannot read afm file sy______.afm");
2248
	warning("cannot read afm file sy______.afm");
2247
	return FALSE;
2249
	return FALSE;
2248
    }
2250
    }
2249
 
2251
 
2250
    if (strlen(pd->filename) == 0) {
2252
    if (strlen(pd->filename) == 0) {
2251
	error("empty file name");
2253
	error("empty file name");
2252
	return FALSE;
2254
	return FALSE;
2253
    } else {
2255
    } else {
2254
	snprintf(buf, 512, pd->filename, pd->pageno + 1); /* page 1 to start */
2256
	snprintf(buf, 512, pd->filename, pd->pageno + 1); /* page 1 to start */
2255
	pd->psfp = R_fopen(R_ExpandFileName(buf), "w");
2257
	pd->psfp = R_fopen(R_ExpandFileName(buf), "w");
2256
    }
2258
    }
2257
    if (!pd->psfp) return FALSE;
2259
    if (!pd->psfp) return FALSE;
2258
    /* assume tmpname is less than PATH_MAX */
2260
    /* assume tmpname is less than PATH_MAX */
2259
    strcpy(pd->tmpname, R_tmpnam("Rxfig", R_TempDir));
2261
    strcpy(pd->tmpname, R_tmpnam("Rxfig", R_TempDir));
2260
    pd->tmpfp = R_fopen(pd->tmpname, "w");
2262
    pd->tmpfp = R_fopen(pd->tmpname, "w");
2261
    if (!pd->tmpfp) {
2263
    if (!pd->tmpfp) {
2262
	fclose(pd->psfp);
2264
	fclose(pd->psfp);
2263
	return FALSE;
2265
	return FALSE;
2264
    }
2266
    }
2265
    XF_FileHeader(pd->psfp, pd->papername, pd->landscape, pd->onefile);
2267
    XF_FileHeader(pd->psfp, pd->papername, pd->landscape, pd->onefile);
2266
    pd->fontstyle = 1;
2268
    pd->fontstyle = 1;
2267
    pd->fontsize = 10;
2269
    pd->fontsize = 10;
2268
    pd->pageno = 0;
2270
    pd->pageno = 0;
2269
    return TRUE;
2271
    return TRUE;
2270
}
2272
}
2271
 
2273
 
2272
 
2274
 
2273
static void XFig_Clip(double x0, double x1, double y0, double y1, NewDevDesc *dd)
2275
static void XFig_Clip(double x0, double x1, double y0, double y1, NewDevDesc *dd)
2274
{
2276
{
2275
}
2277
}
2276
 
2278
 
2277
static void XFig_Size(double *left, double *right,
2279
static void XFig_Size(double *left, double *right,
2278
		      double *bottom, double *top,
2280
		      double *bottom, double *top,
2279
		      NewDevDesc *dd)
2281
		      NewDevDesc *dd)
2280
{
2282
{
2281
    *left = dd->left;
2283
    *left = dd->left;
2282
    *right = dd->right;
2284
    *right = dd->right;
2283
    *bottom = dd->bottom;
2285
    *bottom = dd->bottom;
2284
    *top = dd->top;
2286
    *top = dd->top;
2285
}
2287
}
2286
 
2288
 
2287
#define CHUNK 10000
2289
#define CHUNK 10000
2288
static void XFig_NewPage(R_GE_gcontext *gc,
2290
static void XFig_NewPage(R_GE_gcontext *gc,
2289
			 NewDevDesc *dd)
2291
			 NewDevDesc *dd)
2290
{
2292
{
2291
    char buf[PATH_MAX];
2293
    char buf[PATH_MAX];
2292
    XFigDesc *pd = (XFigDesc *) dd->deviceSpecific;
2294
    XFigDesc *pd = (XFigDesc *) dd->deviceSpecific;
2293
    FILE *fp = pd->tmpfp;
2295
    FILE *fp = pd->tmpfp;
2294
 
2296
 
2295
    pd->pageno++;
2297
    pd->pageno++;
2296
    if(pd->onefile) {
2298
    if(pd->onefile) {
2297
	fprintf(pd->tmpfp, "#Start of page %d\n", pd->pageno);
2299
	fprintf(pd->tmpfp, "#Start of page %d\n", pd->pageno);
2298
	if(pd->pageno > 1) XF_EndPage(pd->tmpfp);
2300
	if(pd->pageno > 1) XF_EndPage(pd->tmpfp);
2299
    } else {
2301
    } else {
2300
	char buffer[CHUNK];
2302
	char buffer[CHUNK];
2301
	size_t nread;
2303
	size_t nread;
2302
	if(pd->pageno == 1) return;
2304
	if(pd->pageno == 1) return;
2303
	XF_FileTrailer(pd->tmpfp);
2305
	XF_FileTrailer(pd->tmpfp);
2304
	fclose(pd->tmpfp);
2306
	fclose(pd->tmpfp);
2305
	pd->tmpfp = R_fopen(pd->tmpname, "r");
2307
	pd->tmpfp = R_fopen(pd->tmpname, "r");
2306
	while(1) {
2308
	while(1) {
2307
	    nread = fread(buffer, 1, CHUNK, pd->tmpfp);
2309
	    nread = fread(buffer, 1, CHUNK, pd->tmpfp);
2308
	    if(nread > 0) fwrite(buffer, 1, nread, pd->psfp);
2310
	    if(nread > 0) fwrite(buffer, 1, nread, pd->psfp);
2309
	    if(nread < CHUNK) break;
2311
	    if(nread < CHUNK) break;
2310
	}
2312
	}
2311
	fclose(pd->tmpfp);
2313
	fclose(pd->tmpfp);
2312
	fclose(pd->psfp);
2314
	fclose(pd->psfp);
2313
	snprintf(buf, PATH_MAX, pd->filename, pd->pageno);
2315
	snprintf(buf, PATH_MAX, pd->filename, pd->pageno);
2314
	pd->psfp = R_fopen(R_ExpandFileName(buf), "w");
2316
	pd->psfp = R_fopen(R_ExpandFileName(buf), "w");
2315
	pd->tmpfp = R_fopen(pd->tmpname, "w");
2317
	pd->tmpfp = R_fopen(pd->tmpname, "w");
2316
	XF_FileHeader(pd->psfp, pd->papername, pd->landscape, pd->onefile);
2318
	XF_FileHeader(pd->psfp, pd->papername, pd->landscape, pd->onefile);
2317
	pd->XFigColors[7] = 0xffffff;
2319
	pd->XFigColors[7] = 0xffffff;
2318
	pd->nXFigColors = 32;
2320
	pd->nXFigColors = 32;
2319
    }
2321
    }
2320
     if(R_ALPHA(gc->fill) == 0) {
2322
     if(R_ALPHA(gc->fill) == 0) {
2321
	 int cbg = XF_SetColor(gc->fill, pd);
2323
	 int cbg = XF_SetColor(gc->fill, pd);
2322
	 int ix0, iy0, ix1, iy1;
2324
	 int ix0, iy0, ix1, iy1;
2323
	 double x0 = 0.0, y0 = 0.0, x1 = 72.0 * pd->pagewidth,
2325
	 double x0 = 0.0, y0 = 0.0, x1 = 72.0 * pd->pagewidth,
2324
	     y1 = 72.0 * pd->pageheight;
2326
	     y1 = 72.0 * pd->pageheight;
2325
	 XFconvert(&x0, &y0, pd); XFconvert(&x1, &y1, pd);
2327
	 XFconvert(&x0, &y0, pd); XFconvert(&x1, &y1, pd);
2326
	 ix0 = (int)x0; iy0 = (int)y0; ix1 = (int)x1; iy1 = (int)y1;
2328
	 ix0 = (int)x0; iy0 = (int)y0; ix1 = (int)x1; iy1 = (int)y1;
2327
	 fprintf(fp, "2 2 "); /* Polyline */
2329
	 fprintf(fp, "2 2 "); /* Polyline */
2328
	 fprintf(fp, "%d %d ", 0, 0); /* style, thickness */
2330
	 fprintf(fp, "%d %d ", 0, 0); /* style, thickness */
2329
	 fprintf(fp, "%d %d ", cbg, cbg); /* pen colour fill colour */
2331
	 fprintf(fp, "%d %d ", cbg, cbg); /* pen colour fill colour */
2330
	 fprintf(fp, "200 0 20 4.0 0 0 -1 0 0 ");
2332
	 fprintf(fp, "200 0 20 4.0 0 0 -1 0 0 ");
2331
	 fprintf(fp, "%d\n", 5); /* number of points */
2333
	 fprintf(fp, "%d\n", 5); /* number of points */
2332
	 fprintf(fp, "%d %d ", ix0, iy0);
2334
	 fprintf(fp, "%d %d ", ix0, iy0);
2333
	 fprintf(fp, "%d %d ", ix0, iy1);
2335
	 fprintf(fp, "%d %d ", ix0, iy1);
2334
	 fprintf(fp, "%d %d ", ix1, iy1);
2336
	 fprintf(fp, "%d %d ", ix1, iy1);
2335
	 fprintf(fp, "%d %d ", ix1, iy0);
2337
	 fprintf(fp, "%d %d ", ix1, iy0);
2336
	 fprintf(fp, "%d %d\n", ix0, iy0);
2338
	 fprintf(fp, "%d %d\n", ix0, iy0);
2337
   }
2339
   }
2338
}
2340
}
2339
 
2341
 
2340
#ifdef HAVE_UNISTD_H
2342
#ifdef HAVE_UNISTD_H
2341
#include <unistd.h>
2343
#include <unistd.h>
2342
#endif
2344
#endif
2343
 
2345
 
2344
static void XFig_Close(NewDevDesc *dd)
2346
static void XFig_Close(NewDevDesc *dd)
2345
{
2347
{
2346
    char buf[CHUNK];
2348
    char buf[CHUNK];
2347
    size_t nread;
2349
    size_t nread;
2348
    XFigDesc *pd = (XFigDesc *) dd->deviceSpecific;
2350
    XFigDesc *pd = (XFigDesc *) dd->deviceSpecific;
2349
 
2351
 
2350
    XF_FileTrailer(pd->tmpfp);
2352
    XF_FileTrailer(pd->tmpfp);
2351
    fclose(pd->tmpfp);
2353
    fclose(pd->tmpfp);
2352
    pd->tmpfp = R_fopen(pd->tmpname, "r");
2354
    pd->tmpfp = R_fopen(pd->tmpname, "r");
2353
    while(1) {
2355
    while(1) {
2354
	nread = fread(buf, 1, CHUNK, pd->tmpfp);
2356
	nread = fread(buf, 1, CHUNK, pd->tmpfp);
2355
	if(nread > 0) fwrite(buf, 1, nread, pd->psfp);
2357
	if(nread > 0) fwrite(buf, 1, nread, pd->psfp);
2356
	if(nread < CHUNK) break;
2358
	if(nread < CHUNK) break;
2357
    }
2359
    }
2358
    fclose(pd->tmpfp);
2360
    fclose(pd->tmpfp);
2359
    unlink(pd->tmpname);
2361
    unlink(pd->tmpname);
2360
    fclose(pd->psfp);
2362
    fclose(pd->psfp);
2361
    free(pd);
2363
    free(pd);
2362
}
2364
}
2363
 
2365
 
2364
static void XFig_Activate(NewDevDesc *dd) {}
2366
static void XFig_Activate(NewDevDesc *dd) {}
2365
static void XFig_Deactivate(NewDevDesc *dd) {}
2367
static void XFig_Deactivate(NewDevDesc *dd) {}
2366
 
2368
 
2367
static void XFig_Rect(double x0, double y0, double x1, double y1,
2369
static void XFig_Rect(double x0, double y0, double x1, double y1,
2368
		      R_GE_gcontext *gc,
2370
		      R_GE_gcontext *gc,
2369
		      NewDevDesc *dd)
2371
		      NewDevDesc *dd)
2370
{
2372
{
2371
    XFigDesc *pd = (XFigDesc *) dd->deviceSpecific;
2373
    XFigDesc *pd = (XFigDesc *) dd->deviceSpecific;
2372
    FILE *fp = pd->tmpfp;
2374
    FILE *fp = pd->tmpfp;
2373
    int ix0, iy0, ix1, iy1;
2375
    int ix0, iy0, ix1, iy1;
2374
    int cbg = XF_SetColor(gc->fill, pd), cfg = XF_SetColor(gc->col, pd), cpen,
2376
    int cbg = XF_SetColor(gc->fill, pd), cfg = XF_SetColor(gc->col, pd), cpen,
2375
	dofill, lty = XF_SetLty(gc->lty), lwd = gc->lwd*0.833 + 0.5;
2377
	dofill, lty = XF_SetLty(gc->lty), lwd = gc->lwd*0.833 + 0.5;
2376
 
2378
 
2377
    cpen = (R_ALPHA(gc->col) == 0)? cfg: -1;
2379
    cpen = (R_ALPHA(gc->col) == 0)? cfg: -1;
2378
    dofill = (R_ALPHA(gc->fill) == 0)? 20: -1;
2380
    dofill = (R_ALPHA(gc->fill) == 0)? 20: -1;
2379
 
2381
 
2380
    XFconvert(&x0, &y0, pd);
2382
    XFconvert(&x0, &y0, pd);
2381
    XFconvert(&x1, &y1, pd);
2383
    XFconvert(&x1, &y1, pd);
2382
    ix0 = (int)x0; iy0 = (int)y0; ix1 = (int)x1; iy1 = (int)y1;
2384
    ix0 = (int)x0; iy0 = (int)y0; ix1 = (int)x1; iy1 = (int)y1;
2383
    fprintf(fp, "2 2 "); /* Polyline */
2385
    fprintf(fp, "2 2 "); /* Polyline */
2384
    fprintf(fp, "%d %d ", lty, lwd>0?lwd:1); /* style, thickness */
2386
    fprintf(fp, "%d %d ", lty, lwd>0?lwd:1); /* style, thickness */
2385
    fprintf(fp, "%d %d ", cpen, cbg); /* pen colour fill colour */
2387
    fprintf(fp, "%d %d ", cpen, cbg); /* pen colour fill colour */
2386
    fprintf(fp, "100 0 %d ", dofill); /* depth, pen style, area fill */
2388
    fprintf(fp, "100 0 %d ", dofill); /* depth, pen style, area fill */
2387
    fprintf(fp, "%.2f 0 0 -1 0 0 ", 4.0*lwd); /* style value, join .... */
2389
    fprintf(fp, "%.2f 0 0 -1 0 0 ", 4.0*lwd); /* style value, join .... */
2388
    fprintf(fp, "%d\n", 5); /* number of points */
2390
    fprintf(fp, "%d\n", 5); /* number of points */
2389
    fprintf(fp, "  %d %d ", ix0, iy0);
2391
    fprintf(fp, "  %d %d ", ix0, iy0);
2390
    fprintf(fp, "  %d %d ", ix0, iy1);
2392
    fprintf(fp, "  %d %d ", ix0, iy1);
2391
    fprintf(fp, "  %d %d ", ix1, iy1);
2393
    fprintf(fp, "  %d %d ", ix1, iy1);
2392
    fprintf(fp, "  %d %d ", ix1, iy0);
2394
    fprintf(fp, "  %d %d ", ix1, iy0);
2393
    fprintf(fp, "  %d %d\n", ix0, iy0);
2395
    fprintf(fp, "  %d %d\n", ix0, iy0);
2394
}
2396
}
2395
 
2397
 
2396
static void XFig_Circle(double x, double y, double r,
2398
static void XFig_Circle(double x, double y, double r,
2397
			R_GE_gcontext *gc,
2399
			R_GE_gcontext *gc,
2398
			NewDevDesc *dd)
2400
			NewDevDesc *dd)
2399
{
2401
{
2400
    XFigDesc *pd = (XFigDesc *) dd->deviceSpecific;
2402
    XFigDesc *pd = (XFigDesc *) dd->deviceSpecific;
2401
    FILE *fp = pd->tmpfp;
2403
    FILE *fp = pd->tmpfp;
2402
    int ix, iy, ir;
2404
    int ix, iy, ir;
2403
    int cbg = XF_SetColor(gc->fill, pd), cfg = XF_SetColor(gc->col, pd), cpen,
2405
    int cbg = XF_SetColor(gc->fill, pd), cfg = XF_SetColor(gc->col, pd), cpen,
2404
	dofill, lty = XF_SetLty(gc->lty), lwd = gc->lwd*0.833 + 0.5;
2406
	dofill, lty = XF_SetLty(gc->lty), lwd = gc->lwd*0.833 + 0.5;
2405
 
2407
 
2406
    cpen = (R_ALPHA(gc->col) == 0)? cfg: -1;
2408
    cpen = (R_ALPHA(gc->col) == 0)? cfg: -1;
2407
    dofill = (R_ALPHA(gc->fill) == 0)? 20: -1;
2409
    dofill = (R_ALPHA(gc->fill) == 0)? 20: -1;
2408
 
2410
 
2409
    XFconvert(&x, &y, pd);
2411
    XFconvert(&x, &y, pd);
2410
    ix = (int)x; iy = (int)y; ir = (int)(16.667*r);
2412
    ix = (int)x; iy = (int)y; ir = (int)(16.667*r);
2411
 
2413
 
2412
    fprintf(fp, "1 3 "); /* Circle + radius */
2414
    fprintf(fp, "1 3 "); /* Circle + radius */
2413
    fprintf(fp, "%d %d ", lty, lwd>0?lwd:1); /* style, thickness */
2415
    fprintf(fp, "%d %d ", lty, lwd>0?lwd:1); /* style, thickness */
2414
    fprintf(fp, "%d %d ", cpen, cbg); /* pen colour fill colour */
2416
    fprintf(fp, "%d %d ", cpen, cbg); /* pen colour fill colour */
2415
    fprintf(fp, "100 0 %d ", dofill); /* depth, pen style, area fill */
2417
    fprintf(fp, "100 0 %d ", dofill); /* depth, pen style, area fill */
2416
    fprintf(fp, "%.2f 1 0 ", 4.0*lwd); /* style value, direction, x, angle */
2418
    fprintf(fp, "%.2f 1 0 ", 4.0*lwd); /* style value, direction, x, angle */
2417
    fprintf(fp, "  %d %d %d %d %d %d %d %d \n",
2419
    fprintf(fp, "  %d %d %d %d %d %d %d %d \n",
2418
	    ix, iy, ir, ir, ix, iy, ix+ir, iy);
2420
	    ix, iy, ir, ir, ix, iy, ix+ir, iy);
2419
}
2421
}
2420
 
2422
 
2421
static void XFig_Line(double x1, double y1, double x2, double y2,
2423
static void XFig_Line(double x1, double y1, double x2, double y2,
2422
		      R_GE_gcontext *gc,
2424
		      R_GE_gcontext *gc,
2423
		      NewDevDesc *dd)
2425
		      NewDevDesc *dd)
2424
{
2426
{
2425
    XFigDesc *pd = (XFigDesc *) dd->deviceSpecific;
2427
    XFigDesc *pd = (XFigDesc *) dd->deviceSpecific;
2426
    FILE *fp = pd->tmpfp;
2428
    FILE *fp = pd->tmpfp;
2427
    int lty = XF_SetLty(gc->lty), lwd = gc->lwd*0.833 + 0.5;
2429
    int lty = XF_SetLty(gc->lty), lwd = gc->lwd*0.833 + 0.5;
2428
 
2430
 
2429
    XFconvert(&x1, &y1, pd);
2431
    XFconvert(&x1, &y1, pd);
2430
    XFconvert(&x2, &y2, pd);
2432
    XFconvert(&x2, &y2, pd);
2431
    if(R_ALPHA(gc->col) == 0) {
2433
    if(R_ALPHA(gc->col) == 0) {
2432
	fprintf(fp, "2 1 "); /* Polyline */
2434
	fprintf(fp, "2 1 "); /* Polyline */
2433
	fprintf(fp, "%d %d ", lty, lwd>0?lwd:1); /* style, thickness */
2435
	fprintf(fp, "%d %d ", lty, lwd>0?lwd:1); /* style, thickness */
2434
	fprintf(fp, "%d %d ", XF_SetColor(gc->col, pd), 7);
2436
	fprintf(fp, "%d %d ", XF_SetColor(gc->col, pd), 7);
2435
	/* pen colour fill colour */
2437
	/* pen colour fill colour */
2436
	fprintf(fp, "100 0 -1 "); /* depth, pen style, area fill */
2438
	fprintf(fp, "100 0 -1 "); /* depth, pen style, area fill */
2437
	fprintf(fp, "%.2f 0 0 -1 0 0 ", 4.0*lwd); /* style value, join .... */
2439
	fprintf(fp, "%.2f 0 0 -1 0 0 ", 4.0*lwd); /* style value, join .... */
2438
	fprintf(fp, "%d\n", 2); /* number of points */
2440
	fprintf(fp, "%d\n", 2); /* number of points */
2439
	fprintf(fp, "%d %d %d %d\n", (int)x1, (int)y1, (int)x2, (int)y2);
2441
	fprintf(fp, "%d %d %d %d\n", (int)x1, (int)y1, (int)x2, (int)y2);
2440
    }
2442
    }
2441
}
2443
}
2442
 
2444
 
2443
static void XFig_Polygon(int n, double *x, double *y,
2445
static void XFig_Polygon(int n, double *x, double *y,
2444
			 R_GE_gcontext *gc,
2446
			 R_GE_gcontext *gc,
2445
			 NewDevDesc *dd)
2447
			 NewDevDesc *dd)
2446
{
2448
{
2447
    XFigDesc *pd = (XFigDesc *) dd->deviceSpecific;
2449
    XFigDesc *pd = (XFigDesc *) dd->deviceSpecific;
2448
    FILE *fp = pd->tmpfp;
2450
    FILE *fp = pd->tmpfp;
2449
    double xx, yy;
2451
    double xx, yy;
2450
    int i;
2452
    int i;
2451
    int cbg = XF_SetColor(gc->fill, pd), cfg = XF_SetColor(gc->col, pd), cpen,
2453
    int cbg = XF_SetColor(gc->fill, pd), cfg = XF_SetColor(gc->col, pd), cpen,
2452
	dofill, lty = XF_SetLty(gc->lty), lwd = gc->lwd*0.833 + 0.5;
2454
	dofill, lty = XF_SetLty(gc->lty), lwd = gc->lwd*0.833 + 0.5;
2453
 
2455
 
2454
    cpen = (R_ALPHA(gc->col) == 0)? cfg: -1;
2456
    cpen = (R_ALPHA(gc->col) == 0)? cfg: -1;
2455
    dofill = (R_ALPHA(gc->fill) == 0)? 20: -1;
2457
    dofill = (R_ALPHA(gc->fill) == 0)? 20: -1;
2456
 
2458
 
2457
    fprintf(fp, "2 3 "); /* Polyline */
2459
    fprintf(fp, "2 3 "); /* Polyline */
2458
    fprintf(fp, "%d %d ", lty, lwd>0?lwd:1); /* style, thickness */
2460
    fprintf(fp, "%d %d ", lty, lwd>0?lwd:1); /* style, thickness */
2459
    fprintf(fp, "%d %d ", cpen, cbg); /* pen colour fill colour */
2461
    fprintf(fp, "%d %d ", cpen, cbg); /* pen colour fill colour */
2460
    fprintf(fp, "100 0 %d ", dofill); /* depth, pen style, area fill */
2462
    fprintf(fp, "100 0 %d ", dofill); /* depth, pen style, area fill */
2461
    fprintf(fp, "%.2f 0 0 -1 0 0 ", 4.0*lwd); /* style value, join .... */
2463
    fprintf(fp, "%.2f 0 0 -1 0 0 ", 4.0*lwd); /* style value, join .... */
2462
    fprintf(fp, "%d\n", n+1); /* number of points */
2464
    fprintf(fp, "%d\n", n+1); /* number of points */
2463
    /* close the path */
2465
    /* close the path */
2464
    for(i = 0 ; i <= n ; i++) {
2466
    for(i = 0 ; i <= n ; i++) {
2465
	xx = x[i%n];
2467
	xx = x[i%n];
2466
	yy = y[i%n];
2468
	yy = y[i%n];
2467
	XFconvert(&xx, &yy, pd);
2469
	XFconvert(&xx, &yy, pd);
2468
	fprintf(fp, "  %d %d\n", (int)xx, (int)yy);
2470
	fprintf(fp, "  %d %d\n", (int)xx, (int)yy);
2469
    }
2471
    }
2470
}
2472
}
2471
 
2473
 
2472
static void XFig_Polyline(int n, double *x, double *y,
2474
static void XFig_Polyline(int n, double *x, double *y,
2473
			  R_GE_gcontext *gc,
2475
			  R_GE_gcontext *gc,
2474
			  NewDevDesc *dd)
2476
			  NewDevDesc *dd)
2475
{
2477
{
2476
    XFigDesc *pd = (XFigDesc*) dd->deviceSpecific;
2478
    XFigDesc *pd = (XFigDesc*) dd->deviceSpecific;
2477
    FILE *fp = pd->tmpfp;
2479
    FILE *fp = pd->tmpfp;
2478
    double xx, yy;
2480
    double xx, yy;
2479
    int i, lty = XF_SetLty(gc->lty), lwd = gc->lwd*0.833 + 0.5;
2481
    int i, lty = XF_SetLty(gc->lty), lwd = gc->lwd*0.833 + 0.5;
2480
 
2482
 
2481
    if(R_ALPHA(gc->col) == 0) {
2483
    if(R_ALPHA(gc->col) == 0) {
2482
	fprintf(fp, "2 1 "); /* Polyline */
2484
	fprintf(fp, "2 1 "); /* Polyline */
2483
	fprintf(fp, "%d %d ", lty, lwd>0?lwd:1); /* style, thickness */
2485
	fprintf(fp, "%d %d ", lty, lwd>0?lwd:1); /* style, thickness */
2484
	fprintf(fp, "%d %d ", XF_SetColor(gc->col, pd), 7); /* pen colour fill colour */
2486
	fprintf(fp, "%d %d ", XF_SetColor(gc->col, pd), 7); /* pen colour fill colour */
2485
	fprintf(fp, "100 0 -1 "); /* depth, pen style, area fill */
2487
	fprintf(fp, "100 0 -1 "); /* depth, pen style, area fill */
2486
	fprintf(fp, "%.2f 0 0 -1 0 0 ", 4.0*lwd); /* style value, join .... */
2488
	fprintf(fp, "%.2f 0 0 -1 0 0 ", 4.0*lwd); /* style value, join .... */
2487
	fprintf(fp, "%d\n", n); /* number of points */
2489
	fprintf(fp, "%d\n", n); /* number of points */
2488
	for(i = 0 ; i < n ; i++) {
2490
	for(i = 0 ; i < n ; i++) {
2489
	    xx = x[i];
2491
	    xx = x[i];
2490
	    yy = y[i];
2492
	    yy = y[i];
2491
	    XFconvert(&xx, &yy, pd);
2493
	    XFconvert(&xx, &yy, pd);
2492
	    fprintf(fp, "  %d %d\n", (int)xx, (int)yy);
2494
	    fprintf(fp, "  %d %d\n", (int)xx, (int)yy);
2493
	}
2495
	}
2494
    }
2496
    }
2495
}
2497
}
2496
 
2498
 
2497
static const int styles[4] = {0,2,1,3};
2499
static const int styles[4] = {0,2,1,3};
2498
 
2500
 
2499
static void XFig_Text(double x, double y, char *str,
2501
static void XFig_Text(double x, double y, char *str,
2500
		      double rot, double hadj,
2502
		      double rot, double hadj,
2501
		      R_GE_gcontext *gc,
2503
		      R_GE_gcontext *gc,
2502
		      NewDevDesc *dd)
2504
		      NewDevDesc *dd)
2503
{
2505
{
2504
    XFigDesc *pd = (XFigDesc *) dd->deviceSpecific;
2506
    XFigDesc *pd = (XFigDesc *) dd->deviceSpecific;
2505
    FILE *fp = pd->tmpfp;
2507
    FILE *fp = pd->tmpfp;
2506
    int fontnum, style = gc->fontface;
2508
    int fontnum, style = gc->fontface;
2507
    double size = floor(gc->cex * gc->ps + 0.5);
2509
    double size = floor(gc->cex * gc->ps + 0.5);
2508
 
2510
 
2509
    if(style < 1 || style > 5) style = 1;
2511
    if(style < 1 || style > 5) {
-
 
2512
	warning("attempt to use invalid font %d replaced by font 1", style);
-
 
2513
	style = 1;
-
 
2514
    }
2510
    pd->fontsize = size;
2515
    pd->fontsize = size;
2511
    pd->fontstyle = style;
2516
    pd->fontstyle = style;
2512
    if(style == 5) fontnum = 32;
2517
    if(style == 5) fontnum = 32;
2513
    else fontnum = pd->fontnum + styles[style-1];
2518
    else fontnum = pd->fontnum + styles[style-1];
2514
 
2519
 
2515
    XFconvert(&x, &y, pd);
2520
    XFconvert(&x, &y, pd);
2516
    if(R_ALPHA(gc->col) == 0) {
2521
    if(R_ALPHA(gc->col) == 0) {
2517
	fprintf(fp, "4 %d ", (int)floor(2*hadj)); /* Text, how justified */
2522
	fprintf(fp, "4 %d ", (int)floor(2*hadj)); /* Text, how justified */
2518
	fprintf(fp, "%d 100 0 ", XF_SetColor(gc->col, pd));
2523
	fprintf(fp, "%d 100 0 ", XF_SetColor(gc->col, pd));
2519
	/* color, depth, pen_style */
2524
	/* color, depth, pen_style */
2520
	fprintf(fp, "%d %d %.4f 4 ", fontnum, (int)size, rot * DEG2RAD);
2525
	fprintf(fp, "%d %d %.4f 4 ", fontnum, (int)size, rot * DEG2RAD);
2521
	/* font pointsize angle flags (Postscript font) */
2526
	/* font pointsize angle flags (Postscript font) */
2522
	/* FIXME:  Why is this calling GStr[Height|Width] when it
2527
	/* FIXME:  Why is this calling GStr[Height|Width] when it
2523
	 * presumably could be calling XFig_Str[Height|Width] ?
2528
	 * presumably could be calling XFig_Str[Height|Width] ?
2524
	 */
2529
	 */
2525
	fprintf(fp, "%d %d ",
2530
	fprintf(fp, "%d %d ",
2526
		(int)(16.667*GStrHeight(str, DEVICE,
2531
		(int)(16.667*GStrHeight(str, DEVICE,
2527
					GetDevice(devNumber((DevDesc*) dd)))
2532
					GetDevice(devNumber((DevDesc*) dd)))
2528
		      +0.5),
2533
		      +0.5),
2529
		(int)(16.667*GStrWidth(str, DEVICE,
2534
		(int)(16.667*GStrWidth(str, DEVICE,
2530
				       GetDevice(devNumber((DevDesc*) dd)))
2535
				       GetDevice(devNumber((DevDesc*) dd)))
2531
		      +0.5));
2536
		      +0.5));
2532
	fprintf(fp, "%d %d ", (int)x, (int)y);
2537
	fprintf(fp, "%d %d ", (int)x, (int)y);
2533
	XF_WriteString(fp, str);
2538
	XF_WriteString(fp, str);
2534
	fprintf(fp, "\\001\n");
2539
	fprintf(fp, "\\001\n");
2535
    }
2540
    }
2536
}
2541
}
2537
 
2542
 
2538
static Rboolean XFig_Locator(double *x, double *y, NewDevDesc *dd)
2543
static Rboolean XFig_Locator(double *x, double *y, NewDevDesc *dd)
2539
{
2544
{
2540
    return FALSE;
2545
    return FALSE;
2541
}
2546
}
2542
 
2547
 
2543
static void XFig_Mode(int mode, NewDevDesc* dd)
2548
static void XFig_Mode(int mode, NewDevDesc* dd)
2544
{
2549
{
2545
}
2550
}
2546
 
2551
 
2547
static void XFig_Hold(NewDevDesc *dd)
2552
static void XFig_Hold(NewDevDesc *dd)
2548
{
2553
{
2549
}
2554
}
2550
 
2555
 
2551
static double XFig_StrWidth(char *str, 
2556
static double XFig_StrWidth(char *str, 
2552
			    R_GE_gcontext *gc,
2557
			    R_GE_gcontext *gc,
2553
			    NewDevDesc *dd)
2558
			    NewDevDesc *dd)
2554
{
2559
{
2555
    XFigDesc *pd = (XFigDesc *) dd->deviceSpecific;
2560
    XFigDesc *pd = (XFigDesc *) dd->deviceSpecific;
-
 
2561
    int face = gc->fontface;
-
 
2562
 
-
 
2563
    if(face < 1 || face > 5) face = 1;
2556
 
2564
 
2557
    return floor(gc->cex * gc->ps + 0.5) *
2565
    return floor(gc->cex * gc->ps + 0.5) *
2558
	PostScriptStringWidth((unsigned char *)str,
2566
	PostScriptStringWidth((unsigned char *)str,
2559
			      &(pd->metrics[gc->fontface-1]));
2567
			      &(pd->metrics[face-1]));
2560
}
2568
}
2561
 
2569
 
2562
static void XFig_MetricInfo(int c, 
2570
static void XFig_MetricInfo(int c, 
2563
			    R_GE_gcontext *gc,
2571
			    R_GE_gcontext *gc,
2564
			    double* ascent, double* descent,
2572
			    double* ascent, double* descent,
2565
			    double* width, NewDevDesc *dd)
2573
			    double* width, NewDevDesc *dd)
2566
{
2574
{
2567
    XFigDesc *pd = (XFigDesc *) dd->deviceSpecific;
2575
    XFigDesc *pd = (XFigDesc *) dd->deviceSpecific;
-
 
2576
    int face = gc->fontface;
-
 
2577
 
-
 
2578
    if(face < 1 || face > 5) face = 1;
2568
 
2579
 
2569
    PostScriptMetricInfo(c, ascent, descent, width,
2580
    PostScriptMetricInfo(c, ascent, descent, width,
2570
			 &(pd->metrics[gc->fontface-1]));
2581
			 &(pd->metrics[face-1]));
2571
    *ascent = floor(gc->cex * gc->ps + 0.5) * *ascent;
2582
    *ascent = floor(gc->cex * gc->ps + 0.5) * *ascent;
2572
    *descent = floor(gc->cex * gc->ps + 0.5) * *descent;
2583
    *descent = floor(gc->cex * gc->ps + 0.5) * *descent;
2573
    *width = floor(gc->cex * gc->ps + 0.5) * *width;
2584
    *width = floor(gc->cex * gc->ps + 0.5) * *width;
2574
}
2585
}
2575
 
2586
 
2576
 
2587
 
2577
/***********************************************************************
2588
/***********************************************************************
2578
 
2589
 
2579
                 PDF driver also shares font handling
2590
                 PDF driver also shares font handling
2580
 
2591
 
2581
************************************************************************/
2592
************************************************************************/
2582
 
2593
 
2583
/* TODO
2594
/* TODO
2584
   Flate encoding?
2595
   Flate encoding?
2585
*/
2596
*/
2586
 
2597
 
2587
 
2598
 
2588
typedef struct {
2599
typedef struct {
2589
    char filename[PATH_MAX];
2600
    char filename[PATH_MAX];
2590
 
2601
 
2591
    int pageno;		/* page number */
2602
    int pageno;		/* page number */
2592
    int fileno;		/* file number */
2603
    int fileno;		/* file number */
2593
 
2604
 
2594
    int fontfamily;	/* font family */
2605
    int fontfamily;	/* font family */
2595
    char encpath[PATH_MAX]; /* font encoding */
2606
    char encpath[PATH_MAX]; /* font encoding */
2596
    char encname[100];
2607
    char encname[100];
2597
    char **afmpaths;	/* for user-specified family */
2608
    char **afmpaths;	/* for user-specified family */
2598
    int maxpointsize;
2609
    int maxpointsize;
2599
 
2610
 
2600
    double width;	/* plot width in inches */
2611
    double width;	/* plot width in inches */
2601
    double height;	/* plot height in inches */
2612
    double height;	/* plot height in inches */
2602
    Rboolean onefile;	/* one file or one file per page? */
2613
    Rboolean onefile;	/* one file or one file per page? */
2603
 
2614
 
2604
    FILE *pdffp;		/* output file */
2615
    FILE *pdffp;		/* output file */
2605
 
2616
 
2606
    FontMetricInfo metrics[5];	/* font metrics */
2617
    FontMetricInfo metrics[5];	/* font metrics */
2607
 
2618
 
2608
    /* This group of variables track the current device status.
2619
    /* This group of variables track the current device status.
2609
     * They should only be set by routines that emit PDF. */
2620
     * They should only be set by routines that emit PDF. */
2610
    struct {
2621
    struct {
2611
	double lwd;		 /* line width */
2622
	double lwd;		 /* line width */
2612
	int lty;		 /* line type */
2623
	int lty;		 /* line type */
2613
	int fontstyle;	         /* font style, R, B, I, BI, S */
2624
	int fontstyle;	         /* font style, R, B, I, BI, S */
2614
	int fontsize;	         /* font size in points */
2625
	int fontsize;	         /* font size in points */
2615
	rcolor col;		 /* color */
2626
	rcolor col;		 /* color */
2616
	rcolor fill;	         /* fill color */
2627
	rcolor fill;	         /* fill color */
2617
	rcolor bg;		 /* color */
2628
	rcolor bg;		 /* color */
2618
    } current;
2629
    } current;
2619
 
2630
 
2620
    int nobjs;  /* number of objects */
2631
    int nobjs;  /* number of objects */
2621
    int *pos; /* object positions */
2632
    int *pos; /* object positions */
2622
    int *pageobj; /* page object numbers */
2633
    int *pageobj; /* page object numbers */
2623
    int pagemax;
2634
    int pagemax;
2624
    int startstream; /* position of start of current stream */
2635
    int startstream; /* position of start of current stream */
2625
    Rboolean inText;
2636
    Rboolean inText;
2626
    char title[1024];
2637
    char title[1024];
2627
}
2638
}
2628
PDFDesc;
2639
PDFDesc;
2629
 
2640
 
2630
/* Device Driver Actions */
2641
/* Device Driver Actions */
2631
 
2642
 
2632
static Rboolean PDF_Open(NewDevDesc*, PDFDesc*);
2643
static Rboolean PDF_Open(NewDevDesc*, PDFDesc*);
2633
static void PDF_Activate(NewDevDesc *dd);
2644
static void PDF_Activate(NewDevDesc *dd);
2634
static void PDF_Circle(double x, double y, double r,
2645
static void PDF_Circle(double x, double y, double r,
2635
		       R_GE_gcontext *gc,
2646
		       R_GE_gcontext *gc,
2636
		       NewDevDesc *dd);
2647
		       NewDevDesc *dd);
2637
static void PDF_Clip(double x0, double x1, double y0, double y1,
2648
static void PDF_Clip(double x0, double x1, double y0, double y1,
2638
		     NewDevDesc *dd);
2649
		     NewDevDesc *dd);
2639
static void PDF_Close(NewDevDesc *dd);
2650
static void PDF_Close(NewDevDesc *dd);
2640
static void PDF_Deactivate(NewDevDesc *dd);
2651
static void PDF_Deactivate(NewDevDesc *dd);
2641
static void PDF_Hold(NewDevDesc *dd);
2652
static void PDF_Hold(NewDevDesc *dd);
2642
static Rboolean PDF_Locator(double *x, double *y, NewDevDesc *dd);
2653
static Rboolean PDF_Locator(double *x, double *y, NewDevDesc *dd);
2643
static void PDF_Line(double x1, double y1, double x2, double y2,
2654
static void PDF_Line(double x1, double y1, double x2, double y2,
2644
		     R_GE_gcontext *gc,
2655
		     R_GE_gcontext *gc,
2645
		     NewDevDesc *dd);
2656
		     NewDevDesc *dd);
2646
static void PDF_MetricInfo(int c, 
2657
static void PDF_MetricInfo(int c, 
2647
			   R_GE_gcontext *gc,
2658
			   R_GE_gcontext *gc,
2648
			   double* ascent, double* descent,
2659
			   double* ascent, double* descent,
2649
			   double* width, NewDevDesc *dd);
2660
			   double* width, NewDevDesc *dd);
2650
static void PDF_Mode(int mode, NewDevDesc *dd);
2661
static void PDF_Mode(int mode, NewDevDesc *dd);
2651
static void PDF_NewPage(R_GE_gcontext *gc, NewDevDesc *dd);
2662
static void PDF_NewPage(R_GE_gcontext *gc, NewDevDesc *dd);
2652
static void PDF_Polygon(int n, double *x, double *y,
2663
static void PDF_Polygon(int n, double *x, double *y,
2653
			R_GE_gcontext *gc,
2664
			R_GE_gcontext *gc,
2654
			NewDevDesc *dd);
2665
			NewDevDesc *dd);
2655
static void PDF_Polyline(int n, double *x, double *y,
2666
static void PDF_Polyline(int n, double *x, double *y,
2656
			 R_GE_gcontext *gc,
2667
			 R_GE_gcontext *gc,
2657
			 NewDevDesc *dd);
2668
			 NewDevDesc *dd);
2658
static void PDF_Rect(double x0, double y0, double x1, double y1,
2669
static void PDF_Rect(double x0, double y0, double x1, double y1,
2659
		     R_GE_gcontext *gc,
2670
		     R_GE_gcontext *gc,
2660
		     NewDevDesc *dd);
2671
		     NewDevDesc *dd);
2661
static void PDF_Size(double *left, double *right,
2672
static void PDF_Size(double *left, double *right,
2662
		     double *bottom, double *top,
2673
		     double *bottom, double *top,
2663
		     NewDevDesc *dd);
2674
		     NewDevDesc *dd);
2664
static double PDF_StrWidth(char *str,
2675
static double PDF_StrWidth(char *str,
2665
			   R_GE_gcontext *gc,
2676
			   R_GE_gcontext *gc,
2666
			   NewDevDesc *dd);
2677
			   NewDevDesc *dd);
2667
static void PDF_Text(double x, double y, char *str,
2678
static void PDF_Text(double x, double y, char *str,
2668
		     double rot, double hadj,
2679
		     double rot, double hadj,
2669
		     R_GE_gcontext *gc,
2680
		     R_GE_gcontext *gc,
2670
		     NewDevDesc *dd);
2681
		     NewDevDesc *dd);
2671
 
2682
 
2672
static Rboolean
2683
static Rboolean
2673
innerPDFDeviceDriver(NewDevDesc* dd, char *file, char *family, char *encoding,
2684
innerPDFDeviceDriver(NewDevDesc* dd, char *file, char *family, char *encoding,
2674
		     char *bg, char *fg, double width, double height,
2685
		     char *bg, char *fg, double width, double height,
2675
		     double ps, int onefile, char *title)
2686
		     double ps, int onefile, char *title)
2676
{
2687
{
2677
    /* If we need to bail out with some sort of "error" */
2688
    /* If we need to bail out with some sort of "error" */
2678
    /* then we must free(dd) */
2689
    /* then we must free(dd) */
2679
 
2690
 
2680
    double xoff = 0.0, yoff = 0.0, pointsize;
2691
    double xoff = 0.0, yoff = 0.0, pointsize;
2681
    rcolor setbg, setfg;
2692
    rcolor setbg, setfg;
2682
 
2693
 
2683
    PDFDesc *pd;
2694
    PDFDesc *pd;
2684
 
2695
 
2685
    /* Check and extract the device parameters */
2696
    /* Check and extract the device parameters */
2686
 
2697
 
2687
    if(strlen(file) > PATH_MAX - 1) {
2698
    if(strlen(file) > PATH_MAX - 1) {
2688
	free(dd);
2699
	free(dd);
2689
	error("filename too long in pdf");
2700
	error("filename too long in pdf");
2690
    }
2701
    }
2691
 
2702
 
2692
    /* allocate new PDF device description */
2703
    /* allocate new PDF device description */
2693
    if (!(pd = (PDFDesc *) malloc(sizeof(PDFDesc))))
2704
    if (!(pd = (PDFDesc *) malloc(sizeof(PDFDesc))))
2694
	return 0;
2705
	return 0;
2695
    /* from here on, if need to bail out with "error", must also */
2706
    /* from here on, if need to bail out with "error", must also */
2696
    /* free(pd) */
2707
    /* free(pd) */
2697
 
2708
 
2698
    pd->pos = (int *) calloc(350, sizeof(int));
2709
    pd->pos = (int *) calloc(350, sizeof(int));
2699
    if(!pd->pos) {
2710
    if(!pd->pos) {
2700
	free(pd); free(dd);
2711
	free(pd); free(dd);
2701
	error("cannot allocate pd->pos");
2712
	error("cannot allocate pd->pos");
2702
    }
2713
    }
2703
    pd->pageobj = (int *) calloc(100, sizeof(int));
2714
    pd->pageobj = (int *) calloc(100, sizeof(int));
2704
    if(!pd->pageobj) {
2715
    if(!pd->pageobj) {
2705
	free(pd->pos);free(pd); free(dd);
2716
	free(pd->pos);free(pd); free(dd);
2706
	error("cannot allocate pd->pageobj");
2717
	error("cannot allocate pd->pageobj");
2707
    }
2718
    }
2708
    pd->pagemax = 100;
2719
    pd->pagemax = 100;
2709
 
2720
 
2710
 
2721
 
2711
    /* initialize PDF device description */
2722
    /* initialize PDF device description */
2712
    strcpy(pd->filename, file);
2723
    strcpy(pd->filename, file);
2713
    strncpy(pd->title, title, 1024);
2724
    strncpy(pd->title, title, 1024);
2714
    pd->fontfamily = MatchFamily(family);
2725
    pd->fontfamily = MatchFamily(family);
2715
    if(strlen(encoding) > PATH_MAX - 1) {
2726
    if(strlen(encoding) > PATH_MAX - 1) {
2716
	free(dd);
2727
	free(dd);
2717
	free(pd->pos); free(pd->pageobj); free(pd);
2728
	free(pd->pos); free(pd->pageobj); free(pd);
2718
	error("encoding path is too long");
2729
	error("encoding path is too long");
2719
    }
2730
    }
2720
    strcpy(pd->encpath, encoding);
2731
    strcpy(pd->encpath, encoding);
2721
    setbg = str2col(bg);
2732
    setbg = str2col(bg);
2722
    setfg = str2col(fg);
2733
    setfg = str2col(fg);
2723
 
2734
 
2724
    pd->width = width;
2735
    pd->width = width;
2725
    pd->height = height;
2736
    pd->height = height;
2726
    pointsize = floor(ps);
2737
    pointsize = floor(ps);
2727
    if(setbg == NA_INTEGER && setfg  == NA_INTEGER) {
2738
    if(setbg == NA_INTEGER && setfg  == NA_INTEGER) {
2728
	free(dd);
2739
	free(dd);
2729
	free(pd->pos); free(pd->pageobj); free(pd);
2740
	free(pd->pos); free(pd->pageobj); free(pd);
2730
	error("invalid foreground/background color (pdf)");
2741
	error("invalid foreground/background color (pdf)");
2731
    }
2742
    }
2732
 
2743
 
2733
    pd->onefile = onefile;
2744
    pd->onefile = onefile;
2734
    pd->maxpointsize = 72.0 * ((height > width) ? height : width);
2745
    pd->maxpointsize = 72.0 * ((height > width) ? height : width);
2735
    pd->pageno = pd->fileno = 0;
2746
    pd->pageno = pd->fileno = 0;
2736
    /* Base Pointsize */
2747
    /* Base Pointsize */
2737
    /* Nominal Character Sizes in Pixels */
2748
    /* Nominal Character Sizes in Pixels */
2738
    /* Only right for 12 point font. */
2749
    /* Only right for 12 point font. */
2739
    /* Max pointsize suggested by Peter Dalgaard */
2750
    /* Max pointsize suggested by Peter Dalgaard */
2740
 
2751
 
2741
    if(pointsize < 6.0) pointsize = 6.0;
2752
    if(pointsize < 6.0) pointsize = 6.0;
2742
    if(pointsize > pd->maxpointsize) pointsize = pd->maxpointsize;
2753
    if(pointsize > pd->maxpointsize) pointsize = pd->maxpointsize;
2743
    dd->startps = pointsize;
2754
    dd->startps = pointsize;
2744
    dd->startlty = 0;
2755
    dd->startlty = 0;
2745
    dd->startfont = 1;
2756
    dd->startfont = 1;
2746
    dd->startfill = setbg;
2757
    dd->startfill = setbg;
2747
    dd->startcol = setfg;
2758
    dd->startcol = setfg;
2748
    dd->startgamma = 1;
2759
    dd->startgamma = 1;
2749
 
2760
 
2750
    /* Set graphics parameters that must be set by device driver. */
2761
    /* Set graphics parameters that must be set by device driver. */
2751
    /* Page dimensions in points. */
2762
    /* Page dimensions in points. */
2752
 
2763
 
2753
    dd->left = 72 * xoff;			/* left */
2764
    dd->left = 72 * xoff;			/* left */
2754
    dd->right = 72 * (xoff + pd->width);	/* right */
2765
    dd->right = 72 * (xoff + pd->width);	/* right */
2755
    dd->bottom = 72 * yoff;			/* bottom */
2766
    dd->bottom = 72 * yoff;			/* bottom */
2756
    dd->top = 72 * (yoff + pd->height);	/* top */
2767
    dd->top = 72 * (yoff + pd->height);	/* top */
2757
 
2768
 
2758
    dd->cra[0] = 0.9 * pointsize;
2769
    dd->cra[0] = 0.9 * pointsize;
2759
    dd->cra[1] = 1.2 * pointsize;
2770
    dd->cra[1] = 1.2 * pointsize;
2760
 
2771
 
2761
    /* Character Addressing Offsets */
2772
    /* Character Addressing Offsets */
2762
    /* These offsets should center a single */
2773
    /* These offsets should center a single */
2763
    /* plotting character over the plotting point. */
2774
    /* plotting character over the plotting point. */
2764
    /* Pure guesswork and eyeballing ... */
2775
    /* Pure guesswork and eyeballing ... */
2765
 
2776
 
2766
    dd->xCharOffset =  0.4900;
2777
    dd->xCharOffset =  0.4900;
2767
    dd->yCharOffset =  0.3333;
2778
    dd->yCharOffset =  0.3333;
2768
    dd->yLineBias = 0.2;
2779
    dd->yLineBias = 0.2;
2769
 
2780
 
2770
    /* Inches per Raster Unit */
2781
    /* Inches per Raster Unit */
2771
    /* 1200 dpi */
2782
    /* 1200 dpi */
2772
    dd->ipr[0] = 1.0/72.0;
2783
    dd->ipr[0] = 1.0/72.0;
2773
    dd->ipr[1] = 1.0/72.0;
2784
    dd->ipr[1] = 1.0/72.0;
2774
 
2785
 
2775
    dd->canResizePlot = 0;
2786
    dd->canResizePlot = 0;
2776
    dd->canChangeFont = 1;
2787
    dd->canChangeFont = 1;
2777
    dd->canRotateText = 1;
2788
    dd->canRotateText = 1;
2778
    dd->canResizeText = 1;
2789
    dd->canResizeText = 1;
2779
    dd->canClip = 1;
2790
    dd->canClip = 1;
2780
    dd->canHAdj = 0;
2791
    dd->canHAdj = 0;
2781
    dd->canChangeGamma = FALSE;
2792
    dd->canChangeGamma = FALSE;
2782
 
2793
 
2783
    /*	Start the driver */
2794
    /*	Start the driver */
2784
 
2795
 
2785
    if(!PDF_Open(dd, pd)) {
2796
    if(!PDF_Open(dd, pd)) {
2786
	free(pd->pos); free(pd->pageobj); free(pd);
2797
	free(pd->pos); free(pd->pageobj); free(pd);
2787
	return 0;
2798
	return 0;
2788
    }
2799
    }
2789
 
2800
 
2790
    dd->newDevStruct = 1;
2801
    dd->newDevStruct = 1;
2791
 
2802
 
2792
    dd->open	      = PDF_Open;
2803
    dd->open	      = PDF_Open;
2793
    dd->close      = PDF_Close;
2804
    dd->close      = PDF_Close;
2794
    dd->activate   = PDF_Activate;
2805
    dd->activate   = PDF_Activate;
2795
    dd->deactivate = PDF_Deactivate;
2806
    dd->deactivate = PDF_Deactivate;
2796
    dd->size     = PDF_Size;
2807
    dd->size     = PDF_Size;
2797
    dd->newPage    = PDF_NewPage;
2808
    dd->newPage    = PDF_NewPage;
2798
    dd->clip	      = PDF_Clip;
2809
    dd->clip	      = PDF_Clip;
2799
    dd->text	      = PDF_Text;
2810
    dd->text	      = PDF_Text;
2800
    dd->strWidth   = PDF_StrWidth;
2811
    dd->strWidth   = PDF_StrWidth;
2801
    dd->metricInfo = PDF_MetricInfo;
2812
    dd->metricInfo = PDF_MetricInfo;
2802
    dd->rect	      = PDF_Rect;
2813
    dd->rect	      = PDF_Rect;
2803
    dd->circle     = PDF_Circle;
2814
    dd->circle     = PDF_Circle;
2804
    dd->line	      = PDF_Line;
2815
    dd->line	      = PDF_Line;
2805
    dd->polygon    = PDF_Polygon;
2816
    dd->polygon    = PDF_Polygon;
2806
    dd->polyline   = PDF_Polyline;
2817
    dd->polyline   = PDF_Polyline;
2807
    dd->locator    = PDF_Locator;
2818
    dd->locator    = PDF_Locator;
2808
    dd->mode	      = PDF_Mode;
2819
    dd->mode	      = PDF_Mode;
2809
    dd->hold	      = PDF_Hold;
2820
    dd->hold	      = PDF_Hold;
2810
 
2821
 
2811
    dd->deviceSpecific = (void *) pd;
2822
    dd->deviceSpecific = (void *) pd;
2812
    dd->displayListOn = FALSE;
2823
    dd->displayListOn = FALSE;
2813
    return 1;
2824
    return 1;
2814
}
2825
}
2815
 
2826
 
2816
static void PDF_Invalidate(NewDevDesc *dd)
2827
static void PDF_Invalidate(NewDevDesc *dd)
2817
{
2828
{
2818
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
2829
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
2819
 
2830
 
2820
    pd->current.fontsize = -1;
2831
    pd->current.fontsize = -1;
2821
    pd->current.fontstyle = -1;
2832
    pd->current.fontstyle = -1;
2822
    /*
2833
    /*
2823
     * Paul:  make all these settings "invalid"
2834
     * Paul:  make all these settings "invalid"
2824
     pd->current.lwd = 1;
2835
     pd->current.lwd = 1;
2825
     */
2836
     */
2826
    pd->current.lwd = -1;
2837
    pd->current.lwd = -1;
2827
    pd->current.lty = -1;
2838
    pd->current.lty = -1;
2828
    /* page starts with black as the default fill and stroke colours */
2839
    /* page starts with black as the default fill and stroke colours */
2829
    /*
2840
    /*
2830
     * Paul:  make all these settings "invalid"
2841
     * Paul:  make all these settings "invalid"
2831
     pd->current.col = 0;
2842
     pd->current.col = 0;
2832
     pd->current.fill = 0;
2843
     pd->current.fill = 0;
2833
     */
2844
     */
2834
    pd->current.col = INVALID_COL;
2845
    pd->current.col = INVALID_COL;
2835
    pd->current.fill = INVALID_COL;
2846
    pd->current.fill = INVALID_COL;
2836
    pd->current.bg = INVALID_COL;
2847
    pd->current.bg = INVALID_COL;
2837
}
2848
}
2838
 
2849
 
2839
Rboolean
2850
Rboolean
2840
PDFDeviceDriver(DevDesc* dd, char *file, char *family, char *encoding,
2851
PDFDeviceDriver(DevDesc* dd, char *file, char *family, char *encoding,
2841
		char *bg, char *fg, double width, double height, double ps,
2852
		char *bg, char *fg, double width, double height, double ps,
2842
		int onefile, char *title)
2853
		int onefile, char *title)
2843
{
2854
{
2844
    return innerPDFDeviceDriver((NewDevDesc*) dd, file, family, encoding,
2855
    return innerPDFDeviceDriver((NewDevDesc*) dd, file, family, encoding,
2845
				bg, fg, width, height, ps, onefile, title);
2856
				bg, fg, width, height, ps, onefile, title);
2846
}
2857
}
2847
 
2858
 
2848
static void PDF_SetLineColor(int color, NewDevDesc *dd)
2859
static void PDF_SetLineColor(int color, NewDevDesc *dd)
2849
{
2860
{
2850
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
2861
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
2851
 
2862
 
2852
    if(color != pd->current.col) {
2863
    if(color != pd->current.col) {
2853
	fprintf(pd->pdffp, "%.3f %.3f %.3f RG\n",
2864
	fprintf(pd->pdffp, "%.3f %.3f %.3f RG\n",
2854
		R_RED(color)/255.0,
2865
		R_RED(color)/255.0,
2855
		R_GREEN(color)/255.0,
2866
		R_GREEN(color)/255.0,
2856
		R_BLUE(color)/255.0);
2867
		R_BLUE(color)/255.0);
2857
	pd->current.col = color;
2868
	pd->current.col = color;
2858
    }
2869
    }
2859
}
2870
}
2860
 
2871
 
2861
static void PDF_SetFill(int color, NewDevDesc *dd)
2872
static void PDF_SetFill(int color, NewDevDesc *dd)
2862
{
2873
{
2863
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
2874
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
2864
    if(color != pd->current.fill) {
2875
    if(color != pd->current.fill) {
2865
	fprintf(pd->pdffp, "%.3f %.3f %.3f rg\n",
2876
	fprintf(pd->pdffp, "%.3f %.3f %.3f rg\n",
2866
		   R_RED(color)/255.0,
2877
		   R_RED(color)/255.0,
2867
		   R_GREEN(color)/255.0,
2878
		   R_GREEN(color)/255.0,
2868
		   R_BLUE(color)/255.0);
2879
		   R_BLUE(color)/255.0);
2869
	pd->current.fill = color;
2880
	pd->current.fill = color;
2870
    }
2881
    }
2871
}
2882
}
2872
 
2883
 
2873
/* Note that the line texture is scaled by the line width.*/
2884
/* Note that the line texture is scaled by the line width.*/
2874
static void PDFSetLineTexture(FILE *fp, char *dashlist, int nlty, double lwd)
2885
static void PDFSetLineTexture(FILE *fp, char *dashlist, int nlty, double lwd)
2875
{
2886
{
2876
    PP_SetLineTexture("d");
2887
    PP_SetLineTexture("d");
2877
}
2888
}
2878
 
2889
 
2879
static void PDF_SetLineStyle(int newlty, double newlwd, NewDevDesc *dd)
2890
static void PDF_SetLineStyle(int newlty, double newlwd, NewDevDesc *dd)
2880
{
2891
{
2881
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
2892
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
2882
    char dashlist[8];
2893
    char dashlist[8];
2883
    int i;
2894
    int i;
2884
 
2895
 
2885
    if (pd->current.lty != newlty || pd->current.lwd != newlwd) {
2896
    if (pd->current.lty != newlty || pd->current.lwd != newlwd) {
2886
	pd->current.lwd = newlwd;
2897
	pd->current.lwd = newlwd;
2887
	pd->current.lty = newlty;
2898
	pd->current.lty = newlty;
2888
	fprintf(pd->pdffp, "%.2f w\n", newlwd * 0.75);
2899
	fprintf(pd->pdffp, "%.2f w\n", newlwd * 0.75);
2889
	/* process lty : */
2900
	/* process lty : */
2890
	for(i = 0; i < 8 && newlty & 15 ; i++) {
2901
	for(i = 0; i < 8 && newlty & 15 ; i++) {
2891
	    dashlist[i] = newlty & 15;
2902
	    dashlist[i] = newlty & 15;
2892
	    newlty = newlty >> 4;
2903
	    newlty = newlty >> 4;
2893
	}
2904
	}
2894
	PDFSetLineTexture(pd->pdffp, dashlist, i, newlwd * 0.75);
2905
	PDFSetLineTexture(pd->pdffp, dashlist, i, newlwd * 0.75);
2895
    }
2906
    }
2896
}
2907
}
2897
 
2908
 
2898
static void texton(PDFDesc *pd)
2909
static void texton(PDFDesc *pd)
2899
{
2910
{
2900
    fprintf(pd->pdffp, "BT\n");
2911
    fprintf(pd->pdffp, "BT\n");
2901
    pd->inText = TRUE;
2912
    pd->inText = TRUE;
2902
}
2913
}
2903
 
2914
 
2904
static void textoff(PDFDesc *pd)
2915
static void textoff(PDFDesc *pd)
2905
{
2916
{
2906
    fprintf(pd->pdffp, "ET\n");
2917
    fprintf(pd->pdffp, "ET\n");
2907
    pd->inText = FALSE;
2918
    pd->inText = FALSE;
2908
}
2919
}
2909
 
2920
 
2910
static void PDF_EncodeFont(PDFDesc *pd, int nobj)
2921
static void PDF_EncodeFont(PDFDesc *pd, int nobj)
2911
{
2922
{
2912
    char *encname = pd->encname;
2923
    char *encname = pd->encname;
2913
 
2924
 
2914
    fprintf(pd->pdffp, "%d 0 obj\n<<\n/Type /Encoding\n", nobj);
2925
    fprintf(pd->pdffp, "%d 0 obj\n<<\n/Type /Encoding\n", nobj);
2915
    if (strcmp(encname, "WinAnsiEncoding") == 0 ||
2926
    if (strcmp(encname, "WinAnsiEncoding") == 0 ||
2916
	strcmp(encname, "MacRomanEncoding") == 0 ||
2927
	strcmp(encname, "MacRomanEncoding") == 0 ||
2917
	strcmp(encname, "PDFDocEncoding") == 0) {
2928
	strcmp(encname, "PDFDocEncoding") == 0) {
2918
	fprintf(pd->pdffp, "/BaseEncoding /%s\n", encname);
2929
	fprintf(pd->pdffp, "/BaseEncoding /%s\n", encname);
2919
	fprintf(pd->pdffp, "/Differences [ 45/minus ]\n");
2930
	fprintf(pd->pdffp, "/Differences [ 45/minus ]\n");
2920
    } else if (strcmp(encname, "ISOLatin1Encoding") == 0) {
2931
    } else if (strcmp(encname, "ISOLatin1Encoding") == 0) {
2921
	fprintf(pd->pdffp, "/BaseEncoding /PDFDocEncoding\n");
2932
	fprintf(pd->pdffp, "/BaseEncoding /PDFDocEncoding\n");
2922
	fprintf(pd->pdffp, "/Differences [ 45/minus 96/quoteleft\n144/dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent\n/dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron /space]\n");
2933
	fprintf(pd->pdffp, "/Differences [ 45/minus 96/quoteleft\n144/dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent\n/dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron /space]\n");
2923
    } else {
2934
    } else {
2924
	fprintf(pd->pdffp, "/BaseEncoding /PDFDocEncoding\n");
2935
	fprintf(pd->pdffp, "/BaseEncoding /PDFDocEncoding\n");
2925
	fprintf(pd->pdffp, "/Differences [ 0 %s ]\n", enccode);
2936
	fprintf(pd->pdffp, "/Differences [ 0 %s ]\n", enccode);
2926
    }
2937
    }
2927
    fprintf(pd->pdffp, ">>\nendobj\n");
2938
    fprintf(pd->pdffp, ">>\nendobj\n");
2928
}
2939
}
2929
 
2940
 
2930
#include <time.h>
2941
#include <time.h>
2931
#include <Rversion.h>
2942
#include <Rversion.h>
2932
 
2943
 
2933
static void PDF_startfile(PDFDesc *pd)
2944
static void PDF_startfile(PDFDesc *pd)
2934
{
2945
{
2935
    int i;
2946
    int i;
2936
    struct tm *ltm;
2947
    struct tm *ltm;
2937
    time_t ct;
2948
    time_t ct;
2938
 
2949
 
2939
    pd->nobjs = 0;
2950
    pd->nobjs = 0;
2940
    pd->pageno = 0;
2951
    pd->pageno = 0;
2941
    fprintf(pd->pdffp, "%%PDF-1.1\n%%âãÏÓ\r\n");
2952
    fprintf(pd->pdffp, "%%PDF-1.1\n%%âãÏÓ\r\n");
2942
    pd->pos[++pd->nobjs] = (int) ftell(pd->pdffp);
2953
    pd->pos[++pd->nobjs] = (int) ftell(pd->pdffp);
2943
 
2954
 
2944
    /* Object 1 is Info node. Date format is from the PDF manual */
2955
    /* Object 1 is Info node. Date format is from the PDF manual */
2945
 
2956
 
2946
    ct = time(NULL);
2957
    ct = time(NULL);
2947
    ltm = localtime(&ct);
2958
    ltm = localtime(&ct);
2948
    fprintf(pd->pdffp,
2959
    fprintf(pd->pdffp,
2949
	    "1 0 obj\n<<\n/CreationDate (D:%04d%02d%02d%02d%02d%02d)\n",
2960
	    "1 0 obj\n<<\n/CreationDate (D:%04d%02d%02d%02d%02d%02d)\n",
2950
	    1900 + ltm->tm_year, ltm->tm_mon+1, ltm->tm_mday,
2961
	    1900 + ltm->tm_year, ltm->tm_mon+1, ltm->tm_mday,
2951
	    ltm->tm_hour, ltm->tm_min, ltm->tm_sec);
2962
	    ltm->tm_hour, ltm->tm_min, ltm->tm_sec);
2952
    fprintf(pd->pdffp,
2963
    fprintf(pd->pdffp,
2953
	    "/ModDate (D:%04d%02d%02d%02d%02d%02d)\n",
2964
	    "/ModDate (D:%04d%02d%02d%02d%02d%02d)\n",
2954
	    1900 + ltm->tm_year, ltm->tm_mon+1, ltm->tm_mday,
2965
	    1900 + ltm->tm_year, ltm->tm_mon+1, ltm->tm_mday,
2955
	    ltm->tm_hour, ltm->tm_min, ltm->tm_sec);
2966
	    ltm->tm_hour, ltm->tm_min, ltm->tm_sec);
2956
    fprintf(pd->pdffp, "/Title (%s)\n", pd->title);
2967
    fprintf(pd->pdffp, "/Title (%s)\n", pd->title);
2957
    fprintf(pd->pdffp, "/Producer (R %s.%s)\n/Creator (R)\n>>\nendobj\n",
2968
    fprintf(pd->pdffp, "/Producer (R %s.%s)\n/Creator (R)\n>>\nendobj\n",
2958
	    R_MAJOR, R_MINOR);
2969
	    R_MAJOR, R_MINOR);
2959
 
2970
 
2960
    /* Object 2 is the Catalog, pointing to pages list in object 3 (at end) */
2971
    /* Object 2 is the Catalog, pointing to pages list in object 3 (at end) */
2961
 
2972
 
2962
    pd->pos[++pd->nobjs] = (int) ftell(pd->pdffp);
2973
    pd->pos[++pd->nobjs] = (int) ftell(pd->pdffp);
2963
    fprintf(pd->pdffp, "2 0 obj\n<<\n/Type /Catalog\n/Pages 3 0 R\n>>\nendobj\n");
2974
    fprintf(pd->pdffp, "2 0 obj\n<<\n/Type /Catalog\n/Pages 3 0 R\n>>\nendobj\n");
2964
 
2975
 
2965
    /* Object 3 will be at the end */
2976
    /* Object 3 will be at the end */
2966
 
2977
 
2967
    /* Object 4 is the standard resources dict for each page */
2978
    /* Object 4 is the standard resources dict for each page */
2968
 
2979
 
2969
    ++pd->nobjs;
2980
    ++pd->nobjs;
2970
    pd->pos[++pd->nobjs] = (int) ftell(pd->pdffp);
2981
    pd->pos[++pd->nobjs] = (int) ftell(pd->pdffp);
2971
    fprintf(pd->pdffp,
2982
    fprintf(pd->pdffp,
2972
	    "4 0 obj\n<<\n/ProcSet [/PDF /Text]\n/Font << %s %s %s %s %s %s >>\n>>\nendobj\n",
2983
	    "4 0 obj\n<<\n/ProcSet [/PDF /Text]\n/Font << %s %s %s %s %s %s >>\n>>\nendobj\n",
2973
	    "/F1 6 0 R","/F2 7 0 R","/F3 8 0 R","/F4 9 0 R","/F5 10 0 R",
2984
	    "/F1 6 0 R","/F2 7 0 R","/F3 8 0 R","/F4 9 0 R","/F5 10 0 R",
2974
	    "/F6 11 0 R");
2985
	    "/F6 11 0 R");
2975
 
2986
 
2976
    /* Object 5 is the encoding for text fonts */
2987
    /* Object 5 is the encoding for text fonts */
2977
 
2988
 
2978
    pd->pos[++pd->nobjs] = (int) ftell(pd->pdffp);
2989
    pd->pos[++pd->nobjs] = (int) ftell(pd->pdffp);
2979
    PDF_EncodeFont(pd, pd->nobjs);
2990
    PDF_EncodeFont(pd, pd->nobjs);
2980
 
2991
 
2981
    /* Objects 6, 7, 8, 9 are the fonts for the text family */
2992
    /* Objects 6, 7, 8, 9 are the fonts for the text family */
2982
    /* Object 10 is the Symbol font */
2993
    /* Object 10 is the Symbol font */
2983
    /* Object 11 is Dingbats, used for (small) circles */
2994
    /* Object 11 is Dingbats, used for (small) circles */
2984
 
2995
 
2985
    for (i = 0; i < 4; i++) {
2996
    for (i = 0; i < 4; i++) {
2986
	pd->pos[++pd->nobjs] = (int) ftell(pd->pdffp);
2997
	pd->pos[++pd->nobjs] = (int) ftell(pd->pdffp);
2987
	fprintf(pd->pdffp, "%d 0 obj\n<<\n/Type /Font\n/Subtype /Type1\n/Name /F%d\n/BaseFont /%s\n/Encoding 5 0 R\n>>\nendobj\n",
2998
	fprintf(pd->pdffp, "%d 0 obj\n<<\n/Type /Font\n/Subtype /Type1\n/Name /F%d\n/BaseFont /%s\n/Encoding 5 0 R\n>>\nendobj\n",
2988
		i+6, i+1, familyname[i]);
2999
		i+6, i+1, familyname[i]);
2989
    }
3000
    }
2990
    pd->pos[++pd->nobjs] = (int) ftell(pd->pdffp);
3001
    pd->pos[++pd->nobjs] = (int) ftell(pd->pdffp);
2991
    fprintf(pd->pdffp, "10 0 obj\n<<\n/Type /Font\n/Subtype /Type1\n/Name /F5\n/BaseFont /Symbol\n>>\nendobj\n");
3002
    fprintf(pd->pdffp, "10 0 obj\n<<\n/Type /Font\n/Subtype /Type1\n/Name /F5\n/BaseFont /Symbol\n>>\nendobj\n");
2992
    pd->pos[++pd->nobjs] = (int) ftell(pd->pdffp);
3003
    pd->pos[++pd->nobjs] = (int) ftell(pd->pdffp);
2993
    fprintf(pd->pdffp, "11 0 obj\n<<\n/Type /Font\n/Subtype /Type1\n/Name /F6\n/BaseFont /ZapfDingbats\n>>\nendobj\n");
3004
    fprintf(pd->pdffp, "11 0 obj\n<<\n/Type /Font\n/Subtype /Type1\n/Name /F6\n/BaseFont /ZapfDingbats\n>>\nendobj\n");
2994
}
3005
}
2995
 
3006
 
2996
static void PDF_endfile(PDFDesc *pd)
3007
static void PDF_endfile(PDFDesc *pd)
2997
{
3008
{
2998
    int i, startxref;
3009
    int i, startxref;
2999
    /* object 3 lists all the pages */
3010
    /* object 3 lists all the pages */
3000
 
3011
 
3001
    pd->pos[3] = (int) ftell(pd->pdffp);
3012
    pd->pos[3] = (int) ftell(pd->pdffp);
3002
    fprintf(pd->pdffp, "3 0 obj\n<<\n/Type /Pages\n/Kids [\n");
3013
    fprintf(pd->pdffp, "3 0 obj\n<<\n/Type /Pages\n/Kids [\n");
3003
    for(i = 0; i < pd->pageno; i++)
3014
    for(i = 0; i < pd->pageno; i++)
3004
	fprintf(pd->pdffp, "%d 0 R\n", pd->pageobj[i]);
3015
	fprintf(pd->pdffp, "%d 0 R\n", pd->pageobj[i]);
3005
 
3016
 
3006
    fprintf(pd->pdffp,
3017
    fprintf(pd->pdffp,
3007
	    "]\n/Count %d\n/MediaBox [0 0 %d %d]\n>>\nendobj\n",
3018
	    "]\n/Count %d\n/MediaBox [0 0 %d %d]\n>>\nendobj\n",
3008
	    pd->pageno,
3019
	    pd->pageno,
3009
	    (int) (0.5 + 72*pd->width), (int) (0.5 + 72*pd->height));
3020
	    (int) (0.5 + 72*pd->width), (int) (0.5 + 72*pd->height));
3010
 
3021
 
3011
    /* write out xref table */
3022
    /* write out xref table */
3012
 
3023
 
3013
    startxref = (int) ftell(pd->pdffp);
3024
    startxref = (int) ftell(pd->pdffp);
3014
    /* items here must be exactly 20 bytes including terminator */
3025
    /* items here must be exactly 20 bytes including terminator */
3015
    fprintf(pd->pdffp, "xref\n0 %d\n", pd->nobjs+1);
3026
    fprintf(pd->pdffp, "xref\n0 %d\n", pd->nobjs+1);
3016
    fprintf(pd->pdffp, "0000000000 65535 f \n");
3027
    fprintf(pd->pdffp, "0000000000 65535 f \n");
3017
    for(i = 1; i <= pd->nobjs; i++) {
3028
    for(i = 1; i <= pd->nobjs; i++) {
3018
	fprintf(pd->pdffp, "%010d 00000 n \n", pd->pos[i]);
3029
	fprintf(pd->pdffp, "%010d 00000 n \n", pd->pos[i]);
3019
    }
3030
    }
3020
    fprintf(pd->pdffp,
3031
    fprintf(pd->pdffp,
3021
	    "trailer\n<<\n/Size %d\n/Info 1 0 R\n/Root 2 0 R\n>>\nstartxref\n%d\n",
3032
	    "trailer\n<<\n/Size %d\n/Info 1 0 R\n/Root 2 0 R\n>>\nstartxref\n%d\n",
3022
	    pd->nobjs+1, startxref);
3033
	    pd->nobjs+1, startxref);
3023
    fprintf(pd->pdffp, "%%%%EOF\n");
3034
    fprintf(pd->pdffp, "%%%%EOF\n");
3024
 
3035
 
3025
    fclose(pd->pdffp);
3036
    fclose(pd->pdffp);
3026
}
3037
}
3027
 
3038
 
3028
 
3039
 
3029
static Rboolean PDF_Open(NewDevDesc *dd, PDFDesc *pd)
3040
static Rboolean PDF_Open(NewDevDesc *dd, PDFDesc *pd)
3030
{
3041
{
3031
    char buf[512];
3042
    char buf[512];
3032
    int i;
3043
    int i;
3033
 
3044
 
3034
    if (!LoadEncoding(pd->encpath, pd->encname, TRUE)) {
3045
    if (!LoadEncoding(pd->encpath, pd->encname, TRUE)) {
3035
	warning("problem loading encoding file");
3046
	warning("problem loading encoding file");
3036
	return FALSE;
3047
	return FALSE;
3037
    }
3048
    }
3038
    for(i = 0; i < 4 ; i++) {
3049
    for(i = 0; i < 4 ; i++) {
3039
	char const *p = Family[pd->fontfamily].afmfile[i];
3050
	char const *p = Family[pd->fontfamily].afmfile[i];
3040
	if(!PostScriptLoadFontMetrics(p, &(pd->metrics[i]),
3051
	if(!PostScriptLoadFontMetrics(p, &(pd->metrics[i]),
3041
				      familyname[i], 1)) {
3052
				      familyname[i], 1)) {
3042
	    warning("cannot read afm file %s", p);
3053
	    warning("cannot read afm file %s", p);
3043
	    return FALSE;
3054
	    return FALSE;
3044
	}
3055
	}
3045
    }
3056
    }
3046
    if(!PostScriptLoadFontMetrics("sy______.afm", &(pd->metrics[4]),
3057
    if(!PostScriptLoadFontMetrics("sy______.afm", &(pd->metrics[4]),
3047
				  familyname[4], 0)) {
3058
				  familyname[4], 0)) {
3048
	warning("cannot read afm file sy______.afm");
3059
	warning("cannot read afm file sy______.afm");
3049
	return FALSE;
3060
	return FALSE;
3050
    }
3061
    }
3051
 
3062
 
3052
    /* NB: this must be binary to get tell positions and line endings right */
3063
    /* NB: this must be binary to get tell positions and line endings right */
3053
 
3064
 
3054
    snprintf(buf, 512, pd->filename, pd->fileno + 1); /* file 1 to start */
3065
    snprintf(buf, 512, pd->filename, pd->fileno + 1); /* file 1 to start */
3055
    pd->pdffp = R_fopen(R_ExpandFileName(buf), "wb");
3066
    pd->pdffp = R_fopen(R_ExpandFileName(buf), "wb");
3056
    if (!pd->pdffp) {
3067
    if (!pd->pdffp) {
3057
	warning("cannot open `pdf' file argument `%s'", buf);
3068
	warning("cannot open `pdf' file argument `%s'", buf);
3058
	return FALSE;
3069
	return FALSE;
3059
    }
3070
    }
3060
 
3071
 
3061
    PDF_startfile(pd);
3072
    PDF_startfile(pd);
3062
    return TRUE;
3073
    return TRUE;
3063
}
3074
}
3064
 
3075
 
3065
static void PDF_Clip(double x0, double x1, double y0, double y1, NewDevDesc *dd)
3076
static void PDF_Clip(double x0, double x1, double y0, double y1, NewDevDesc *dd)
3066
{
3077
{
3067
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
3078
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
3068
 
3079
 
3069
    if(pd->inText) textoff(pd);
3080
    if(pd->inText) textoff(pd);
3070
    if(x0 != 0.0 || y0 != 0.0 || x1 != 72*pd->width || y1 != 72*pd->height)
3081
    if(x0 != 0.0 || y0 != 0.0 || x1 != 72*pd->width || y1 != 72*pd->height)
3071
	fprintf(pd->pdffp, "Q q %.2f %.2f %.2f %.2f re W n\n",
3082
	fprintf(pd->pdffp, "Q q %.2f %.2f %.2f %.2f re W n\n",
3072
		x0, y0, x1 - x0, y1 - y0);
3083
		x0, y0, x1 - x0, y1 - y0);
3073
    else fprintf(pd->pdffp, "Q q\n");
3084
    else fprintf(pd->pdffp, "Q q\n");
3074
    PDF_Invalidate(dd);
3085
    PDF_Invalidate(dd);
3075
}
3086
}
3076
 
3087
 
3077
static void PDF_Size(double *left, double *right,
3088
static void PDF_Size(double *left, double *right,
3078
		     double *bottom, double *top,
3089
		     double *bottom, double *top,
3079
		     NewDevDesc *dd)
3090
		     NewDevDesc *dd)
3080
{
3091
{
3081
    *left = dd->left;
3092
    *left = dd->left;
3082
    *right = dd->right;
3093
    *right = dd->right;
3083
    *bottom = dd->bottom;
3094
    *bottom = dd->bottom;
3084
    *top = dd->top;
3095
    *top = dd->top;
3085
}
3096
}
3086
 
3097
 
3087
static void PDF_endpage(PDFDesc *pd)
3098
static void PDF_endpage(PDFDesc *pd)
3088
{
3099
{
3089
    int here;
3100
    int here;
3090
    if(pd->inText) textoff(pd);
3101
    if(pd->inText) textoff(pd);
3091
    fprintf(pd->pdffp, "Q\n");
3102
    fprintf(pd->pdffp, "Q\n");
3092
    here = (int) ftell(pd->pdffp);
3103
    here = (int) ftell(pd->pdffp);
3093
    fprintf(pd->pdffp, "endstream\nendobj\n");
3104
    fprintf(pd->pdffp, "endstream\nendobj\n");
3094
    pd->pos[++pd->nobjs] = (int) ftell(pd->pdffp);
3105
    pd->pos[++pd->nobjs] = (int) ftell(pd->pdffp);
3095
    fprintf(pd->pdffp, "%d 0 obj\n%d\nendobj\n", pd->nobjs,
3106
    fprintf(pd->pdffp, "%d 0 obj\n%d\nendobj\n", pd->nobjs,
3096
	    here - pd->startstream);
3107
	    here - pd->startstream);
3097
}
3108
}
3098
 
3109
 
3099
static void PDF_NewPage(R_GE_gcontext *gc,
3110
static void PDF_NewPage(R_GE_gcontext *gc,
3100
			NewDevDesc *dd)
3111
			NewDevDesc *dd)
3101
{
3112
{
3102
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
3113
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
3103
    char buf[512];
3114
    char buf[512];
3104
 
3115
 
3105
    if(pd->pageno >= pd->pagemax || pd->nobjs >= 3*pd->pagemax) {
3116
    if(pd->pageno >= pd->pagemax || pd->nobjs >= 3*pd->pagemax) {
3106
	pd->pageobj = (int *)
3117
	pd->pageobj = (int *)
3107
	    realloc(pd->pageobj, 2*pd->pagemax * sizeof(int));
3118
	    realloc(pd->pageobj, 2*pd->pagemax * sizeof(int));
3108
	pd->pos = (int *) realloc(pd->pos,
3119
	pd->pos = (int *) realloc(pd->pos,
3109
				  (6*pd->pagemax + 50) * sizeof(int));
3120
				  (6*pd->pagemax + 50) * sizeof(int));
3110
	if(!pd->pos || !pd->pageobj)
3121
	if(!pd->pos || !pd->pageobj)
3111
	    error("unable to increase page limit: please shutdown the pdf device");
3122
	    error("unable to increase page limit: please shutdown the pdf device");
3112
	pd->pagemax *= 2;
3123
	pd->pagemax *= 2;
3113
    }
3124
    }
3114
 
3125
 
3115
 
3126
 
3116
    if(pd->pageno > 0) {
3127
    if(pd->pageno > 0) {
3117
	PDF_endpage(pd);
3128
	PDF_endpage(pd);
3118
	if(!pd->onefile) {
3129
	if(!pd->onefile) {
3119
	    PDF_endfile(pd);
3130
	    PDF_endfile(pd);
3120
	    pd->fileno++;
3131
	    pd->fileno++;
3121
	    snprintf(buf, 512, pd->filename, pd->fileno + 1); /* file 1 to start */
3132
	    snprintf(buf, 512, pd->filename, pd->fileno + 1); /* file 1 to start */
3122
	    pd->pdffp = R_fopen(R_ExpandFileName(buf), "wb");
3133
	    pd->pdffp = R_fopen(R_ExpandFileName(buf), "wb");
3123
	    if (!pd->pdffp)
3134
	    if (!pd->pdffp)
3124
		error("cannot open `pdf' file argument `%s'\n  please shut down the PDFdevice", buf);
3135
		error("cannot open `pdf' file argument `%s'\n  please shut down the PDFdevice", buf);
3125
	    PDF_startfile(pd);
3136
	    PDF_startfile(pd);
3126
	}
3137
	}
3127
    }
3138
    }
3128
 
3139
 
3129
    pd->pos[++pd->nobjs] = (int) ftell(pd->pdffp);
3140
    pd->pos[++pd->nobjs] = (int) ftell(pd->pdffp);
3130
    pd->pageobj[pd->pageno++] = pd->nobjs;
3141
    pd->pageobj[pd->pageno++] = pd->nobjs;
3131
    fprintf(pd->pdffp, "%d 0 obj\n<<\n/Type /Page\n/Parent 3 0 R\n/Contents %d 0 R\n/Resources 4 0 R\n>>\nendobj\n",
3142
    fprintf(pd->pdffp, "%d 0 obj\n<<\n/Type /Page\n/Parent 3 0 R\n/Contents %d 0 R\n/Resources 4 0 R\n>>\nendobj\n",
3132
	    pd->nobjs, pd->nobjs+1);
3143
	    pd->nobjs, pd->nobjs+1);
3133
    pd->pos[++pd->nobjs] = (int) ftell(pd->pdffp);
3144
    pd->pos[++pd->nobjs] = (int) ftell(pd->pdffp);
3134
    fprintf(pd->pdffp, "%d 0 obj\n<<\n/Length %d 0 R\n>>\nstream\r\n",
3145
    fprintf(pd->pdffp, "%d 0 obj\n<<\n/Length %d 0 R\n>>\nstream\r\n",
3135
	    pd->nobjs, pd->nobjs + 1);
3146
	    pd->nobjs, pd->nobjs + 1);
3136
    pd->startstream = (int) ftell(pd->pdffp);
3147
    pd->startstream = (int) ftell(pd->pdffp);
3137
    fprintf(pd->pdffp, "1 J 1 j 10 M q\n");
3148
    fprintf(pd->pdffp, "1 J 1 j 10 M q\n");
3138
    PDF_Invalidate(dd);
3149
    PDF_Invalidate(dd);
3139
    if(R_ALPHA(gc->fill) == 0) {
3150
    if(R_ALPHA(gc->fill) == 0) {
3140
	PDF_SetFill(gc->fill, dd);
3151
	PDF_SetFill(gc->fill, dd);
3141
	fprintf(pd->pdffp, "0 0 %.2f %.2f re f\n",
3152
	fprintf(pd->pdffp, "0 0 %.2f %.2f re f\n",
3142
		72.0 * pd->width, 72.0 * pd->height);
3153
		72.0 * pd->width, 72.0 * pd->height);
3143
    }
3154
    }
3144
    pd->inText = FALSE;
3155
    pd->inText = FALSE;
3145
}
3156
}
3146
 
3157
 
3147
static void PDF_Close(NewDevDesc *dd)
3158
static void PDF_Close(NewDevDesc *dd)
3148
{
3159
{
3149
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
3160
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
3150
 
3161
 
3151
    if(pd->pageno > 0) PDF_endpage(pd);
3162
    if(pd->pageno > 0) PDF_endpage(pd);
3152
    PDF_endfile(pd);
3163
    PDF_endfile(pd);
3153
    free(pd->pos); free(pd->pageobj); free(pd);
3164
    free(pd->pos); free(pd->pageobj); free(pd);
3154
}
3165
}
3155
 
3166
 
3156
static void PDF_Activate(NewDevDesc *dd) {}
3167
static void PDF_Activate(NewDevDesc *dd) {}
3157
static void PDF_Deactivate(NewDevDesc *dd) {}
3168
static void PDF_Deactivate(NewDevDesc *dd) {}
3158
 
3169
 
3159
static void PDF_Rect(double x0, double y0, double x1, double y1,
3170
static void PDF_Rect(double x0, double y0, double x1, double y1,
3160
		     R_GE_gcontext *gc,
3171
		     R_GE_gcontext *gc,
3161
		     NewDevDesc *dd)
3172
		     NewDevDesc *dd)
3162
{
3173
{
3163
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
3174
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
3164
    int code;
3175
    int code;
3165
 
3176
 
3166
    code = 2 * (R_ALPHA(gc->fill) == 0) + (R_ALPHA(gc->col) == 0);
3177
    code = 2 * (R_ALPHA(gc->fill) == 0) + (R_ALPHA(gc->col) == 0);
3167
    if (code) {
3178
    if (code) {
3168
	if(pd->inText) textoff(pd);
3179
	if(pd->inText) textoff(pd);
3169
	if(code & 2)
3180
	if(code & 2)
3170
	    PDF_SetFill(gc->fill, dd);
3181
	    PDF_SetFill(gc->fill, dd);
3171
	if(code & 1) {
3182
	if(code & 1) {
3172
	    PDF_SetLineColor(gc->col, dd);
3183
	    PDF_SetLineColor(gc->col, dd);
3173
	    PDF_SetLineStyle(gc->lty, gc->lwd, dd);
3184
	    PDF_SetLineStyle(gc->lty, gc->lwd, dd);
3174
	}
3185
	}
3175
	fprintf(pd->pdffp, "%.2f %.2f %.2f %.2f re", x0, y0, x1-x0, y1-y0);
3186
	fprintf(pd->pdffp, "%.2f %.2f %.2f %.2f re", x0, y0, x1-x0, y1-y0);
3176
	switch(code){
3187
	switch(code){
3177
	case 1: fprintf(pd->pdffp, " S\n"); break;
3188
	case 1: fprintf(pd->pdffp, " S\n"); break;
3178
	case 2: fprintf(pd->pdffp, " f\n"); break;
3189
	case 2: fprintf(pd->pdffp, " f\n"); break;
3179
	case 3: fprintf(pd->pdffp, " B\n"); break;
3190
	case 3: fprintf(pd->pdffp, " B\n"); break;
3180
	}
3191
	}
3181
    }
3192
    }
3182
}
3193
}
3183
 
3194
 
3184
/* r is in device coords */
3195
/* r is in device coords */
3185
static void PDF_Circle(double x, double y, double r,
3196
static void PDF_Circle(double x, double y, double r,
3186
		       R_GE_gcontext *gc,
3197
		       R_GE_gcontext *gc,
3187
		       NewDevDesc *dd)
3198
		       NewDevDesc *dd)
3188
{
3199
{
3189
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
3200
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
3190
    int code, tr;
3201
    int code, tr;
3191
    double xx, yy, a;
3202
    double xx, yy, a;
3192
 
3203
 
3193
    code = 2 * (R_ALPHA(gc->fill) == 0) + (R_ALPHA(gc->col) == 0);
3204
    code = 2 * (R_ALPHA(gc->fill) == 0) + (R_ALPHA(gc->col) == 0);
3194
 
3205
 
3195
    if (code) {
3206
    if (code) {
3196
	if(code & 2)
3207
	if(code & 2)
3197
	    PDF_SetFill(gc->fill, dd);
3208
	    PDF_SetFill(gc->fill, dd);
3198
	if(code & 1) {
3209
	if(code & 1) {
3199
	    PDF_SetLineColor(gc->col, dd);
3210
	    PDF_SetLineColor(gc->col, dd);
3200
	    PDF_SetLineStyle(gc->lty, gc->lwd, dd);
3211
	    PDF_SetLineStyle(gc->lty, gc->lwd, dd);
3201
	}
3212
	}
3202
	if(r > 10) { /* somewhat arbitrary, use font up to 20pt */
3213
	if(r > 10) { /* somewhat arbitrary, use font up to 20pt */
3203
            /* Use four Bezier curves, hand-fitted to quadrants */
3214
            /* Use four Bezier curves, hand-fitted to quadrants */
3204
	    double s = 0.55 * r;
3215
	    double s = 0.55 * r;
3205
	    if(pd->inText) textoff(pd);
3216
	    if(pd->inText) textoff(pd);
3206
	    fprintf(pd->pdffp, "  %.2f %.2f m\n", x - r, y);
3217
	    fprintf(pd->pdffp, "  %.2f %.2f m\n", x - r, y);
3207
	    fprintf(pd->pdffp, "  %.2f %.2f %.2f %.2f %.2f %.2f c\n",
3218
	    fprintf(pd->pdffp, "  %.2f %.2f %.2f %.2f %.2f %.2f c\n",
3208
		   x - r, y + s, x - s, y + r, x, y + r);
3219
		   x - r, y + s, x - s, y + r, x, y + r);
3209
	    fprintf(pd->pdffp, "  %.2f %.2f %.2f %.2f %.2f %.2f c\n",
3220
	    fprintf(pd->pdffp, "  %.2f %.2f %.2f %.2f %.2f %.2f c\n",
3210
		   x + s, y + r, x + r, y + s, x + r, y);
3221
		   x + s, y + r, x + r, y + s, x + r, y);
3211
	    fprintf(pd->pdffp, "  %.2f %.2f %.2f %.2f %.2f %.2f c\n",
3222
	    fprintf(pd->pdffp, "  %.2f %.2f %.2f %.2f %.2f %.2f c\n",
3212
		   x + r, y - s, x + s, y - r, x, y - r);
3223
		   x + r, y - s, x + s, y - r, x, y - r);
3213
	    fprintf(pd->pdffp, "  %.2f %.2f %.2f %.2f %.2f %.2f c\n",
3224
	    fprintf(pd->pdffp, "  %.2f %.2f %.2f %.2f %.2f %.2f c\n",
3214
		   x - s, y - r, x - r, y - s, x - r, y);
3225
		   x - s, y - r, x - r, y - s, x - r, y);
3215
	    switch(code){
3226
	    switch(code){
3216
	    case 1: fprintf(pd->pdffp, "S\n"); break;
3227
	    case 1: fprintf(pd->pdffp, "S\n"); break;
3217
	    case 2: fprintf(pd->pdffp, "f\n"); break;
3228
	    case 2: fprintf(pd->pdffp, "f\n"); break;
3218
	    case 3: fprintf(pd->pdffp, "B\n"); break;
3229
	    case 3: fprintf(pd->pdffp, "B\n"); break;
3219
	    }
3230
	    }
3220
	} else {
3231
	} else {
3221
	    /* Use char 108 in Dingbats, which is a solid disc
3232
	    /* Use char 108 in Dingbats, which is a solid disc
3222
	       afm is C 108 ; WX 791 ; N a71 ; B 35 -14 757 708 ;
3233
	       afm is C 108 ; WX 791 ; N a71 ; B 35 -14 757 708 ;
3223
	       so diameter = 0.722 * size
3234
	       so diameter = 0.722 * size
3224
	       centre = (0.396, 0.347) * size
3235
	       centre = (0.396, 0.347) * size
3225
	    */
3236
	    */
3226
	    a = 2./0.722 * r;
3237
	    a = 2./0.722 * r;
3227
	    xx = x - 0.396*a;
3238
	    xx = x - 0.396*a;
3228
	    yy = y - 0.347*a;
3239
	    yy = y - 0.347*a;
3229
	    tr = (R_ALPHA(gc->fill) == 0) + 2 * (R_ALPHA(gc->col) == 0) - 1;
3240
	    tr = (R_ALPHA(gc->fill) == 0) + 2 * (R_ALPHA(gc->col) == 0) - 1;
3230
	    if(!pd->inText) texton(pd);
3241
	    if(!pd->inText) texton(pd);
3231
	    fprintf(pd->pdffp,
3242
	    fprintf(pd->pdffp,
3232
		    "/F6 1 Tf %d Tr %.2f 0 0 %.2f %.2f %.2f Tm",
3243
		    "/F6 1 Tf %d Tr %.2f 0 0 %.2f %.2f %.2f Tm",
3233
		    tr, a, a, xx, yy);
3244
		    tr, a, a, xx, yy);
3234
	    fprintf(pd->pdffp, " (l) Tj 0 Tr\n");
3245
	    fprintf(pd->pdffp, " (l) Tj 0 Tr\n");
3235
	}
3246
	}
3236
    }
3247
    }
3237
}
3248
}
3238
 
3249
 
3239
static void PDF_Line(double x1, double y1, double x2, double y2,
3250
static void PDF_Line(double x1, double y1, double x2, double y2,
3240
		     R_GE_gcontext *gc,
3251
		     R_GE_gcontext *gc,
3241
		     NewDevDesc *dd)
3252
		     NewDevDesc *dd)
3242
{
3253
{
3243
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
3254
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
3244
 
3255
 
3245
    if(R_ALPHA(gc->col) == 0) {
3256
    if(R_ALPHA(gc->col) == 0) {
3246
	PDF_SetLineColor(gc->col, dd);
3257
	PDF_SetLineColor(gc->col, dd);
3247
	PDF_SetLineStyle(gc->lty, gc->lwd, dd);
3258
	PDF_SetLineStyle(gc->lty, gc->lwd, dd);
3248
	if(pd->inText) textoff(pd);
3259
	if(pd->inText) textoff(pd);
3249
	fprintf(pd->pdffp, "%.2f %.2f m %.2f %.2f l S\n", x1, y1, x2, y2);
3260
	fprintf(pd->pdffp, "%.2f %.2f m %.2f %.2f l S\n", x1, y1, x2, y2);
3250
    }
3261
    }
3251
}
3262
}
3252
 
3263
 
3253
static void PDF_Polygon(int n, double *x, double *y,
3264
static void PDF_Polygon(int n, double *x, double *y,
3254
			R_GE_gcontext *gc,
3265
			R_GE_gcontext *gc,
3255
			NewDevDesc *dd)
3266
			NewDevDesc *dd)
3256
{
3267
{
3257
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
3268
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
3258
    double xx, yy;
3269
    double xx, yy;
3259
    int i, code;
3270
    int i, code;
3260
 
3271
 
3261
    code = 2 * (R_ALPHA(gc->fill) == 0) + (R_ALPHA(gc->col) == 0);
3272
    code = 2 * (R_ALPHA(gc->fill) == 0) + (R_ALPHA(gc->col) == 0);
3262
 
3273
 
3263
    if (code) {
3274
    if (code) {
3264
	if(pd->inText) textoff(pd);
3275
	if(pd->inText) textoff(pd);
3265
	if(code & 2)
3276
	if(code & 2)
3266
	    PDF_SetFill(gc->fill, dd);
3277
	    PDF_SetFill(gc->fill, dd);
3267
	if(code & 1) {
3278
	if(code & 1) {
3268
	    PDF_SetLineColor(gc->col, dd);
3279
	    PDF_SetLineColor(gc->col, dd);
3269
	    PDF_SetLineStyle(gc->lty, gc->lwd, dd);
3280
	    PDF_SetLineStyle(gc->lty, gc->lwd, dd);
3270
	}
3281
	}
3271
	xx = x[0];
3282
	xx = x[0];
3272
	yy = y[0];
3283
	yy = y[0];
3273
	fprintf(pd->pdffp, "  %.2f %.2f m\n", xx, yy);
3284
	fprintf(pd->pdffp, "  %.2f %.2f m\n", xx, yy);
3274
	for(i = 1 ; i < n ; i++) {
3285
	for(i = 1 ; i < n ; i++) {
3275
	    xx = x[i];
3286
	    xx = x[i];
3276
	    yy = y[i];
3287
	    yy = y[i];
3277
	    fprintf(pd->pdffp, "  %.2f %.2f l\n", xx, yy);
3288
	    fprintf(pd->pdffp, "  %.2f %.2f l\n", xx, yy);
3278
	}
3289
	}
3279
	switch(code){
3290
	switch(code){
3280
	case 1: fprintf(pd->pdffp, "s\n"); break;
3291
	case 1: fprintf(pd->pdffp, "s\n"); break;
3281
	case 2: fprintf(pd->pdffp, "h f\n"); break;
3292
	case 2: fprintf(pd->pdffp, "h f\n"); break;
3282
	case 3: fprintf(pd->pdffp, "b\n"); break;
3293
	case 3: fprintf(pd->pdffp, "b\n"); break;
3283
	}
3294
	}
3284
    }
3295
    }
3285
 
3296
 
3286
}
3297
}
3287
 
3298
 
3288
static void PDF_Polyline(int n, double *x, double *y,
3299
static void PDF_Polyline(int n, double *x, double *y,
3289
			 R_GE_gcontext *gc,
3300
			 R_GE_gcontext *gc,
3290
			 NewDevDesc *dd)
3301
			 NewDevDesc *dd)
3291
{
3302
{
3292
    PDFDesc *pd = (PDFDesc*) dd->deviceSpecific;
3303
    PDFDesc *pd = (PDFDesc*) dd->deviceSpecific;
3293
    double xx, yy;
3304
    double xx, yy;
3294
    int i;
3305
    int i;
3295
 
3306
 
3296
    if(pd->inText) textoff(pd);
3307
    if(pd->inText) textoff(pd);
3297
    if(R_ALPHA(gc->col) == 0) {
3308
    if(R_ALPHA(gc->col) == 0) {
3298
	PDF_SetLineColor(gc->col, dd);
3309
	PDF_SetLineColor(gc->col, dd);
3299
	PDF_SetLineStyle(gc->lty, gc->lwd, dd);
3310
	PDF_SetLineStyle(gc->lty, gc->lwd, dd);
3300
	xx = x[0];
3311
	xx = x[0];
3301
	yy = y[0];
3312
	yy = y[0];
3302
	fprintf(pd->pdffp, "%.2f %.2f m\n", xx, yy);
3313
	fprintf(pd->pdffp, "%.2f %.2f m\n", xx, yy);
3303
	for(i = 1 ; i < n ; i++) {
3314
	for(i = 1 ; i < n ; i++) {
3304
	    xx = x[i];
3315
	    xx = x[i];
3305
	    yy = y[i];
3316
	    yy = y[i];
3306
	    fprintf(pd->pdffp, "%.2f %.2f l\n", xx, yy);
3317
	    fprintf(pd->pdffp, "%.2f %.2f l\n", xx, yy);
3307
	}
3318
	}
3308
	fprintf(pd->pdffp, "S\n");
3319
	fprintf(pd->pdffp, "S\n");
3309
    }
3320
    }
3310
}
3321
}
3311
 
3322
 
3312
 
3323
 
3313
static void PDF_Text(double x, double y, char *str,
3324
static void PDF_Text(double x, double y, char *str,
3314
		     double rot, double hadj,
3325
		     double rot, double hadj,
3315
		     R_GE_gcontext *gc,
3326
		     R_GE_gcontext *gc,
3316
		     NewDevDesc *dd)
3327
		     NewDevDesc *dd)
3317
{
3328
{
3318
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
3329
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
3319
    int size = (int)floor(gc->cex * gc->ps + 0.5);
3330
    int size = (int)floor(gc->cex * gc->ps + 0.5);
3320
    int face = gc->fontface;
3331
    int face = gc->fontface;
3321
    double a, b, rot1;
3332
    double a, b, rot1;
3322
 
3333
 
3323
    if(face < 1 || face > 5) face = 1;
3334
    if(face < 1 || face > 5) {
-
 
3335
	warning("attempt to use invalid font %d replaced by font 1", face);
-
 
3336
	face = 1;
-
 
3337
    }
3324
    rot1 = rot * DEG2RAD;
3338
    rot1 = rot * DEG2RAD;
3325
    a = size * cos(rot1);
3339
    a = size * cos(rot1);
3326
    b = size * sin(rot1);
3340
    b = size * sin(rot1);
3327
    if(!pd->inText) texton(pd);
3341
    if(!pd->inText) texton(pd);
3328
    if(R_ALPHA(gc->col) == 0) {
3342
    if(R_ALPHA(gc->col) == 0) {
3329
	PDF_SetFill(gc->col, dd);
3343
	PDF_SetFill(gc->col, dd);
3330
	fprintf(pd->pdffp, "/F%d 1 Tf %.2f %.2f %.2f %.2f %.2f %.2f Tm ",
3344
	fprintf(pd->pdffp, "/F%d 1 Tf %.2f %.2f %.2f %.2f %.2f %.2f Tm ",
3331
		face, a, b, -b, a, x, y);
3345
		face, a, b, -b, a, x, y);
3332
	PostScriptWriteString(pd->pdffp, str);
3346
	PostScriptWriteString(pd->pdffp, str);
3333
	fprintf(pd->pdffp, " Tj\n");
3347
	fprintf(pd->pdffp, " Tj\n");
3334
    }
3348
    }
3335
}
3349
}
3336
 
3350
 
3337
static Rboolean PDF_Locator(double *x, double *y, NewDevDesc *dd)
3351
static Rboolean PDF_Locator(double *x, double *y, NewDevDesc *dd)
3338
{
3352
{
3339
    return FALSE;
3353
    return FALSE;
3340
}
3354
}
3341
 
3355
 
3342
static void PDF_Mode(int mode, NewDevDesc* dd)
3356
static void PDF_Mode(int mode, NewDevDesc* dd)
3343
{
3357
{
3344
}
3358
}
3345
 
3359
 
3346
static void PDF_Hold(NewDevDesc *dd)
3360
static void PDF_Hold(NewDevDesc *dd)
3347
{
3361
{
3348
}
3362
}
3349
 
3363
 
3350
static double PDF_StrWidth(char *str,
3364
static double PDF_StrWidth(char *str,
3351
			   R_GE_gcontext *gc,
3365
			   R_GE_gcontext *gc,
3352
			   NewDevDesc *dd)
3366
			   NewDevDesc *dd)
3353
{
3367
{
3354
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
3368
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
3355
 
3369
 
3356
    if(gc->fontface < 1 || gc->fontface > 5) gc->fontface = 1;
3370
    if(gc->fontface < 1 || gc->fontface > 5) gc->fontface = 1;
3357
    return floor(gc->cex * gc->ps + 0.5) *
3371
    return floor(gc->cex * gc->ps + 0.5) *
3358
	PostScriptStringWidth((unsigned char *)str,
3372
	PostScriptStringWidth((unsigned char *)str,
3359
			      &(pd->metrics[gc->fontface-1]));
3373
			      &(pd->metrics[gc->fontface-1]));
3360
}
3374
}
3361
 
3375
 
3362
static void PDF_MetricInfo(int c, 
3376
static void PDF_MetricInfo(int c, 
3363
			   R_GE_gcontext *gc,
3377
			   R_GE_gcontext *gc,
3364
			   double* ascent, double* descent,
3378
			   double* ascent, double* descent,
3365
			   double* width, NewDevDesc *dd)
3379
			   double* width, NewDevDesc *dd)
3366
{
3380
{
3367
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
3381
    PDFDesc *pd = (PDFDesc *) dd->deviceSpecific;
3368
 
3382
 
3369
    if(gc->fontface < 1 || gc->fontface > 5) gc->fontface = 1;
3383
    if(gc->fontface < 1 || gc->fontface > 5) gc->fontface = 1;
3370
    PostScriptMetricInfo(c, ascent, descent, width,
3384
    PostScriptMetricInfo(c, ascent, descent, width,
3371
			 &(pd->metrics[gc->fontface-1]));
3385
			 &(pd->metrics[gc->fontface-1]));
3372
    *ascent = floor(gc->cex * gc->ps + 0.5) * *ascent;
3386
    *ascent = floor(gc->cex * gc->ps + 0.5) * *ascent;
3373
    *descent = floor(gc->cex * gc->ps + 0.5) * *descent;
3387
    *descent = floor(gc->cex * gc->ps + 0.5) * *descent;
3374
    *width = floor(gc->cex * gc->ps + 0.5) * *width;
3388
    *width = floor(gc->cex * gc->ps + 0.5) * *width;
3375
}
3389
}